Python - 异步日志记录

Ziv*_*iva 12 python logging asynchronous python-2.7

我需要在运行系统代码时记录大量数据。我可以使用哪些日志包来实现高效的异步日志记录?默认情况下,标准 Python 日志记录包 ( https://docs.python.org/2/library/logging.html ) 是异步的吗?

Tod*_*odd 19

异步代码可以使用常用的日志记录功能,而无需求助于特殊的异步模块或包装器。这样的代码是可以的。

import logging


async def do_some_async_stuff(self):
    logging.getLogger(__name__).info("Started doing stuff...")

    logging.getLogger(__name__).warn("Things went awry...")
Run Code Online (Sandbox Code Playgroud)

这里的问题是提交日志条目是否会在条目写入文件时产生一些延迟,从而剥夺异步系统在这段时间内运行其他任务的机会。如果将写入文件的阻塞处理程序直接添加到日志记录层次结构的某个位置,则可能会发生这种情况。

标准模块为此提供了一个简单的解决方案logging:使用非阻塞处理程序,将其消息排队到在其自己的私有线程中运行的所需阻塞处理程序。

除了纯粹主义之外,没有任何硬性规则阻止使用 来QueueHandler提供使用非阻塞日志处理程序进行日志记录的异步代码,与托管在QueueListener.

下面的解决方案与调用记录器logging并以典型方式提交条目的协程完全兼容 - 不需要调用的包装器.run_in_executor()。异步代码不会遇到日志系统的任何阻塞行为。

例如,QueueHandler可以将 a 设置为根处理程序

import queue
from logging.handlers import QueueHandler

log_queue     = queue.Queue()
queue_handler = QueueHandler(log_queue)  # Non-blocking handler.

root = logging.getLogger()
root.addHandler(queue_handler)           # Attached to the root logger.
Run Code Online (Sandbox Code Playgroud)

您想要的阻塞处理程序可以放入QueueListener

from logging.handlers import QueueListener
from logging.handlers import RotatingFileHandler

rot_handler    = RotatingFileHandler(...)   # The blocking handler.
queue_listener = QueueListener(log_queue, 
                               rot_handler) # Sitting comfortably in its
                                            # own thread, isolated from
                                            # async code.
queue_listener.start()
Run Code Online (Sandbox Code Playgroud)

然后使用您需要的任何日志条目格式配置嵌套在侦听器中的处理程序。

我个人喜欢旋转文件处理程序,因为它限制了生成的日志文件的大小和数量,在创建新备份时删除最旧的日志文件。


tas*_*tas 12

您可以logging.info()使用n 个工作线程池执行消息,使用concurrent.futures.ThreadPoolExecutor, n 应始终等于 1 :

import concurrent.futures 
import logging

executor = concurrent.futures.ThreadPoolExecutor(max_workers=1) 

def info(self, msg, *args):
    executor.submit(logging.info, msg, *args)
Run Code Online (Sandbox Code Playgroud)

  • 请注意,如果您在调用“info”后更改正在记录的值,则不确定将记录哪个版本。 (5认同)