将所有 celery 任务的日志消息发送到单个文件

Posted

技术标签:

【中文标题】将所有 celery 任务的日志消息发送到单个文件【英文标题】:Send log messages from all celery tasks to a single file 【发布时间】:2011-09-05 17:49:19 【问题描述】:

我想知道如何设置更具体的日志记录系统。我所有的任务都使用

logger = logging.getLogger(__name__)

作为模块范围的记录器。

我希望 celery 记录到“celeryd.log”,我的任务记录到“tasks.log”,但我不知道如何让它工作。使用 django-celery 中的CELERYD_LOG_FILE,我可以将所有与 celeryd 相关的日志消息路由到 celeryd.log,但我的任务中创建的日志消息没有任何痕迹。

【问题讨论】:

【参考方案1】:

注意:这个答案在 Celery 3.0 中已经过时了,你现在使用get_task_logger() 来设置你的每任务记录器。详情请见the Logging section of the What's new in Celery 3.0 document。


Celery 专门支持每个任务的日志记录。见Task documentation on the subject:

您可以使用工作人员记录器将诊断输出添加到工作人员日志:

@celery.task()
def add(x, y):
    logger = add.get_logger()
    logger.info("Adding %s + %s" % (x, y))
    return x + y

有多个日志级别可用,worker loglevel 设置决定 是否将它们写入日志文件。

当然,您也可以简单地使用 print,因为任何写入标准输出/-err 的内容都将是 也写入日志文件。

在底层,这仍然是标准的 python 日志记录模块。您可以将 CELERYD_HIJACK_ROOT_LOGGER option 设置为 False 以允许您自己的日志记录设置工作,否则 Celery 将为您配置处理。

但是,对于任务,.get_logger() 调用确实允许您为每个单独的任务设置单独的日志文件。只需传入一个 logfile 参数,它就会将日志消息路由到该单独的文件:

@celery.task()
def add(x, y):
    logger = add.get_logger(logfile='tasks.log')
    logger.info("Adding %s + %s" % (x, y))
    return x + y 

最后但并非最不重要的一点是,您可以在python logging module 中配置您的***包并为其提供自己的文件处理程序。我会使用celery.signals.after_setup_task_logger 信号进行设置;在这里,我假设您的所有模块都位于一个名为 foo.tasks 的包中(如 foo.tasks.emailfoo.tasks.scaling):

from celery.signals import after_setup_task_logger
import logging

def foo_tasks_setup_logging(**kw):
    logger = logging.getLogger('foo.tasks')
    if not logger.handlers:
        handler = logging.FileHandler('tasks.log')
        formatter = logging.Formatter(logging.BASIC_FORMAT) # you may want to customize this.
        handler.setFormatter(formatter)
        logger.addHandler(handler)
        logger.propagate = False

after_setup_task_logger.connect(foo_tasks_setup_logging)

现在任何名称以foo.tasks 开头的记录器都会将其所有消息发送到tasks.log 而不是根记录器(因为.propagate 为假,根记录器看不到任何这些消息)。

【讨论】:

日志消息是缓冲的还是非缓冲的?我想知道无序的日志消息是否表明任务执行无序。 @EricWalker:logging 不缓冲任何东西。 FileHandler 使用常规的 open() 调用,默认以文本模式打开文件,因此写入该文件将使用行缓冲(在每个换行符之后刷新,这意味着每个日志条目)。 似乎“CELERYD_HIJACK_ROOT_LOGGER”(而不是“CELERY_HIJACK_ROOT_LOGGER”)中有错字 @imbolc:我找不到对CELERY_WORKER_HIJACK_ROOT_LOGGER 的任何引用,不确定你在说什么。只有CELERYD_HIJACK_ROOT_LOGGERworker_hijack_root_logger配置选项名(后者是前者的4.x小写版本)。 @MartijnPieters 是的,它大约是 4.x,您只需将其设为前缀和大写即可在 settings.py 中使用【参考方案2】:

提示:Celery 有自己的日志处理程序:

from celery.utils.log import get_task_logger
logger = get_task_logger(__name__)

此外,Celery 记录任务的所有输出。更多详情Celery docs for Task Logging

【讨论】:

【参考方案3】:

加入 --concurrency=1 --loglevel=INFO 用命令运行 celery worker

例如:python xxxx.py celery worker --concurrency=1 --loglevel=INFO

最好在每个 python 文件中设置日志级别

【讨论】:

以上是关于将所有 celery 任务的日志消息发送到单个文件的主要内容,如果未能解决你的问题,请参考以下文章

Celery 任务未捕获的异常未发送到 Sentry

Django Channels 从 Celery 任务发送组消息。 Asyncio 事件循环在所有异步任务完成之前停止

如何将定期任务发送到 Celery 中的特定队列

Celery 使用

从 Celery 任务向 Channels 发送消息

php怎么调用celery任务