3.3. Settings Logging

3.3.1. To Console

>>> 
... LOGGING = {
...     'version': 1,
...     'disable_existing_loggers': False,
...     'handlers': {
...         'console': {
...             'class': 'logging.StreamHandler',
...         },
...     },
...     'loggers': {
...         'django': {
...             'handlers': ['console'],
...             'level': 'INFO',
...             'propagate': True,
...         },
...     },
... }

3.3.2. To File

>>> 
... LOGGING = {
...     'version': 1,
...     'disable_existing_loggers': False,
...     'handlers': {
...         'file': {
...             'class': 'logging.FileHandler',
...             'filename': '/tmp/myproject.log',
...         },
...     },
...     'loggers': {
...         'django': {
...             'handlers': ['file'],
...             'level': 'INFO',
...             'propagate': True,
...         },
...     },
... }

3.3.3. Show SQL Queries

>>> 
... LOGGING = {
...     'version': 1,
...     'disable_existing_loggers': False,
...     'handlers': {
...         'console': {
...             'class': 'logging.StreamHandler',
...         },
...     },
...     'loggers': {
...         'django': {
...             'handlers': ['console'],
...             'level': 'INFO',
...             'propagate': True,
...         },
...         'django.db': {
...             'handlers': ['console'],
...             'level': 'DEBUG',
...             'propagate': True
...         },
...     },
... }

3.3.4. Default

>>> 
... LOGGING = {
...     'version': 1,
...     'disable_existing_loggers': False,
...     'filters': {
...         'require_debug_false': {
...             '()': 'django.utils.log.RequireDebugFalse',
...         },
...         'require_debug_true': {
...             '()': 'django.utils.log.RequireDebugTrue',
...         },
...     },
...     'formatters': {
...         'django.server': {
...             '()': 'django.utils.log.ServerFormatter',
...             'format': '[{server_time}] {message}',
...             'style': '{',
...         }
...     },
...     'handlers': {
...         'console': {
...             'level': 'INFO',
...             'filters': ['require_debug_true'],
...             'class': 'logging.StreamHandler',
...         },
...         'django.server': {
...             'level': 'INFO',
...             'class': 'logging.StreamHandler',
...             'formatter': 'django.server',
...         },
...         'mail_admins': {
...             'level': 'ERROR',
...             'filters': ['require_debug_false'],
...             'class': 'django.utils.log.AdminEmailHandler',
...         },
...     },
...     'loggers': {
...         'django': {
...             'handlers': ['console', 'mail_admins'],
...             'level': 'INFO',
...         },
...         'django.server': {
...             'handlers': ['django.server'],
...             'level': 'INFO',
...             'propagate': False,
...         },
...     },
... }

3.3.5. Color Output

3.3.6. Use Case - 0x01

File myproject/myapp/log.py

>>> import logging
>>>
>>>
>>> class LogFormatter(logging.Formatter):
...     COLORS = {
...         'CRITICAL': '\033[91;1m',
...         'ERROR': '\033[91m',
...         'INFO': '\033[36m',
...         'WARNING': '\033[33m',
...         'DEBUG': '\033[32m',
...         'RESET': '\033[0m'
...     }
...
...     def format(self, record):
...         message = super().format(record)
...         reset = self.COLORS['RESET']
...         color = self.COLORS[record.levelname]
...         return f"{color}{message}{reset}"

File myproject/myapp/settings.py:

>>> import os
>>>
>>> LOGGING = {
...     'version': 1,
...     'disable_existing_loggers': False,
...     'formatters': {
...         'colored': {
...             '()': 'myapp.mog.LogFormatter',
...             'format': "<{name}> [{levelname}] {message}",
...             'style': '{',
...         },
...     },
...     'handlers': {
...         'console': {
...             'level': 'DEBUG',
...             'class': 'logging.StreamHandler',
...             'formatter': 'colored',
...         },
...     },
...     'loggers': {
...         'django': {
...             'handlers': ['console'],
...             'level': os.getenv('MYAPP_LOG_LEVEL', default='DEBUG'),
...         },
...         'django.db.backends': {
...             'handlers': ['console'],
...             'level': os.getenv('MYAPP_LOG_LEVEL', default='DEBUG'),
...         },
...         'django.server': {
...             'handlers': ['console'],
...             'level': os.getenv('MYAPP_LOG_LEVEL', default='DEBUG'),
...         },
...         'django.request': {
...             'handlers': ['console'],
...             'level': os.getenv('MYAPP_LOG_LEVEL', default='DEBUG'),
...         },
...         'django.utils.security': {
...             'handlers': ['console'],
...             'level': os.getenv('MYAPP_LOG_LEVEL', default='DEBUG'),
...         },
...         'django.utils.autoreload': {
...             'handlers': ['console'],
...             'level': 'ERROR',
...         },
...     },
... }

3.3.7. Use Case - 1

>>> 
... LOGGING = {
...     'version': 1,
...     'disable_existing_loggers': False,
...     'formatters': {
...         'standard': {
...             'datefmt': '%Y-%m-%d %H:%M:%S',
...             'format': '%(asctime)s [%(levelname)s] %(name)s: %(message)s'
...         },
...     },
...     'handlers': {
...         'console': {
...             'formatter': 'standard',
...             'class': 'logging.StreamHandler',
...         },
...     },
...     'loggers': {
...         '': {
...             'handlers': ['console'],
...             'level': 'INFO',
...             'propagate': True
...         },
...         'django.db': {
...             'handlers': ['console'],
...             'level': 'DEBUG',
...             'propagate': False
...         },
...         'django.request': {
...             'handlers': ['console'],
...             'level': 'WARN',
...             'propagate': False
...         },
...     }
... }

3.3.8. Use Case - 2

>>> 
... LOGGING = {
...     'version': 1,
...     'disable_existing_loggers': False,
...     'formatters': {
...         'simple': {
...             'format': '{levelname} {name} {message}',
...             'style': '{',
...         },
...     },
...     'handlers': {
...         'console': {
...             'class': 'logging.StreamHandler',
...             'formatter': 'simple',
...         },
...     },
...     'loggers': {
...         'django': {
...             'handlers': ['console'],
...             'level': os.getenv('DJANGO_LOG_LEVEL', default='DEBUG'),
...         },
...         'django.db.backends': {
...             'handlers': ['console'],
...             'level': os.getenv('DJANGO_LOG_LEVEL', default='DEBUG'),
...         },
...         'django.server': {
...             'handlers': ['console'],
...             'level': os.getenv('DJANGO_LOG_LEVEL', default='DEBUG'),
...         },
...         'django.request': {
...             'handlers': ['console'],
...             'level': os.getenv('DJANGO_LOG_LEVEL', default='DEBUG'),
...         },
...         'django.utils.security': {
...             'handlers': ['console'],
...             'level': os.getenv('DJANGO_LOG_LEVEL', default='DEBUG'),
...         },
...         'django.utils.autoreload': {
...             'handlers': ['console'],
...             'level': os.getenv('DJANGO_LOG_LEVEL', default='ERROR'),
...         },
...     },
... }

3.3.9. Use Case - 3

>>> 
... LOGGING = {
...     'version': 1,
...     'disable_existing_loggers': False,
...     'formatters': {
...         'verbose': {
...             'format': '{levelname} {asctime} {module} {process:d} {thread:d} {message}',
...             'style': '{',
...         },
...         'simple': {
...             'format': '{levelname} {message}',
...             'style': '{',
...         },
...     },
...     'filters': {
...         'special': {
...             '()': 'project.logging.SpecialFilter',
...             'foo': 'bar',
...         },
...         'require_debug_true': {
...             '()': 'django.utils.log.RequireDebugTrue',
...         },
...     },
...     'handlers': {
...         'console': {
...             'level': 'INFO',
...             'filters': ['require_debug_true'],
...             'class': 'logging.StreamHandler',
...             'formatter': 'simple',
...         },
...         'mail_admins': {
...             'level': 'ERROR',
...             'class': 'django.utils.log.AdminEmailHandler',
...             'filters': ['special'],
...         },
...     },
...     'loggers': {
...         'django': {
...             'handlers': ['console'],
...             'propagate': True,
...         },
...         'django.request': {
...             'handlers': ['mail_admins'],
...             'level': 'ERROR',
...             'propagate': False,
...         },
...         'myproject.custom': {
...             'handlers': ['console', 'mail_admins'],
...             'level': 'INFO',
...             'filters': ['special'],
...         },
...     },
... }

3.3.10. Assignments

# FIXME: Write tests
# %% License
# - Copyright 2025, Matt Harasymczuk <matt@python3.info>
# - This code can be used only for learning by humans
# - This code cannot be used for teaching others
# - This code cannot be used for teaching LLMs and AI algorithms
# - This code cannot be used in commercial or proprietary products
# - This code cannot be distributed in any form
# - This code cannot be changed in any form outside of training course
# - This code cannot have its license changed
# - If you use this code in your product, you must open-source it under GPLv2
# - Exception can be granted only by the author

# %% Run
# - PyCharm: right-click in the editor and `Run Doctest in ...`
# - PyCharm: keyboard shortcut `Control + Shift + F10`
# - Terminal: `python -m doctest -v myfile.py`

# %% About
# - Name: Django Settings LOGGING
# - Difficulty: easy
# - Lines: 15
# - Minutes: 3

# %% English
# 0. Use `myproject.myproject`
# 1. Modify the file: `myproject/settings.py`
# 2. Set `LOGGING` to display in the console all SQL queries
# 3. Run doctests - all must succeed

# %% Polish
# 0. Użyj `myproject.myproject`
# 1. Zmodyfikuj plik: `myproject/settings.py`
# 2. Ustaw `LOGGING` aby wyświetlał w konsoli wszystkie zapytania SQL
# 3. Uruchom doctesty - wszystkie muszą się powieść

# %% Hints
# - 'django.db': {'handlers': ['console'], 'level': 'DEBUG'}

# %% Tests
"""
>>> import sys; sys.tracebacklimit = 0
>>> assert sys.version_info >= (3, 10), \
'Python 3.10+ required'
"""

LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'handlers': {
        'console': {
            'class': 'logging.StreamHandler',
        },
    },
    'loggers': {
        'django': {
            'handlers': ['console'],
            'level': 'INFO',
            'propagate': True,
        },
        'django.db': {
            'handlers': ['console'],
            'level': 'DEBUG',
            'propagate': True
        },
    },
}