Подтвердить что ты не робот

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 способ обработки конфигурации регистратора, как это?

4b9b3361

Ответ 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 как один из его методов.