Add custom log records in Django
Asked Answered
M

3

6

I've added the following logging configuration to my Django App's settings.py file:

LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'handlers': {
        'console': {
            'class': 'logging.StreamHandler',
        },
    },
    'loggers': {
        'django': {
            'handlers': ['console'],
            'level': os.getenv('DJANGO_LOG_LEVEL', 'INFO'),
        },
    },
}

Now, I simply want to add some custom log records to one of my views in views.py, but it appears the logger is NOTSET, which means only levels of warning and higher are logged:

import logging
from django.http import JsonResponse

logger = logging.getLogger(__name__)

def testing(request):
    logger.info("Doesn't show...")
    logger.warning(f"Log Level: {logger.level} = {logging.getLevelName(logger.level)}")
    return JsonResponse({"Hello": "World"})

The snippet above logs the following:

Log Level: 0 = NOTSET

Am I doing something wrong? Why is the logger's level not set (even though I clearly set it in settings.py)?

Mathur answered 9/12, 2019 at 18:41 Comment(0)
L
10

Why this behavior?

The logging.getLogger(__name__) statement will initialize a python logger with a dotted path to the current module. In your case, it would be my_app.views. Django is not able to understand the logs that you have created from the views.py since your logger name my_app.views which is not listed in settings.py. Django won't do anything to the logs if you are not specified the logger name/ logger-name pattern accordingly.

How warning logs are displayed?

I hope this So post this explains well, Python logging not outputting anything

Solution

Option-1

change either your logger name in settings.py

LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'handlers': {
        'console': {
            'class': 'logging.StreamHandler',
        },
    },
    'loggers': {
        'my_app.views': {
            'handlers': ['console'],
            'level': os.getenv('DJANGO_LOG_LEVEL', 'INFO'),
        },
    },
}

Key Change: I have changed the logger name django to my_app.views

Option-2

Specify logger name in the getLogger method

logger = logging.getLogger('django')

Key Point: The name of the logger and the logger defined in the Django Settings module should be same.

Liquidation answered 19/12, 2019 at 3:9 Comment(1)
Why we should use: os.getenv('DJANGO_LOG_LEVEL', 'INFO') , instead just 'INFO' . I've print the value of DJANGO_LOG_LEVEL on the shell, but it returns None.Inflationary
C
2

Since you configured the logger for 'django' and your module is (presumably) not in the django package, you need to get the 'django' logger explicitly:

# logger = logging.getLogger(__name__)
logger = logging.getLogger('django')

Otherwise, you get a logger that is not configured so logger.level is NOTSET.

Django, however, will use your logging configuration.

From https://docs.python.org/3/library/logging.html:

The logger name hierarchy is analogous to the Python package hierarchy, and identical to it if you organise your loggers on a per-module basis using the recommended construction logging.getLogger(__name__). That’s because in a module, __name__ is the module’s name in the Python package namespace.

Coltson answered 19/12, 2019 at 2:54 Comment(0)
M
0

Because logging.getLogger(__name__) create a python logger with a path to the current module and since you don't register this logger in your setting, Django is not able to understand the logger that you have created from the views.py. One solution is to register it in your setting as @JPG said before. Another solution is to create it manually. For example you can create an Utils.py file and create this function to create your logger.

import logging
def get_view_logger(view_name):
    logger = logging.getLogger(view_name)
    logger.setLevel(logging.INFO)
    handler = TimedRotatingFileHandler(os.path.join(BASE_DIR, 'log/' + view_name + '.log'),
                                       when='midnight', backupCount=20, encoding="utf8")
    formatter = logging.Formatter('%(asctime)s [%(levelname)s] : %(message)s')
    handler.setFormatter(formatter)
    logger.addHandler(handler)
    return logger

You can customize each of component of your logger like handler, formatter and etc.

Moses answered 20/12, 2019 at 7:22 Comment(2)
Django is not able to understand the logs → Django doesn't play any part in "understanding" the logs. Python's logging library simply returns a logger that is not configured.Coltson
Django doesn't play any part in understanding the logger either. It might even be accurate to say that Django plays no part at all in this case.Coltson

© 2022 - 2024 — McMap. All rights reserved.