一、logging模块的主要结构
实现主要功能的四个类:
1、Loggers(记录器)
提供应用程序直接使用的接口,如相关配置设置。
Logger
是一个树形层级结构,在使用接口debug
,info
,warn
,error
,critical
之前必须创建Logger
实例,即创建一个记录器,如果没有显式的进行创建,则默认创建一个root logger
,并应用默认的日志级别(WARN)
,处理器Handler
(StreamHandler,即将日志信息打印输出在标准输出上),和格式化器Formatter
(默认的格式即为第一个简单使用程序中输出的格式)。
创建方法:
logger = logging.getLogger(logger_name)
创建Logger实例后,可以使用以下方法进行日志级别设置,增加处理器Handler
。
logger.setLevel(logging.ERROR) # 设置日志级别为ERROR,即只有日志级别大于等于ERROR的日志才会输出
logger.addHandler(handler_name) # 为Logger实例增加一个处理器
logger.removeHandler(handler_name) # 为Logger实例删除一个处理器
2、Handlers(处理器)
将Logger
产生的日志信息传到指定位置,设置日志的保存位置。
Handler
处理器类型有很多种,比较常用的有三个:StreamHandler
,FileHandler
,NullHandler
创建StreamHandler
之后,可以通过使用以下方法设置日志级别,设置格式化器Formatter
,增加或删除过滤器Filter
。
ch.setLevel(logging.WARN) # 指定日志级别,低于WARN级别的日志将被忽略
ch.setFormatter(formatter_name) # 设置一个格式化器formatter
ch.addFilter(filter_name) # 增加一个过滤器,可以增加多个
ch.removeFilter(filter_name) # 删除一个过滤器
(1)StreamHandler
创建方法:
sh = logging.StreamHandler(stream = None)
(2)FileHandler
创建方法:
fh = logging.FileHandler(filename, mode=‘a’, encoding=None, delay=False)
其他的一些Handler
处理器:
(3)RotatingFileHandler
类似于FileHandler
,但他可以管理文件大小。当文件达到一定大小之后,他会自动将当前日志文件改名,然后创建一个新的同名日志文件继续输出。
创建方法:
rfh = logging.RotatingFileHandler(filename, mode, maxBytes, backupCount)
maxBytes
:指定日志文件大小,如果为0,意味着文件可以无限大,这时上面的重命名过程就不会发生。backupCount
指定保留备份文件的个数。
(4)TimedRotatingFileHandler
类似于RotatingFileHandler
,不过他没有通过判断文件大小来决定何时重新创建日志,二是间隔一定时间就自动创建一个新的日志文件。
创建方法:
trfh = logging.TimedRotatingFileHandler(filename, when, interval, backupCount)
-
interval
:表示时间间隔 -
when
:参数是一个字符串。表示时间间隔的单位,不区分大小写,他的取值为:S 秒
,M 分
,H 小时
,D 天
,W每星期
(interval==0代表星期一),midnight
每天凌晨
(5)NullHandler
NullHandler
类位于核心logging包,不做任何的格式化或者输出。
本质上它是个“什么都不做”的handler
,由库开发者使用。
(6)SocketHandler
、DatagramHandler
以上两个Handler
类似,都是讲日志信息发送到网络,不同的是前者使用TCP协议,后者使用UDP协议。他们的构造函数是:Handler
(host
, port
)(主机名, 端口名)
(7)其他:
SysLogHandler
、NTEventLogHandler
、SMTPHandler
、MemoryHandler
、HTTPHandler
3、Filters
(过滤器)
对输出日志进行过滤操作
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='')
4、Formatters
(格式化器)
控制日志的输出格式
使用Formatter
对象设置日志信息最后的规则、结构和内容,默认的时间格式为%Y-%m-%d %H:%M:%S
。
创建方法:
formatter = logging.Formatter(fmt=None, datafmt=None)
其中,fmt
是消息的格式化字符串,datefmt
是日期字符串。如果不指明fmt
,将使用'%(message)s'
。如果不指明datefmt
,将使用ISO8601
日期格式。
5、总结:
Logger
是一个树形层级结构;一个Logger
可以包含一个或者多个Handler
和Filter
。即Logger
和Handler
或者Filter
时一对多的关系。
一个Logger
示例可以新增多个Handler
,一个Handler
可以新增多个格式化器或者多个过滤器,而且日志界别将会继承。
【示例】
import logging
import sys
def get_logger(appname):
# 获取logger实例,如果参数为空则返回root logger
logger = logging.getLogger(appname)
# 创建日志输出格式
formatter = logging.Formatter('%(asctime)s %(levelname)s: %(message)s')
# 设置文件处理器,加载处理格式
file_handler = logging.FileHandler("test.log") # 指定输出的文件路径
file_handler.setFormatter(formatter)
# 控制台日志
console_handler = logging.StreamHandler(sys.stdout)
console_handler.formatter = formatter
# 为logger添加的日志处理器
logger.addHandler(file_handler)
logger.addHandler(console_handler)
# 指定日志的最低输出级别,默认为WARN级别
logger.setLevel(logging.INFO)
if __name__ == "__main__":
logger = get_logger('test')
logger.debug('this is debug info')
logger.info('this is information')
logger.warn('this is warning message')
logger.error('this is error message')
logger.fatal('this is fatal message, it is same as logger.critical')
logger.critical('this is critical message')
二、Logger日志记录的逻辑调用过程
1. 记录日志通过调用logger.debug()
等方法;
2. 首先判断本条记录的日志级别是否大于设置的级别,如果不是,直接pass
,不再执行;
3. 将日志信息当做参数创建一个LogRecord
日志记录对象;
4. 将LogRecord
对象经过logger
过滤器过滤,如果被过滤掉则pass
;
5. 日志记录对象被Handler
处理器的过滤器过滤;
6. 判断本条记录的日志级别是否大于Handler
处理器设置的级别,如果不是,直接pass
,不再执行,最后调用处理器的emit
方法处理日志记录;
三、logging的配置
logging的配置有以下几种方式:
1、通过代码进行完整配置,主要通过getLogger
方法实现,但不好修改
2、通过BasicConfig
方法实现,这种方式快速但不够层次分明
3、通过logging.config.file(filepath)
,文件配置
4、通过dictConfig
的字典方式配置,这事py3.2版本引入的新的方法
5、通过网络进行配置,使用listen()
函数进行网络配置
常用的配置方式为1、2、3,下面通过示例分别对这三种配置方式进行介绍。
1、通过代码配置
import logging
import sys
def get_logger(appname):
# 获取logger实例,如果参数为空则返回root logger
logger = logging.getLogger(appname)
# 创建日志输出格式
formatter = logging.Formatter('%(asctime)s %(levelname)s: %(message)s')
# 设置文件处理器,加载处理格式
file_handler = logging.FileHandler("test.log") # 指定输出的文件路径
file_handler.setFormatter(formatter)
# 控制台日志
console_handler = logging.StreamHandler(sys.stdout)
console_handler.formatter = formatter
# 为logger添加的日志处理器
logger.addHandler(file_handler)
logger.addHandler(console_handler)
# 指定日志的最低输出级别,默认为WARN级别
logger.setLevel(logging.INFO)
if __name__ == "__main__":
logger = get_logger('test')
logger.debug('this is debug info')
logger.info('this is information')
logger.warn('this is warning message')
logger.error('this is error message')
logger.fatal('this is fatal message, it is same as logger.critical')
logger.critical('this is critical message')
2、通过BasicConfig配置
# -*- 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')```
3、通过文件配置
配置文件logging.conf
# logging.conf
[loggers] # 定义日志的对象名称是什么,注意必须定义root,否则报错。
keys=root,main
[handlers] # 定义处理器的名称是什么,可以有多个,用逗号隔开
keys=consoleHandler
[formatters] # 定义输出格式对象的名称,可以有多个,用逗号隔开
keys=simpleFormatter
[logger_root] # 配置root对象的日志记录级别和使用的处理器
level=INFO
handlers=consoleHandler
[logger_main] # 配置main对象的日志记录级别和使用的处理器,qualname值得就是日志对象的名字
level=INFO
handlers=consoleHandler
qualname=main
propagate=0 # logger对象把日志记录传递给所有相关的handler的时候,会(逐级向上)寻找这个logger和它所有的父logger的全部handler,propagate=1表示会继续向上搜寻;propagate=0表示停止搜寻,这个参数涉及重复打印的坑。
[handler_consoleHandler] # 配置处理器consoleHandler
class=StreamHandler
level=WARNING
formatter=simpleFormatter
args=(sys.stdout,)
[formatter_simpleFormatter] # 配置输出格式过滤器simpleFormatter
format=%(asctime)s - %(name)s - %(levelname)s - %(message)s
定义好配置文件后,需要在使用时加载配置文件。
【示例】
#!/usr/bin/python
# -*- 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’)