临时更改Python日志处理器

2 投票
2 回答
1153 浏览
提问于 2025-04-16 19:11

我正在开发一个应用程序,使用标准的日志模块来记录日志。我们的设置是根据不同的级别等,将日志记录到多个文件中。同时,我们还使用celery来处理一些主应用程序之外的任务(通常是一些耗时的维护工作)。

这个celery任务除了调用一些函数(比如说spam)来完成实际工作外,什么也不做。这些函数使用日志模块来输出状态信息。现在,我想写一个装饰器,能够拦截所有spam函数的日志调用,并将它们放入一个StringIO中,这样我就可以把它们放到其他地方。

我想到的一个解决方案是在函数执行期间,为根日志记录器插入一个处理器,以捕获所有日志信息。不过,这样做会干扰全局共享对象,可能会在后面造成问题。

我看到过这个回答,但它并不是我想要的解决方案。

2 个回答

0

对于StringIO处理器,你可以为根日志记录器添加一个额外的处理器,这样可以捕捉到所有的日志信息,但同时加一个虚假的过滤器(Logger.addFilter),这个过滤器会把所有的日志信息都过滤掉(所以实际上什么都不会被记录到StringIO中)。

然后,你可以为spam函数写一个装饰器,在函数执行之前移除这个过滤器(Logger.removeFilter),执行完后再把虚假的过滤器加回来。

2

关于StringIO的事情是,可能会有多个进程在运行(比如Celery任务),所以会有多个StringIO,对吧?

你可以这样做:

  1. 在Celery运行的进程中,给根日志记录器添加一个处理器,这个处理器可以把事件发送到一个套接字(如果是TCP就用SocketHandler,如果是UDP就用DatagramHandler)。
  2. 创建一个套接字接收器来接收和处理这些事件,具体的做法可以参考这里。这样就可以在多个Celery进程之间整合成一个统一的StringIO。

如果你在使用多进程,也可以参考这里描述的方法。虽然那篇文章是关于Python 3.2的,但Python 2.x也可以用logutils实现类似的功能。

更新:如果你想避免使用单独的接收进程,可以直接把日志记录到数据库,使用类似于这个答案中的处理器。如果你想在进程结束之前都不记录日志,可以使用MemoryHandler和数据库处理器结合来实现。

撰写回答