Python - Избегать прохождения ссылки на регистратор между функциями?
У меня есть простой Python script, который использует встроенный logging
.
Я настраиваю ведение журнала внутри функции. Основная структура будет примерно такой:
#!/usr/bin/env python
import logging
import ...
def configure_logging():
logger = logging.getLogger("my logger")
logger.setLevel(logging.DEBUG)
# Format for our loglines
formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")
# Setup console logging
ch = logging.StreamHandler()
ch.setLevel(logging.DEBUG)
ch.setFormatter(formatter)
logger.addHandler(ch)
# Setup file logging as well
fh = logging.FileHandler(LOG_FILENAME)
fh.setLevel(logging.DEBUG)
fh.setFormatter(formatter)
logger.addHandler(fh)
return logger
def count_parrots():
...
logger.debug??
if __name__ == '__main__':
logger = configure_logging()
logger.debug("I'm a log file")
parrots = count_parrots()
Я могу нормально записывать логгер внутри __main__
. Однако как я могу вызвать регистратор из функции count_parrots()? Какой самый pythonic способ обработки конфигурации регистратора, как это?
Ответы
Ответ 1
Вы можете использовать корневой (по умолчанию) регистратор, и, таким образом, функции уровня модуля logging.debug
,... или получить ваш регистратор в функции, используя его.
Действительно, функция getLogger
представляет собой factory -подобную функцию с реестром (singleton like), т.е. Всегда возвращает тот же экземпляр для данного имени регистратора.
Таким образом, вы можете получить свой регистратор в count_parrots, просто используя
logger = logging.getLogger("my logger")
в начале. Тем не менее, соглашение заключается в использовании точечного иерархического имени для вашего регистратора. См. http://docs.python.org/library/logging.html#logging.getLogger
EDIT:
Вы можете использовать декоратор, чтобы добавить поведение ведения журнала к вашим индивидуальным функциям, например:
def debug(loggername):
logger = logging.getLogger(loggername)
def log_(enter_message, exit_message=None):
def wrapper(f):
def wrapped(*args, **kargs):
logger.debug(enter_message)
r = f(*args, **kargs)
if exit_message:
logger.debug(exit_message)
return r
return wrapped
return wrapper
return log_
my_debug = debug('my.logger')
@my_debug('enter foo', 'exit foo')
def foo(a, b):
return a+b
вы можете "жестко закодировать" имя регистратора и удалить закрытие верхнего уровня и my_debug.
Ответ 2
Вы можете просто сделать:
logger = logging.getLogger("my logger")
в вашем методе count_parrots()
. Когда вы передаете имя, которое использовалось ранее (т.е. "Мой журнал" ), модуль регистрации вернет тот же экземпляр, который был создан, соответствующий этому имени.
Обновление: из ведения журнала
(Эрдвайс мой)
getLogger() возвращает ссылку на экземпляра журнала с указанным имя, если оно предоставлено, или root, если не. Имена разделены по периодам иерархических структур. <Б > Multiple вызовы getLogger() с тем же имя вернет ссылку на тот же объект журнала.
Ответ 3
Типичным способом обработки журнала является наличие логатора на каждом модуле, хранящегося в глобальной переменной. Любые функции и методы внутри этого модуля затем ссылаются только на тот же экземпляр журнала.
Это кратко обсуждается во вступлении к учебному руководству по продвижению в документации:
http://docs.python.org/howto/logging.html#advanced-logging-tutorial
Вы можете передавать экземпляры журнала в качестве параметров, но это обычно редко.
Ответ 4
Я запутался в том, как глобальные переменные работают в Python. Внутри функции вам нужно объявить global logger
, если вы делаете что-то вроде logger = logging.getLogger("my logger")
и надеетесь изменить глобальный logger
.
Итак, чтобы изменить ваш пример, вы можете создать глобальный объект журнала в начале файла. Если ваш модуль может быть импортирован другим, вы должны добавить NullHandler
, чтобы, если импортер библиотеки не хочет, чтобы регистрация была включена, у них нет никаких проблем с вашей lib (ref).
#!/usr/bin/env python
import logging
import ...
logger = logging.getLogger("my logger").addHandler(logging.NullHandler())
def configure_logging():
logger.setLevel(logging.DEBUG)
# Format for our loglines
formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")
# Setup console logging
ch = logging.StreamHandler()
ch.setLevel(logging.DEBUG)
ch.setFormatter(formatter)
logger.addHandler(ch)
# Setup file logging as well
fh = logging.FileHandler(LOG_FILENAME)
fh.setLevel(logging.DEBUG)
fh.setFormatter(formatter)
logger.addHandler(fh)
def count_parrots():
...
logger.debug('counting parrots')
...
return parrots
if __name__ == '__main__':
configure_logging()
logger.debug("I'm a log file")
parrots = count_parrots()
Ответ 5
Вы можете дать logger
в качестве аргумента для count_parrots()
Или, что бы я сделал, создайте попугаев классов и используем logger как один из его методов.