Журналювання 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кореневий реєстратор повинен виводити повідомлення. Чому моя програма нічого не видає, і як я можу це виправити?

Відповіді:


103

Рівень реєстрації за замовчуванням - попередження. Оскільки ви не змінили рівень, рівень кореневого реєстратора все ще попереджає. Це означає, що він буде ігнорувати будь-які журнали з рівнем нижче рівня попередження, включаючи реєстрацію налагодження.

Це пояснюється у підручнику :

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

Рядок "інформація" нічого не друкує, оскільки рівень вищий, ніж інформація.

Щоб змінити рівень, просто встановіть його в кореневому журналі:

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

Іншими словами, недостатньо визначити обробник з level = DEBUG, фактичний рівень реєстрації також повинен бути DEBUG, щоб змусити його щось вивести.


7
У документації сказано, що за замовчуванням це рівень NOTSET - рівень 0, який повинен видавати все ... Чому це не так?
Бен

@Ben, де це написано? Я бачу лише "Рівень за замовчуванням - ПОПЕРЕДЖЕННЯ, що означає, що будуть відстежуватися лише події цього рівня та вище, якщо тільки пакет реєстрації не налаштований на інше".
Омрі Барель


1
@Ben згідно з документами, що обходять реєстратори, щоб знайти першого батька з level != NOTSETабо коренем (якщо жодного не знайдено). Корінь має WARNINGрівень за замовчуванням. Це написано в розділі, до якого ви пов’язали ( Logger.setLevel).
Омрі Барель

5
Майте на увазі, що після імпорту loggingвам потрібно зателефонувати logging.basicConfig()хоча б раз. Інакше ви можете бути сильно здивовані тим, що дочірні лісоруби нічого не надрукують. Функції реєстрації в кореневому реєстраторі називають це ліниво.
Губерт zesжесковяк

72

Багато років потому, схоже, проблема реєстрації 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, можливо, ти захочеш створити нове запитання та надати детальну інформацію. Це також дасть шанс іншим допомогти вам.
Губерт zesжесковяк,

Я зробив. Часто задавати коментар - це швидший спосіб знайти відповідь, оскільки принаймні одна обізнана людина побачить моє запитання
Райлан Шеффер,

26

Для всіх, хто хоче отримати надзвичайно просту відповідь: просто встановіть рівень, який потрібно відображати. У верхній частині всіх своїх сценаріїв я просто помістив:

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 і чому вони там для початку? Або, можливо, питання в тому, чому basicConfig не замінює їх / не замінює?
jrh
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.