Как включить поле сообщения в журналы 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
в дикте логгеров должна помочь вам отладить это.