在多个类中记录日志并包含模块名称
我想用日志模块来代替打印输出调试信息和文档。我的目标是在控制台上以DEBUG级别打印信息,同时以INFO级别记录到文件中。
我看了很多关于日志模块的文档、食谱和其他教程,但还是搞不清楚怎么按照我想要的方式使用它。(我用的是python25)
我希望在我的日志文件中能看到写入日志的模块名称。
文档上说我应该使用 logger = logging.getLogger(__name__)
,但是我该怎么在其他模块/包中的类里声明日志记录器,以便它们使用和主日志记录器相同的处理器呢?为了识别“父级”,我可以用 logger = logging.getLogger(parent.child)
,但我怎么知道是谁调用了这个类/方法呢?
下面的例子展示了我的问题,如果我运行这个,输出中只会有 __main__
的日志,而忽略了 Class
中的日志。
这是我的 Mainfile:
# main.py
import logging
from module import Class
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)
# create file handler which logs info messages
fh = logging.FileHandler('foo.log', 'w', 'utf-8')
fh.setLevel(logging.INFO)
# create console handler with a debug log level
ch = logging.StreamHandler()
ch.setLevel(logging.DEBUG)
# creating a formatter
formatter = logging.Formatter('- %(name)s - %(levelname)-8s: %(message)s')
# setting handler format
fh.setFormatter(formatter)
ch.setFormatter(formatter)
# add the handlers to the logger
logger.addHandler(fh)
logger.addHandler(ch)
if __name__ == '__main__':
logger.info('Script starts')
logger.info('calling class Class')
c = Class()
logger.info('calling c.do_something()')
c.do_something()
logger.info('calling c.try_something()')
c.try_something()
模块:
# module.py
imnport logging
class Class:
def __init__(self):
self.logger = logging.getLogger(__name__) # What do I have to enter here?
self.logger.info('creating an instance of Class')
self.dict = {'a':'A'}
def do_something(self):
self.logger.debug('doing something')
a = 1 + 1
self.logger.debug('done doing something')
def try_something(self):
try:
logging.debug(self.dict['b'])
except KeyError, e:
logging.exception(e)
在 控制台 的输出:
- __main__ - INFO : Script starts
- __main__ - INFO : calling class Class
- __main__ - INFO : calling c.do_something()
- __main__ - INFO : calling c.try_something()
No handlers could be found for logger "module"
另外:有没有办法在我的日志文件中获取发生日志的模块名称,而不需要像上面那样在每个类中声明一个新的日志记录器?而且这样的话,每次我想记录日志都得用 self.logger.info()
。我更希望在整个代码中使用 logging.info()
或 logger.info()
。
是不是全局日志记录器可能是这个问题的正确答案?但那样我就无法在日志中看到错误发生的模块了……
最后一个问题:这样做算不算符合Python的风格?或者有没有更好的建议来正确处理这些事情。
2 个回答
一般来说,推荐的日志记录设置是每个模块最多有一个日志记录器。
如果你的项目是正确打包的,__name__
的值会是"mypackage.mymodule"
,但在你的主文件中,它的值会是"__main__"
。
如果你想要更详细的上下文信息,比如记录消息的代码部分,你可以用一个格式化字符串来设置你的格式器,比如%(funcName)s
,这样就会把函数名加到所有的消息里。
如果你真的想要每个类都有自己的日志记录器,你可以这样做:
class MyClass:
def __init__(self):
self.logger = logging.getLogger(__name__+"."+self.__class__.__name__)
在你的主模块中,你正在设置一个名为 '__main__'
的日志记录器(或者在你的情况下,__name__
代表的名字)。而在 module.py 里,你使用的是一个不同的日志记录器。你需要为每个模块单独配置日志记录器,或者你可以在主模块中配置根日志记录器(通过配置 logging.getLogger()
),这样就会默认应用到你项目中的所有日志记录器。
我建议使用配置文件来设置日志记录器。这个链接可以让你了解一些好的实践: http://victorlin.me/posts/2012/08/26/good-logging-practice-in-python
补充:在你的格式化器中使用 %(module) 来在日志信息中包含模块名称。