python的标准库logging
提供了非常强大的日志记录功能,合适的日志输出对于调试代码可以提供非常大的帮助。这个库的基本用法非常的简单,这里不做赘述,而是记录一种稍微复杂的用法。
1、背景
在项目开发的过程中,难免要引入第三方库,这些第三方库中大多也会用logging
模块来进行日志记录。如果不加任何处理,那么很可能我们自己项目的日志中会夹杂许多第三方库的日志——而这些信息是我们不想要的,因此,要想一个办法,来阻止这些额外日志的输出。
2、利用logging.Filter
来进行过滤
通过Filter的名字就可以猜到,这是用来对日志信息进行过滤的。通过设置合适的过滤规则,可以使日志记录器只记录你想让它记录的内容。
明白了这一点,就可以利用logging.Filter
来过滤掉你自己项目中第三方库的日志信息了。一种可行的想法时:只记录项目文件所打印的日志,而不记录之外的文件打印的日志。针对这种项目,具体的实施过程分为以下几步。
1.找到项目的所有.py
文件
首先,任何一个项目都有一个主文件,或者叫做入口文件,这个文件一般存放在项目根目录中,通过这个文件,可以很容易找到项目中所有的.py
文件:
import os
py_dir = os.path.split(os.path.realpath(__file__))[0]
pys = [] # 记录项目所有的py文件
for _, _, i in os.walk(py_dir):
pys.extend([j for j in i if j.endswith('py')])
2.创建一个满足要求的过滤器
我们的目标是过滤掉所有第三方库的日志,那么,过滤器可以按如下代码定义:
import logging
class MyFilter(logging.Filter):
def filter(self, record):
if record.filename in pys:
return True
return False
这里创建了一个过滤器类,继承自logging.Filter
,且该类中必须要有一个filter
方法,该方法接受一个参数,record
,实际是一个logging.LogRecord
实例;返回值为布尔型,True
表示允许该实例通过,False
相反。因此,在filter
中就可以利用logging.LogRecord
的所有属性来对是否过滤掉一个即将输出的record。这里的代码使用的是输出日志的文件的名称,与第一步中的结果对应,意思就是,如果输出日志的文件的名称属于项目文件的名称列表中,则输出该日志;否则,过滤掉。
由于输入的是一个logging.LogRecord
实例,因此你可以用该实例的所有方法来设置过滤规则。logging.LogRecord
实例的所有方法可以在这里找到。
3.完整的例子
将上面的代码组合,得到一个完整的例子如下:
import os
import logging
import sys
def get_project_pys():
"""获取项目的所有py文件"""
py_dir = os.path.split(os.path.realpath(__file__))[0]
pys = [] # 记录项目所有的py文件
for _, _, i in os.walk(py_dir):
pys.extend([j for j in i if j.endswith('py')])
return pys
class MyFilter(logging.Filter):
"""构造一个过滤器"""
def __init__(self, pys):
self.pys = pys
def filter(self, record):
if record.filename in self.pys:
return True
return False
pys = get_project_pys()
# 设置日志输出的样式
formatter = logging.Formatter('%(asctime)s - %(filename)s - %(levelname)s - %(message)s')
# 设置日志在控制台输出
stream_handler = logging.StreamHandler(sys.stdout)
# 给该handler绑定formatter
stream_handler.setFormatter(formatter)
# 给该handerl绑定自定义的过滤器
stream_handler.addFilter(MyFilter(pys))
# 在主线程中调用此方法
logging.basicConfig(level=logging.DEBUG, handlers=[stream_handler])
logger = logging.getLogger(__name__)
logger.info('hi you')
上述操作的含义是:主线程定义了所有其他模块在当前解释器环境中使用logging
时的规则,由于pys
里面只包含当前项目的文件,因此,其他第三方的文件便不再被打印了。
- 2021.9.16更新
现在,可以只创建一个接受record
的函数来实现过滤功能:
...
def filter_fn(record):
if record.filename in pys:
return True
return False
...
stream_handler.addFilter(filter_fn)
...
具体地,可以参看它的源码。