python logging模块

logging模块处理流程:

image

分为几个模块:

  • logger: 最高层模块,用来输出log
    • logger.level来筛选log
    • logger.debug()/info()/warning()/error()等输出log
  • handler: 经过logger过滤后log会分发给所有handler处理。每个handler有自己的level, formatter, 以及输出流
    • handler.level 过滤log
    • handler.formatter 决定log输出的样式

StreamHandler: 常见的StreamHandler输出到标准流,FileHandler,输出到文件

level的排序:NOTSET < DEBUG < INFO < WARNING < ERROR

只有大于level的才会被处理

注意:一条log会经历两次过滤,一次是logger.level,一次是handler.level,被前者过滤掉的log不会进入handler处理流程。handler的level和logger的level没有什么必然关系。

e.g. 1. 最基本的使用方法:

import logging
logging.info('这条不会输出,因为默认level是WARNING')
logging.warning('这条会输出')

默认会输出到stderr

e.g. 2. 带自定义输出的基本使用方法:

import logging, sys
if __name__ == '__main__':
	logger = logging.getLogger(__name__)
	logging.basicConfig(
        format="%(asctime)s - %(levelname)s - %(name)s - %(message)s",
        datefmt="%m/%d/%Y %H:%M:%S",
        handlers=[logging.StreamHandler(sys.stdout), logging.FileHandler('output.log')],
    )
	logger.setLevel(logging.INFO)

	logger.info('hello world')

输出如下:

09/18/2022 21:50:53 - INFO - __main__ - hello world

同时会输出到文件output.log

一些重要的默认值

  • 默认有一个root logger,是自己定义的logger的parent
  • root的level默认是WARNING,无handler
  • logger 所有parent直到root都没有handler时使用一个默认的全局handler,该handler的level是WARNING,输出到stderr
  • 如果logger没定义level,会使用第一个找到的parent的非0(NOTSET)的level,一般是root的level (WARNING),如果所有parent都没有level,则使用NOTSET(最低级)
  • basicConfig函数配置root logger的一些属性,如果root有handler,则basicConfig不起作用
  • 手动创建的handler默认level是NOTSET,手动创建的logger默认level也是NOTSET,但是如果parent有非NOTSET的level,则优先使用parent的level(比如root的WARNING)

上文的e.g.2就是给root handler配置了两个handler,一个输出到stdout,一个输出到文件, 两个共用一个formatter,自己定义的logger是没有handler的,最终递归地使用了root的handler

e.g.3 INFO和WARNING分开输出到不同的地方

import logging
from sys import stdout, stderr
if __name__ == "__main__":
	format="%(asctime)s - %(levelname)s - %(name)s - %(message)s"
    datefmt="%m/%d/%Y %H:%M:%S"
    formatter = logging.Formatter(format, datefmt, '%')

    # logger to stdout
    logger  = logging.getLogger(__name__)
    # 不能设置成NOTSET,不然优先使用root的level,即warning
    logger.setLevel(logging.DEBUG)
    hdlr = logging.StreamHandler(stdout)
    hdlr.setFormatter(formatter)
    logger.addHandler(hdlr)

    # logger to stderr
    err = logging.getLogger(__name__ + 'err')
    err.setLevel(logging.WARNING)
    hdlr = logging.StreamHandler(stderr)
    hdlr.setFormatter(formatter)
    err.addHandler(hdlr)

format字符串格式

推荐一个格式:

format="[%(levelname)s|%(filename)s:%(lineno)s] %(asctime)s >> %(message)s"

会显示文件名:行号,可以通过vscode的终端直接点进去文件的具体位置,这也是huggingface transformers库默认的logger格式,本人也比较喜欢。

posted @ 2022-09-18 22:48  王冰冰  阅读(76)  评论(0编辑  收藏  举报