Рубрики
Без рубрики

ведение журнала – отчет о состоянии, ошибках и информационных сообщениях

Автор оригинала: Doug Hellmann.

Цель:

Сообщать о состоянии, ошибках и информационных сообщениях.

Модуль logging определяет стандартный API для отчетов об ошибках и информации о состоянии из приложений и библиотек. Ключевым преимуществом наличия API журналирования, предоставляемого стандартным библиотечным модулем, является то, что все модули Python могут участвовать в журналировании, поэтому журнал приложения может включать сообщения от сторонних модулей.

Компоненты ведения журнала

Система регистрации состоит из четырех взаимодействующих типов объектов. Каждый модуль или приложение, которое хочет вести журнал, использует экземпляр Logger для добавления информации в журналы. При вызове регистратора создается LogRecord , который используется для хранения информации в памяти до ее обработки. Logger может иметь несколько объектов Handler , настроенных для получения и обработки записей журнала.

Вход в приложения и библиотеки

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

Разработчики приложений настраивают модуль logging , направляя сообщения в соответствующие выходные каналы. Можно регистрировать сообщения с разной степенью детализации или по разным адресатам. Включены обработчики для записи сообщений журнала в файлы, местоположения HTTP GET/POST, электронная почта через SMTP, общие сокеты или механизмы ведения журнала для конкретной ОС, и можно создавать собственные классы назначения журнала для особых требований, которые не обрабатываются.

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

Вход в файл

Большинство приложений настроены для входа в файл. Используйте функцию basicConfig () , чтобы настроить обработчик по умолчанию, чтобы сообщения отладки записывались в файл.

logging_file_example.py

import logging

LOG_FILENAME  'logging_example.out'
logging.basicConfig(
    filenameLOG_FILENAME,
    levellogging.DEBUG,
)

logging.debug('This message should go to the log file')

with open(LOG_FILENAME, 'rt') as f:
    body  f.read()

print('FILE:')
print(body)

После запуска сценария сообщение журнала записывается в logging_example.out :

$ python3 logging_file_example.py

FILE:
DEBUG:root:This message should go to the log file

Ротация файлов журнала

Многократный запуск сценария приводит к добавлению дополнительных сообщений к файлу. Чтобы создавать новый файл при каждом запуске программы, передайте аргумент filemode в basicConfig () со значением 'w' . Однако вместо того, чтобы управлять созданием файлов таким образом, лучше использовать RotatingFileHandler , который автоматически создает новые файлы и сохраняет при этом старый файл журнала.

logging_rotatingfile_example.py

import glob
import logging
import logging.handlers

LOG_FILENAME  'logging_rotatingfile_example.out'

# Set up a specific logger with our desired output level
my_logger  logging.getLogger('MyLogger')
my_logger.setLevel(logging.DEBUG)

# Add the log message handler to the logger
handler  logging.handlers.RotatingFileHandler(
    LOG_FILENAME,
    maxBytes20,
    backupCount5,
)
my_logger.addHandler(handler)

# Log some messages
for i in range(20):
    my_logger.debug('i = %d' % i)

# See what files are created
logfiles  glob.glob('%s*' % LOG_FILENAME)
for filename in sorted(logfiles):
    print(filename)

В результате получается шесть отдельных файлов, каждый из которых содержит часть истории журнала для приложения.

$ python3 logging_rotatingfile_example.py

logging_rotatingfile_example.out
logging_rotatingfile_example.out.1
logging_rotatingfile_example.out.2
logging_rotatingfile_example.out.3
logging_rotatingfile_example.out.4
logging_rotatingfile_example.out.5

Самый последний файл – это всегда logging_rotatingfile_example.out , и каждый раз, когда он достигает предельного размера, он переименовывается с суффиксом .1 . Каждый из существующих файлов резервных копий переименовывается, чтобы увеличить суффикс ( .1 становится .2 и т. Д.), А файл .5 удаляется.

Примечание

Очевидно, что в этом примере длина журнала слишком мала в качестве крайнего примера. Установите для maxBytes более подходящее значение в реальной программе.

Уровни детализации

Еще одна полезная функция logging API – это возможность создавать разные сообщения на разных уровнях журнала . Это означает, что код можно оснастить, например, сообщениями отладки, а уровень журнала можно установить так, чтобы эти сообщения отладки не записывались в производственной системе. в таблице ниже перечислены уровни ведения журнала, определенные logging .

Уровни регистрации

Уровень

Ценить

КРИТИЧЕСКИЙ

50

ОШИБКА

40

ПРЕДУПРЕЖДЕНИЕ

30

ИНФОРМАЦИЯ

20

ОТЛАЖИВАТЬ

10

UNSET

Сообщение журнала создается только в том случае, если обработчик и средство ведения журнала настроены на отправку сообщений этого уровня или выше. Например, если сообщение имеет тип CRITICAL и для регистратора установлено значение ERROR , сообщение будет отправлено (50> 40). Если сообщение представляет собой WARNING , а регистратор настроен на создание только сообщений, для которых установлено значение ERROR , сообщение не отправляется.

logging_level_example.py

import logging
import sys

LEVELS  {
    'debug': logging.DEBUG,
    'info': logging.INFO,
    'warning': logging.WARNING,
    'error': logging.ERROR,
    'critical': logging.CRITICAL,
}

if len(sys.argv) > 1:
    level_name  sys.argv[1]
    level  LEVELS.get(level_name, logging.NOTSET)
    logging.basicConfig(levellevel)

logging.debug('This is a debug message')
logging.info('This is an info message')
logging.warning('This is a warning message')
logging.error('This is an error message')
logging.critical('This is a critical error message')

Запустите сценарий с аргументом вроде «отладка» или «предупреждение», чтобы узнать, какие

$ python3 logging_level_example.py debug

DEBUG:root:This is a debug message
INFO:root:This is an info message
WARNING:root:This is a warning message
ERROR:root:This is an error message
CRITICAL:root:This is a critical error message

$ python3 logging_level_example.py info

INFO:root:This is an info message
WARNING:root:This is a warning message
ERROR:root:This is an error message
CRITICAL:root:This is a critical error message

Именование экземпляров регистратора

Все предыдущие сообщения журнала имеют встроенный «root», потому что код использует корневое средство ведения журнала. Простой способ узнать, откуда приходит конкретное сообщение журнала, – это использовать отдельный объект журнала для каждого модуля. Сообщения журнала, отправляемые регистратору, включают имя этого регистратора. Вот пример того, как вести журнал из разных модулей, чтобы можно было легко отследить источник сообщения.

logging_modules_example.py

import logging

logging.basicConfig(levellogging.WARNING)

logger1  logging.getLogger('package1.module1')
logger2  logging.getLogger('package2.module2')

logger1.warning('This message comes from one module')
logger2.warning('This comes from another module')

Выходные данные показывают разные имена модулей для каждой выходной строки.

$ python3 logging_modules_example.py

WARNING:package1.module1:This message comes from one module
WARNING:package2.module2:This comes from another module

Дерево регистрации

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

digraph {
  rankdir = BT;

  узел [форма = двойной круг];
  “”; “пакет1” -> “”; “package1.module1” -> “package1”; “пакет2” -> “”; “package2.module2” -> “package2″; }” />

Пример дерева регистратора

Древовидная структура полезна для настройки ведения журнала, поскольку она означает, что каждому регистратору не нужен собственный набор обработчиков. Если регистратор не имеет обработчиков, сообщение передается его родительскому объекту для обработки. Это означает, что для большинства приложений необходимо настроить обработчики только на корневом регистраторе, и вся информация журнала будет собираться и отправляться в одно и то же место, как показано на рисунке.

digraph {
  rankdir = BT;

  узел [форма = двойной круг];
  “”; “package1.module2” -> “package1”; “пакет2” -> “”; “package2.module2” -> “package2”; “myapp” -> “”; узел [shape = note]; “” -> “/var/log/app.log”; {ранг = такой же; “”; “/var/log/app.log”} }” />

Один обработчик журналов

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

digraph {
  rankdir = BT;

  узел [форма = двойной круг];
  “” [label = “level = INFO”]; “package1.module2” -> “package1”; “пакет2” -> “” [label = “level = WARNING”]; “package2.module2” -> “package2”; “myapp” -> “” [label = “level = DEBUG”]; }” />

Различные уровни и обработчики

Интеграция с модулем предупреждений

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

logging_capture_warnings.py

import logging
import warnings

logging.basicConfig(
    levellogging.INFO,
)

warnings.warn('This warning is not sent to the logs')

logging.captureWarnings(True)

warnings.warn('This warning is sent to the logs')

Предупреждение отправляется регистратору с именем py.warnings с использованием уровня WARNING .

$ python3 logging_capture_warnings.py

logging_capture_warnings.py:13: UserWarning: This warning is not
 sent to the logs
  warnings.warn('This warning is not sent to the logs')
WARNING:py.warnings:logging_capture_warnings.py:17: UserWarning:
 This warning is sent to the logs
  warnings.warn('This warning is sent to the logs')

Смотрите также