写在篇前
logging是Python的一个标准库,其中定义的函数和类为应用程序和库的开发实现了一个灵活的事件日志系统。Python logging 的配置由四个部分组成:Logger、Handlers、Filter、Formatter。本篇博客将依次介绍这四个主要部分以及logging的基本应用。
在开始之前,我们有必要先了解一下,什么时候我们才有必要使用logging模块,什么时候抛出异常(raise Exception
),什么时候使用简单的print
函数即可,官方文档给我们总结了一个表格:
Task you want to perform | The best tool for the task |
---|---|
命令行终端输出或则程序一般的输出情景 | print() |
报告程序正常运行期间发生的事件(例如,状态监视或故障调查) | logging.info() (或则 logging.debug() 用于诊断目的细节输出) |
发出有关特定运行时事件的警告 | warnings.warn() : 用于如果问题是可以避免的,且应修改应用程序以消除警告的情景;logging.warning() 用于如果应用程序无法处理该情况,但仍应注意该事件的情景。 |
报告有关特定运行时事件的错误 | Raise an exception |
报告在不引发异常的情况下抑制错误(例如,长时间运行的服务器进程中的错误处理程序) | logging.error() , logging.exception() 或则logging.critical() 适用于特定错误和应用程序域 |
Loggers
logger是暴露给代码进行日志操作的接口。需要注意的是,logger不应该直接实例化,而应通过模块级函数logging.getLogger(name)
创建。如果name是具有层级结构的命名方式,则logger之间也会有层级关系。如name为foo.bar
,foo.bar.baz
, foo.bam
的logger是foo
的子孙,默认子logger日志会向父logger传播,可以通过logger.propagate=False
禁止;对具有相同名称的getLogger()
的多次调用将始终返回同一Logger对象的引用。logger对象的功能包括以下三项:
- 向应用程序暴露
info
、debug
等方法,用于程序运行时进行日志记录; - 根据log level(默认过滤工具)或Filter对象确定要处理的日志消息;
- 将日志消息传递给所有感兴趣的Log Handler;
另外,需要理清以下两个概念:
-
Log Record
Each message that is written to the
Logger
is aLog Record
. 可以使用makeLogRecord()
函数创建record对象(一般用不上),record对象常用的属性如下,全部属性请参考官方文档:record.levelname
# record levelrecord.levelno
# record level numberrecord.msg
# record承载的日志消息record.pathname
# emit该日志消息的程序文件record.lineno
# emit该日志消息的程序行号record.getMessage()
# 同record.msg
从python 3.2起,logging模块提供了工厂函数
getLogRecordFactory()
和setLogRecordFactory()
方便、支持用户自定义record属性。old_factory = logging.getLogRecordFactory() def record_factory(*args, **kwargs): record = old_factory(*args, **kwargs) record.custom_attribute = 0xdecafbad return record logging.setLogRecordFactory(record_factory)
-
Log Level
每个logger都需要设置一个log level,该log level描述了logger将处理日志消息的级别; 每个log record也具有一个log Level,指示该特定日志消息的级别。 log record还可以包含被记录事件的metadata,包括诸如堆栈跟踪或错误代码之类的详细信息。如果设置了logger的log level,系统便只会输出 level 数值大于或等于该 level 的的日志结果,例如我们设置了输出日志 level 为 INFO,那么输出级别小于 INFO 的日志,如DEBUG 和 NOSET 级别的消息不会输出。logger还有一个effective level的概念,如果logger没有显式设置log level,则使用其parent logger的log level作为其effective level,其中root logger的默认log level是
WARNING
。-
NOTEST
:lowest level# Level Num 0 logger.setLevel(level=logging.NOTEST)
-
DEBUG
: Low level system information for debugging purposes# Level Num 10 logger.setLevel(level=logging.DEBUG logger.debug('Debugging')
-
INFO
: General system information# Level Num 20 logger.setLevel(level=logging.INFO) logger.info('This is a log info')
-
WARNING
: Information describing a minor problem that has occurred.# Level Num 30,默认是该level logger.setLevel(level=logging.WARNING) logger.warning('Warning exists') logger.warn('Warning exists') # deprecated
-
ERROR
: Information describing a major problem that has occurred.# Level Num 40 logger.setLevel(level=logging.ERROR) logger.error('some error occur')
-
CRITICAL
: Information describing a critical problem that has occurred.# Level Num 50 logger.setLevel(level=logging.NOTEST) logger.critical('critical err occur') logger.fatal('fatal error occur')
-
上面各个函数还有一个统一的调用方式logger.log(level, msg, exc_info=True)
,其中,level
是指上面标注的level num
,exc_info
指示是否打印执行信息;Logger.exception()
创建与 Logger.error()
相似的日志消息,不同之处是, Logger.exception()
同时还记录当前的堆栈追踪,请仅从异常处理程序调用此方法。
logger对象还有一些其他属性、方法值得关注:
>>>logger = logging.getLogger('main') # 如果不指定name将会返回root logger
>>>logger.setLevel(level=logging.DEBUG)
>>>logger.disabled # False
>>>logger.propagate=False
>>>logger.getEffectiveLevel() # 10
>>>logger.isEnabledFor(20) # True
>>>logging.disable(20)
>>>logger.isEnabledFor(20) # False
>>>logger.isEnabledFor(30) # True
>>>child_logger = logger.getChild('def.ghi') # <Logger main.def.ghi (DEBUG)>
# Filter
addFilter(filter)
removeFilter(filter)
# handler
logger.hasHandlers() # False
addHandler(hdlr)
removeHandler(hdlr)
关于上面各种Level的调用情景,官方文档也给出了相应说明:
Level | When it’s used |
---|---|
DEBUG |
Detailed information, typically of interest only when diagnosing problems. |
INFO |
Confirmation that things are working as expected. |
WARNING |
An indication that something unexpected happened, or indicative of some problem in the near future (e.g. ‘disk space low’). The software is still working as expected. |
ERROR |
Due to a more serious problem, the software has not been able to perform some function. |