日志输出

日志在问题分析时必不可少,好的程序应该输出足够的日志信息。

那么,用 Python 语言开发程序时,如何输出日志呢?

—— logging 模块!

  1. >>> import logging
  2. >>> logging.warning('something wrong happended.')
  3. WARNING:root:Something wrong happended.
  4. >>> logging.info('seems good!')

这是一个入门级例子,导入 logging 模块后,调用 warning 方法即可输出警告信息。

日志级别

日志输出视轻重缓急,可分为多个级别。例子还调用 info 方法输出一条普通信息,级别比警告信息低。Python 支持的日志级别包括:

表格-1 日志级别
名称数值方法含义
CRITICALlogging.CRITICALlogger.critical严重错误
ERRORlogging.ERRORlogger.error错误
WARNINGlogging.WARNINGlogger.warning警告
INFOlogging.INFOlogger.info普通信息
DEBUGlogging.DEBUGlogger.debug调试信息
NOTSETlogging.NOTSET 未指定

注意到,例子中 info 输出的普通信息并没有真正打印到屏幕上,这是因为默认的 logger 对象只输出较高级别日志。为了输出想要的级别,我们需要自行定制 Logger 对象。

日志对象

Logger 对象通过 getLogger 方法创建:

  1. >>> logger = logging.getLogger(__name__)
  2. >>> logger.setLevel(logging.INFO)
  3. >>> logger.info('you must be able to see me!')
  4. INFO:__main__:you must be able to see me!

调用 Logger 对象 setLevel 方法设置日志输出级别,后续将忽略比该级别低的日志。调用 debug 方法输出日志将被忽略:

  1. >>> logger.debug('you cant see me now!')

更多定制方法,请查看 帮助文档

  1. >>> help(logger)

日志处理器

前面几个例子,日志均输出到标准输出,因此我们可以在屏幕中看到。当然了,日志还可以输出到文件,甚至可以通过网络发送出去,这都是通过 Handler 对象控制的。

标准输出

日志对象默认输出到标准输出,等价于:

  1. logger_handler = logging.StreamHandler(sys.stdout)
  2.  
  3. logger = logging.getLogger(__name__)
  4. logger.setLevel(logging.DEBUG)
  5. logger.addHandler(logger_handler)

可以进一步控制处理器可以输出的 日志级别

  1. logger_handler = logging.StreamHandler(sys.stdout)
  2. logger_handler.setLevel(logging.WARNING)

这样一来,只有不低于 WARNING 级别的日志才会被该处理器处理。需要注意的是, Logger 对象以及 Handler 对象级别同时影响日志输出行为。

文件

相比标准输出,将日志输出到文件更为妥当,文件可以保留一定的历史待查。

日志格式

采用默认格式输出的日志非常丑陋,信息量也不够,甚至连时间都没有!因此,需要根据应用需求,灵活调整日志输出格式。为 Handler 对象自定义格式:

  1. import logging, sys
  2.  
  3. FMT = '%(asctime)s %(levelname) 8s: [%(filename)s:%(lineno)d] [%(processName)s:%(process)d %(threadName)s] - %(message)s'
  4. DATEFMT = '[%Y-%m-%d %H:%M:%S]'
  5.  
  6. logger_handler = logging.StreamHandler(sys.stdout)
  7. logger_handler.setLevel(logging.DEBUG)
  8.  
  9. formatter = logging.Formatter(fmt=FMT, datefmt=DATEFMT)
  10. logger_handler.setFormatter(formatter)
  11.  
  12. logger = logging.getLogger(__name__)
  13. logger.setLevel(logging.DEBUG)
  14. logger.addHandler(logger_handler)

关键代码是 9-10 行,初始化一个格式化器,并设置到 Handler 对象上。初始化器需要两个参数, fmt 指定日志格式, datefmt 指定日期格式。除了日志内容,日志记录可以注入 时间级别代码文件名代码行数进程名进程ID线程名 等信息。

例子输出大致如下,可以看到 格式更为美观,信息更为丰富 了:

  1. >>> logger.info('Hello, world!')
  2. [2019-01-08 11:25:50] INFO: [<stdin>:1] [MainProcess:99324 MainThread] - Hello, world!

下一步

订阅更新,获取更多学习资料,请关注我们的 微信公众号

../_images/wechat-mp-qrcode.png 小菜学编程

参考文献