在python中如何只记录目标文件输出的日志

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)
...

具体地,可以参看它的源码

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

芳樽里的歌

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值