Как регистрироваться в журнале celery вне задач celery (внутри представления django)?

Представьте конечную точку в проекте django

def my_view(request, my_id):
    if is_request_valid(request):
        logger = logging.getLogger('celery.task')
        logger.info('Starting a task for a thing with ID %i', my_id)
        my_cool_task.apply_async()

Теперь, согласно документам celery, это может войти в журнал, поскольку

Доступен специальный логгер под названием "celery.task", вы можете наследоваться от этого логгера, чтобы автоматически получать имя задачи и уникальный идентификатор как часть логов.

Но логгер "celery.task" работает только внутри задачи. Поэтому в представлении этот лог уйдет в никуда.

Кроме того, я играл с установкой некоторой переменной логирования внутри settings.py, а затем переназначил логирование сельдерея. Я играл с CELERY_WORKER_HIJACK_ROOT_LOGGER, но даже когда я использую корневой логгер, журналы не появляются в консоли. Не помогает и использование getLogger("celery").

Это кажется простым делом, но я целый день пытаюсь это сделать, пожалуйста, помогите.

UPD: Я видел пост на reddit с той же проблемой, но там нет ответов

So, as the question stands, it is impossible to hack into the celery's logger.

However, there are a few workarounds:

  1. Make a task for logging, e.g.
from celery.utils.log import get_task_logger

@shared_task
def log_stuff(level, message, *args, **kwargs):
    get_task_logger().log(level, message, *args, **kwargs)

However, this is dirty for many reasons: mainly because your log will get executed when the worker will get to it, and so this just becomes a mess.

  1. Log into the same file. Go into your_projects_name/settings.py, define LOGGING variable, for example:
LOGGING = {
    'version': 1,
    'disable_existing_loggers': False, 
    'formatters': {
        'simple': {
            'format': '[%(levelname)s] %(message)s',
        },
    },
    'handlers': {
        'console': {
            'level': 'INFO',
            'class': 'logging.StreamHandler',
            'formatter': 'simple'
        },
        'file': {
            'level': 'INFO',
            # with rotating handlers you can configure max size and other stuff
            'class': 'logging.FileHandler',
            'formatter': 'simple',
            'filename': 'my_log.log',
        },
    # that's the most interesting part
    'loggers':
        'django': {
            'handlers': ['file', 'console'],
            'level': 'INFO',
        },
        'celery': {
            'handlers': ['file', 'console'],
            'level': 'INFO',
        },
}

Note: your logging configuration should be more complex.

Now, no further action is required, given the default django celery setup from the docs, and that your django version is 4.2.11, and celery is 5.3.6 - on the older versions you might want to play with celery.signals.setup_logging.

2nd note: streams are set up for separate django and celery processes: you will not see them all in one place

  1. Consider using tools like logstash, sentry, graypy, new relic - they will gather all logs into one place. I haven't tried neither one of them, but it's something that is also used.

Lastly, of course this could work with anything, not necessarily just django.

Вернуться на верх