Python logging 模块详述

Python logging 模块 TOC

前言

logging模块的设计

logger在逻辑上的继承结构

日志输出可到多种i/o设备

日志格式和内容丰富

日志分级别,也是日志在级别维度上的分类。

可根据日志对象的级别进行过滤、指定输出i/o。

logger主要负责继承关系基本单位

handler负责输出方向的基本单位

formater负责日志格式

filter负责过滤,可安置于logger和handler,配合上继承传播机制,灵活过滤。

logging.basicConfig()

Logger

handler

formatter

filter

log recoder

读取logging配置

logging模块实践

前言

Python在日志记录处理上是非常灵活的,且功能完备,足以满足所有对日志方面的需求。
如此强大,当然是日志系统设计非常的流弊了。
除此之外,了解其设计时,要梳理清楚模块中几个重要对象之间的关系,和他们各自负责的Mission任务!

logging模块的设计

可以参考Java的日志系统设计,这篇文章采用幽默诙谐的语言基调,从需求出发,阐明日志系统是怎么设计出来的。
我这里按照这篇文章,简单勾画下重点

需求

日志消息可以输出到多种媒介中

日志消息内容可以做格式化

程序代码是通过package,module来组织分类的,要满足不同包,不同模块的代码,有自己的日志处理方式,同时也要有日志分类(日志其实就是某个Event事件发生了的记录),由于是某个事件发生触发了日志,所以这个事件的级别要通过日志来体现,所以日志还要分级别。

按照上一条需求,日志有了级别,那么就要在这种日志分类上有文章可做。比如,不同日志级别的处理方式不同,不同日志级别之间还有有轻重缓急的关系。根据轻重缓急可以已设置某个日志级别以上的处理方式和以下的级别的处理方式。

日志的处理和日志的输出两个地方还可以定制化过滤需求。

分析需求

首先,要有个类来抽象出日志消息,这个类至少有两个属性时间戳,消息本身。日志消息本来就是记录了一个事件的发生。那就用LogRecord类来表示日志消息。

LogRecord要输出到不同媒介中,那就抽象一个Handler类,不同的Handler处理LogRecord到不同的媒介中

LogRecord要格式化输出,那么就要有一个Formatter类,不同Formatter可以处理为不同的格式类型。

要满足不同包,模块,有自己的处理方式。从用户最后使用的角度考虑,我要每次都创建多个Handler太麻烦了,那就还需要一个来整合这些对象的一个处理器,这是一个抽象出来的类,就叫Logger。每个包,模块都可以有自己的logger,可以用独特的名字来标识这个Logger的唯一性。

日志消息LogRecord是分级别的,其它处理LogRecord的也都可以根据其级别做不同处理。

在logger和handler这两个日志路由位置进行过滤。即增加一个Filter过滤对象到logger和handler。

这样根据需求围绕核心几个类的关系
Logger包含Handler,Handler包含Formatter。都处理LogRecord。Logger和Handler都可以添加Filter对LogRecord进行过滤。

logger的继承

1.就是通过logger的名字的命名层级来查找其parent logger。使用'.'来表示继承关系。
2.logger的继承其实是继承几个方面
    2.1. level的继承:子logger写日志的时候,优先使用本身设置的level,如果没有设置,则逐层向上级父logger查询,直到查询到为止。最极端的情况是,使用rootlogger的默认日志级别——WARNING.可以使用logger.getEffectivaLeve()获取有效的等级。
    2.2. handler的继承,先将日志对象传递给子logger的所有handler处理,处理完毕,如果孩子的logger的propagate属性设置的是1(TRUE),那么日志record对象会被传播给上级父logger,该父logger的handler都会进行处理,如果父logger的propagate也是1,那么会继续向上。如果子logger的propagate就是0,就不会传播,极端,如果是子logger都没有handler,且不传播,那么就会极端的给logging.lastResort这是一个内置的handler,不会和任何一个logger关联,and acts like StreamHandler which the event description message to the current value of sys.stderr.这个logging.lastResort是没有formatted的,所以我们会看到就message原始格式,输出到标准输出中。
3. 总的来说,其实是逻辑上的继承,只是利用层级关系,可以来使用父logger的level和handler。

logger在逻辑上的继承结构

logger的构建是通过logger的命名创建出的。名字在整个程序中都是唯一的表示。
这样说的设计就可以实现将你自己的日志和使用第三方模块所产生的日志结合在一起。不用在自己的代码中去刻意再写兼容第三方模块产生的日志的处理。都交给logging就可以整合处理了。
Logger 间继承关系的表示:

是通过'.'号来表示的。如:'foo' 'foo.bar' 'foo.bar.baz' 'foo'是'foo.bar'的父亲,'foo.bar' 是'foo.bar.baz' 的父亲。'foo'的父亲其实就是'root'logger。

这种等级关系的表示方法,非常类似于包和模块之间的表示层级关系的方法。

logging.basicConfig()

该模块级函数是设置root logger.如果root logger已经有handler的化,那么调用函数是没有作用的,以下是源码:

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/6375a23318a4f54e75a71b6d6113a6c5.html