Logger

Print statement generally does not work in production so, to get message we use logger

What is Logging?

How Logging Works in Django

  • Django comes with Python's built-in logging module to leverage system logging.
    1. Loggers
    2. Handlers
    3. Filters
    4. Formatters

Loggers

  • Loggers are basically the entry point of the logging system.
  • If the log-level is same or exceeds the log-level of the logger, the message is sent to the handler for further processing.
DEBUG:		     10 --> Low-level system information
INFO:		     20 --> General system information
WARNING:	     30 --> Minor problems related information
ERROR/EXCEPTION: 40 --> Major problems related information
CRITICAL:	     50 --> Critical problems related information
dblogger.debug("Test Debug")

dblogger.info("Test Info")

dblogger.warning("Test Warning")
dblogger.warn("Test Warn")  # Depricated

dblogger.error("Test Error")
dblogger.exception("Test Exception")

dblogger.critical("Test Critical")

Handlers

Handlers basically determine what happens to each message in a logger eg: write to a file or console.

For example: ERROR log level messages can be sent in real-time to the developer, while INFO log levels can just be stored in a system file.

Filters

A filter can sit between a Logger and a Handler. It can be used to filter the log record.

For example: in CRITICAL messages, you can set a filter which only allows a particular source to be processed.

Formatters

As the name suggests, formatters describe the format of the text which will be rendered.

Logger

Django provides several built-in loggers.

django
django.request
django.server
django.template
django.db.backends
django.security.*
django.db.backends.schema

Handlers

  • logging.StreamHandler
    • console
    • which prints any INFO (or higher) message to sys.stderr
  • logging.FileHandler
    • This handler is used to write logs into a file
  • logging.handlers.WatchedFileHandler
  • logging.handlers.RotatingFileHandler
  • django.utils.log.AdminEmailHandler
    • mail_admins
    • which emails any ERROR (or higher) message to the site ADMINS

Examples

Without logger

[02/Jan/2022 18:59:25] "GET /api/posts/ HTTP/1.1" 200 14956

Add log in console and file

  • 'handlers': ['file', 'console'] is used –> to log on File & Console
LOGGING ={
    'version': 1,
    # The version number of our log
    'loggers':{
        'django':{
        	# handler name is added here
            'handlers': ['file', 'console'],
            'level': 'DEBUG'
        }
    },
    'handlers':{
    	# file --> user-define name
        'file' :{
            'level': 'DEBUG',
            'class': 'logging.FileHandler',
            'filename': './logs/debug.log'
        },

        # console --> user-define name
        'console' :{
            'level': 'DEBUG',
            'class': 'logging.StreamHandler',
        }
    },
    'formatters':{}
}

# OP
"GET / HTTP/1.1" 200 830

Adding logger formatter

  • For level INFO –> INFO and above level will be logged
LOGGING ={
    'version': 1,
    # The version number of our log
    'loggers':{
        'django':{
            'handlers': ['console'],
            'level': 'DEBUG'
        }
    },
    'handlers':{
        'console' :{
            'level': 'INFO',
            'class': 'logging.StreamHandler',
            'formatter': 'simple',
        }
    },
    'formatters':{
    	# simple --> user-define name
        'simple':{
            'format': '{levelname} {asctime} {module} {message}',
            'style': '{'
        }
    }
}

# OP
INFO 2022-01-02 19:46:52,580 basehttp "GET / HTTP/1.1" 200 830
  • Use logger instead of print statement with logger-level
# views.py
logger = logging.getLogger('django')

def home(request):
	logger.error('getting some error')
	return

ERROR 2022-01-02 19:46:52,538 views getting some error

formatter

  • simple, verbose –> are user-define variable
  • datefmt –> is formate of asctime
'formatters': {
    'simple': {
        'format': '[%(asctime)s] %(levelname)s %(message)s',
        'datefmt': '%Y-%m-%d %H:%M:%S'
    },
    'verbose': {
        'format': '[%(asctime)s] %(levelname)s [%(name)s.%(funcName)s:%(lineno)d] %(message)s',
        'datefmt': '%Y-%m-%d %H:%M:%S'
    },

filter

  • require_debug_true –> Log only if DEBUG=True
  • require_debug_false –> LOg only if DEBUG=False
LOGGING ={
    'version': 1,
    # The version number of our log
    'loggers':{
        'django':{
            'handlers': ['console'],
            'level': 'DEBUG'
        }
    },
    'handlers':{
        'console' :{
            'level': 'INFO',
            'filters': ['require_debug_true'],
            'class': 'logging.StreamHandler',
            'formatter': 'simple',
        }
    },
    'filters': {
        'require_debug_false': {
            '()': 'django.utils.log.RequireDebugFalse',
        },
        'require_debug_true': {
            '()': 'django.utils.log.RequireDebugTrue',
        },
    },
}

Django’s logging extensions

Complete Example


LOGGING = {
    'version': 1,
    # The version number of our log
    'disable_existing_loggers': True,
    # django uses some of its own loggers for internal operations. 
    # In case you want to disable them just replace the False above with True.
    'filters': {
        'require_debug_false': {
            '()': 'django.utils.log.RequireDebugFalse',
        },
        'require_debug_true': {
            '()': 'django.utils.log.RequireDebugTrue',
        },
    },
    'formatters': {
        'simple': {
            'format': '[%(asctime)s] %(levelname)s %(message)s',
            'datefmt': '%Y-%m-%d %H:%M:%S'
        },
        'verbose': {
            'format': '[%(asctime)s] %(levelname)s [%(name)s.%(funcName)s:%(lineno)d] %(message)s',
            'datefmt': '%Y-%m-%d %H:%M:%S'
        },
    },
    'handlers': {
        # A handler for DEBUG. It is basically writing the DEBUG messages into the console
        'console': {
            'level': 'DEBUG',
            'filters': ['require_debug_true'],
            'class': 'logging.StreamHandler',
            'formatter': 'verbose'
        },
        # A handler for DEBUG. It is basically writing the DEBUG messages into '/tmp/django_dev.log' file
        'development_logfile': {
            'level': 'DEBUG',
            'filters': ['require_debug_true'],
            'class': 'logging.FileHandler',
            'filename': '/tmp/django_dev.log',
            'formatter': 'verbose'
        },
        # A handler for ERROR. It is basically writing the ERROR messages into '/var/log/django/django_production.log' file
        'production_logfile': {
            'level': 'ERROR',
            'filters': ['require_debug_false'],
            'class': 'logging.handlers.RotatingFileHandler',
            'filename': '/var/log/django/django_production.log',
            'maxBytes': 1024*1024*100, # 100MB
            'backupCount': 5,
            'formatter': 'simple'
        },
        'dba_logfile': {
            'level': 'DEBUG',
            'filters': ['require_debug_false','require_debug_true'],
            'class': 'logging.handlers.WatchedFileHandler',
            'filename': '/var/log/dba/django_dba.log',
            'formatter': 'simple'
        },
        'mail_admins': {
            'level': 'ERROR',
            'filters': ['require_debug_false'],
            'class': 'django.utils.log.AdminEmailHandler'
        }
    },
    'root': {
        'level': 'DEBUG',
        'handlers': ['console'],
    },  
    # A logger can have multiple handle
    'loggers': {
        'newmore': {
            'handlers': ['development_logfile','production_logfile','mail_admins'],
         },
        'dba': {
            'handlers': ['dba_logfile','mail_admins'],
        },
        'django': {
            'handlers': ['development_logfile','production_logfile','mail_admins'],
        },
        'py.warnings': {
            'handlers': ['development_logfile'],
        },
    }
}

ADMINS = [('Development', '[email protected]')]

Reference