Главная страница
Навигация по странице:

  • Уровень Значение Описание

  • Именованный аргумент Описание

  • Формат Описание

  • Создание экземпляра класса Logger Создать новый объект класса Logger можно с помощью следующей функ- ции:getLogger([ logname ])

  • Запись сообщений в журнал

  • Уровень важности Описание

  • Фильтрование журналируемых сообщений

  • Filter( logname )

  • Атрибут Описание

  • Распространение сообщений и иерархии регистраторов

  • справочник по Python. мм isbn 9785932861578 9 785932 861578


    Скачать 4.21 Mb.
    Названиемм isbn 9785932861578 9 785932 861578
    Анкорсправочник по Python
    Дата08.05.2022
    Размер4.21 Mb.
    Формат файлаpdf
    Имя файлаBizli_Python-Podrobnyy-spravochnik.440222.pdf
    ТипСправочник
    #518195
    страница36 из 82
    1   ...   32   33   34   35   36   37   38   39   ...   82
    Примечание
    Модуль io появился совсем недавно, впервые он был включен в состав стандарт- ной библиотеки в версии Python 3 и затем был перенесен в версию Python 2.6.
    К моменту написания этих строк модуль был еще недостаточно доработанным и имел очень низкую производительность, что особенно заметно в приложениях,

    Модуль logging
    445
    выполняющих массивные операции ввода-вывода текстовой информации. Если вы используете Python 2, использование встроенной функции open() позволит добиться лучших показателей по сравнению с использованием классов ввода- вывода, объявленных в модуле io. Если вы используете Python 3, то у вас нет дру-
    Python 3, то у вас нет дру-
    3, то у вас нет дру- гой альтернативы. В будущих выпусках производительность модуля наверняка будет увеличена, тем не менее многоуровневая архитектура ввода-вывода в со- единении с декодированием Юникода едва ли сравнится по производительности с низкоуровневыми операциями ввода-вывода, реализованными в стандартной библиотеке языка C, которая является основой реализации механизмов ввода- вывода в Python 2.
    Модуль logging
    М
    одуль logging предоставляет гибкую возможность реализовать в прило- жениях журналирование событий, ошибок, предупреждений и отладочной информации. Эта информация может собираться, фильтроваться, записы- ваться в файлы, отправляться в системный журнал и даже передаваться по сети на удаленные машины. В этом разделе приводятся самые основные сведения об использовании этого модуля в наиболее типичных ситуациях.
    Уровни журналирования
    Основной задачей модуля logging является получение и обработка сообще- ний. Каждое сообщение состоит из некоторого текста и ассоциированного с ним уровня, определяющего его важность. Уровни имеют как символиче- ские, так и числовые обозначения:
    Уровень
    Значение
    Описание
    CRITICAL
    50
    Критические ошибки/сообщения
    ERROR
    40
    Ошибки
    WARNING
    30
    Предупреждения
    INFO
    20
    Информационные сообщения
    DEBUG
    10
    Отладочная информация
    NOTSET
    0
    Уровень не установлен
    Эти уровни являются основой для различных функций и методов в модуле logging
    . Например, существуют методы, которые различают уровни важно- сти сообщений и выполняют фильтрацию, блокируя запись сообщений, уро- вень важности которых не соответствует заданному пороговому значению.
    Базовая настройка
    Перед использованием функций из модуля logging необходимо выполнить базовую настройку специального объекта, известного как корневой регист-
    ратор
    . Корневой регистратор содержит настройки по умолчанию, включая

    446
    Глава 19. Службы операционной системы уровень журналирования, поток вывода, формат сообщений и другие па- раметры. Для выполнения настройки используется следующая функция:
    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
    Имя модуля, откуда была выполнена запись в журнал.

    Модуль logging
    447
    Формат
    Описание
    %(lineno)d
    Н
    омер строки, откуда была выполнена запись в журнал.
    %(created)f
    Время, когда была выполнена запись в журнал. Значением должно быть число, такое как возвращаемое функцией time.
    time()
    %(asctime)s
    Время в формате ASCII, когда была выполнена запись в журнал.
    %(msecs)s
    Миллисекунда, когда была выполнена запись в журнал.
    %(thread)d
    Числовой идентификатор потока выполнения.
    %(threadName)s
    Имя потока выполнения.
    %(process)d
    Числовой идентификатор процесса.
    %(message)s
    Текст журналируемого сообщения (определяется пользова- телем).
    Ниже приводится пример, иллюстрирующий настройки для случая, когда в файл журнала записываются сообщения с уровнем INFO или выше:
    import logging logging.basicConfig(
    filename = “app.log”,
    format = “%(levelname)-10s %(asctime)s %(message)s”
    level = logging.INFO
    )
    При таких настройках вывод сообщения ‘Hello World’ с уровнем важности
    CRITICAL
    будет выглядеть в файле журнала ‘app.log’, как показано ниже.
    CRITICAL 2005-10-25 20:46:57,126 Hello World
    Объекты класса Logger
    Чтобы выводить сообщения в журнал, необходимо получить объект класса
    Logger
    . В этом разделе описывается процесс создания, настройки и исполь- зования этих объектов.
    Создание экземпляра класса Logger
    Создать новый объект класса Logger можно с помощью следующей функ- ции:
    getLogger([logname])
    Возвращает экземпляр класса Logger с именем logname. Если объект с та- ким именем не существует, то создается и возвращается новый экземпляр класса Logger. В аргументе logname передается строка, определяющая имя или последовательность имен, разделенных точками (например, ‘app’ или
    ‘app.net’
    ). При вызове без аргумента logname вернет объект Logger корневого регистратора.

    448
    Глава 19. Службы операционной системы
    Э
    кземпляры класса Logger создаются иначе, чем экземпляры большинства классов в других библиотечных модулях. При создании объекта Logger с помощью функции getLogger() ей всегда необходимо передавать аргумент
    logname
    . За кулисами функция getLogger() хранит кэш экземпляров класса
    Logger вместе с их именами. Если в какой-либо части программы будет за- прошен регистратор с тем же именем, она возвратит экземпляр, созданный ранее. Это существенно упрощает обработку журналируемых сообщений в крупных приложениях, потому что не приходится заботиться о способах передачи экземпляров класса Logger из одного модуля программы в другой.
    Вместо этого в каждом модуле, где возникает необходимость журналиро- вания сообщений, достаточно просто вызвать функцию getLogger(), чтобы получить ссылку на соответствующий объект Logger.
    Выбор имен
    По причинам, которые станут очевидными чуть ниже, при использовании функции getLogger() желательно всегда выбирать говорящие имена. На- пример, если приложение называется ‘app’, тогда как минимум следует ис- пользовать getLogger(‘app’) в начале каждого модуля, составляющего при- ложение. Например:
    import logging log = logging.getLogger(‘app’)
    Можно также добавить имя модуля, например getLogger(‘app.net’) или getLogger(‘app.user’)
    , чтобы более четко указать источник сообщений. Реа- лизовать это можно с помощью инструкций, как показано ниже:
    import logging log = logging.getLogger(‘app.’+__name__)
    Добавление имен модулей упрощает выборочное отключение или перена- стройку механизма журналирования для каждого модуля в отдельности, как будет описано ниже.
    Запись сообщений в журнал
    Если допустить, что переменная log является экземпляром класса Logger
    (созданного вызовом функции getLogger(), описанной в предыдущем разде- ле), то для записи сообщений с разными уровнями важности можно будет использовать следующие методы:
    Уровень важности
    Описание
    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]]])

    Модуль logging
    449
    В аргументе fmt передается строка формата, определяющая формат вывода сообщения в журнал. Все остальные аргументы в args будут служить пара- метрами спецификаторов формата в строке fmt. Для формирования оконча- тельного сообщения из этих аргументов используется оператор форматиро- вания строк %. Если передается несколько аргументов, они будут переданы оператору форматирования в виде кортежа. Если передается единствен- ный аргумент, он будет помещен сразу вслед за оператором %. То есть, если в качестве единственного аргумента передается словарь, имеется возмож- ность использовать имена ключей этого словаря в строке формата. Ниже приводится несколько примеров, иллюстрирующих эту возможность:
    log = logging.getLogger(“app”)
    # Записать сообщение, используя позиционные аргументы форматирования log.critical(“Can’t connect to %s at port %d”, host, port)
    ёё
    # Записать сообщение, используя словарь значений parms = {
    ‘host’ : ‘www.python.org’,
    ‘port’ : 80
    }
    log.critical(“Can’t connect to %(host)s at port %(port)d”, parms)
    Если в именованном аргументе exc_info передается значение True, в сообще- ние добавляется информация об исключении, полученная вызовом sys.
    exc_info()
    . Если в этом аргументе передается кортеж с информацией об ис- ключении, какой возвращает sys.exc_info(), то будет использоваться эта информация. В именованном аргументе extra передается словарь с допол- нительными значениями для использования в строке формата (описывает- ся ниже). Оба аргумента, exc_info и extra, должны передаваться как имено- ванные аргументы.
    Выполняя вывод журналируемых сообщений, не следует использовать возможности форматирования строк при вызове функции (то есть следует избегать приемов, когда сообщение сначала форматируется, а затем пере- дается модулю logging). Например:
    log.critical(“Can’t connect to %s at port %d” % (host, port))
    В этом примере оператор форматирования строки всегда будет выполнять- ся перед вызовом самой функции log.critical(), потому что аргументы должны передаваться функции или методу уже полностью вычисленны- ми. Однако в более раннем примере значения для спецификаторов формата просто передаются модулю logging и используются, только когда сообще- ние действительно будет выводиться. Это очень тонкое отличие, но так как в большинстве приложений задействуется механизм фильтрации сообще- ний или сообщения выводятся только в процессе отладки, первый подход обеспечивает более высокую производительность, когда журналирование отключено.
    В дополнение к методам, показанным выше, существует еще несколько методов экземпляра log класса Logger, позволяющих выводить сообщения в журнал.

    450
    Глава 19. Службы операционной системы
    log.exception(fmt [, *args ])
    Выводит сообщение с уровнем ERROR и добавляет информацию о текущем обрабатываемом исключении. Может использоваться только внутри бло- ков except.
    log.log(level, fmt [, *args [, exc_info [, extra]]])
    Выводит сообщение с уровнем level. Может использоваться в случаях, ког- да уровень важности определяется значением переменной или когда требу- ется использовать дополнительные уровни важности, не входящие в число пяти базовых уровней.
    log.findCaller()
    Возвращает кортеж (filename, lineno, funcname) с именем файла источни- ка сообщения, номером строки и именем функции. Эта информация может пригодиться, например, когда желательно знать, в какой точке программы было выведено сообщение.
    Фильтрование журналируемых сообщений
    Каждый объект log класса Logger имеет свой уровень и обладает внутрен- ним механизмом фильтрации, с помощью которого определяет, какие со- общения следует обрабатывать. Следующие два метода используются для выполнения простой фильтрации на основе числового значения уровня важности сообщений:
    log.setLevel(level)
    Устанавливает уровень важности в объекте log, в соответствии со значе- нием аргумента level. Обрабатываться будут только сообщения с уровнем важности равным или выше значения level. Все остальные сообщения по- просту игнорируются. По умолчанию аргумент level получает значение logging.NOTSET
    , при котором обрабатываются все сообщения.
    log.isEnabledFor(level)
    Возвращает True, если сообщение с уровнем level должно обрабатываться.
    Журналируемые сообщения могут также фильтроваться по информации, ассоциированной с самим сообщением, например, по имени файла, по но- меру строки и другим сведениям. Для этих целей используются следую- щие методы:
    log.addFilter(filt)
    Добавляет в регистратор объект filt фильтра.
    log.removeFilter(filt)
    Удаляет объект filt фильтра из регистратора.
    Оба метода принимают в аргументе filt экземпляр класса Filter.
    Filter(logname)
    Создает фильтр, который пропускает только сообщения из регистратора
    logname
    или его потомков. Например, если в аргументе logname передать имя
    ‘app’
    , то фильтр будет пропускать сообщения из регистраторов с именами,

    Модуль logging
    451
    такими как ‘app’, ‘app.net’ или ‘app.user’, а сообщения из регистратора, на- пример с именем ‘spam’, пропускаться не будут.
    Собственные фильтры можно создавать, определяя подклассы класса Fil- ter с собственной реализацией метода filter(record), который принимает запись record с информацией о сообщении и возвращает True или False, в за- висимости от того, должно ли обрабатываться сообщение. Объект record, который передается этому методу, обычно обладает следующими атрибу- тами:
    Атрибут
    Описание
    record.name
    Имя, присвоенное объекту регистратора
    record.levelname
    Символическое имя уровня важности
    record.levelno
    Числовое значение уровня важности
    record.pathname
    Путь к модулю
    record.filename
    Имя файла модуля
    record.module
    Имя модуля
    record.exc_info
    Информация об исключении
    record.lineno
    Номер строки, где была выполнена попытка вывести сообщение
    record.funcName
    Имя функции, где была выполнена попытка вывести сообщение
    record.created
    Время вывода сообщения
    record.thread
    Числовой идентификатор потока управления
    record.threadName
    Имя потока управления
    record.process
    Числовой идентификатор текущего процесса (PID)
    Следующий пример демонстрирует, как создавать собственные фильтры:
    class FilterFunc(logging.Filter):
    def __init__(self,name):
    self.funcName = name def filter(self, record):
    if record.funcName == self.funcName: return False else: return True
    ёё
    log.addFilter(FilterFunc(‘foo’)) # Игнорировать все сообщения из функции foo()
    log.addFilter(FilterFunc(‘bar’)) # Игнорировать все сообщения из функции bar()
    Распространение сообщений и иерархии регистраторов
    В приложениях со сложной организацией процесса журналирования объ- екты класса Logger могут объединяться в иерархии. Для этого достаточно присвоить объекту класса Logger соответствующее имя, такое как ‘app.net.
    client’
    . В данном случае фактически существует три разных объекта Log- ger с именами ‘app’, ‘app.net’ и ‘app.net.client’. Если какому-либо из реги-

    452
    Глава 19. Службы операционной системы страторов будет передано сообщение и оно благополучно будет пропущено фильтром этого регистратора, это сообщение продолжит распространение вверх по дереву иерархии и будет обработано всеми родительскими реги- страторами. Например, сообщение, благополучно принятое регистратором
    ‘app.net.client’
    , будет также передано регистраторам ‘app.net’, ‘app’ и кор- невому регистратору.
    Распространением сообщений управляют следующие атрибуты и методы объекта log класса Logger.
    log.propagate
    Логический флаг, который определяет, должно ли сообщение передаваться родительскому регистратору. По умолчанию имеет значение True.
    log.getEffectiveLevel()
    Возвращает действующий уровень регистратора. Если уровень был уста- действующий уровень регистратора. Если уровень был уста- действующий уровень регистратора. Если уровень был уста- уровень регистратора. Если уровень был уста- уровень регистратора. Если уровень был уста- регистратора. Если уровень был уста- регистратора. Если уровень был уста-
    . Если уровень был уста-
    Если уровень был уста- новлен вызовом метода setLevel(), вернет этот уровень. Если уровень не был указан явно в вызове метода setLevel() (в этом случае по умолчанию уро- вень принимает значение logging.NOTSET), этот метод вернет действующий уровень родительского регистратора. Если ни в одном из родительских ре- гистраторов не был явно установлен уровень, возвращается действующий уровень корневого регистратора.
    Основное назначение иерархий регистраторов состоит в том, чтобы упро- стить фильтрование сообщений, поступающих из различных частей круп- ного приложения. Например, если потребуется предотвратить вывод со- общений, поступающих из регистратора ‘app.net.client’, достаточно будет просто добавить следующий программный код, выполняющий необходи- мые настройки:
    import logging logging.getLogger(‘app.net.client’).propagate = False
    Или сохранить возможность вывода только критических сообщений:
    import logging logging.getLogger(‘app.net.client’).setLevel(logging.CRITICAL)
    Отличительной особенностью иерархий регистраторов является то обстоя- тельство, что решение о выводе сообщения принимается самим объектом
    Logger
    , которому это сообщение было передано, исходя из его собственного уровня важности и фильтров, а не какими-либо родительскими регистра- торами. То есть, если сообщение было пропущено первым встретившимся набором фильтров, оно продолжит свое распространение и будет обрабо- тано всеми родительскими регистраторами, независимо от их фильтров и уровней важности, даже если при других обстоятельствах эти фильтры могли бы отвергнуть сообщение. На первый взгляд такой механизм работы кажется противоестественным и может даже восприниматься как ошибка.
    Однако установка уровня в дочернем регистраторе в более низкое значение, чем у его родителя, является одним из способов преодолеть ограничения, накладываемые родителем, и обеспечить возможность вывода сообщений с более низким уровнем важности. Например:

    Модуль logging
    1   ...   32   33   34   35   36   37   38   39   ...   82


    написать администратору сайта