The Missing How-to for Django Logging

The Missing How-to for Django Logging

Fix Django logging the right way

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 (at least for you) logging config.

import logging.config

# ... other settings

LOGGING_CONFIG = None # This empties out Django's logging config
LOGGING = {
    "version": 1,
    "disable_existing_loggers": False,
    "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 behavior). The logs are also all going to the 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.

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