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. 最基本的使用方法:

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

默认会输出到stderr

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

1
2
3
4
5
6
7
8
9
10
11
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')

输出如下:

1
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分开输出到不同的地方

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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字符串格式

推荐一个格式:

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

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


python logging模块
https://jcdu.top/2022/09/18/python logging模块/
作者
horizon86
发布于
2022年9月18日
许可协议