Django Logging
Every application developed has some bugs and errors. It is the responsibility of the developers to maintain the application by making it bug-free and error-free. To debug the application code and resolve those errors, developers need. The traditional way of debugging the application code is using the print() statements to understand the flow of code. Thus, Django has an important, useful, and underused functionality called Logging that helps us identifying when and where the error has occurred.
Logging helps developers to track some events in the application as and when they occur. The Logging API allows all the python modules to participate in Logging, meaning custom messages can be integrated with the third-party modules. The Logging functionality has made error identification and resolving those errors faster. It is similar to a simple file-writer as it records down the track of the events into the console or as text format into files called log files with .log extension. The features of Logging are:
- Multi-threading execution is possible
- Categorize messages via different log levels
- Flexible and configurable
- Structured Information
Classes of Logging
1. Logger
The entry point of the logging system when Logging is called, and the events are recorded for processing. A message created by the Loggers called the log records are sent to one or more handlers that route the message to the final destination like console, file, or a network socket.
A logger is configured to have a log level that describes the severity of the messages that need to be handled by the logger. Generally, a python module consists of a single logger, but multiple loggers can be defined in a single module, or a logger can be used across multiple modules. It should always be initiated through module-level function logging.getLogger(name).
Python defines the following log levels:
Level | Description | When is it Used? | Severity |
DEBUG | System information and everything is working fine | For Debugging Purposes | 10 |
INFO | General System Information | Confirm if things working as expected | 20 |
WARNING | Information that describes the minor problem that has occurred | Indicate some problem in near future | 30 |
ERROR | Information that describes the major problem that has occurred | Some function not performing due to serious issues | 40 |
CRITICAL | Information that describes the critical problem that has occurred | The program may stop running, indicating a serious issue | 50 |
The default log level is WARNING which will track events at this level and above unless the logging package is configured to desired. Django uses one of the following loggers:
Logger |
Description |
Context |
|
|
django |
Parent logger for messages |
|
||
django.request |
Log message related to the handling of requests.
5XX response raised as ERROR message 4XX response raised as WARNING message |
status_code: HTTP response code associated with the request request: Request object generating the message
|
|
|
django.server |
Log message related to the handling of requests received by the server by runserver command.
5XX response raised as ERROR message 4XX response raised as WARNING message Rest logged as INFO |
|
||
django.template |
Log message related to rendering templates. The missing context is logged as DEBUG message |
|
||
django.security.* (DisallowedHost, csrf) |
Log message on any SuspiciousOperation and other security issues. Most occurance logged as WARNING. SuspiciousOperation reaching WSGI handler logged as ERROR |
|
||
django.db.backends.schema |
Logs of SQL queries executed during schema changes by the migration framework. |
sql: SQL statement that was executed
params: parameters used in SQL call
|
|
|
django.db.backends |
Message related to the interaction of code with the database. Application-level SQL statement executed by request logged at DEBUG level |
|||
duration: time to execute SQL statement alias: alias of a database used in SQL call
|
There are several logger objects offered:
Logger Object | Description |
Logger.debug(msg,*args, **kwargs) | Logs message with level DEBUG |
Logger.info(msg,*args, **kwargs) | Logs message with level INFO |
Logger.warning(msg,*args, **kwargs) | Logs message with level WARNING |
Logger.error(msg,*args, **kwargs) | Logs message with level ERROR |
Logger.critical(msg,*args, **kwargs) | Logs message with level CRITICAL |
Logger.log(level, msg,*args, **kwargs) | Logs message with integer level LEVEL |
Logger.exception(msg,*args, **kwargs) | Exception info is added to the logging message |
Logger.addFilter(filter), Logger.removeFilter(filter) | Add or Remove specified filter to/from this logger |
Logger.addHandler(hdlr), Logger.removeHandler(hdlr) | Add or Remove specified handler to/from this logger |
Logger.hasHandlers() | Check if any loggers are configured to this logger. |
Logger.setLevel(level) | Set threshold for this logger to level. Logging messages with less severity will be ignored. |
2. Handler
Handlers contain the information that determines what will happen to the log records in the loggers. It has information about the location, the type of filter, and the formatter to be applied to the log record. Multiple loggers can use it. The default logging behavior is writing messages to the screen, a file, or a network socket. The various other handlers are provided by the logging module. The different forms of notification can be provided depending on the importance of the message, as a single logger can have multiple handlers.
3. Filters
The filters, as the name suggests, filter the messages. A filter is used to provide additional control over which log records are passed from logger to handler.
4. Formatters
A log record needs to be rendered as text. Formatters describe the exact format of that text. Handlers cannot send the information as it's a Python data type it needs to be converted.
Logging in Django:
Once you have configured your loggers, handlers, filters, and formatters, you need to place logging calls into your code. Using the logging framework works like this:
# import the logging library
import logging
# Get an instance of a logger
logger = logging.getLogger(__name__)
def my_view(request, arg1, arg):
...
if bad_mojo:
# Log an error message
logger.error('Something went wrong!')
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.
Configuring Logging
Django provides Logging by using the logging module of Python. The logging module can be easily configured. For including Logging in Django, we need to configure its settings. Since Django works with different modules, we use the dictConfig method." dictConfig "is Django's default behavior.
The code for Logging is written below.
LOGGING = {
'version': 1,
# Version of logging
'disable_existing_loggers': False,
#disable logging
# Handlers
'handlers': {
'file': {
'level': 'DEBUG',
'class': 'logging.FileHandler',
'filename': 'django-debug.log',
},
'console': {
'class': 'logging.StreamHandler',
},
},
# Loggers
'loggers': {
'django': {
'handlers': ['file', 'console'],
'level': 'DEBUG',
'propagate': True,
'level': os.getenv('DJANGO_LOG_LEVEL', 'DEBUG')
},
},
}
We get a built-in variable LOGGING from Django. Its logging default values come from this dictionary. Since we are configuring settings using a dictionary, it's called the dictConfig method.
There are some important keys inside the LOGGING dictionary.
- version
- disable_existing_loggers
- handlers
- loggers
Custom Logging Configuration
If you don't want to use Python's dictConfig format to configure your logger, you can specify your own configuration scheme. The LOGGING_CONFIG setting defines the callable that will be used to configure Django's loggers. By default, it points at Python's Logging.config.dictConfig() function. However, if you want to use a different configuration process, you can use any other callable that takes a single argument. The contents of LOGGING will be provided as the value of that argument when Logging is configured.