logging模块
日志级别
logging中的日志级别是通过数值比较来进行的,可以是非下列表中的数值,但不推荐。
Level | value |
---|---|
CRITICAL | 50 |
ERROR | 40 |
WARNING | 30,default |
INFO | 20 |
DEBUG | 10 |
NOTSET | 0 |
设置通知level后,低于该级别的日志信息都会被忽略。
使用log时需要传入上述级别参数
也可以直接使用下列方法
critical() error() waring() info() debug()
格式化字符串
属性名 | 格式 | 描述 |
---|---|---|
asctime | %(asctime)s | 当前时间 |
message | %(message)s | 输出时追加的内容 |
filename | %(filename)s | 文件名 |
funcName | %(funcName)s | 函数名 |
levelname | %(levelname)s | 级别名 |
levelno | %(levelno)s | 级别数值 |
module | %(module)s | 模块名 |
name | %(name)s | 调用者名称 |
process | %(process)d | 进程id |
thread | %(thread)d | 线程id |
processName | %(processName)s | 进程名 |
threadName | %(threadName)s | 线程名 |
logging.basicConfig()
参数 | 用法 |
---|---|
level | 设置等级,默认WARNING |
format | 使用上面的格式化字符串来设置,会添加到输出的字符串前 |
datefmt | 对asctime单独格式化 |
filename | 传入一个文件名,将输出写入文件 |
filemode | 打开模式,默认使用a模式 |
import logging
fmt = '%(asctime)s %(levelname)s %(message)s'
logging.basicConfig(level=logging.INFO,
format=fmt,
datefmt='%Y-%m-%d %H:%M:%S')
logging.warning('hello logging')
#>>>2020-07-30 16:43:01 WARNING hello logging
输出时是支持C风格格式化字符串的
logging.warning('%d %s', 123, 'string')
#>>>2020-07-30 16:45:59 WARNING 123 string
extra
除了模块自带的格式化属性外,也可以自己定义并使用extra参数传入
import logging
fmt = '%(asctime)s %(levelname)s %(message)s %(descrip)s' #descrip属性是自定义的
logging.basicConfig(level=logging.INFO, format=fmt, datefmt='%Y-%m-%d %H:%M:%S')
logging.warning('hello logging', extra={'descrip':'这里需要一个字典'})
#>>>2020-07-30 16:50:07 WARNING hello logging 这里需要一个字典
进阶用法
在上面的使用中,调用的都是logging模块中的函数,其实在函数的调用过程中已经创建了实例。使用logging.getLogger(name)方法来获取实例。如果传入的name为空字符串或者传参时会返回root实例。
继承
-
这里的继承有别于面向对象的继承
-
获取到的实例存在继承关系,默认继承于root实例。如果name字符串中存在
.
的话,例如s.s1
,如果此时s存在,s1的父就为s。并且在创建时父就存在的话,就会从父继承到level属性。
logging.getLogger(name)
利用该实例直接来调用critical(),error(),waring(),info() ,debug()等就能应用个性的level了
方法 | 用法 |
---|---|
setLevel | 重新设置级别 |
getEffectiveLevel | 返回有效级别 |
parent | 返回父对象 |
addHandler | 添加一个Handler |
Handler
使用getLogger获取到的实例无法直接来设置format和datefmt,这时需要handler来进行设置
logging模块中提供了以下几个Handler
-
Handler
- FileHandler
-
StreamHandler
- NullHandler
类
类 | 参数or用法 |
---|---|
FileHandler | filename:文件名 mode:打开模式 encoding:文本编码 |
StreamHandler | 可以传入一个输出流,默认是sys.stderr 标准错误输出 |
NullHandler | 什么也不干 |
主要方法
方法 | 用法 |
---|---|
setLevel | 设置级别 |
setFormat | 与basicConfig相同的格式字符串 |
addFilter | 增加过滤器 |
通过logging.getLogger(name)返回的实例的addHandler来增加Handler实例
特性
Handler和logging.Logger实例都有各自level,判断的时候如何来判断,继承时又该如何继承
- 将logging.Logger和Handler单独来看,logging.Logger是log的一个对象,而Handler是具体输出的一个工具。类似于人和打印机之间的关系。
- 继承时只继承父的level
- 判断时会判断当前Logger对象的level,如果输出的是有效的level,就会依次判断自身和祖先的Handler,如果大于等于Handler的level就会执行该Handler,不会再判断祖先logger对象的level了。
- 把logger实例比作一个员工的话。如果要打印的内容符合员工要求的话,员工就开始找打印机,将自己家族(即自己到祖先)的所有符合要求的打印机都拿来打印。
- 像上面我们直接使用logging的函数来输出,其实隐式地创建了root实例,并可以通过logging.basicConfig()来修改其Handler。(注意:logging.basicConfig()的参数level指的是logger对象的level,而非Handler)
注意:如果logger对象的propagate属性为False,则只会使用自身的Handler,缺省值为True
流程图
addFilter
将指定的过滤器 filter 添加到此处理器。判断顺序和规则与level相同。
Filter类
使用一个logger名来初始化。基本过滤器类只允许低于日志记录器层级结构中低于特定层级的事件。 例如,一个用 ‘A.B’ 初始化的过滤器将允许 ‘A.B’, ‘A.B.C’, ‘A.B.C.D’, ‘A.B.D’ 等日志记录器所记录的事件。 但 ‘A.BB’, ‘B.A.B’ 等则不允许。 如果用空字符串初始化,则所有事件都会被略过。
建议
由于Python模块不会重复加载的特性,当多个模块之间都使用了Logger时,可能会出现字符串重复的情况。建议使用模块名来实例化Logger对象,模块名具有唯一性,而在同一模块中也可以用模块名+函数名的方式。