Django logging json format
Install package json-log-formatter
$ pip install json-log-formatter
Configure settings
Create file log.py
import os
import time
import logging
class JSONFormatter(json_log_formatter.VerboseJSONFormatter):
def json_record(self, message, extra, record):
additional_data = {"level": record.levelname,
"pathname": record.pathname,
"lineno": record.lineno}
if request := extra.pop("request", None):
additional_data.update({
"user": str(request.user),
"remote_addr": request.META.get("REMOTE_ADDR"),
"method": request.META.get("REQUEST_METHOD"),
"path": request.path,
"server_protocol": request.META.get('SERVER_PROTOCOL'),
"server_name": request.META.get('SERVER_NAME'),
"content_type": request.META.get('CONTENT_TYPE'),
"http_user_agent": request.META.get('HTTP_USER_AGENT'),
"hostname": os.uname().nodename,
"python": os.getenv("PYTHON_VERSION"),
"timestamp": time.time()
})
extra.update(additional_data)
return super().json_record(message, extra, record)
In settings.py update LOGGING, add formatter
"json": {
"()": "log.JSONFormatter",
},
Full LOGGING example
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'formatters': {
'verbose': {
'format': '{levelname} {asctime} {module} {lineno} {process} {message}',
"style": "{",
},
"json": {
"()": "log.JSONFormatter",
},
},
'handlers': {
'console': {
'level': 'DEBUG',
'formatter': 'json',
'class': 'logging.StreamHandler',
}
},
'loggers': {
'django': {
'handlers': ['console'],
'propagate': True,
'level': "WARNING",
},
'django.request': {
'handlers': ['console'],
'level': LOGLEVEL,
'propagate': False,
},
'django.server': {
'handlers': ['console'],
'level': "ERROR",
'propagate': False,
},
"": {
"level": LOGLEVEL,
"handlers": ['ntfy', 'console'],
"propagate": False,
}
}
}
Create logging base class
class MetaLog(type):
log = None
logger_name = None
def __new__(cls, name, bases, dct):
x = super().__new__(cls, name, bases, dct)
x.log = logging.getLogger(cls.logger_name or __name__)
return x
class Log(metaclass=MetaLog):
def logs(self, msg, level="info"):
return self.log.log(
logging.getLevelName(level.upper()),
msg,
extra={"request": self.request})
Use logging in django classes
class MainTemplateView(TemplateView, Log):
def get(self, request, *args, **kwargs):
self.logs("Test message")
self.log.info("Test message", extra={"request": self.request})
return super().get(request, *args, **kwargs)
Output example
{
"level": "INFO",
"pathname": "/home/alex/venv/pay/src/pay/mixin.py",
"lineno": 233,
"user": "AnonymousUser",
"remote_addr": "127.0.0.1",
"method": "GET",
"path": "/",
"server_protocol": "HTTP/1.1",
"server_name": "localhost",
"content_type": "text/plain",
"http_user_agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
"hostname": "acer",
"python": null,
"timestamp": 1704395939.1455264,
"filename": "mixin.py",
"funcName": "get",
"levelname": "INFO",
"module": "mixin",
"name": "pay.mixin",
"process": 13893,
"processName": "MainProcess",
"stack_info": null,
"thread": 140252349982272,
"threadName": "Thread-3 (process_request_thread)",
"message": "Test message",
"time": "2024-01-04T19:18:59.145540"
}