在多个模块中使用Python日志logging

我有一个小型的Python项目,具有以下结构 –

Project -- pkg01 -- test01.py -- pkg02 -- test02.py -- logging.conf 

我打算使用默认日志logging模块将消息打印到标准输出和日志文件。 要使用日志logging模块,需要进行一些初始化 –

 import logging.config logging.config.fileConfig('logging.conf') logr = logging.getLogger('pyApp') logr.info('testing') 

目前,我开始logging消息之前,我在每个模块执行此初始化。 是否可以在一个地方只执行一次这样的初始化,以便通过在整个项目中进行日志logging来重复使用相同的设置?

最好的做法是在每个模块中都有一个像这样定义的logging器:

 import logging logger = logging.getLogger(__name__) 

靠近模块的顶部,然后在模块的其他代码中做例如

 logger.debug('My message with %s', 'variable data') 

如果您需要细分模块内部的日志logging活动,请使用例如

 loggerA = logging.getLogger(__name__ + '.A') loggerB = logging.getLogger(__name__ + '.B') 

并根据情况login到loggerAloggerB

在你的主程序中,例如:

 def main(): "your program code" if __name__ == '__main__': import logging.config logging.config.fileConfig('/path/to/logging.conf') main() 

要么

 def main(): import logging.config logging.config.fileConfig('/path/to/logging.conf') # your program code if __name__ == '__main__': main() 

在这里可以看到从多个模块login, 在这里logging代码的configuration,这些代码将被其他代码用作库模块。

更新:当调用fileConfig() ,如果您使用的是Python 2.6或更高版本,则可能需要指定disable_existing_loggers=False (请参阅文档以获取更多信息)。 为了向后兼容,默认值为True ,这会导致所有现有的logging器被fileConfig()禁用,除非它们或其祖先在configuration中明确指定。 将值设置为False ,现有的logging器将被保留。 如果使用Python 2.7 / Python 3.2或更高版本,您可能希望考虑比fileConfig()更好的dictConfig() API,因为它可以更好地控制configuration。

实际上,每个logging器都是父级包logging器的子级(即package.subpackage.modulepackage.subpackage)inheritanceconfigurationpackage.subpackage) ,所以您只需要configuration根logging器即可。 这可以通过logging.config.fileConfig (您自己的logging器configuration)或logging.basicConfig (设置根logging器)来实现。 安装日志logging在你的入口模块( __main__.py或任何你想运行,例如main_script.py也适用)

使用basicConfig:

 # package/__main__.py import logging import sys logging.basicConfig(stream=sys.stdout, level=logging.INFO) 

使用fileConfig:

 # package/__main__.py import logging import logging.config logging.config.fileConfig('logging.conf') 

然后使用以下命令创build每个logging器:

 # package/submodule.py # or # package/subpackage/submodule.py import logging log = logging.getLogger(__name__) log.info("Hello logging!") 

有关更多信息,请参阅高级logging教程 。

我总是这样做如下。

使用一个Python文件来configuration我的日志为单身模式,名为“ log_conf.py

 #-*-coding:utf-8-*- import logging.config def singleton(cls): instances = {} def get_instance(): if cls not in instances: instances[cls] = cls() return instances[cls] return get_instance() @singleton class Logger(): def __init__(self): logging.config.fileConfig('logging.conf') self.logr = logging.getLogger('root') 

在其他模块中,只需导入configuration。

 from log_conf import Logger Logger.logr.info("Hello") 

这是一个简单而有效的单一模式。

扔在另一个解决scheme。

在我的模块的主要初始化我有这样的:

 import logging def get_module_logger(mod_name): logger = logging.getLogger(mod_name) handler = logging.StreamHandler() formatter = logging.Formatter( '%(asctime)s %(name)-12s %(levelname)-8s %(message)s') handler.setFormatter(formatter) logger.addHandler(handler) logger.setLevel(logging.DEBUG) return logger 

然后在每个class级我需要一个logging器,我做:

 from [modname] import get_module_logger logger = get_module_logger(__name__) 

当日志丢失时,您可以通过它们来自的模块区分它们的源。

Yarkee的解决scheme似乎更好。 我想补充一点 –

 class Singleton(type): _instances = {} def __call__(cls, *args, **kwargs): if cls not in cls._instances.keys(): cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs) return cls._instances[cls] class LoggerManager(object): __metaclass__ = Singleton _loggers = {} def __init__(self, *args, **kwargs): pass @staticmethod def getLogger(name=None): if not name: logging.basicConfig() return logging.getLogger() elif name not in LoggerManager._loggers.keys(): logging.basicConfig() LoggerManager._loggers[name] = logging.getLogger(str(name)) return LoggerManager._loggers[name] log=LoggerManager().getLogger("Hello") log.setLevel(level=logging.DEBUG) 

所以LoggerManager可以是整个应用程序的插件。 希望它是有道理的和有价值的。

你也可以拿出这样的东西!

 def get_logger(name=None): default = "__app__" formatter = logging.Formatter('%(levelname)s: %(asctime)s %(funcName)s(%(lineno)d) -- %(message)s', datefmt='%Y-%m-%d %H:%M:%S') log_map = {"__app__": "app.log", "__basic_log__": "file1.log", "__advance_log__": "file2.log"} if name: logger = logging.getLogger(name) else: logger = logging.getLogger(default) fh = logging.FileHandler(log_map[name]) fh.setFormatter(formatter) logger.addHandler(fh) logger.setLevel(logging.DEBUG) return logger 

现在,如果在一个单独的模块中定义了上述内容,并且在其他模块中导入了日志logging,则可以在同一模块中使用多个logging器。

 a=get_logger("__app___") b=get_logger("__basic_log__") a.info("Starting logging!") b.debug("Debug Mode") 

其中几个答案表明,在你做的模块的顶部

 import logging logger = logging.getLogger(__name__) 

我的理解是这被认为是非常糟糕的做法 。 原因是文件configuration将默认禁用所有现有的logging器。 例如

 #my_module import logging logger = logging.getLogger(__name__) def foo(): logger.info('Hi, foo') class Bar(object): def bar(self): logger.info('Hi, bar') 

而在你的主要模块中:

 #main import logging # load my module - this now configures the logger import my_module # This will now disable the logger in my module by default, [see the docs][1] logging.config.fileConfig('logging.ini') my_module.foo() bar = my_module.Bar() bar.bar() 

现在,logging.ini中指定的日志将为空,因为现有的日志logging程序已被fileconfig调用禁用。

虽然是肯定可以解决这个问题(disable_existing_Loggers = False),你的图书馆的许多客户端实际上不会知道这种行为,并将不会收到您的日志。 通过始终在本地调用logging.getLogger,使您的客户变得轻松。 提示:我从Victor Lin的网站了解到这个行为。

所以好的做法是总是在本地调用logging.getLogger。 例如

 #my_module import logging logger = logging.getLogger(__name__) def foo(): logging.getLogger(__name__).info('Hi, foo') class Bar(object): def bar(self): logging.getLogger(__name__).info('Hi, bar') 

另外,如果在main中使用fileconfig,请设置disable_existing_loggers = False,以防库devise人员使用模块级logging器实例。