How to Include a Message Field in Structlog Logs and Best Practices for ElasticSearch Integration

I'm working on a Django project where logging is critical, and I'm using structlog to format and manage logs. The plan is to send these logs to ElasticSearch. However, I've encountered an issue: the logs are missing the "message" field, even though I explicitly pass a message in the logger call.

Here’s the log output I currently get:

{
    "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"
}

What I want is to include the "message" field, for example:

{
    "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"
}

Here’s my current setup: 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 Example:

import structlog
logger = structlog.get_logger(__name__)

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

Despite calling logger.info with a message, it doesn’t appear in the logs. How can I ensure that the "message" field is included?

Also, any suggestions or best practices for posting structured logs into ElasticSearch would be greatly appreciated.

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