实现非阻塞的远程日志处理程序

6

我正在尝试实现一个简单的日志处理程序,该程序使用Python的标准 logging 库将事件记录到远程服务器。因此,我创建了一个自定义类,继承自 logging.Handler,名为 RemoteLogHandler,它接受 LogRecord 并将其发送到远程服务器。该处理程序以标准的 addHandler() 方式附加到根记录器。

from urllib import requests

class RemoteLogHandler(logging.Handler):
    def emit(self, record):
        remote_url = "http://foo.bar.baz"
        req = request.Request(remote_url, data=record.msg)
        request.urlopen(req, timeout=1)

这个功能是按预期工作的,但当remote_url变得无法访问或响应变慢时,显然会导致调用线程被锁定。因此,我正在尝试找到使此调用与调用线程无关的最佳方法。
我考虑了以下几种方案:
1.包括某些非标准库,使http请求异步化 2.使用QueueHandler和QueueListener,如这里所述 3.使用asyncio
所有这些解决方案似乎都过于复杂/不必要,无法实现如此简单的任务。是否有更好的方法可以减少开销,使此处理程序非阻塞?

2
你的应用程序不应该将其日志路由到任何地方,参见 https://12factor.net/logs - jonrsharpe
1
你为什么认为排队解决方案过于复杂?这是唯一的解决方案:一个工作线程远程推送记录,正常线程在发出记录时将其添加到队列中。 - Sergey Vasilyev
1
您也可以切换到UDP流量,并在发射方法中仅发送数据报,以非阻塞方式进行。但是,无法保证远程传递和处理(syslog处理程序就是这样工作的,据我所知)。 - Sergey Vasilyev
你是对的,我最终使用了logging包中的QueueHandler/Listener,结果证明这非常简单。 - tvm
1个回答

10

对于那些将要面临这个问题的人,解决方案就像这里所描述的那样简单

import queue
from logging.handlers import QueueHandler, QueueListener

# instantiate queue & attach it to handler
log_queue = queue.Queue(-1)
queue_handler = QueueHandler(log_queue)

# instantiate our custom log handler (see question)
remote_handler = RemoteLogHandler()

# instantiate listener
remote_listener = QueueListener(log_queue, remote_handler)

# attach custom handler to root logger
logging.getLogger().addHandler(queue_handler)

# start the listener
remote_listener.start()

QueueListener 运行在它自己的线程中,监听由 QueueHandlers 发送的 LogRecords,从而实现非阻塞记录日志。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接