В чем смысл setLevel в обработчике каротажа python?
Скажем, у меня есть следующий код:
import logging
import logging.handlers
a = logging.getLogger('myapp')
h = logging.handlers.RotatingFileHandler('foo.log')
h.setLevel(logging.DEBUG)
a.addHandler(h)
# The effective log level is still logging.WARN
print a.getEffectiveLevel()
a.debug('foo message')
a.warn('warning message')
Я ожидаю, что установка logging.DEBUG
на обработчике заставит сообщения отладочного уровня быть записаны в файл журнала. Тем не менее, это печатает 30 для эффективного уровня (равный logging.WARNING
, по умолчанию) и только регистрирует сообщение warn
в файле журнала, а не отладочное сообщение.
Похоже, что уровень журнала обработчика падает на пол, например. он молча игнорируется. Что заставляет меня задаться вопросом, почему вообще есть setLevel
на обработчике?
Ответы
Ответ 1
Это позволяет более тонкое управление. По умолчанию у корневого регистратора установлен уровень WARNING
, это означает, что он не печатает сообщения с более низким уровнем (независимо от того, как устанавливаются уровни обработчиков!). Но если вы установите уровень корневого регистратора на DEBUG
, действительно сообщение отправляется в файл журнала:
import logging
import logging.handlers
a = logging.getLogger('myapp')
a.setLevel(logging.DEBUG) # set root level
h = logging.handlers.RotatingFileHandler('foo.log')
h.setLevel(logging.DEBUG)
a.addHandler(h)
print a.getEffectiveLevel()
a.debug('foo message')
a.warn('warning message')
Теперь изображение, которое вы хотите добавить нового обработчика, который не записывает информацию об отладке.
Вы можете сделать это, просто установив уровень ведения журнала обработчика:
import logging
import logging.handlers
a = logging.getLogger('myapp')
a.setLevel(logging.DEBUG) # set root level
h = logging.handlers.RotatingFileHandler('foo.log')
h.setLevel(logging.DEBUG)
a.addHandler(h)
h2 = logging.handlers.RotatingFileHandler('foo2.log')
h2.setLevel(logging.WARNING)
a.addHandler(h2)
print a.getEffectiveLevel()
a.debug('foo message')
a.warn('warning message')
Теперь файл журнала foo.log
будет содержать оба сообщения, а файл foo2.log
будет содержать только предупреждающее сообщение. Вам может быть интересно иметь файл журнала только сообщений об ошибках, а затем просто добавить Handler
и установить его уровень на logging.ERROR
, используя все те же Logger
.
Вы можете думать о уровне ведения журнала Logger
в качестве глобального ограничения на то, что сообщения "интересны" для данного регистратора и его обработчиков. После этого сообщения, которые затем регистрируются регистратором, отправляются обработчикам, которые выполняют собственный процесс фильтрации и регистрации.
Ответ 2
В протоколе Python существует два разных понятия: уровень, на который регистрируется журнал регистрации, и уровень, на который фактически активируется обработчик.
Когда выполняется вызов журнала, то, что в основном происходит, является:
if self.level <= loglevel:
for handler in self.handlers:
handler(loglevel, message)
Пока каждый из этих обработчиков вызовет:
if self.level <= loglevel:
# do something spiffy with the log!
Если вы хотите продемонстрировать это в реальном мире, вы можете посмотреть настройки настроек Django. Здесь я укажу соответствующий код.
LOGGING = {
#snip
'handlers': {
'null': {
'level': 'DEBUG',
'class': 'logging.NullHandler',
},
'console':{
'level': 'DEBUG',
'class': 'logging.StreamHandler',
'formatter': 'simple'
},
'mail_admins': {
'level': 'ERROR',
'class': 'django.utils.log.AdminEmailHandler',
'filters': ['special']
}
},
'loggers': {
#snip
'myproject.custom': {
# notice how there are two handlers here!
'handlers': ['console', 'mail_admins'],
'level': 'INFO',
'filters': ['special']
}
}
}
Итак, в приведенной выше конфигурации только журналы с getLogger('myproject.custom').info
и выше будут обработаны для ведения журнала. Когда это произойдет, консоль выведет все результаты (она выведет все, потому что она установлена на уровень DEBUG
), а журнал mail_admins
будет выполняться для всех ERROR
s, FATAL
и CRITICAL
с.
Я полагаю, что некоторый код, который не является Django, тоже может помочь:
import logging.handlers as hand
import logging as logging
# to make things easier, we'll name all of the logs by the levels
fatal = logging.getLogger('fatal')
warning = logging.getLogger('warning')
info = logging.getLogger('info')
fatal.setLevel(logging.FATAL)
warning.setLevel(logging.WARNING)
info.setLevel(logging.INFO)
fileHandler = hand.RotatingFileHandler('rotating.log')
# notice all three are re-using the same handler.
fatal.addHandler(fileHandler)
warning.addHandler(fileHandler)
info.addHandler(fileHandler)
# the handler should log everything except logging.NOTSET
fileHandler.setLevel(logging.DEBUG)
for logger in [fatal,warning,info]:
for level in ['debug','info','warning','error','fatal']:
method = getattr(logger,level)
method("Debug " + logger.name + " = " + level)
# now, the handler will only do anything for *fatal* messages...
fileHandler.setLevel(logging.FATAL)
for logger in [fatal,warning,info]:
for level in ['debug','info','warning','error','fatal']:
method = getattr(logger,level)
method("Fatal " + logger.name + " = " + level)
Это приводит к:
Debug fatal = fatal
Debug warning = warning
Debug warning = error
Debug warning = fatal
Debug info = info
Debug info = warning
Debug info = error
Debug info = fatal
Fatal fatal = fatal
Fatal warning = fatal
Fatal info = fatal
Снова обратите внимание, как info
записал что-то в info
, warning
, ERROR
и FATAL
, когда обработчик журнала был установлен в DEBUG
, но когда обработчик был установлен в FATAL
внезапно только сообщения FATAL
внесли его в файл.
Ответ 3
Обработчики представляют разные аудитории для регистрации событий. Уровни на обработчиках используются для контроля многословности вывода, видимого определенной аудиторией, и действуют в дополнение к любым уровням, установленным на регистраторах. Уровни на регистраторах используются для управления общей детализацией ведения журнала из разных частей приложения или библиотеки.
Подробнее о том, как обрабатываются события регистрации, см. эту диаграмму:
![введите описание изображения здесь]()