Python: настраиваемая регистрация во всех модулях
задача
У меня есть коллекция сценариев, и яМне бы хотелось, чтобы они создавали унифицированные сообщения регистрации с минимальными изменениями в модулях, выполняющих запись реальных сообщений.
мы написали небольшой модульcustom_logger» который я планирую вызвать из основного приложения один раз, пусть он вернет логгер, который яЗатем продолжите использование.
Подмодули I 'импортировать в приложение следует только (точнее, я бы этого хотел)
должен толькоимпортировать логи как логи - так что ничего конкретного для моего сайта не требуется, чтобы заставить их просто работать, если кто-то считает их полезными.должен просто регистрировать сообщения с log.info/error ('сообщение') не добавляя к ним ничего специфичного для сайтаследует использовать уже настроенныйкорень» регистратор со всеми его форматированием и обработчиками и не влияет на корневой регистраторконфигурация с* Custom_logger.py *
import logging
import logging.handlers
import os
import sys
def getLogger(name='root', loglevel='INFO'):
logger = logging.getLogger(name)
# if logger 'name' already exists, return it to avoid logging duplicate
# messages by attaching multiple handlers of the same type
if logger.handlers:
return logger
# if logger 'name' does not already exist, create it and attach handlers
else:
# set logLevel to loglevel or to INFO if requested level is incorrect
loglevel = getattr(logging, loglevel.upper(), logging.INFO)
logger.setLevel(loglevel)
fmt = '%(asctime)s %(filename)-18s %(levelname)-8s: %(message)s'
fmt_date = '%Y-%m-%dT%T%Z'
formatter = logging.Formatter(fmt, fmt_date)
handler = logging.StreamHandler()
handler.setFormatter(formatter)
logger.addHandler(handler)
if logger.name == 'root':
logger.warning('Running: %s %s',
os.path.basename(sys.argv[0]),
' '.join(sys.argv[1:]))
return logger
Затем идет субмодуль, в котором есть несколько тестовых сообщений с примерами того, что работает, а что нет.т.
submodule.py
import sys
import custom_logger
import logging
class SubClass(object):
def __init__(self):
# NOK (no idea why since by default (no name parameter), it should return the root logger)
#log = logging.getLogger()
#log.info('message from SubClass / __init__')
# OK (works as expected)
#log = logging.getLogger('root')
#log.info('message from SubClass / __init__')
# OK (works as expected)
log = custom_logger.getLogger('root')
log.info('message from SubClass / __init__')
def SomeMethod(self):
# OK but I'd have to define `log` for every method, which is unacceptable
# Please see question below all code snippets
log = custom_logger.getLogger('root')
log.info('message from SubClass / SomeMethod')
И главное приложение:app.py Здесь нет ничего особенного:
#!/usr/bin/python
import custom_logger
import submodule
log = custom_logger.getLogger('root', loglevel='DEBUG')
log.debug('debug message')
log.info('info message')
log.warning('warning message')
log.error('error message')
a = submodule.SubClass() # this should produce a log message
a.SomeMethod() # so should this
Вывод что ям после и что яЯ получаю, просто очень уродливо:
% ./app.py
2013-04-08T03:07:46BST custom_logger.py WARNING : Running: app.py
2013-04-08T03:07:46BST app.py DEBUG : debug message
2013-04-08T03:07:46BST app.py INFO : info message
2013-04-08T03:07:46BST app.py WARNING : warning message
2013-04-08T03:07:46BST app.py ERROR : error message
2013-04-08T03:07:46BST submodule.py INFO : message from SubClass / __init__
2013-04-08T03:07:46BST submodule.py INFO : message from SubClass / SomeMethod
Я хочу иметь возможность определить регистратор в app.py, а затем в подмодулях использовать только стандартную библиотеку журналов Python, чтобы использовать уже настроенный регистратор в app.py.
Кроме того, уродливый обходной путь: если я помещу приведенный ниже код после импорта в submodule.py:
log = custom_logger.getLogger('root')
он будет выполнен до того, как мой регистратор будет настроен в app.py, что сделает субмодуль эффективным, а не запись моего приложения в конфигурацию.
Другой обходной путь, который я рассмотрел: в конструкторе класса SubClass я мог бы определить
self.log = custom_logger.getLogger('root')
а затем используйте self.log.error ('какая-то ошибка). Должен быть более хороший способ - если вы можете предложить что-то полезное или указать, где я неправильно понял документацию, яБуду очень признателен!
PS. Я'Мы потратили немало времени, читая Howto по регистрации в Python (базовый и расширенный) и кулинарную книгу, так что если ямы пропустили что-то полезное там, пожалуйста, укажите это.
Спасибо!