我正在尝试使用python logging
模块,但在这里有点困惑。以下是首先创建logger
,然后创建file handler
和console handler
logger
并添加import logging
logger = logging.getLogger('logging_test')
logger.setLevel(logging.DEBUG)
print(len(logger.handlers)) # output: 0
# create file handler which logs even debug messages
fh = logging.FileHandler('/home/Jian/Downloads/spam.log', mode='w')
fh.setLevel(logging.DEBUG)
# create console handler with a higher log level
ch = logging.StreamHandler()
ch.setLevel(logging.DEBUG)
# create formatter and add it to the handlers
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
ch.setFormatter(formatter)
fh.setFormatter(formatter)
# add the handlers to logger
logger.addHandler(ch)
logger.addHandler(fh)
print(len(logger.handlers)) # output: 2
# write some log messages
logger.debug('debug message')
logger.info('info message')
logger.warn('warn message')
logger.error('error message')
logger.critical('critical message')
的标准脚本。
file handler
我在新启动的内核上运行它。 2015-07-14 10:59:26,942 - logging_test - DEBUG - debug message
DEBUG:logging_test:debug message
2015-07-14 10:59:26,944 - logging_test - INFO - info message
INFO:logging_test:info message
2015-07-14 10:59:26,944 - logging_test - WARNING - warn message
WARNING:logging_test:warn message
2015-07-14 10:59:26,945 - logging_test - ERROR - error message
ERROR:logging_test:error message
2015-07-14 10:59:26,946 - logging_test - CRITICAL - critical message
CRITICAL:logging_test:critical message
按预期工作。但是在控制台输出中,我得到了某种重复的消息:
console handler
我认为那些带有时间戳的日志消息来自用户定义的MailItem.Printout
,但重复的消息来自哪里?我可以摆脱它们,比如说,只保留其他所有线路吗?任何帮助表示赞赏。
答案 0 :(得分:6)
问题已经提出here。
观察结果如下:在普通的python或IPython控制台中,在根记录器本身用于发出日志消息之前,没有安装根记录器的处理程序:
In [1]: import logging
In [2]: logging.getLogger().handlers
Out[2]: []
In [3]: logging.warn('Something happened!')
WARNING:root:Something happened!
In [4]: logging.getLogger().handlers
Out[4]: [<logging.StreamHandler at 0x42acef0>]
但是,在IPython笔记本中,立即安装了默认的stderr根记录器:
In [1]: import logging
In [2]: logging.getLogger().handlers
Out[2]: [<logging.StreamHandler at 0x35eedd8>]
也许我错过了什么,但我认为在笔记本中,不应该自动安装处理程序,原因有很多:
propagate
属性设置为False
,这样日志消息就不会传播到根记录器,但这不仅会禁止调试输出进入笔记本,还会禁止更严重的消息。此外,它还可以防止用户实际捕获所有日志输出。另一种方法可能是添加一个配置选项,为自动添加的流处理程序指定日志级别,以便可以忽略不太严重的消息自动显示在笔记本中。但这仍然会使IPython控制台和IPython笔记本之间的行为不同。
我确定没有默认处理程序集的唯一缺点是,正在使用的某些库/笔记本可能依赖于此行为并主动解决它,例如,如果它们检测到它们正在运行,则禁用它们自己的处理程序在ipython笔记本中。这种情况可能会因这种变化而破裂。
因此,将logger.propagate
设置为False
或使用reload(logging)
可以防止重复输出,但视情况会产生副作用。
请注意,reload
在较新版本的python中不可用(3.4,可能更早)。从3.1开始,请参阅importlib.reload
答案 1 :(得分:2)
执行时
# create console handler with a higher log level
ch = logging.StreamHandler()
ch.setLevel(logging.DEBUG)
您正在创建另一个StreamHandler。 要解决您的问题,您应该从iPython中捕获StreamHandler:
import logging
handlers = logging.getLogger().handlers
for h in handlers:
if isinstance(h, logging.StreamHandler):
handler_console = h
break
如果它不存在,您可以创建自己的:
if handler_console is None:
handler_console = logging.StreamHandler()
最后根据需要格式化(设置其他属性):
if handler_console is not None:
# first we need to remove to avoid duplication
logging.getLogger().removeHandler(handler_console)
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
handler_console.setFormatter(formatter)
# then add it back
logger.addHandler(handler_console)
答案 2 :(得分:1)
我的解决方案是:
import logging
logger = logging.getLogger()
logger.propagate = False