Еще один важный этап при написании приложения — возможность получать логи критично важного функционала приложения
Логи мои логи
Логи — важная часть приложения на любом языке программирования. Они помогут определить ошибку не на этапе написания кода, а на этапе работы с готовым продуктом. С их помощью легче находить баги и оказывать техническую поддержку конечным пользователям. В питоне это можно реализовать с помощью встроенного модуля logging.
Модуль logging
Данный модуль создан, чтобы мониторить и записывать события, ошибки, предупреждения и отладочную информацию в приложениях. Их можно хранить как локально, так и отсылать на удаленный хост. Модуль имеет встроенную фильтрацию, чтобы мы могли настроить логи под себя — какую информацию, куда и как часто передавать
[adace-ad id=»3482″]
Уровни логов
Уровни созданы для того, чтобы устанавливать важность и тем самым, определять будет ли сделана запись в лог или нет. Имеют как числовое, так и текстовое обозначение. Уровень — пороговое значение, ниже которого, запись не будет сделана в лог. Каждый уровень к каждой функции мы выставляем самостоятельно — решаем, насколько это важно в каждом конкретном случае.
Уровень | Значение | Описание |
CRITICAL | 50 | Критические ошибки/сообщения |
ERROR | 40 | Ошибки |
WARNING | 30 | Предупреждения |
INFO | 20 | Информационные сообщения |
DEBUG | 10 | Отладочная информация |
NOTSET | 0 | Уровень не установлен |
Для этого используется метод log.setLevel(level) используется для выполнения простой фильтрации на основе числового значения уровня важности сообщений. Он устанавливает этот уровень в объекте log в соответствии со значением аргумента level. Обрабатываться будут только сообщения с уровнем важности, равным значению level или выше его. Например: log.setLevel(logging.INFO) [adace-ad id=»3473″]
Основная настройка модуля 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 и так далее.
[adace-ad id=»3475″]
Как записать лог?
Итак, мы создали объект 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
Результат:
Формат логов с помощью 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]
Результат:
