Django logger refuse to show full traceback in file message
Question:
Currently, i’m setting up logging in Django following the document https://docs.djangoproject.com/en/2.2/topics/logging/ (I’m using Django 2.2 with python3.7) and Django rest framework.
Here is my settings.py:
# LOGGING
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'formatters': {
'simple': {
'format': '{levelname} {asctime} {message}',
'style': '{',
},
},
'handlers': {
'file': {
'level': 'ERROR',
'class': 'logging.FileHandler',
'filename': '/var/log/django_errors.log',
'formatter': 'simple'
},
},
'loggers': {
'django': {
'handlers': ['file'],
'level': 'ERROR',
},
},
}
Here is my view using django-rest-framework:
import logging
logger = logging.getLogger(__name__)
class Countries(APIView):
permission_classes = ()
authentication_classes = []
def get(self, request):
try:
... some API process
except Exception as e:
import traceback
print(traceback.format_exc())
logger.error(traceback.format_exc())
return JsonResponse({'code': 500, 'message': str(e)}, status=500)
From the console I can see the print() show the correct full stack traceback. But in the logging file, it doesn’t show any traceback.
django_errors.log:
ERROR 2022-12-22 11:35:21,051 "GET /api/countries HTTP/1.1" 500 72
ERROR 2022-12-22 11:35:21,065 "GET /api/countries HTTP/1.1" 500 72
I also tried logger.exception()
the same thing happens, file doesn’t log full stack traceback
I tried looking online for solutions and tried them but to no prevail, hope someone can help me figure out why
expected log to show correct traceback for example like console print():
Traceback (most recent call last):
File "/app/api/views/countries.py", line 40, in get
country["currency"] =
get_currency_code_from_country_code(country["data"])
File "/app/utils/django_utils.py", line 470, in
get_currency_code_from_country_code
return currency.alpha_3
AttributeError: 'NoneType' object has no attribute 'alpha_3
‘
I even tried adding {stack_info} to my formatter, but it just returns None:
ERROR 2022-12-22 11:58:18,921 "GET /api/countries HTTP/1.1" 500 72 None
Answers:
I misunderstood how Django uses its own named hierarchy. I thought by using django
it would apply to all loggers, but it’s not the case because Django default only logs info without stack trace.
For it to work I take a look again at the docs, I need to specify the logger parent name for it to actually get recorded by the logging system.
so I need to have the logger like so to capture the loggers specify in each file:
'loggers': {
'app1': { # need to specify app parent folder in loggers
'handlers': ['file', 'mail_admins'],
'level': 'ERROR',
},
'app2': {
'handlers': ['file', 'mail_admins'],
'level': 'ERROR',
},
'base.celery': {
'handlers': ['file', 'mail_admins'],
'level': 'ERROR',
},
},
and for the logger to show stack trace I need to use logger.exception("") it will trigger ERROR level with stack trace
Now my log files and email contain all stack trace infos
Currently, i’m setting up logging in Django following the document https://docs.djangoproject.com/en/2.2/topics/logging/ (I’m using Django 2.2 with python3.7) and Django rest framework.
Here is my settings.py:
# LOGGING
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'formatters': {
'simple': {
'format': '{levelname} {asctime} {message}',
'style': '{',
},
},
'handlers': {
'file': {
'level': 'ERROR',
'class': 'logging.FileHandler',
'filename': '/var/log/django_errors.log',
'formatter': 'simple'
},
},
'loggers': {
'django': {
'handlers': ['file'],
'level': 'ERROR',
},
},
}
Here is my view using django-rest-framework:
import logging
logger = logging.getLogger(__name__)
class Countries(APIView):
permission_classes = ()
authentication_classes = []
def get(self, request):
try:
... some API process
except Exception as e:
import traceback
print(traceback.format_exc())
logger.error(traceback.format_exc())
return JsonResponse({'code': 500, 'message': str(e)}, status=500)
From the console I can see the print() show the correct full stack traceback. But in the logging file, it doesn’t show any traceback.
django_errors.log:
ERROR 2022-12-22 11:35:21,051 "GET /api/countries HTTP/1.1" 500 72
ERROR 2022-12-22 11:35:21,065 "GET /api/countries HTTP/1.1" 500 72
I also tried logger.exception()
the same thing happens, file doesn’t log full stack traceback
I tried looking online for solutions and tried them but to no prevail, hope someone can help me figure out why
expected log to show correct traceback for example like console print():
Traceback (most recent call last):
File "/app/api/views/countries.py", line 40, in get
country["currency"] =
get_currency_code_from_country_code(country["data"])
File "/app/utils/django_utils.py", line 470, in
get_currency_code_from_country_code
return currency.alpha_3
AttributeError: 'NoneType' object has no attribute 'alpha_3
‘
I even tried adding {stack_info} to my formatter, but it just returns None:
ERROR 2022-12-22 11:58:18,921 "GET /api/countries HTTP/1.1" 500 72 None
I misunderstood how Django uses its own named hierarchy. I thought by using django
it would apply to all loggers, but it’s not the case because Django default only logs info without stack trace.
For it to work I take a look again at the docs, I need to specify the logger parent name for it to actually get recorded by the logging system.
so I need to have the logger like so to capture the loggers specify in each file:
'loggers': {
'app1': { # need to specify app parent folder in loggers
'handlers': ['file', 'mail_admins'],
'level': 'ERROR',
},
'app2': {
'handlers': ['file', 'mail_admins'],
'level': 'ERROR',
},
'base.celery': {
'handlers': ['file', 'mail_admins'],
'level': 'ERROR',
},
},
and for the logger to show stack trace I need to use logger.exception("") it will trigger ERROR level with stack trace
Now my log files and email contain all stack trace infos