A Quick Guide to Django Logging

Posted on May 24, 2018 #python #django

In a production environment where our Django application is running as a service, often it becomes difficult to debug any errors without the console log. Of course, there are many solutions out there to tackle this problem like looking into nginx log, creating custom methods to get error logs or send email to admins when an error occurs which requires writing many lines of code. But in Django, it has its own logging system to handle this problem.

Django uses Python’s built-in logging module to perform system logging. I will not go into the details. But we should at least know that there are four parts in python logging configuration:

  • Loggers
  • Handlers
  • Filters
  • Formatters

Loggers

A logger is the entry point into the logging system. It is configured to have a log level which describes the severity of the messages that the logger will handle. Python defines the following log levels:

  • DEBUG: Low-level system information for debugging purposes
  • INFO: General system information
  • WARNING: Information describing a minor problem that has occurred.
  • ERROR: Information describing a major problem that has occurred.
  • CRITICAL: Information describing a critical problem that has occurred.

Handlers

The handler is the engine that determines what happens to each message in a logger. It describes a particular logging behavior, such as writing a message to the screen, to a file, or to a network socket. Like loggers, handlers also have a log level. Also, A logger can have multiple handlers, and each handler can have a different log level.

Filters

A filter is used to provide additional control over which log records are passed from logger to handler. Filters can be installed on loggers or on handlers; multiple filters can be used in a chain to perform multiple filtering actions.

Formatters

Formatters describe the exact format of the text log record.

Logging Configuration

In order to configure logging, we use LOGGING to define a dictionary of logging settings in settings.py.

Here’s a straightforward configuration which writes all logging from the Django logger to the console as well as in a local file:

LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'formatters': {
        'verbose': {
            'format': '%(levelname)s %(asctime)s %(module)s %(process)d %(thread)d %(message)s'
        },
        'simple': {
            'format': '%(levelname)s %(message)s'
        },
    },
    'handlers': {
        'console': {
            'class': 'logging.StreamHandler',
            'formatter': 'simple'
        },
        'file': {
            'level': 'INFO',
            'class': 'logging.FileHandler',
            'filename': '/path/to/django/info.log',
            'formatter': 'verbose'
        },
    },
    'loggers': {
        'mylogger': {
            'handlers': ['console', 'file'],
            'level': 'INFO',
            'propagate': True,
        },
    },
}

Here, If the disable_existing_loggers key in the LOGGING dictConfig is set to True then all default logging configuration will be disabled.

Making Logging Calls

Once we have configured out loggers, handlers, filters, and formatters, we need to place logging calls into our code. Using the logging framework is very simple. Here’s an example:

# import the logging library
import logging

# Get an instance of a logger
logger = logging.getLogger('mylogger')

def my_view(request, arg1, arg):
    ...
    if error_code:
        # Log an error message
        logger.error('Something went wrong!')

Here, our logger name is mylogger. But if we want to filter and handle logging calls on per-module basis, we can use __name__ as the logger name which indicates the name of the python module that contains the logger.

The logger instance contains an entry method for each of the default log levels:

  • logger.debug()
  • logger.info()
  • logger.warning()
  • logger.error()
  • logger.critical()

There are two other logging calls available:

  • logger.log(): Manually emits a logging message with a specific log level.
  • logger.exception(): Creates an ERROR level logging message wrapping the current exception stack frame.

For in depth details about logging, visit Django Logging.

comments powered by Disqus