主题
Python内置模块 - 日志
日志模块
在程序开发中,日记记录是不可缺少的。Python处理日志的模式是logging,它是内置模块之一,提供了丰富的处理流,包括写入文件、发送到邮箱、发送到控制台等。Python中常用的异常处理信息输出如下表所示。
场景 | 推荐措施 |
---|---|
将结果显示在控制台 | print() |
监控和记录程序运行状态 | 使用logging.info()函数(当由诊断目的需要详细输出的使用logging.debug()函数) |
发出一个警告信息 | 使用logging.warning(),在控制台显示红色 |
对业务之外的错误处理 | 抛出异常 |
只报告错误,不抛出异常 | 使用logging.error()函数 |
日志的使用
使用import logging
导入日志模块。
日志模块有以下该概念:
- 记录器:Logger是日志的记录器,对外提供logging的接口,应用程序可以直接使用这个对象。
- 处理器:Handler是日志的处理器,负责将适当的日志信息分派成处理程序的目标。
- 格式化器:Formatter是日志的格式化器,负责将日志按照格式字符串输出。
- 过滤器:Filter是日志的过滤器,提供了更加精细的附加功能。
- 日志级别:用于划分错误的严重级别。
- 日志等级
日志等级分为6种,如下表。
级别 | 数值 | 备注 |
---|---|---|
NOTSET | 0 | 当logger是根logger时,将处理所有消息,若logger是非根logger,则所有消息会委派给父级 |
DEBUG | 10 | 细节消息,仅当诊断问题时使用 |
INFO | 20 | 确认程序按预期执行 |
WARNING | 30 | 表明有已经或即将发生的意外,程序仍按预期执行 |
ERROR | 40 | 由于严重的问题,程序的某些功能已经不能正常执行 |
CRITICAL | 50 | 有严重的错误,程序不能继续执行 |
- 格式化器
格式化器对象用于配置日志信息的输出内容,由一些字符串定义。
字段 | 含义 |
---|---|
%(levelno)s | 打印日志级别的数值 |
%(levelname)s | 打印日志级别名称 |
%(pathname)s | 打印当前执行程序的路径,相当于sys.argv[0] |
%(filename) | 打印当前执行程序名 |
%(funcName)s | 打印日志的当前函数 |
%(lineno)d | 打印日志的当前函数 |
%(asctime)s | 打印日志的时间 |
%(thread)d | 打印线程ID |
%(threadName)s | 打印线程名称 |
%(process)d | 打印进程ID |
%(message)s | 打印日志信息 |
%(msecs)d | 打印记录时的毫秒部分 |
%(created)f | 打印记录时的时间戳 |
%(name)s | 打印记录器的名称,默认为root |
%(processName)s | 打印进程名 |
%(relativeCreated)d | 打印日志记录时相对于日志模块初始化的时间(毫秒) |
%(module)s | 打印模块 |
Logger
记录器对外提供logging的接口。它具有以下属性。
propagate
:判断日志是否向上传播。setLevel(level)
:设置记录阈值,日志等级大于阈值的会被记录。默认为WARNING级别。isEnabledFor(level)
:判断当前记录器是否处理级别为参数传入的level级别信息。getEffectiveLevel()
:获取此记录器的有效级别。getChild(suffix)
:用于返回由参数确定的记录器。debug(msg, *args, **kwargs)
:用于DEBUG在此记录器上记录级别的消息,在关键字参数中制定了三个参数:exc_info
:若不为False,则将异常信息添加到日志信息中。stack_info
:若为True,则将堆栈信息添加到日志信息中。extra
:它不常用,可通过字典指定。
info(msg, *args, **kwargs)
:用于记录INFO级别的信息。- 以下函数都是记录对应级别的信息:
warning(msg, *args, **kwargs)
、error(msg, *args, **kwargs)
、critical(msg, *args, **kwargs)
、log(msg, *args, **kwargs)
、exception(msg, *args, **kwargs)
。 addFilter(filter)
:将过滤器添加到记录器。remove(filter)
:从记录器中移除过滤器。filter(record)
:用过滤器检查记录事件对象record,若有一条不符合要求则不处理此事件。addHandler(hdlr)
:将处理程序添加到记录器。removeHandler(hdlr)
:从记录器中删除指定的处理程序。findCaller(stack_info=False)
:以元组形式返回记录器所在的文件名、行号、函数名称和堆栈信息。handle(record)
:将记录对象record传递给记录器或其祖先关联的所有处理程序。此方法用于从套接字接受的为选择记录以及本机创建记录。makeRecord(name, lvl, fn, info, lno, msg, exe_info, func=None, extra=None, sinfo=None)
:用于重写或创建专门的LogRecord实例。hasHandler
:用于检查此记录是否配置了处理程序。
python
import logging
logger = logging.getLogger()
logger.setLevel(logging.DEBUG)
class MyFilter(logging.Filter):
def filter(self, record: object) -> bool:
return "测试消息" not in record.msg
ch = logging.StreamHandler()
ch.setLevel(logging.DEBUG)
formatter = logging.Formatter('%(asctime)s - %(filename)s[line: %(lineno)d] - %(levelname)s: %(message)s - %(name)s')
ch.setFormatter(formatter)
logger.addHandler(ch)
filter = MyFilter()
logger.addFilter(filter)
if __name__ == '__main__':
logger.info('这是日志消息')
logger.info('过滤器将过滤掉含测试消息字段的日志')
logger.removeFilter(filter)
logger.info('移除测试消息过滤器')
Handler
Handler的作用是负责将适当的日志消息分派给对应的处理程序。一般不直接实例化Handler,它只是一个基类,它内部提供了很多处理程序,直接使用它们即可。
它的属性和方法如下:
__init__(level=NOTSET)
:初始化实例,传入处理日志级别。createLock()
:初始化一个线程锁,确保对文件访问是安全的。acquire()
:获取使用createLock()初始化的线程锁。release()
:释放锁。setLevel(level)
:设置处理阈值。setFormatter(fmt)
:设置消息格式。addFilter(filter)
:添加过滤器。removeFilter(filter)
:移除过滤器。filter(record)
:将此处理器的过滤器应用于记录,若要处理该条记录,则返回True。依次查询过滤器,直到其中返回一个False后处理器就不会处理记录。flush()
:确保已清除所有日志输出记录。close()
:关闭当前处理程序使用的所有资源,并删除处理程序。handle(record)
:经处理器处理后将记录对象record发送给实际处理程序。handleError(record)
:当Handle遇到异常时,将记录对象传递给emit()处理。若raiseExceptions属性为False,则异常将被忽略。format(record)
:如果设置了格式化程序将会对记录格式化,否则使用默认的格式化程序。emit(record)
:处理当处理程序出现异常时的记录对象。处理器一般很少自由使用。
Python日志模板内置数十种日志处理器,下面列举出常用的。
StreamHandler
:将日志记录输出发送到流,如控制台。FileHandler
:将日志记录发送到磁盘文件。NullHandler
:不做任何的格式输出。RotatingFileHandler
:按照日志文件大小分割日志。TimedRotatingFileHandler
:按照日志文件记录时间分割日志。STMPHandler
:将日志文件发送到指定电子邮箱。MemoryHandler
:将日志记录缓冲到内存中。HTTPHandler
:将日志记录发送到Web服务器。
- 将日志写入磁盘文件。
python
import logging
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)
ch = logging.StreamHandler()
ch.setLevel(logging.DEBUG) # 输出到console的log等级的开关
fh = logging.FileHandler('log.log', mode='w')
fh.setLevel(logging.DEBUG) # 输出到file的log等级的开关
fmt = logging.Formatter("%(asctime)s - %(filename)s[line:%(lineno)d] - %(levelname)s: %(message)s") # 创建一个格式化器
ch.setFormatter(fmt) # 格式化器添加到流处理器
fh.setFormatter(fmt) # 格式化器添加到文件写入处理器
logger.addHandler(ch) # 记录器添加流处理器
logger.addHandler(fh) # 记录器添加文件写入处理器
if __name__ == '__main__':
logger.info("这是一条常规日志信息1")
- 将日志文件按照时间分割
python
import time
import logging.handlers
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)
ch = logging.StreamHandler()
ch.setLevel(logging.DEBUG) # 输出到console的log等级的开关
fh = logging.handlers.TimedRotatingFileHandler(filename='log.log', when="m", interval=1,
backupCount=5, encoding='utf-8') # 按照时间分割日志
fh.setLevel(logging.DEBUG) # 输出到file的log等级的开关
fmt = logging.Formatter("%(asctime)s - %(filename)s[line:%(lineno)d] - %(levelname)s: %(message)s") # 创建一个格式化器
ch.setFormatter(fmt) # 格式化器添加到流处理器
fh.setFormatter(fmt) # 格式化器添加到文件按时分割处理器
logger.addHandler(ch) # 记录器添加流处理器
logger.addHandler(fh) # 记录器添加文件按时分割处理器
if __name__ == '__main__':
while True:
logger.info(f"这是一条常规日志信息,时间戳{time.time()}")
time.sleep(1)
- 将日志按照大小分割
python
import time
import logging.handlers
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)
ch = logging.StreamHandler()
ch.setLevel(logging.DEBUG) # 输出到console的log等级的开关
fh = logging.handlers.RotatingFileHandler(filename='log.log', maxBytes=1024, backupCount=5) # 按照日志文件大小分割日志
fh.setLevel(logging.DEBUG) # 输出到file的log等级的开关
fmt = logging.Formatter("%(asctime)s - %(filename)s[line:%(lineno)d] - %(levelname)s: %(message)s") # 创建一个格式化器
ch.setFormatter(fmt) # 格式化器添加到流处理器
fh.setFormatter(fmt) # 格式化器添加到文件按时分割处理器
logger.addHandler(ch) # 记录器添加流处理器
logger.addHandler(fh) # 记录器添加文件按大小割处理器
if __name__ == '__main__':
while True:
logger.info(f"这是一条常规日志信息,时间戳{time.time()}")
time.sleep(1)
- 将日志发送到邮箱
python
import time
import logging.handlers
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)
ch = logging.StreamHandler()
ch.setLevel(logging.DEBUG) # 输出到console的log等级的开关
fh = logging.handlers.SMTPHandler(
mailhost=('smtp.qq.com', 587), # SMTP邮件服务器地址和端口号
fromaddr='255xxx277@qq.com', # 发件人地址
toaddrs='243xxx539@qq.com', # 收件人地址
subject='发生了一个错误', # 邮件主题
credentials=('255xxx77@qq.com', 'ouqpcxxxbab')) # SMTP邮箱账号和SMTP服务授权码,不是邮箱登陆授权码
fh.setLevel(logging.ERROR) # 输出到file的log等级的开关
fmt = logging.Formatter("%(asctime)s - %(filename)s[line:%(lineno)d] - %(levelname)s: %(message)s") # 创建一个格式化器
ch.setFormatter(fmt) # 格式化器添加到流处理器
fh.setFormatter(fmt) # 格式化器添加到邮件发送处理器
logger.addHandler(ch) # 记录器添加流处理器
logger.addHandler(fh) # 记录器添加邮件发送处理器
if __name__ == '__main__':
try:
1 + "s"
except BaseException as e:
logger.exception(e)
Formatter
格式化器的作用就是将日志按照开发者想要的格式输出。它具有如下成员属性和方法。
__init__(fmt=None, datefmt=None, style='%')
:初始化方法,参数fmt代表格式化字符串,默认为%(message)s,参数datefmt是时间格式化字符串,style参数确定如何将格式字符串与数字合并,可选值有“%”、“{”、“$”。format(record)
:它是日志记录的属性字典,用作字符串格式化操作的数据,返回结果字符串。formatTime(record, datefmt=None)
:用自定义的格式化时间字符串来处理记录对象record,默认为“%Y-%m-%d%H:%M:%S,uuu”格式的时间格式化字符串。formatException(exc_info)
:将指定的异常信息格式化成字符串。formatStack(stack_info)
:将指定的堆栈信息转换为字符串。
可选择的格式化字段及输出示例如下表所示。
字段 | 含义 | 输出示例 |
---|---|---|
%(levelinfo)s | 打印日志级别的数值 | 20 |
%(levelname)s | 打印日志级别名称 | INFO |
%(pathname)s | 打印当前执行程序的路径 | C:/User/PythonProject/code/log.py |
%(filename)s | 打印当前执行程序名 | log.py |
%(funcName)s | 打印日志的当前函数 | <module> |
%(lineno)d | 打印日志的当前行号 | 35 |
%(asctime)s | 打印日志的时间 | 2020-02-25 22:00:58,759 |
%(thread)d | 打印线程ID | 1772 |
%(threadName)s | 打印线程名称 | MainThread |
%(process)d | 打印进程ID | 5732 |
%(message)s | 打印日志信息 | 日志初步使用 |
%(msecs)d | 打印日志时的毫秒时分 | 759 |
%(created)f | 打印记录日志时的时间戳 | 15823412441.522445 |
%(name)s | 打印记录器的名称,默认为root | root |
(processName)s | 打印进程名 | MainProcess |
(relativeCreated)d | 打印日志记录时相对于日志模块初始化的时间 | 358 |
%(module)s | 打印模块 | log |
Filters
过滤器提供了更加精细的附加功能,用于确定要输出的日志。过滤器可以单独添加到记录器和处理器,以便更为精准地输出日志记录。同时过滤器还可以负责记录日志的上下文处理,比如技术、附加消息等。
Filters有如下的成员属性和方法。
__init__(name='')
:初始化过滤器,name代表传入记录器或处理器名字,处理记录对象时会对比对象的处理器或记录器的名字与传入的name。若name为空则代表允许经过所有过滤器。filter(record)
:用于判断记录日志对象record是否需要记录。
过滤逻辑支持一个过滤器对象和过滤函数,执行逻辑为:检查filter对象是否有filter属性,若有假定其过滤函数为filter,并调用filter方法,否则假设它是可调用的单个函数,并以记录对象为单个参数进行调用。
下面示例如何自定义过滤器和过滤函数。
python
import logging
class WordFilter(logging.Filter):
def __init__(self, word, name=''):
"""
初始化一个字符检测过滤器
过滤日志消息中含有指定字符的消息
:param word: 要过滤的字符串
:param name: 记录器或处理器名字
"""
super().__init__(name)
self.name = name
self.nlen = len(name)
self.word = word
def filter(self, record: object) -> bool:
if self.nlen == 0 or self.name != record.name:
return True
if self.word in record.msg:
return False
else:
return True
logger_a = logging.getLogger('a') # 获取一个名为a的记录器
logger_b = logging.getLogger('b') # 获取一个名为b的记录器
logger_a.setLevel(logging.DEBUG) # 给a记录器设置记录日志等级
logger_b.setLevel(logging.DEBUG) # 给b记录器设置记录日志等级
ch = logging.StreamHandler() # 创建一个处理器
ch.setLevel(logging.DEBUG) # 给处理器设置日志等级
fmt = logging.Formatter("%(asctime)s - %(filename)s[line:%(lineno)d] - %(levelname)s: %(message)s-%(name)s") # 创建一个格式化器
ch.setFormatter(fmt) # 将格式化器添加到处理器
logger_a.addHandler(ch) # 给a记录器添加处理器
logger_b.addHandler(ch) # 给b记录器添加处理器
wordfilter = WordFilter("名字", "a")
logger_a.addFilter(wordfilter) # 给a记录器添加过滤器wordfilter
logger_b.addFilter(wordfilter) # 给b记录器添加过滤器wordfilter
if __name__ == '__main__':
logger_a.info("我是记录器,我的名字是a,我添加了wordfilter过滤器")
logger_b.info("我是记录器,我的名字是b,我添加了wordfilter过滤器")
logger_a.removeFilter(wordfilter)
logger_a.info("我是记录器,我的名字是a,我移除了wordfilter过滤器")
上述结果中,三条日志只处理了两条是因为自定义过滤器在过滤目标处理器a中生效,检查是否含关键词时第一条日志记录被过滤掉了。
python
import logging
def wordfilter(record: object) -> bool:
"""
自定义过滤器函数
:param record:
:return:
"""
if "名字" in record.msg:
return False
else:
return True
logger = logging.getLogger(__name__) # 创建一个过滤器
logger.setLevel(logging.DEBUG) # 设置处理的日志级别
ch = logging.StreamHandler() # 创建一个处理器
ch.setLevel(logging.DEBUG) # 设置处理器的日志级别
fmt = logging.Formatter(
"%(asctime)s - %(filename)s[line:%(lineno)d] - %(levelname)s: %(message)s-%(name)s") # 创建一个格式化器
ch.setFormatter(fmt) # 将格式化器添加到处理器
logger.addHandler(ch) # 将处理器添加到记录器
logger.addFilter(wordfilter) # 将自定义过滤函数添加到记录器
if __name__ == '__main__':
logger.info("我是记录器,我的名字是__main__,我添加了wordfilter过滤器函数")
logger.removeFilter(wordfilter)
logger.info("我是记录器,我的名字是__main__,我移除了wordfilter过滤器")
LogRecord对象
LogRecord对象在Logger每次记录时自动创建,并且可以通过makeLogRecord函数手动创建。它在logging四大组件之间流动,用于传递日志消息。它是连通日志记录四大组件的重要对象。
LogRecord对象的属性和方法如下。
__init__(name, level, pathname, lineno, msg, args, esc_info, func=None, sinfo=None)
:产生LogRecord的初始方法,相关参数解释如下。- name:产生LogRecord实例的事件记录器的名称。
- level:日志记录事件的数字级别。该属性将转换为LogRecord的levelno数字值和levelname相应的级别名称。
- pathname:日志记录时调用的源文件的完整路径。
- lineno:记录日志时代码的行号。
- msg:事件描述信息,可能是带有占位符的格式字符串。
- args:合并到msg参数中的可变数据,可以此获得事件描述。
- exc_info:具有当前异常信息的异常元组。
- func:从中调用日志记录的函数或方法的名称。
- sinfo:一个文本字符串,表示从当前线程中的堆栈底部到日志记录调用的堆栈信息。
getMessage()
:用于返回LogRecord对象实例化时的消息内容。
LogRecord实例化对象的全部属性见下表。
属性名称 | 格式 | 说明 | 示例值 |
---|---|---|---|
args | 不需要格式化 | 将参数的元组合并到msg,生成消息 | () |
asctime | %(asctime)s | LogRecird创建时的格式化可读时间 | 2020-02-27 12:00:00, 054 |
created | %(created)f | LogRecord创建的时间戳 | 2939848123.24241 |
exc_info | 不需要格式化 | 异常信息元组或者None | None |
filename | %(filename)s | 路径名的文件名部分 | log.py |
funcName | %(funcName)s | 包含创建日志的函数名称 | <module> |
levelname | %(levelname)s | 文本日志记录消息的级别 | DEBUG |
levelno | %(levelno)s | 日志记录的级别表示数字 | 20 |
lineno | %(lineno)d | 发出日志记录调用的源码符号 | 18 |
message | %(message)s | 记录的消息。是调用Formatter.format函数填充args函数后得到的 | 发送日志服务器 |
module | %(module)s | 模块(filename的名称部分) | log |
msecs | %(msecs)d | LogRecord创建时间的毫秒部分 | 53.01134490866797 |
msg | 不需要格式化 | 原始日志记录调用中传递的格式字符串 | 发送日志服务器 |
name | %(name)s | 对应记录器的名称 | __main__ |
pathname | %(pathname)s | 调用日志记录的源文件的完整路径 | A:/log/log.py |
process | %(process)d | 进程ID | 16011 |
processName | %(processName)s | 进程名 | MainProcess |
relativeCreated | %(relativeCreated)d | 创建LogRecord时相对于加载日志模块的时间 | 3005.11234123231 |
stack_info | 不需要格式化 | 当前线程中堆栈底部的堆栈帧信息,直至导致创建此纪录的日志调用的堆栈帧 | None |
thread | %(thread)d | 线程ID | 844 |
threadName | %(threadName)s | 线程名 | MainThread |
构造LogRecord不能直接使用上方的属性作为传入参数实例化LogRecord类,一般使用logging.makeRecord({})创建一个没有任何属性的LogRecord对象,然后使用update函数更新这个示例中__dict__的全部参数,即可实现恢复一个LogRecord实例化对象,但是要注意这个实例的字段的数据类型不能改变。
日志的配置
日志配置有以下方法:
- 使用配置方法显式创建记录器,处理程序和格式化程序;
- 使用fileConfig()函数读取日志配置文件。
- 使用dictConfig()函数读取配置信息字典。
显式配置
该方法指直接使用logging四大组件的相关设置函数来配置。在之前的例子中都是在代码中重复使用配置,如使用logger=logging.getLogger()获取记录器,这种代码放在业务代码中很不整洁,因此常用的方法是将这些配置代码放到单独的文件中,需要时导入即可。多次导入记录器不会重复实例化配置,它们的导入都是第一次配置的记录器。
通过fileConfig()配置
该函数可以从.conf文件中读取日志配置,该函数位于logging.config模块。conf文件必须包含名为[loggers]、[handlers]、[formatters]的节点,这些节点通过名称标识定义出每种类型的组件,其节点下的项以keys=value1,value2等格式组成。
新建一个log.conf文件,写入下方配置项。
ini
[loggers] # 声明是loggers节点
keys = root,log02
# 配置两个记录器分别是root和log02
[handlers] # 声明是handlers节点
keys = hand01
# 配置一个处理器
[formatters] # 声明是formatters节点
keys = fmt
# 配置一个格式化器fmt
[logger_root] # 对root记录器配置
level = NOTSET
handlers = hand01
[logger_log02] # 对log02记录器配置
level = DEBUG
handlers = hand01
propagate = 1
qualname = compiler.parser
[handler_hand01] # 对hand01处理器配置
class = StreamHandler
level = DEBUG
formatter = fmt
args = (sys.stdout,)
[formatter_fmt] # 对格式化器fmt进行配置
format = %(asctime)s - %(filename)s[line:%(lineno)d] - %(levelname)s: %(message)s-%(name)s
datefmt =
class = logging.Formatter
然后创建一个读取该配置文件的log.py。
python
import logging.config
logging.config.fileConfig('log.conf')
logger = logging.getLogger('log02')
if __name__ == '__main__':
logger.info("读取配置")
运行结果
2023-07-07 23:06:12,181 - 3-13-2 fileConfig读取配置.py[line:7] - INFO: 读取配置-log02
通过dictConfig读取
dictConfig可以从字典中获取日志记录配置,该函数位于logging.config中。dictConfig同时支持在dict中导入外部对象。在配置处理器、过滤器、格式化器中使用自定义对象用特殊键“()”,兹定于i对象所需的构造参数以及键值对在配置字典中列出。当引用外部对象时使用“ext://”+自定义对象导入路径的方式,配置系统会自动分割字符串,并使用常规导入机制处理值的剩余部分。dictConfig还支持引用配置文件内部的对象。对于日志系统内部的对象通过提供ID引用或隐式转换,如DEBUG会自动换成logging.DEBUG。若为用户自定义的对象就要通过“dfg://”+相对配置文件来引用,该位置即字典获取值的路径。如“cfg://handler.email”指的是config_dict[]'handlers']['email']。
dictConfig所需的配置字典应包含下列键。
version指版本号。
formatters:格式化器,其值为dict类型,其中键为ID,值为含有format、datefmt的配置字典。
json
"fmt": {
"format": "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
}
- filters:过滤器,值为dict类型,键位ID,值位含有name固定字段的配置字典。
json
"filters": {
"wordfilter": {
"name": "WordFilter"
}
}
- handlers:处理器,值位dict类型,键为ID,值为含有clas、level、formatter、filters等字段的配置字典。
json
"handlers": {
"hand01": {
"class": "logging.StreamHandler",
"level": "INFO",
"filters": [
"wordfilter"
],
"formatter": "fmt"
}
}
- loggers:记录器,值为dict类型,其中键为记录器名称,值为含有propagate、level、filters、handlers等字段的配置字典。
json
"loggers": {
"log02": {
"propagate": 1,
"level": "DEBUG",
"handlers": ["hand01"]
},
"root": {
"level": "DEBUG",
"handlers": ["hand01"]
}
}
root:根记录器,配置和logger相同,但是配置字典不能使用propagate属性。
incremental:用来决定是否替换现有配置,默认为False。
disable_existing_logger:用于判断是否禁用现有的记录器,默认为True。
python
from logging import getLogger, config
data = {
"word": "去除", # 一个过滤关键字
"version": 1,
"disable_existing_loggers": True,
"formatters": {
"fmt": {
"format": "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
}
},
"filters": {
"wordfilter": {
"()": "ext://自定义类过滤器.WordFilter", "word": "名字", "name": "log02"
},
"wordfilter2": {
"()": "ext://自定义类过滤器.WordFilter", "word": "cfg://word", "name": "log02"
}
},
"handlers": {
"hand01": {
"class": "logging.StreamHandler",
"level": "DEBUG",
"formatter": "fmt",
"filters": [
"wordfilter", "wordfilter2"
],
}
},
"loggers": {
"log02": {
"propagate": 1,
"level": "DEBUG",
"handlers": ["hand01"],
},
"root": {
"level": "DEBUG",
"handlers": ["hand01"]
}
}
}
config.dictConfig(data)
logger = getLogger('log02')
if __name__ == '__main__':
logger.info("本条将不被过滤,不含过滤关键字")
logger.info("本条将过滤,含过滤关键字:名字")
logger.info("本条将过滤,含过滤关键字:去除")
运行结果
2020-03-01 10:02:29,968 - log02 - INFO - 本条将不被过滤,不含过滤关键字