Django Logging

Shanmukh
4 min readJan 7, 2020
Definitely not this 😅

Django uses python’s own logging module for executing system logging. So Django just gives an option to configure logging but internally the python’s logging module will be responsible for logging.

If you are new to logging or want to learn advanced topics in logging I would recommend you to first go through my article on Python Logging and then continue with this article.

Before going further, make sure you know about these 4 logging components

  • Loggers
  • Handlers
  • Filters
  • Formatters

Like I have mentioned I have explained all these components with examples in the above article.

Django uses python’s logging module’s dictConfig() method to configure logging in the application and create loggers, handlers, filters, and formatters respectively. The configuration is a part of Django’s main function setup() which will execute when you run the runserver command.

Let’s check out an example

So, what does the above code means for Django

'version': 1,

This statement says Django to use version 1 of dictConfig

'disable_existing_loggers': True,

As the variable name says it will disable all the existing loggers(default loggers if logging is not configured)

Yeah guessed it right Django will internally create some loggers by default and you can disable them using these keys. This configuration does not delete the loggers it will basically disable them. Just make a global search in your Django project on LOGGING and you can see where all it is being used.

Apart from that, python basically takes care of the logging so look at the configure() method in python /logging/config.py to understand it much better. It’s very simple.

'root': { 
'level': 'WARNING',
'handlers': ['general'],
},

root is the default logger for python’s logging module and as per configuration the log level is set to warning and the handler we will be using is the general handler. Since loggers have the concept of hierarchy(We will see it in later sections) the default logger is called as root.

'formatters': {
'default': {
'format': '%(levelname)s %(asctime)s %(message)s'
}
},

The key formatters will hold all the possible formats of the log messages and you can assign any one of them to the loggers you define.

'handlers': {
'general': {
'level': 'INFO',
'class': 'logging.handlers.WatchedFileHandler',
'formatter': 'default',
'filename': 'django/log/general.log'
},
'user': {
'level': 'INFO',
'class': 'logging.handlers.WatchedFileHandler',
'formatter': 'default',
'filename': 'django/log/user.log'
}
},

You can define your handlers in here where you can set your log level, class(FileHandler or StreamHandler or any other), formatter and filename in case of fileHandler. Make sure the user who runs the Django application has the permissions to write to these files.

'loggers': {
'general': {
'level': 'INFO',
'handlers': ['general'],
'propagate': False,
},
'user': {
'level': 'INFO',
'handlers': ['user'],
'propagate': False,
}
}

You can define your loggers which is the most important component in here where you can set your log level along with the handlers. As we already know that a single logger can have multiple handlers the data structure used is a list.

Propagate

Before understanding this we need to understand the hierarchy in loggers which I have mentioned above so let’s say you have a module structure as below in your code

User
|
---> Balance
|
---> Transactions

As you can see they have a hierarchy, and let’s say each of them have separate loggers for logging their respective messages. Say we have a scenario where if there are any exceptions in transactions we have to log them in the user log and balance log too as the transactions belong to a user. In such scenario’s you can define a logger using a dot operator which defines a hierarchy

logger = logging.getLogger('user.balance.transactions')

Now we have three loggers user parent of user.balance which is again a parent of user.balance.transactions. You can set the handlers to the user logger which is the root of this hierarchy and this handler will collect all the logs from the root and all of its subtree loggers i.e, if there is any log in the lower level of tree it will be captured by all of its parent loggers too. This is called propagating logging to its parent.

Now you configuring this propagation using the key

'propagate': False

I believe maintaining a hierarchy complicates things but it totally depends on your decision, project structuring and requirements.

I hope we covered everything regarding logging in Django and if you are new to Django I would recommend you to check out my article

Creating and Understanding your first Django Project

I am also attaching my code for reference

If you like the article please drop a 👏. Thanks for reading.

P.S: If you have any doubts drop me a message on Linkedin

--

--

Shanmukh

Senior Backend Engineer who loves to explore technologies.