Python日志记录模块:重复的控制台输出[IPython Notebook/Qtconsole]

Jia*_* Li 12 python logging

我正在尝试使用python logging模块,但在这里有点困惑.下面是一个标准的脚本来创建一个logger第一,然后创建并添加file handlerconsole handlerlogger.

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')
Run Code Online (Sandbox Code Playgroud)

我在新启动的内核上运行它.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
Run Code Online (Sandbox Code Playgroud)

我想那些带有时间戳的日志消息来自用户定义的console handler,但重复的消息来自哪里?我可以摆脱它们,比如说,只保留其他所有线路吗?任何帮助表示赞赏.

Pad*_*ham 6

这里提出这个问题.

观察结果如下:在普通的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>]
Run Code Online (Sandbox Code Playgroud)

但是,在IPython笔记本中,立即安装了默认的stderr根记录器:

In [1]: import logging

In [2]: logging.getLogger().handlers
Out[2]: [<logging.StreamHandler at 0x35eedd8>]
Run Code Online (Sandbox Code Playgroud)

也许我错过了一些东西,但我认为在笔记本中,不应该自动安装处理程序,原因有很多:

  1. 这将使标准python,IPython控制台和IPython笔记本之间的默认日志记录配置保持一致.
  2. 一旦用户使用根记录器写入日志消息,处理程序就会自动安装,因此不容易错过日志消息.
  3. 使用当前行为,配置子记录器的库以及该子记录器的处理程序可能很容易使用应该只在日志文件(或其他地方)中的调试消息向笔记本发送垃圾邮件.例如,astropy似乎有这样的问题,我和我自己的库遇到了同样的问题.问题是对于这样的库,没有"干净"的方法.该库可以在导入时删除根记录器的处理程序,这是hack-y.它可以将自己的记录器propagate属性设置为False,以便日志消息不会传播到根记录器,但这不仅会禁止调试输出进入笔记本,还会禁用更严重的消息.此外,它还可以防止用户在需要时实际捕获所有日志输出.

另一种方法是添加一个配置选项,为自动添加的流处理程序指定日志级别,以便可以忽略不太严重的消息自动显示在笔记本中.但这仍然会使IPython控制台和IPython笔记本之间的行为不同.

确保没有默认处理程序集的唯一缺点是,正在使用的某些库/笔记本可能依赖于此行为并积极解决它,例如,如果它们检测到它们在ipython中运行,则禁用它们自己的处理程序笔记本.这种情况可能会因这种变化而破裂.

因此,设置logger.propagateFalse或使用reload(logging)将防止重复输出,但根据会有副作用.

请注意,reload在较新版本的python中不可用(3.4,可能更早).从3.1开始,请参阅importlib.reload