Python 常用内建模块-logging

2018-12-21 13:53:32 +08:00
 1024dada

简单使用

#!/usr/local/bin/python
# -*- coding:utf-8 -*-
import logging

logging.debug('debug message') logging.info('info message') logging.warn('warn message') logging.error('error message') logging.critical('critical message')

输出:

WARNING:root:warn message
ERROR:root:error message
CRITICAL:root:critical message

默认情况下,logging 模块将日志打印到屏幕上(stdout),日志级别为 WARNING(即只有日志级别高于 WARNING 的日志信息才会输出),日志格式如下图所示:

问题来了

日志级别等级及设置是怎样的?
怎样设置日志的输出方式?比如输出到日志文件中?

简单配置

日志级别

<colgroup><col width="49.923547400611625%"><col width="50.076452599388375%"></colgroup>
DEBUG详细信息,典型地调试问题时会感兴趣。
INFO证明事情按预期工作。
WARNING表明发生了一些意外,或者不久的将来会发生问题(如‘磁盘满了’)。软件还是在正常工作。
ERROR由于更严重的问题,软件已不能执行一些功能了。
CRITICAL严重错误,表明软件已不能继续运行了。

简单配置

#!/usr/local/bin/python
# -- coding:utf-8 --
import logging

# 通过下面的方式进行简单配置输出方式与日志级别 logging.basicConfig(filename='logger.log', level=logging.INFO)

logging.debug('debug message') logging.info('info message') logging.warn('warn message') logging.error('error message') logging.critical('critical message')

输出:
标准输出(屏幕)未显示任何信息,发现当前工作目录下生成了 logger.log ,内容如下:

INFO:root:info message
WARNING:root:warn message
ERROR:root:error message
CRITICAL:root:critical message

因为通过 level=logging.INFO 设置日志级别为 INFO,所以所有的日志信息均输出出来了。

问题又来了

通过上述配置方法都可以配置那些信息?

在解决以上问题之前,需要先了解几个比较重要的概念,LoggerHandlerFormatterFilter

几个重要的概念

Logger 记录器

Logger 是一个树形层级结构,在使用接口 debug,info,warn,error,critical 之前必须创建 Logger 实例,即创建一个记录器,如果没有显式的进行创建,则默认创建一个 root logger,并应用默认的日志级别(WARN),处理器 Handler(StreamHandler,即将日志信息打印输出在标准输出上),和格式化器 Formatter(默认的格式即为第一个简单使用程序中输出的格式)。

创建方法: logger = logging.getLogger(logger_name)

创建 Logger 实例后,可以使用以下方法进行日志级别设置,增加处理器 Handler。

Handler 处理器

Handler 处理器类型有很多种,比较常用的有三个,StreamHandlerFileHandlerNullHandler

创建 StreamHandler 之后,可以通过使用以下方法设置日志级别,设置格式化器 Formatter,增加或删除过滤器 Filter。

StreamHandler

创建方法: sh = logging.StreamHandler(stream=None)

FileHandler

创建方法: fh = logging.FileHandler(filename, mode='a', encoding=None, delay=False)

NullHandler

NullHandler 类位于核心 logging 包,不做任何的格式化或者输出。本质上它是个“什么都不做”的 handler,由库开发者使用。

Formatter 格式化器

使用 Formatter 对象设置日志信息最后的规则、结构和内容,默认的时间格式为%Y-%m-%d %H:%M:%S。

创建方法: formatter = logging.Formatter(fmt=None, datefmt=None)

其中,fmt 是消息的格式化字符串,datefmt 是日期字符串。如果不指明 fmt,将使用'%(message)s'。如果不指明 datefmt,将使用 ISO8601 日期格式。

Filter 过滤器

Handlers 和 Loggers 可以使用 Filters 来完成比级别更复杂的过滤。Filter 基类只允许特定 Logger 层次以下的事件。例如用‘ A.B ’初始化的 Filter 允许 Logger ‘ A.B ’, ‘ A.B.C ’, ‘ A.B.C.D ’, ‘ A.B.D ’等记录的事件,logger ‘ A.BB ’, ‘ B.A.B ’ 等就不行。 如果用空字符串来初始化,所有的事件都接受。

创建方法: filter = logging.Filter(name='')

以下是相关概念总结:

熟悉了这些概念之后,有另外一个比较重要的事情必须清楚,即Logger 是一个树形层级结构;
Logger 可以包含一个或多个 Handler 和 Filter,即 Logger 与 Handler 或 Fitler 是一对多的关系;
一个 Logger 实例可以新增多个 Handler,一个 Handler 可以新增多个格式化器或多个过滤器,而且日志级别将会继承。

Logging 工作流程

logging 模块使用过程

  1. 第一次导入 logging 模块或使用 reload 函数重新导入 logging 模块,logging 模块中的代码将被执行,这个过程中将产生 logging 日志系统的默认配置。
  2. 自定义配置(可选)。logging 标准模块支持三种配置方式: dictConfig,fileConfig,listen。其中,dictConfig 是通过一个字典进行配置 Logger,Handler,Filter,Formatter ; fileConfig 则是通过一个文件进行配置;而 listen 则监听一个网络端口,通过接收网络数据来进行配置。当然,除了以上集体化配置外,也可以直接调用 Logger,Handler 等对象中的方法在代码中来显式配置。
  3. 使用 logging 模块的全局作用域中的 getLogger 函数来得到一个 Logger 对象实例(其参数即是一个字符串,表示 Logger 对象实例的名字,即通过该名字来得到相应的 Logger 对象实例)。
  4. 使用 Logger 对象中的 debug,info,error,warn,critical 等方法记录日志信息。

logging 模块处理流程

  1. 判断日志的等级是否大于 Logger 对象的等级,如果大于,则往下执行,否则,流程结束。
  2. 产生日志。第一步,判断是否有异常,如果有,则添加异常信息。第二步,处理日志记录方法(如 debug,info 等)中的占位符,即一般的字符串格式化处理。
  3. 使用注册到 Logger 对象中的 Filters 进行过滤。如果有多个过滤器,则依次过滤;只要有一个过滤器返回假,则过滤结束,且该日志信息将丢弃,不再处理,而处理流程也至此结束。否则,处理流程往下执行。
  4. 在当前 Logger 对象中查找 Handlers,如果找不到任何 Handler,则往上到该 Logger 对象的父 Logger 中查找;如果找到一个或多个 Handler,则依次用 Handler 来处理日志信息。但在每个 Handler 处理日志信息过程中,会首先判断日志信息的等级是否大于该 Handler 的等级,如果大于,则往下执行(由 Logger 对象进入 Handler 对象中),否则,处理流程结束。
  5. 执行 Handler 对象中的 filter 方法,该方法会依次执行注册到该 Handler 对象中的 Filter。如果有一个 Filter 判断该日志信息为假,则此后的所有 Filter 都不再执行,而直接将该日志信息丢弃,处理流程结束。
  6. 使用 Formatter 类格式化最终的输出结果。 注:Formatter 同上述第 2 步的字符串格式化不同,它会添加额外的信息,比如日志产生的时间,产生日志的源代码所在的源文件的路径等等。
  7. 真正地输出日志信息(到网络,文件,终端,邮件等)。至于输出到哪个目的地,由 Handler 的种类来决定。

注:以上内容摘抄自第三条参考资料,内容略有改动,转载特此声明。

再看日志配置

配置方式

basicConfig 关键字参数

<colgroup><col width="49.923547400611625%"><col width="50.076452599388375%"></colgroup>
filename创建一个 FileHandler,使用指定的文件名,而不是使用 StreamHandler。
filemode如果指明了文件名,指明打开文件的模式(如果没有指明 filemode,默认为'a')。
formathandler 使用指明的格式化字符串。
datefmt使用指明的日期/时间格式。
level指明根 logger 的级别。
stream使用指明的流来初始化 StreamHandler。该参数与'filename'不兼容,如果两个都有,'stream'被忽略。

有用的 format 格式

<colgroup><col width="49.923547400611625%"><col width="50.076452599388375%"></colgroup>
%(levelno)s打印日志级别的数值
%(levelname)s打印日志级别名称
%(pathname)s打印当前执行程序的路径
%(filename)s打印当前执行程序名称
%(funcName)s打印日志的当前函数
%(lineno)d打印日志的当前行号
%(asctime)s打印日志的时间
%(thread)d打印线程 id
%(threadName)s打印线程名称
%(process)d打印进程 ID
%(message)s打印日志信息

有用的 datefmt 格式

参考 time.strftime

配置示例

显式配置

使用程序 logger.py 如下:

# -- encoding:utf-8 --
import logging

# create logger logger_name = "example" logger = logging.getLogger(logger_name) logger.setLevel(logging.DEBUG)

# create file handler log_path = "./log.log" fh = logging.FileHandler(log_path) fh.setLevel(logging.WARN)

# create formatter fmt = "%(asctime)-15s %(levelname)s %(filename)s %(lineno)d %(process)d %(message)s" datefmt = "%a %d %b %Y %H:%M:%S" formatter = logging.Formatter(fmt, datefmt)

# add handler and formatter to logger fh.setFormatter(formatter) logger.addHandler(fh)

# print log info logger.debug('debug message') logger.info('info message') logger.warn('warn message') logger.error('error message') logger.critical('critical message')

文件配置

配置文件 logging.conf 如下:

keys=root,example01

[logger_root] level=DEBUG handlers=hand01,hand02

[logger_example01] handlers=hand01,hand02 qualname=example01 propagate=0

[handlers] keys=hand01,hand02

[handler_hand01] class=StreamHandler level=INFO formatter=form02 args=(sys.stderr,)

[handler_hand02] class=FileHandler level=DEBUG formatter=form01 args=('log.log', 'a')

[formatters] keys=form01,form02

[formatter_form01] format=%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s

使用程序 logger.py 如下:

# -- encoding:utf-8 --
import logging
import logging.config

logging.config.fileConfig("./logging.conf")

# create logger logger_name = "example" logger = logging.getLogger(logger_name)

logger.debug('debug message') logger.info('info message') logger.warn('warn message') logger.error('error message') logger.critical('critical message')


更多教程尽在每日答答官网: https://1024dada.com/?channel=v2ex

1192 次点击
所在节点    问与答
0 条回复

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/519721

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX