使用Python日志模块时重复日志输出

我正在使用Pythonlogging器。 以下是我的代码:

import os import time import datetime import logging class Logger : def myLogger(self): logger = logging.getLogger('ProvisioningPython') logger.setLevel(logging.DEBUG) now = datetime.datetime.now() handler=logging.FileHandler('/root/credentials/Logs/ProvisioningPython'+ now.strftime("%Y-%m-%d") +'.log') formatter = logging.Formatter('%(asctime)s %(levelname)s %(message)s') handler.setFormatter(formatter) logger.addHandler(handler) return logger 

我遇到的问题是,我在每个logger.info调用的日志文件中获取多个条目。 我该如何解决这个问题?

logging.getLogger()已经是一个单例。 ( 文档 )

问题是每次调用myLogger() ,都会向实例添加另一个处理程序,这会导致重复的日志。

也许这样?

 import os import time import datetime import logging loggers = {} def myLogger(name): global loggers if loggers.get(name): return loggers.get(name) else: logger = logging.getLogger(name) logger.setLevel(logging.DEBUG) now = datetime.datetime.now() handler = logging.FileHandler( '/root/credentials/Logs/ProvisioningPython' + now.strftime("%Y-%m-%d") + '.log') formatter = logging.Formatter('%(asctime)s %(levelname)s %(message)s') handler.setFormatter(formatter) logger.addHandler(handler) loggers.update(dict(name=logger)) return logger 
 import datetime import logging class Logger : def myLogger(self): logger=logging.getLogger('ProvisioningPython') if not len(logger.handlers): logger.setLevel(logging.DEBUG) now = datetime.datetime.now() handler=logging.FileHandler('/root/credentials/Logs/ProvisioningPython'+ now.strftime("%Y-%m-%d") +'.log') formatter = logging.Formatter('%(asctime)s %(levelname)s %(message)s') handler.setFormatter(formatter) logger.addHandler(handler) return logger 

为我做了诡计

使用python 2.7

Logger.myLogger()地调用Logger.myLogger() 。 将logging器实例存储到某个地方并重新使用。

另外请注意,如果您在添加任何处理程序之前login,则会创build一个默认的StreamHandler(sys.stderr)

你的logging器应该像单身一样工作。 你不应该多创build一次。 下面是它可能的样子:

 import os import time import datetime import logging class Logger : logger = None def myLogger(self): if None == self.logger: self.logger=logging.getLogger('ProvisioningPython') self.logger.setLevel(logging.DEBUG) now = datetime.datetime.now() handler=logging.FileHandler('ProvisioningPython'+ now.strftime("%Y-%m-%d") +'.log') formatter = logging.Formatter('%(asctime)s %(levelname)s %(message)s') handler.setFormatter(formatter) self.logger.addHandler(handler) return self.logger s = Logger() m = s.myLogger() m2 = s.myLogger() m.info("Info1") m2.info("info2") 

从Python 3.2开始,您可以检查处理程序是否已经存在,如果是,请在添加新的处理程序之前将其清除。 debugging时这非常方便,代码包含logging器初始化

 if (logger.hasHandlers()): logger.handlers.clear() logger.addHandler(handler) 

logging器的实现已经是单身。

对logging.getLogger('someLogger')的多次调用返回对同一个logging器对象的引用。 不仅在同一个模块中,而且在各个模块中都是如此,只要它在同一个Python解释器进程中。 对同一个对象的引用是真实的; 此外,应用程序代码可以在一个模块中定义和configuration一个父logging器,并在一个单独的模块中创build(但不configuration)一个子logging器,并且所有对该孩子的logging器调用都将传递给父代。 这是一个主要模块

源 – 在多个模块中使用日志logging

所以你应该利用这个方法是 –

假设我们已经在主模块中创build并configuration了一个名为“main_logger”的logging器(它简单地configurationlogging器,不会返回任何东西)。

 # get the logger instance logger = logging.getLogger("main_logger") # configuration follows ... 

现在在一个子模块中,如果我们在命名层次结构'main_logger.sub_module_logger'之后创build一个子日志logging器,我们不需要在子模块中进行configuration。 只要按照命名层次结构创buildlogging器就足够了。

 # get the logger instance logger = logging.getLogger("main_logger.sub_module_logger") # no configuration needed # it inherits the configuration from the parent logger ... 

而且它也不会添加重复的处理程序。

看到这个问题更详细的答案。

当您通过importlib.reload重新加载您的模块(出于与接受的答案中所解释的相同的原因)时,也可能发生Double(或者triple或..-基于重载次数)logging器输出。 我只是为了将来的参考添加这个答案,因为它花了我一段时间来弄清楚为什么我的输出是dupli(三)cated。

一个简单的解决方法就像

 logger.handlers[:] = [handler] 

这样你可以避免将新的处理程序追加到底层的“处理程序”列表中。

你可以得到特定logging器的所有处理程序列表,所以你可以做这样的事情

 logger = logging.getLogger(logger_name) handler_installed = False for handler in logger: # Here your condition to check for handler presence if isinstance(handler, logging.FileHandler) and handler.baseFilename == log_filename: handler_installed = True break if not handler_installed: logger.addHandler(your_handler) 

在上面的例子中,我们检查指定文件的处理程序是否已经挂钩到logging器,但是有权访问所有处理程序的列表,使您能够决定哪些条件应该添加另一个处理程序。

今天有这个问题。 由于我的函数是@staticmethod上述build议已解决随机()。

看起来像这样:

 import random logger = logging.getLogger('ProvisioningPython.{}'.format(random.random())) 
 from logging.handlers import RotatingFileHandler import logging import datetime # stores all the existing loggers loggers = {} def get_logger(name): # if a logger exists, return that logger, else create a new one global loggers if name in loggers.keys(): return loggers[name] else: logger = logging.getLogger(name) logger.setLevel(logging.DEBUG) now = datetime.datetime.now() handler = logging.FileHandler( 'path_of_your_log_file' + now.strftime("%Y-%m-%d") + '.log') formatter = logging.Formatter('%(asctime)s %(levelname)s %(message)s') handler.setFormatter(formatter) logger.addHandler(handler) loggers.update(dict(name=logger)) return logger