Еще один важный этап при написании приложения — возможность получать логи критично важного функционала приложения
Логи мои логи
Логи — важная часть приложения на любом языке программирования. Они помогут определить ошибку не на этапе написания кода, а на этапе работы с готовым продуктом. С их помощью легче находить баги и оказывать техническую поддержку конечным пользователям. В питоне это можно реализовать с помощью встроенного модуля logging.
Модуль logging
Данный модуль создан, чтобы мониторить и записывать события, ошибки, предупреждения и отладочную информацию в приложениях. Их можно хранить как локально, так и отсылать на удаленный хост. Модуль имеет встроенную фильтрацию, чтобы мы могли настроить логи под себя — какую информацию, куда и как часто передавать
Уровни логов
Уровни созданы для того, чтобы устанавливать важность и тем самым, определять будет ли сделана запись в лог или нет. Имеют как числовое, так и текстовое обозначение. Уровень — пороговое значение, ниже которого, запись не будет сделана в лог. Каждый уровень к каждой функции мы выставляем самостоятельно — решаем, насколько это важно в каждом конкретном случае.
| Уровень | Значение | Описание |
| CRITICAL | 50 | Критические ошибки/сообщения |
| ERROR | 40 | Ошибки |
| WARNING | 30 | Предупреждения |
| INFO | 20 | Информационные сообщения |
| DEBUG | 10 | Отладочная информация |
| NOTSET | 0 | Уровень не установлен |
Для этого используется метод log.setLevel(level) используется для выполнения простой фильтрации на основе числового значения уровня важности сообщений. Он устанавливает этот уровень в объекте log в соответствии со значением аргумента level. Обрабатываться будут только сообщения с уровнем важности, равным значению level или выше его. Например: log.setLevel(logging.INFO)
Основная настройка модуля logging
Для использования модуля необходимо предварительно его настроить. Конкретно нас интересует корневой регистратор (Logger). Он содержит настройки по умолчанию: уровень важности логов, поток вывода, формат сообщений и другие параметры. Настраивают Logger через функцию basicConfig([**kwargs]). Эта функция должна вызываться первой из модуля logging. Она принимает множество именованных аргументов
| Именованный аргумент | Описание |
| filename | Журналируемые сообщения будут добавляться в файл с указанным именем. |
| filemode | Определяет режим открытия файла. По умолчанию используется режим a (добавление в конец). |
| format | Строка формата для формирования сообщений. |
| datefmt | Строка формата для вывода даты и времени. |
| level | Устанавливает уровень важности корневого регистратора. Обрабатываться будут сообщения с уровнем важности, равным указанному или выше его. Сообщения с более низким уровнем будут игнорироваться. |
| stream | Определяет объект открытого файла, куда будут записываться журналируемые сообщения. По умолчанию используется поток std.stderr. Этот аргумент не может использоваться одновременно с filename. |
Назначение большинства этих аргументов понятно по их названиям. format определяет формат журналируемых сообщений с дополнительной контекстной информацией — именами файлов, уровнями важности, номерами строк. Аргумент datefmt определяет формат вывода дат, совместимый с функцией time.strftime(). Если он не определен, даты форматируются в соответствии со стандартом ISO8601.
Аргумент format
Данный аргумент будет формировать лог по выбранным вами параметрам:
| Формат | Описание |
| %(name)s | Имя регистратора |
| %(levelno)s | Числовой уровень важности |
| %(levelname)s | Символическое имя уровня важности |
| %(pathname)s | Путь к исходному файлу, откуда была выполнена запись в журнал |
| %(filename)s | Имя исходного файла, откуда была выполнена запись в журнал |
| %(funcName)s | Имя функции, выполнившей запись в журнал |
| %(module)s | Имя модуля, откуда была выполнена запись в журнал |
| %(lineno)d | Номер строки, откуда была выполнена запись в журнал |
| %(created)f | Время, когда была выполнена запись в журнал. Значением должно быть число — такое, как возвращаемое функцией time.time() |
| %(asctime)s | Время, когда была выполнена запись в журнал, в формате ASCII |
| %(msecs)s | Миллисекунда, когда была выполнена запись в журнал |
| %(thread)d | Числовой идентификатор потока выполнения |
| %(threadName)s | Имя потока выполнения |
| %(process)d | Числовой идентификатор процесса |
| %(message)s | Текст журналируемого сообщения (определяется пользователем) |
Выглядит это вот так:
import logging
logging.basicConfig(
filename = «app.log»,
format = «%(levelname)-10s %(asctime)s %(message)s»,
level = logging.INFO
)
Как создать объект класса Logger?
Чтобы создать экземпляр класса Logger необходимо вызвать функцию getLogger(). Она возвращает экземпляр класса Logger с именем logname. Если объект с таким именем не существует, создается и возвращается новый экземпляр класса Logger. Вот так: getLogger(‘str’). В качестве аргумента функции нужно передать строку — она же будет являться именем объекта. Например, getLogger(‘logusers’).
Стоит запомнить, что передавать имя в функцию getLogger всегда обязательно. Полный код создания объекта будет выглядеть таким образом: log = logging.getLogger(‘name’). Через точку в имя можно добавить дополнительный идентификатор (например, с чего будем собирать логи). Например, name.serverconnect и так далее.
Как записать лог?
Итак, мы создали объект log, который является экземпляром класса Logger. Можно использовать следующие методы, чтобы сделать запись в журнал. Именованный аргумент exc_info (True/False) определяет, добавлять ли в сообщение информацию об исключении, полученную при вызове sys.exc_info(). Именованный аргумент extra определяет словарь с дополнительными значениями для использования в строке формата.
| Уровень важности | Метод |
| CRITICAL | log.critical(fmt [, *args [, exc_info [, extra]]]) |
| ERROR | log.error(fmt [, *args [, exc_info [, extra]]]) |
| WARNING | log.warning(fmt [, *args [, exc_info [, extra]]]) |
| INFO | log.info(fmt [, *args [, exc_info [, extra]]]) |
| DEBUG | log.debug(fmt [, *args [, exc_info [, extra]]]) |
Как это выглядит?
log.info(‘Информация к сведению’)
log.warning(‘Предупреждение’)
log.critical(‘Критическая ошибка приложения’)
Обработка сообщений
Обычно сообщения обрабатываются корневым регистратором. Однако любой объект класса Logger может иметь свои специальные обработчики, принимающие и обрабатывающие сообщения. Реализовать это можно с помощью следующих методов экземпляра log класса Logger:
- log.addHandler(handler) — добавляет объект класса Handler в регистратор;
- log.removeHandler(handler) — удаляет объект класса Handler из регистратора.
Пример кода:
[code]
import logging
import sys
# Регистратор верхнего уровня с именем ‘log’
test = logging.getLogger(‘log’) # test = экземпляр класса Logger
test.setLevel(logging.INFO) # задаем порог сообщения (уровень логов)
test.propagate = False #отключаем распространение сообщений
# Добавить несколько обработчиков в регистратор ‘test’
test.addHandler(logging.FileHandler(‘test.log’))
test.addHandler(logging.StreamHandler(sys.stderr))
test.critical(‘Red Alert’) # лог попадет в файл test.log
test.info(‘RTFM, son’) # лог будет выведен в поток sys.stderr
[/code]
Формат логов с помощью Formatter
Чтобы определить формат сообщения логов, нужно создать объект класса Formatter. Чтобы задействовать объект класса Formatter, его необходимо подключить к обработчику. Метод log.setFormatter(format) подключает объект форматирования, который будет использоваться экземпляром h класса Handler при создании сообщений. В аргументе format должен передаваться объект класса Formatter.
[code]
import logging
import sys
_format = logging.Formatter(«%(levelname)-10s %(asctime)s %(message)s») #определяем формат сообщения
bug_error = logging.StreamHandler(sys.stderr) # создаем обработчик для передачи в поток
bug_error.setLevel(logging.CRITICAL) # с уровнем critical
bug_error.setFormatter(_format)
log = logging.getLogger(‘basic’) # создаем регистратор
log.addHandler(bug_error) # Добавляем обработчик к регистратору
log.critical(‘BIG TROUBLES, BRO’) # Передаем сообщение обработчику
[/code]



































































