You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让同一Logger在Django和Celery中分别输出到控制台与日志文件

Django与Celery共用Logger配置需求

我需要一个可同时在Django和Celery环境中使用的Logger:在Django中运行时输出至控制台,在Celery任务中运行时则通过Celery默认日志处理器输出到--logfile命令行参数指定的日志文件,这对被Django服务器和Celery任务共用的辅助函数尤为重要。

当前我的settings.py文件中的LOGGING配置如下:

LOGLEVEL = os.environ.get("LOGLEVEL", "info").upper()
LOGGING = {
    "version": 1,  # the dictConfig format version
    "disable_existing_loggers": False,  # retain the default loggers
    "handlers": {
        # console logs to stderr
        "console": {
            "class": "logging.StreamHandler",
            "formatter": "verbose",
        },
        "django.server": DEFAULT_LOGGING["handlers"]["django.server"],
    },
    "formatters": {
        "verbose": {
            "format": "[{asctime}]|{levelname}| {message}",
            "style": "{",
        },
        "django.server": {
            # "()": "django.utils.log.ServerFormatter",
            "format": "[{asctime}]|{levelname}| {message}",
            "style": "{",
        },
    },
    "loggers": {
        # default for all undefined Python modules
        "": {
            "level": "WARNING",
            "handlers": ["console"],
        },
        # Our application code
        "app": {
            "level": LOGLEVEL,
            "handlers": ["console"],
            # Avoid double logging because of root logger
            "propagate": False,
        },
        # Default runserver request logging
        "django.server": DEFAULT_LOGGING["loggers"]["django.server"],
        "django.channels.server": DEFAULT_LOGGING["loggers"]["django.server"],
    },
}

目前我的"app" logger仅配置了console处理器。当我定义Logger为logger = get_task_logger("app").getChild(__name__)时,日志输出到控制台但不写入日志文件;若定义为logger = get_task_logger(__name__),则日志写入日志文件但不输出到控制台。我希望将Celery默认日志处理器添加到我的"app" logger中,是否可行?


解决方案

完全可行,你可以通过以下方式实现共用Logger的需求:

1. 统一Logger获取方式

不要混用get_task_logger和普通Django logger,统一使用标准的logging.getLogger,让Celery自动适配环境添加专属处理器。在共用的辅助函数中这样定义logger:

import logging

logger = logging.getLogger(__name__)  # 或使用 logging.getLogger("app." + __name__) 明确归属app日志组

2. 调整Django LOGGING配置

保留app logger的控制台处理器,同时开启日志向上传播,让Celery的root级处理器能捕获日志:

"app": {
    "level": LOGLEVEL,
    "handlers": ["console"],
    "propagate": True,  # 允许日志传播到root logger,Celery会为root添加文件处理器
},

3. 配置Celery继承Django日志体系

在Celery配置文件(如celery.py)中,关闭root logger劫持,保留Django的日志配置:

from celery import Celery
import os
from django.conf import settings

os.environ.setdefault("DJANGO_SETTINGS_MODULE", "你的项目名.settings")

app = Celery("你的项目名")
app.config_from_object("django.conf:settings", namespace="CELERY")

# 关键配置:不覆盖Django的root logger,保留原有配置同时加载Celery的日志处理器
app.conf.update(
    worker_hijack_root_logger=False,
)

4. 验证效果

  • Django环境下:app logger的日志通过自身配置的console处理器输出到控制台。
  • Celery任务中:app logger的日志会传播到root logger,被Celery自动添加的文件处理器捕获,写入--logfile指定的文件;若Celery开启控制台输出,日志也会同步打印到终端。

替代方案:动态添加Celery处理器

如果不想开启日志传播,可以在Celery启动时手动为app logger添加Celery的处理器:

import logging
from celery.utils.log import get_logger

# 获取Celery默认日志处理器
celery_root_logger = get_logger("celery")
celery_handlers = celery_root_logger.handlers

# 获取我们的app logger
app_logger = logging.getLogger("app")
# 避免重复添加处理器
for handler in celery_handlers:
    if handler not in app_logger.handlers:
        app_logger.addHandler(handler)

这样app logger在Celery环境中会同时拥有控制台和文件处理器,Django环境下仅保留控制台处理器,完全匹配你的需求。


内容的提问来源于stack exchange,提问作者hornobster

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 18:05:58