Render logs as json with python-json-logger

This commit is contained in:
Daniel Egger 2023-08-28 13:32:42 +02:00
parent 163df01f5d
commit e08d5574f7
2 changed files with 35 additions and 31 deletions

View File

@ -8,7 +8,7 @@ import structlog
from environs import Env
from vbv_lernwelt.core.constants import DEFAULT_RICH_TEXT_FEATURES
from vbv_lernwelt.core.utils import structlog_add_app_info
from vbv_lernwelt.core.utils import structlog_add_app_info, structlog_add_to_message
SERVER_ROOT_DIR = Path(__file__).resolve(strict=True).parent.parent.parent
APPS_DIR = SERVER_ROOT_DIR / "vbv_lernwelt"
@ -427,36 +427,16 @@ if IT_DJANGO_LOGGING_CONF == "IT_DJANGO_LOGGING_CONF_CONSOLE_COLOR":
cache_logger_on_first_use=True,
)
else:
shared_processors = [
structlog.threadlocal.merge_threadlocal,
structlog.stdlib.add_log_level,
structlog.stdlib.add_logger_name,
structlog_add_app_info,
structlog.processors.TimeStamper(fmt="iso"),
structlog.processors.CallsiteParameterAdder(),
]
LOGGING = {
"version": 1,
"disable_existing_loggers": True,
"formatters": {
"json": {
"()": structlog.stdlib.ProcessorFormatter,
"processors": [
structlog.stdlib.ProcessorFormatter.remove_processors_meta,
structlog.processors.JSONRenderer(),
],
"foreign_pre_chain": shared_processors,
"()": "pythonjsonlogger.jsonlogger.JsonFormatter",
"format": "%(asctime)s %(levelname)s %(process)d %(thread)d %(name)s %(lineno)d %(funcName)s %(message)s",
},
},
"handlers": {
"file": {
"class": "concurrent_log_handler.ConcurrentRotatingFileHandler",
"filename": f"{SERVER_ROOT_DIR}/log/myservice.log",
"maxBytes": 1024 * 1024 * 100,
"backupCount": 50,
"formatter": "json",
},
"console": {
"level": "DEBUG",
"class": "logging.StreamHandler",
@ -465,30 +445,36 @@ else:
},
"loggers": {
"": {
"handlers": ["console", "file"],
"handlers": ["console"],
"level": "INFO",
},
"django": {
"handlers": ["console", "file"],
"handlers": ["console"],
"level": "WARNING",
"propagate": False,
},
"vbv_lernwelt": {
"handlers": ["console", "file"],
"handlers": ["console"],
"level": "DEBUG",
"propagate": False,
},
"sentry_sdk": {
"level": "ERROR",
"handlers": ["console", "file"],
"handlers": ["console"],
"propagate": False,
},
},
}
structlog.configure(
processors=shared_processors
+ [
processors=[
structlog.stdlib.filter_by_level,
structlog.threadlocal.merge_threadlocal,
structlog_add_app_info,
structlog.processors.StackInfoRenderer(),
structlog.processors.format_exc_info,
structlog.processors.UnicodeDecoder(),
structlog_add_to_message,
structlog.stdlib.ProcessorFormatter.wrap_for_formatter,
],
context_class=dict,

View File

@ -8,15 +8,33 @@ from structlog.types import EventDict
def structlog_add_app_info(
logger: logging.Logger, method_name: str, event_dict: EventDict
_: logging.Logger, __: str, event_dict: EventDict
) -> EventDict:
event_dict["django_app"] = "vbv_lernwelt"
event_dict["APP_ENVIRONMENT"] = settings.APP_ENVIRONMENT
event_dict["app_environment"] = settings.APP_ENVIRONMENT
event_dict["django_app_dev_mode"] = f"vbv_lernwelt_{settings.APP_ENVIRONMENT}"
return event_dict
def structlog_add_to_message(
_: logging.Logger, __: str, event_dict: EventDict
) -> EventDict:
"""
The *event_dict* is added as dict ``message``.
This allows you to defer formatting to `logging`.
"""
return {
"message": event_dict,
**{
kw: event_dict.pop(kw)
for kw in ("exc_info", "stack_info", "stackLevel")
if kw in event_dict
},
}
def structlog_inject_context_dict(test, level, event_dict):
"""
Add the structlog context dict to log events generated by the stdlib logging library.