Журнал Python ничего не выводит

97

В сценарии Python, который я пишу, я пытаюсь регистрировать события с помощью модуля регистрации. У меня есть следующий код для настройки моего регистратора:

ERROR_FORMAT = "%(levelname)s at %(asctime)s in %(funcName)s in %(filename) at line %(lineno)d: %(message)s"
DEBUG_FORMAT = "%(lineno)d in %(filename)s at %(asctime)s: %(message)s"
LOG_CONFIG = {'version':1,
              'formatters':{'error':{'format':ERROR_FORMAT},
                            'debug':{'format':DEBUG_FORMAT}},
              'handlers':{'console':{'class':'logging.StreamHandler',
                                     'formatter':'debug',
                                     'level':logging.DEBUG},
                          'file':{'class':'logging.FileHandler',
                                  'filename':'/usr/local/logs/DatabaseUpdate.log',
                                  'formatter':'error',
                                  'level':logging.ERROR}},
              'root':{'handlers':('console', 'file')}}
logging.config.dictConfig(LOG_CONFIG)

Когда я пытаюсь запустить logging.debug("Some string"), я не получаю вывода на консоль, хотя на этой странице в документации говорится, что logging.debugкорневой регистратор должен выводить сообщение. Почему моя программа ничего не выводит и как это исправить?

murgatroid99
источник

Ответы:

103

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

Это объясняется в руководстве :

import logging
logging.warning('Watch out!') # will print a message to the console
logging.info('I told you so') # will not print anything

Строка info ничего не выводит, потому что уровень выше, чем info.

Чтобы изменить уровень, просто установите его в корневом логгере:

'root':{'handlers':('console', 'file'), 'level':'DEBUG'}

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

Омри Барел
источник
7
В документации говорится, что его уровень по умолчанию - NOTSET, который является уровнем 0, который должен выводить все ... Почему это не так?
Бен
@ Бен, где это сказано? Все, что я вижу, - это «Уровень по умолчанию - ПРЕДУПРЕЖДЕНИЕ, что означает, что будут отслеживаться только события этого уровня и выше, если пакет ведения журнала не настроен на иное».
Омри
1
@Ben в соответствии с документами, по которым регистраторы просматриваются, чтобы найти первого родителя level != NOTSETили корня (если ничего не найдено). По WARNINGумолчанию у корня есть уровень. Это написано в разделе, на который вы указали ( Logger.setLevel).
Омри
6
Учтите, что после импорта loggingнужно logging.basicConfig()хотя бы один раз позвонить . В противном случае вы можете быть сильно удивлены, что дочерние регистраторы ничего не будут печатать. Функции регистрации в корневом регистраторе вызывают его лениво.
Hubert Grzeskowiak
74

Много лет спустя, похоже, все еще существует проблема с удобством использования регистратора Python. Вот некоторые пояснения с примерами:

import logging
# This sets the root logger to write to stdout (your console).
# Your script/app needs to call this somewhere at least once.
logging.basicConfig()

# By default the root logger is set to WARNING and all loggers you define
# inherit that value. Here we set the root logger to NOTSET. This logging
# level is automatically inherited by all existing and new sub-loggers
# that do not set a less verbose level.
logging.root.setLevel(logging.NOTSET)

# The following line sets the root logger level as well.
# It's equivalent to both previous statements combined:
logging.basicConfig(level=logging.NOTSET)


# You can either share the `logger` object between all your files or the
# name handle (here `my-app`) and call `logging.getLogger` with it.
# The result is the same.
handle = "my-app"
logger1 = logging.getLogger(handle)
logger2 = logging.getLogger(handle)
# logger1 and logger2 point to the same object:
# (logger1 is logger2) == True


# Convenient methods in order of verbosity from highest to lowest
logger.debug("this will get printed")
logger.info("this will get printed")
logger.warning("this will get printed")
logger.error("this will get printed")
logger.critical("this will get printed")


# In large applications where you would like more control over the logging,
# create sub-loggers from your main application logger.
component_logger = logger.getChild("component-a")
component_logger.info("this will get printed with the prefix `my-app.component-a`")

# If you wish to control the logging levels, you can set the level anywhere 
# in the hierarchy:
#
# - root
#   - my-app
#     - component-a
#

# Example for development:
logger.setLevel(logging.DEBUG)

# If that prints too much, enable debug printing only for your component:
component_logger.setLevel(logging.DEBUG)


# For production you rather want:
logger.setLevel(logging.WARNING)

Обычный источник путаницы - плохо инициализированный корневой регистратор. Учти это:

import logging
log = logging.getLogger("myapp")
log.warning("woot")
logging.basicConfig()
log.warning("woot")

Выход:

woot
WARNING:myapp:woot

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

Хуберт Гжесковяк
источник
Мой журнал не работает, потому что он не создает выходной файл. Вы видите что-то, что я делаю явно неправильно? logging.basicConfig( filename='logging.txt', level=logging.DEBUG) logger = logging.getLogger() logger.info('Test B') logging.info('Test A')
Райлан Шеффер,
Файл журнала даже не создается
Райлан Шеффер,
Я заметил, что когда я сбрасываю точку останова после logger = logging.getLogger(), уровень устанавливается на ПРЕДУПРЕЖДЕНИЕ, хотя я указал уровень как DEBUG. Вы знаете, что я делаю не так?
Райлан Шеффер,
Привет, @RylanSchaeffer, вы можете создать новый вопрос и предоставить более подробную информацию. Это также даст другим возможность помочь вам.
Хуберт Гжесковяк,
Я сделал. Часто вопрос - это более быстрый способ найти ответ, потому что мой вопрос увидит как минимум один знающий человек
Райлан Шеффер,
27

Для тех, кто хочет получить супер-простой ответ: просто установите желаемый уровень отображения. Вверху всех своих скриптов я просто поставил:

import logging
logging.basicConfig(level = logging.INFO)

Затем, чтобы отобразить что-либо на этом уровне или выше:

logging.info("Hi you just set your fleeb to level plumbus")

Это иерархический набор из пяти уровней, поэтому журналы будут отображаться на установленном вами уровне или выше . Поэтому, если вы хотите отобразить ошибку, вы можете использовать logging.error("The plumbus is broken").

Уровни, в порядке возрастания степени тяжести, являются DEBUG, INFO, WARNING, ERRORи CRITICAL. По умолчанию установлено WARNING.

Это хорошая статья, в которой эта информация выражена лучше, чем мой ответ:
https://www.digitalocean.com/community/tutorials/how-to-use-logging-in-python-3

Эрик
источник
14

Может попробовать это? Кажется, проблема решена после удаления всех обработчиков в моем случае.

for handler in logging.root.handlers[:]:
    logging.root.removeHandler(handler)

logging.basicConfig(filename='output.log', level=logging.INFO)
Юэ дон
источник
SyntaxError: invalid syntax
Эрик
2
Зачем это нужно? Какие обработчики идут в комплекте с Python logger и зачем они нужны? Или, может быть, вопрос в том, почему basicConfig не отменяет / не заменяет их?
jrh