关于 logging 的一些琐事

虽说 logging 模块都用了好久了,不过由于文档不够详细,每次都忍不住去搜索别人的文章,于是就干脆记录下来吧。

懒得分段了,想到哪写到哪吧。

  1. 为什么 logging.info() 默认不输出任何东西?
    因为默认生成的 root logger 的 level 是 logging.WARNING,低于该级别的就不输出了。可以进行如下设置来输出: 

    如果还没配置 handler 的话,可以用 logging.basicConfig() 来配置:

     
  2. 如何定制输出的格式?
    给 logger 的 handler 设置一个 logging.Formatter 对象: 

    如果还没配置 handler 的话,可以用 logging.basicConfig() 来配置:

    详细的格式介绍就查看文档吧。
  3. 为什么我重定向了 stdout,但是却看不到输出?
    因为默认生成的 root logger 的 handler 的 stream 是 stderr,不是 stdout: 

    可以如下分别配置:

     
  4. 如何将日志输出到文件?
    使用 logging.FileHandler(): 

    其中文件名可以使用相对路径,但要保证文件夹存在。默认的文件打开方式是 append。
    如果还没配置 handler 的话,可以用 logging.basicConfig() 来配置:

     
  5. 捕捉了一个异常,如何输出执行堆栈?
    使用 logging.exception(),或在调用 logging.debug() 等方法时加上 exc_info=True 参数。 

     
  6. 能不能针对不同的用途或模块,指定不同的日志?
    可以创建多个 logger: 

    每个 logger 都有个名字,以 ‘.’ 来划分继承关系。名字为空的就是 root_logger,console_logger 的名字是 ‘test’,因此 root_logger 是 console_logger 的 parent;而 file_logger 的名字是 ‘test.file’,因此 console_logger 是 file_logger 的 parent。
    如果 logger 的 propagate 属性为 True(默认值),则它的记录也会传到父 logger。因此,file_logger 在记录到文件的同时,也会在 stdout 输出日志。
    建议每个模块都用自己的 logger。
  7. 如何指定某些记录不输出?
    使用 logging.Filter 来过滤记录: 

     
  8. 单个日志文件太大怎么分卷?
    可以使用 logging.handlers.RotatingFileHandler 和 logging.handlers.TimedRotatingFileHandler。前者按文件大小来分割,后者按时间来分割。
    它们会在达到分割条件时(文件达到指定大小或达到指定时间),把当前的日志重命名为备份文件,然后再打开新文件来记录。
    值得一提的是,如果备份文件名已存在,就会被删除。所以在多进程时不建议使用。我是将日志输出到 stdout 和 stderr,再用 supervisor 来分割日志。
    此外还有一些没考虑到的特殊情况,建议使用前读读源码,然后自行实现。
  9. logging 是线程安全的么?
    是的,handler 内部使用了 threading.RLock() 来保证同一时间只有一个线程能够输出。
    但是,在使用 logging.FileHandler 时,多进程同时写一个日志文件是不支持的
  10. logging 的流程是怎样的?
    这里有张流程图可以参考:
1 5 收藏 1 评论

相关文章

可能感兴趣的话题



直接登录
最新评论
跳到底部
返回顶部