DevGang
Авторизоваться

Python использует Logging для записи программных журналов

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

logging Quick start

Почему бы не использовать печать?

Ведение журнала является чрезвычайно важной частью развертывания программы в производственной среде, и logging полезно для программ тремя способами:

  1. Ведение журнала состояния: для каждого момента времени важно записывать состояние бизнес-операции в это время, и часто вам нужно полагаться на эту информацию для определения бизнес-проблем.
  2. Воспроизведение ошибок: Производственные среды не оборудованы для одноэтапной отладки, а ошибки в производственных средах чрезвычайно трудно воспроизвести, поэтому ведение журнала является единственным и наиболее эффективным средством воспроизведения ошибок.
  3. Установление уровней: установите разные уровни вывода для разных модулей, чтобы файлы журналов выглядели более лаконичными.

logging — это собственная библиотека ведения журналов Python, которая сочетает в себе возможности ведения журналов с гибкостью записи в файл, печати на консоль или на удаленный HTTP/FTP-сервер, независимо от того, хотите ли вы делать все это.

Примеры использования logging

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

Демо:

  1. main.py
  2. auxiliary_module.py

main.py

import logging
import auxiliary_module

# create logger with 'spam_application'
logger = logging.getLogger('spam_application')
logger.setLevel(logging.DEBUG)
# create file handler which logs even debug messages
fh = logging.FileHandler('spam.log')
fh.setLevel(logging.DEBUG)
# create console handler with a higher log level
ch = logging.StreamHandler()
ch.setLevel(logging.ERROR)
# create formatter and add it to the handlers
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
fh.setFormatter(formatter)
ch.setFormatter(formatter)
# add the handlers to the logger
logger.addHandler(fh)
logger.addHandler(ch)

logger.info('creating an instance of auxiliary_module.Auxiliary')
a = auxiliary_module.Auxiliary()
logger.info('created an instance of auxiliary_module.Auxiliary')
logger.info('calling auxiliary_module.Auxiliary.do_something')
a.do_something()
logger.info('finished auxiliary_module.Auxiliary.do_something')
logger.info('calling auxiliary_module.some_function()')
auxiliary_module.some_function()
logger.info('done with auxiliary_module.some_function()')

auxiliary_module.py

import logging

# create logger
module_logger = logging.getLogger('spam_application.auxiliary')

class Auxiliary:
    def __init__(self):
        self.logger = logging.getLogger('spam_application.auxiliary.Auxiliary')
        self.logger.info('creating an instance of Auxiliary')

    def do_something(self):
        self.logger.info('doing something')
        a = 1 + 1
        self.logger.info('done doing something')

def some_function():
    module_logger.info('received a call to "some_function"')

Запустите main.py файл напрямую и получите следующий результат.

2020-07-21 00:39:24,997 - spam_application - INFO - creating an instance of auxiliary_module.Auxiliary
2020-07-21 00:39:24,997 - spam_application.auxiliary.Auxiliary - INFO - creating an instance of Auxiliary
2020-07-21 00:39:24,998 - spam_application - INFO - created an instance of auxiliary_module.Auxiliary
2020-07-21 00:39:24,998 - spam_application - INFO - calling auxiliary_module.Auxiliary.do_something
2020-07-21 00:39:24,998 - spam_application.auxiliary.Auxiliary - INFO - doing something
2020-07-21 00:39:24,998 - spam_application.auxiliary.Auxiliary - INFO - done doing something
2020-07-21 00:39:24,998 - spam_application - INFO - finished auxiliary_module.Auxiliary.do_something
2020-07-21 00:39:24,998 - spam_application - INFO - calling auxiliary_module.some_function()
2020-07-21 00:39:24,999 - spam_application.auxiliary - INFO - received a call to "some_function"
2020-07-21 00:39:24,999 - spam_application - INFO - done with auxiliary_module.some_function()

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

  1. Logger: объект Logger, если он не инициализирован активно, будет объектом Logger по умолчанию при вызове logging.info('hello world').
  2. LogRecord: регистратор получает журналы, переданные объектом Logger, и отправляет их соответствующему обработчику Handler.
  3. Handler: базовый процессор, который выводит сгенерированные журналы в указанное место (т. е. определяет, отправляются ли журналы в службу вывода desk/HTTP server/local).
  4. Filter: фильтр, обеспечивающий лучшую детализацию для управления фильтрацией некоторого определенного выходного содержимого.
  5. Formatter: средство форматирования, которое работает с обработчиком для реализации различных форматов вывода журнала.

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

Для простоты использования нам нужно сосредоточиться только на трех частях, а именно: Logger/Handler/Formatter.

Просто нужно освоить Logger/Handler/Formatter

Logger является основным объектом ведения журнала, например, в примере кода используется logging.getLogger(‘spam_application’) для получения объекта ведения журнала с именем spam_application.

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

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

setLevel(logging.DEBUG)

Установите этот объект ведения журнала для вывода журналов на уровне Debug и выше. Официальная документация для уровня ведения журнала приведена ниже, если установлен уровень Debug, то будут выводиться все журналы со значениями > Уровень DEBUG.

Level Value
CRITICAL 50
FATAL 50
ERROR 40
WARNING 30
WARN 30
INFO 20
DEBUG 10
NOTSET 0
fh = logging.FileHandler('spam.log')

Создается обработчик с именем FH, указывающий выходной формат цели вывода журнала DEBUG, и то же самое для объекта ch, где FileHandler указывает, что это файловый обработчик вывода, который будет выводить журнал в файл, разные обработчики имеют различные параметры, а список общих обработчиков выглядит следующим образом.

Обработчик Описание
StreamHandler Вывод журнала в поток, либо sys.stderr, sys.stdout, либо в пользовательский файл.
FileHandler Вывод журналов в файл
BaseRotatingHandler Прокат журналов
RotatingHandler Вывод скользящего журнала, который позволяет вам контролировать количество журналов.
TimeRotatingHandler Поддержка прокрутки файлов журнала по времени.
SocketHandler Выводить журналы по протоколу socket на указанную удаленную машину
SMTPHandler Вывод журналов на smtp-сервер (email)
SysLogHandler Вывод в системный журнал
HTTPHandler Вывод на HTTP-сервер
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')

formatter создан. Параметры в нем настраиваемые и список параметров выглядит следующим образом.

Параметры Описание
%(levelno)s Значения уровня журнала
%(levelname)s Имя уровня журнала
%(pathname)s Путь к выполняемой в данный момент программе, которая на самом деле является sys.argv[0]
%(filename)s Имя выполняемой в данный момент программы
%(funcName)s Название функции
%(lineno)d Номер строки кода
%(asctime)s Время печати
%(thread)d Идентификатор темы
%(threadName)s Название потока
%(process)d Идентификатор процесса
%(processName)s Имя процесса
%(module)s Имя модуля
%(message)s Сообщения журнала

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

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

Гибкое ведение журнала

Выход исключения

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

import logging

try:
    result = 10 / 0 
except Exception as e:
    logging.error('Error as %s', e)

Тот факт, что вывод e напрямую показывает информацию о стеке, не очевиден. Более рекомендуется использовать logging.error('Error as',exc_info=True)/logging.exception('Error') для печати информации о стеке в обоих направлениях.

Пользовательская конфигурация файла журнала

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

import logging.config
import yaml

with open('logging.yaml','r',encoding='utf-8') as f:
    config = yaml.load(f)
    logging.config.dictConfig(config)

Файлы конфигурации поддерживают широкий спектр форматов, включая config/ini/yaml/json и т. д., и все они могут использоваться в качестве файлов конфигурации ведения журнала.

Ниже приведен файл конфигурации yaml, который автоматически прокручивается по дате.

version: 1
formatters:
  common:
    format: "%(asctime)s - %(levelname)s- %(threadName)s - %(message)s"
    datefmt: "%Y/%m/%d %H:%M:%S"
  console:
    format: "%(asctime)s - %(levelname)s- %(pathname)s - %(message)s"
    datefmt: "%Y/%m/%d %H:%M:%S"
handlers:
  # No logs greater than or equal to this level will be output.
  common:
    class: logging.handlers.TimedRotatingFileHandler
    formatter: common
    level: INFO
    when: D
    interval: 1
    encoding: utf8
    filename: "app.log"
    # suffix: "%Y-%m-%d.log"
    # Number of logs to keep
    backupCount: 7
  console:    
    class : logging.StreamHandler
    formatter: brief
    level   : INFO
    stream  : ext://sys.stdout
loggers:
  main.business:
    level: INFO
    handlers: [common]
# If the module does not use a configuration such as logging.getLogger('main.business') to get the corresponding configuration in loggers, the following root configuration will be used by default.
root:
  level: DEBUG
  handlers: [console]

Соответствующий код можно найти здесь.

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

#Python
Комментарии
Чтобы оставить комментарий, необходимо авторизоваться

Присоединяйся в тусовку

В этом месте могла бы быть ваша реклама

Разместить рекламу