Логирование в Django - NurOrNuLL/ESDP-AP-5-6-TEAM-2 GitHub Wiki

Python logging

Общая информация

Лог — текстовый файл с информацией о действиях программного обеспечения или пользователей, который хранится на компьютере или сервере. Это хронология событий и их источников, ошибок и причин, по которым они произошли. Логированием называют запись логов. Оно позволяет ответить на вопросы, что происходило, когда и при каких обстоятельствах. Правильное ведение логирования играет решающее значение для процесса отладки и устранения неполадок. Оно не только полезно для локальной разработки, но и для продашен. Django использует встроенный модуль Python logging для системного логирования. Хранение логов производится с помощью Docker.

Подробнее о логировании можно увидеть по ссылке в официальной документации Джанго: https://docs.djangoproject.com/en/4.0/topics/logging/

Конфигурация логирования в Django Python:

Конфигурация логирования в Python состоит из четырех частей:

Loggers(Логеры)
Handlers(Обработчики)
Filters(Фильтры)
Formatters(Форматер)

Logger:

Это точка входа в систему логирования. Каждый логер как именованный канал для сообщений, в который они отправляются для обработки.

У каждого логера есть уровень логирования(log level). Уровень логирования указывает важность принимаемых сообщений. Python определяет следующие уровни логирования:

DEBUG: Низкий уровень логирования системной информации для последующего использования в отладке
INFO: Общая системная информация
WARNING: Информация о мелких проблемах возникших при работе приложения
ERROR: Информация об ошибках возникших при работе приложения
CRITICAL: Информация о критических ошибках

Каждое сообщение записанное в логер называется Log Record(Запись). Каждая запись содержит уровень логирования, который указывает важность сообщения. Сообщение так же может содержать метаданные, которые описывают произошедшее событие. Метаданные могут содержать код ошибки или отладочную информацию.

Когда сообщение передается в логер, уровень логирования сообщения сравнивается с уровнем логирования логера. Если уровень логирования сообщения равен или выше уровню логирования логера, сообщение будет обработано, иначе - проигнорировано.

После того, как логер принял сообщение на обработку, оно передается в Handler(Обработчик).

Handler(Обработчик):

Определяет что делать с сообщением пришедшим из логера. Он определяет поведение логирования, например: вывести сообщение на экран, записать в файл или сокет.

Как и логеры, обработчики имеют уровень логирования. Если уровень логирования сообщения ниже уровня логирования обработчика, сообщение будет проигнорировано.

Один Логер может содержать несколько обработчиков, которые могут иметь различный уровень логирования. Это позволяет обрабатывать сообщения в соответствии с их уровнем важности. Например, вы можете установить обработчик для ERROR и CRITICAL сообщений, который будет отправлять через какой-то сервер сообщений, и в то же время обработчик записывающий все сообщения (включая ERROR и CRITICAL) в файл.

Filter(Фильтр):

Предоставляет дополнительный контроль над тем, какие сообщения будут переданы из логера в обработчик.

По умолчанию все сообщения, прошедшие проверку уровня логирования, будут переданы в обработчик. Добавив фильтры вы можете определить дополнительные правила проверки при обработке сообщений. Например, вы можете добавить фильтр, который позволяет обрабатывать ERROR сообщения отправленные определенным источником.

Фильтры так же могу изменить сообщение. Например, вы можете создать фильтр, который изменяет уровень логирования определенных сообщения с ERROR на WARNING.

Фильтр могут быть добавлены к логеру или обработчику, можно использовать несколько фильтров.

Formatter(Форматер):

Определяют формат полученного текста полученного сообщения. Обычно это строка форматирования Python, но вы так же можете создать собственный класс форматера.

Подробнее о конфигурации можно увидеть по ссылке: https://docs.python.org/3/library/logging.config.html#logging-config-dictschema

Безопасность логируемых данных:

Система регистрации обрабатывает потенциально конфиденциальную информацию. Вы должны быть уверены, что знаете:

* какая информация собирается
* где он впоследствии будет храниться
* как это будет передано
* кто может иметь к нему доступ.

Чтобы помочь контролировать сбор конфиденциальной информации, вы можете явно указать, что определенная конфиденциальная информация будет отфильтровываться из отчетов об ошибках. Подробнее о фильтрации по ссылке: https://docs.djangoproject.com/en/4.0/howto/error-reporting/#filtering-error-reports

Использование логирования:

Пример конфигураций в файле settings.py:

import os

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']
        }
    }
}

Добавление логирования в код в файле views.py:

import logging

# Get an instance of a logger
logger = logging.getLogger(__name__)

def my_view(request, arg1, arg):
    ...
    if bad_condition:
        # Log an error message
        logger.error('Something went wrong!')

Именование логеров

Вызов logging.getLogger() возвращает (создает при необходимости) экземпляр логера. Экземпляр логера определяется названием. Это название используется при настройке логирования.

Для удобства обычно используется __name__ в качестве названия – название модуля, который содержит логер.

Это позволяет вам управлять логированием на уровне модулей. Однако, если вы используете другую систему организации сообщений, вы может использовать любое составное название, разделенное точками:

# Get an instance of a specific named logger
logger = logging.getLogger('project.interesting.stuff')

Точки в названии логера позволяют определять иерархию. Логер project.interesting считается родительским по отношению к логеру project.interesting.stuff; логер project родительским по отношению к project.interesting.

Почему иерархия так важна? Потому что логеры могут быть настроены на передачу сообщений родительским логерам. Таким образом вы можете определить один обработчик для корневого логера и обрабатывать сообщения ко всем дочерним логерам. Обработчик назначенный логеру project будет обрабатывать сообщения к project.interesting и project.interesting.stuff.

Передачу сообщений можно настроить для конкретного логера. Если вы не хотите что бы определенный логер передавал свои сообщения родительского логеру, вы можете отключить такое поведение.

Функции логирования:

Логер предоставляет методы для каждого уровня логирования:

logger.critical()
logger.error()
logger.warning()
logger.info()
logger.debug()

Так же есть два дополнительных метода:

logger.log(): отправить сообщение с указанным уровнем логирования

logger.exception(): Создать ERROR сообщение из последнего исключения(пер. the current exception stack frame).

Отключение конфигураций ведения журнала в файле settings.py:

LOGGING_CONFIG = None

import logging.config
logging.config.dictConfig(...)