实现无阻塞的远程日志处理程序
问题描述:
我试图实现简单的日志处理程序,它使用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变得不可访问或开始响应缓慢。所以我试图找出最好的方式使这个调用独立于调用线程。
我已经考虑:
- 包括一些非标准库,这将使HTTP请求的异步
- 使用QueueHandler和QueueListener所概述here
- 使用ASYNCIO
所有这些解决方案对于实现这样简单的任务似乎太复杂/不必要。为了使这个处理程序不被阻塞,是否有更好的方法来减少开销?
答
对于任何将面对此问题的人来说,解决方案结果如简单here所述。
import queue
from logging 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。
您的应用程序不应该将其日志路由到任何地方,请参阅https://12factor.net/logs – jonrsharpe
为什么你认为排队解决方案是过度复杂?这是唯一的解决方案:远程推送记录的工作线程,以及在发布记录时将记录添加到队列中的普通线程。 –
您也可以切换到UDP流量,并只发送发送方法中的数据报,非阻塞。但是不能保证远程交付和处理(系统日志处理程序以这种方式工作,afaik)。 –