参考: https://blog.csdn.net/weixin_47154909/article/details/106203639
前言
显而易见,日志是任何工程及项目中不可或缺的一部分,各种编程语言都会内置或者扩展的日志模块;
logging是Python自带的日志模块,定义了为应用程序和库实现灵活的事件日志记录的函数和类。
特点
作为标准库提供的 logging 模块,主要特点如下:
- 可集成至任意 python 模块,包括第三方库中,复用性极强。
- 提供了大量具有灵活性的功能,支持自定义的扩展。
- 提供不同的日志事件级别,适用性强。
组件
logging模块主要由以下几部分组成:
- 记录器(Logger):提供实例化的日志对象,用来记录不同的代码模块。
- 处理器(Handler):日志记录由什么样的方式承载,比如文件FileHandler。
- 筛选器(Filter):提供了更细粒度的功能,用于确定要输出的日志记录。
- 格式器(Formatter):最终输出日志记录的内容格式。
日志器Logger
日志器是实例化的日志对象,要输出日志,日志器是必不可少的。
创建一个日志器,如果没有指定日志器,默认为root:
# 默认日志器名称为root
logger = logging.getLogger()
当创建多个日志器使用相同的名称时,实际上返回的都是该日志器实例的引用。
logger = logging.getLogger("test")
logger1 = logging.getLogger("test")
print(logger is logger1) # True
处理器Handler
处理器负责将日志消息发送到不同的地方,例如:控制台,日志文件,电子邮件等;logging模块提供很多个类型的处理器,扩展非常方便:
当对同一个日志器Logger对象添加多个处理器Handler时,会使每个处理器都触发一次输入日志操作,每次输出日志记录数量=handler数量。
FileHandler
日志记录发送到磁盘文件中
logging.FileHandler(filename, mode='a', encoding=None, delay=False)
- filename:只填写文件名称,则默认新增文件到当前工作目录;填写工作路径+文件名称,则新增到对应工作目录
- mode:默认a模式,可自定义
- encoding:默认为None,可自定义
- delay:默认为False,为True时,将文件打开延迟到第一次调用时进行emit()
RotatingFileHandler
日志记录到文件中,且支持指定日志文件大小,备份文件数量
logging.handlers.RotatingFileHandler(filename, mode='a', maxBytes=0, backupCount=0, encoding=None, delay=False)
maxBytes:单个日志文件大小,单位为字节
backupCount:日志总文件数量
注意:当maxBytes或backupCount中的任何一个为零,则永远不会发生过渡
例子:使用backupCount 5和的基本文件名app.log,你会得到app.log, app.log.1,app.log.2,达到app.log.5。写入的文件始终为app.log。当这个文件被填满时,它被关闭并重新命名为app.log.1,如果文件app.log.1, app.log.2等存在,那么它们被重命名为app.log.2, app.log.3分别等。
TimedRotatingFileHandler
日志记录到文件中,支持按时间间隔来更新日志
logging.handlers.TimedRotatingFileHandler(filename, when='h', interval=1, backupCount=0, encoding=None, delay=False, utc=False, atTime=None)
基于工作日的轮换时,将“ W0”指定为星期一,将“ W1”指定为星期二,依此类推,直到“ W6”指定为星期日。在这种情况下,不使用为interval传递的值
关于过渡时间:首次(在创建处理程序时)计算下一个过渡时间时,将使用现有日志文件的最后修改时间或当前时间来计算下一个轮换发生的时间。
- interval:时间长度,与when结合使用
- backupCount:如果backupCount不为零,则最多将保留backupCount数的文件,并且如果发生翻转时将创建更多文件,则最早的文件将被删除。删除逻辑使用间隔来确定要删除的文件,因此更改间隔可能会留下旧文件。
- utc:默认为False,使用本地时间;为True时,使用UTC时间
- actime:默认为None,若非None时,必须是一个datetime.time实例,该实例指定发生翻转的一天中的时间,对于将翻转设置为“在午夜”或“在特定工作日”发生的情况。请注意,在这些情况下,atTime值可有效地用于计算初始 翻转,随后的翻转将通过正常间隔计算来计算。
其他Handler
其他还有SocketHandler、DatagramHandler、SysLogHandler、NTEventLogHandler、SMTPHandler、MemoryHandler、HttpHandler、QueueHandler、QueueListener等,可以看官网:https://docs.python.org/3.8/library/logging.handlers.html#logging.handlers
筛选器Filter
Filters可以由级别使用,也可以用于提供一些比级别更复杂的过滤条件,Filters的返回为Bool值,True表示过滤通过,该次日志可以输出,反之为不可以输出。
创建一个Filter示例,大部分日志相关的信息都可以在record参数中获取:
from logging import Filter
# 自定义一个filter
class TestFilter(Filter):
def filter(self, record: logging.LogRecord) -> bool:
# 如果日志级别为 WARNING ,则不输出日志
if record.levelname == "WARNING":
return False
# 日志内容在msg属性中
print(record.msg["c"])
# 可以直接获取 extra 中的属性
print(record.a)
return True
# 为处理器添加一个Filter
test_log = logging.FileHandler('test.txt', 'a', encoding='utf-8')
test_log.addFilter(TestFilter())
logger = logging.getLogger()
logger.addHandler(test_log)
# print会打印: d b
logger.error({"c":"d"},extra={"a":"b"})
# 不会打印,被过滤掉了
# logger.warning("test")
格式器Formatter
格式器可以初始化日志记录的内容格式,结合LogRecord对象提供的属性,可以设置不同的日志格式
logging.Formatter(fmt=None, datefmt=None, style='%')
- fmt:日志格式参数,默认为None,如果不特别指定fmt,则使用’%(message)s’格式
- datafmt:时间格式参数,默认为None,如果不特别指定datafmt,则使用formatTime()文档中描述的格式。
- style:风格参数,默认为’%’,也支持’$’,’{'格式
格式器Formatter有非常多内置的标准输出属性,提供非常强的便捷性,常用的属性值可以参考:https://docs.python.org/3.7/library/logging.html#logrecord-attributes
Formatter简单示例:
from logging import Formatter
# 打印日志级别、日志时间、文件位置、行号、报错信息
formatter = logging.Formatter("%(levelname)s - %(asctime)s - %(filename)s - line:%(lineno)d - %(message)s")
组件关联关系
- 日志器(logger)需要通过处理器(handler)将日志信息输出到目标位置,不同的处理器(handler)可以将日志输出到不同的位置;
- 日志器(logger)可以设置多个处理器(handler)将同一条日志记录输出到不同的位置;
- 每个处理器(handler)都可以设置自己的过滤器(filter)实现日志过滤,从而只保留感兴趣的日志;
- 每个处理器(handler)都可以设置自己的格式器(formatter)实现同一条日志以不同的格式输出到不同的地方。
Logger 可以包含一个或多个 Handler 和 Filter。Logger 与 Handler 或 Fitler 是一对多的关系,一个 Logger 实例可以新增多 个 Handler,一个 Handler 可以新增多个格式化器或多个过滤器,而且日志级别将会继承。