Как включить поле сообщения в журналы Structlog и лучшие практики интеграции с ElasticSearch

Я работаю над проектом Django, где ведение логов имеет решающее значение, и я использую structlog для форматирования и управления логами. Планируется отправлять эти журналы в ElasticSearch. Однако я столкнулся с проблемой: в логах отсутствует поле «message», хотя я явно передаю сообщение в вызове логгера.

Вот вывод журнала, который я сейчас получаю:

{
    "code": 200,
    "request": "POST /api/push-notifications/subscribe/",
    "event": "request_finished",
    "ip": "127.0.0.1",
    "request_id": "d0edd77d-d68b-49d8-9d0d-87ee6ff723bf",
    "user_id": "98c78a2d-57f1-4caa-8b2a-8f5c4e295f95",
    "timestamp": "2025-01-21T10:40:43.233334Z",
    "logger": "django_structlog.middlewares.request",
    "level": "info"
}

Я хочу включить поле «сообщение», например:

{
    "code": 200,
    "request": "POST /api/push-notifications/subscribe/",
    "event": "request_finished",
    "ip": "127.0.0.1",
    "request_id": "d0edd77d-d68b-49d8-9d0d-87ee6ff723bf",
    "user_id": "98c78a2d-57f1-4caa-8b2a-8f5c4e295f95",
    "timestamp": "2025-01-21T10:40:43.233334Z",
    "logger": "django_structlog.middlewares.request",
    "level": "info", 
    "message": "push notification subscribed successfully"
}

Вот моя текущая настройка: settings.py Logger Configuration

LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    "formatters": {
        "json_formatter": {
            "()": structlog.stdlib.ProcessorFormatter,
            "processor": structlog.processors.JSONRenderer(),
        },
        "plain_console": {
            "()": structlog.stdlib.ProcessorFormatter,
            "processor": structlog.dev.ConsoleRenderer(),
        },
        "key_value": {
            "()": structlog.stdlib.ProcessorFormatter,
            "processor": structlog.processors.KeyValueRenderer(key_order=['timestamp', 'level', 'event', 'message']),
        },
    },
    'handlers': {
        "console": {
            "class": "logging.StreamHandler",
            "formatter": "plain_console",
        },
        "json_file": {
            "level": "INFO",
            "class": "logging.handlers.RotatingFileHandler",
            "filename": "logs/ft_json.log",
            "formatter": "json_formatter",
            "maxBytes": 1024 * 1024 * 5,
            "backupCount": 3,
        },
        "flat_line_file": {
            "level": "INFO",
            "class": "logging.handlers.RotatingFileHandler",
            "filename": "logs/flat_line.log",
            "formatter": "key_value",
            "maxBytes": 1024 * 1024 * 5,
            "backupCount": 3,
        },
    },
    "loggers": {
        "django_structlog": {
            "level": "INFO",
            "handlers": ["console", "flat_line_file", "json_file"],
            "propagate": True,
        },
        "ft_log": {
            "level": "INFO",
            "handlers": ["console", "flat_line_file", "json_file"],
            "propagate": False,
        },
    },
}

structlog.configure(
    processors=[
        structlog.contextvars.merge_contextvars,
        structlog.stdlib.filter_by_level,
        structlog.processors.TimeStamper(fmt="iso"),
        structlog.stdlib.add_logger_name,
        structlog.stdlib.add_log_level,
        structlog.stdlib.PositionalArgumentsFormatter(),
        structlog.processors.StackInfoRenderer(),
        structlog.processors.format_exc_info,
        structlog.processors.UnicodeDecoder(),
        structlog.stdlib.ProcessorFormatter.wrap_for_formatter,
    ],
    logger_factory=structlog.stdlib.LoggerFactory(),
    cache_logger_on_first_use=True,
)

views.py Пример:

import structlog
logger = structlog.get_logger(__name__)

def subscribe(request):
    """Subscribes the authenticated user to push notifications."""
    logger.info("push notification subscribed successfully!")

Несмотря на вызов logger.info с сообщением, оно не появляется в журналах. Как обеспечить включение поля «message»?

Кроме того, любые предложения или лучшие практики по размещению структурированных журналов в ElasticSearch будут высоко оценены.

Поле сообщения в structlog является полем event. Другими словами: сообщение журнала, которое вы показываете, не является сообщением журнала, которое вы передаете "push notification subscribed successfully!".

Я не думаю, что имя вашего логгера "django_structlog" (я подозреваю, что это происходит из примера), поэтому я 🔮 что ваш логгер не настроен, что также означает, что он находится на уровне предупреждения.

Думаю, замена django_structlog на root в дикте логгеров должна помочь вам отладить это.

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