我们使用celery作为一种自制的map-reduce工具,我们在多个worker上并行运行作业并等待结果。我们使用celery事件将worker上的python日志消息传送回客户端。我知道我们可以使用像sentry这样的日志聚合工具,但对我们来说这些日志消息会返回给客户端非常重要。问题是,如何在没有线程的情况下在客户端上注册芹菜事件监听器?另外,这是我们完全错了吗?它适用于我们,但也许有更好的方法。
我在github中创建了一个工作示例:
https://github.com/gijzelaerr/celerylog
以下是我们正在做的一个小小的解释。
在工人身上我们运行:
class TaskLogEmitter(logging.Handler):
def __init__(self, celery_app, level=logging.NOTSET):
self.celery_app = celery_app
super(TaskLogEmitter, self).__init__(level=level)
def emit(self, record):
with self.celery_app.events.default_dispatcher() as d:
d.send('task-log', msg=record.getMessage(), levelno=record.levelno,
pathname=record.pathname, lineno=record.lineno,
name=record.name, exc_info=record.exc_info)
@after_setup_logger.connect
@after_setup_task_logger.connect
def setup_task_log_emitter(logger=None, **kwargs):
"""
setup log handler
"""
handler = TaskLogEmitter(celery_app)
logger.addHandler(handler)
这将注册一个python日志处理程序并为每个日志记录发出一个celery事件。在客户端,我们有一个偶数监控功能:
def monitor_events(celery_app):
def on_event(event):
logger = logging.getLogger(event['name'])
logger.log(event['levelno'],event.msg)
with celery_app.connection() as conn:
recv = celery_app.events.Receiver(conn, handlers={'task-log':
on_event})
recv.capture(limit=None, timeout=None, wakeup=True)
我们从一个线程开始,否则它阻止:
def setup_event_listening(celery_app):
thread = threading.Thread(target=monitor_events, args=[celery_app])
thread.daemon = True
thread.start()