The Missing How-to for Django Logging

Siddharth Pant
3 min readFeb 14, 2021

If you are working on Django, you might have faced difficulty in configuring logging with a dict in settings.py file. You go about writing your dict but your values are not valued and have no effect.

Image for logging config done right

There is a very simple solution for this problem and that is properly overriding the logging config so that whatever Django has already configured is replaced with your own best in class(atleast for you) logging config.

Update 9th March, 2024:

Here’s the most basic configuration that will get you what you want

import logging.config
# ... other settings

# Logging
LOGGING_CONFIG = None # This line is important to disable the default django logging configuration
logging.config.dictConfig(
{
'version': 1,
'handlers': {
'console': {
'class': 'logging.StreamHandler',
},
},
'loggers': {
# Default logger for any logger name
'': {
'handlers': ['console'],
'level': env.str('DJANGO_LOG_LEVEL', default='INFO'),
},
},
}
)
# ... other settings

If you need more complex config then below is a more production-ready example for you that include some utilities(colorlog and django-log-request-id) as dependencies as well.

import logging.config

# ... other settings

LOGGING_CONFIG = None # This line is important to disable the default django logging configuration
LOGGING = {
"version": 1,
"formatters": {
"verbose": {
"()": "colorlog.ColoredFormatter",
"format": "%(log_color)s %(levelname)-8s %(asctime)s %(request_id)s %(process)s --- "
"%(lineno)-8s [%(name)s] %(funcName)-24s : %(message)s",
"log_colors": {
"DEBUG": "blue",
"INFO": "white",
"WARNING": "yellow",
"ERROR": "red",
"CRITICAL": "bold_red",
},
},
"aws": {
"format": "%(asctime)s - %(name)s - %(levelname)s - %(funcName)s:%(lineno)d - %(message)s",
"datefmt": "%Y-%m-%d %H:%M:%S",
},
},
"filters": {
"request_id": {"()": "log_request_id.filters.RequestIDFilter"},
},
"handlers": {
"console": {
"class": "logging.StreamHandler",
"formatter": "verbose",
"filters": ["request_id"],
},
},
"loggers": {
# Default logger for any logger name
"": {
"level": "INFO",
"handlers": ["console", ],
"propagate": False,
},
# Logger for django server logs with django.server logger name
"django.server": {
"level": "DEBUG",
"handlers": ["console", ],
"propagate": False,
},
# Logger for 3rd party library to restrict unnecessary log statments by the library
"azure": {"level": "ERROR", "handlers": ["console"], "propogate": False},
},
}
logging.config.dictConfig(LOGGING) # Finally replace our config in python logging

# ... other settings

To provide a wholesome example, The above config is using such awesome projects as colorlog(errors will be red and warnings will be yellow etc), django-log-request-id(append a unique string for a particular user to capture user-journey) and Azure sdk libs(to show how you can reduce some libs logging behaviour). The logs are also all going to console to make it more container friendly for modern deployments to something like Kubernetes.

Now you can add or remove the configs in the dict as you please without any side-effects from Django’s own log configs.

Here are some Django doc references to know more about how Django configures or merges logging for you:

You might be using Celery also which will need additional configuration to be able to work. For that checkout my next article.

--

--