Ведение журнала Python: почему init вызывается дважды?
я пытаюсь использовать ведение журнала python с конфигурационным файлом и собственным обработчиком. В какой-то степени это работает. Что действительно озадачивает меня __init__
вызывается дважды и __del__
вызывается один раз. Когда я удаляю весь файл конфигурации и создаю обработчик непосредственно в коде __init__
вызывается один раз а __del__
никогда не вызывается.
мои вопросы:
- почему
__init__
вызывается дважды? - почему
__del__
вызывается реже, чем__init__
?
код:
#!/bin/env python
import logging
import logging.handlers
import logging.config
class Test1TimedRotatingFileHandler(logging.handlers.TimedRotatingFileHandler):
def __init__(self,filename):
print "init called"
logging.handlers.TimedRotatingFileHandler.__init__(self,filename, when='S', interval=86400, backupCount=8, encoding=None)
def __del__(self):
print "del called"
if hasattr(logging.handlers.TimedRotatingFileHandler,"__del__"):
logging.handlers.TimedRotatingFileHandler.__del__(self)
logging.config.fileConfig('/root/test1.conf')
logger = logging.getLogger("test1")
конфигурационный файл:
[formatters]
keys: simple
[handlers]
keys: file
[loggers]
keys: root
[formatter_simple]
format: "%(message)s"
[handler_file]
class: test1.Test1TimedRotatingFileHandler
args: ("/root/test1.log",)
level=INFO
[logger_root]
level: INFO
handlers: file
qualname: test1
вывод выглядит следующим образом:
init called
init called
del called
использование отладчика для получения трассировки стека, как предложено Sentinal, показывает это:
первый звонок:
> /root/test1.py(12)__init__()
-> print "init called"
(Pdb) where
/root/test1.py(21)<module>()
-> logging.config.fileConfig('/root/test1.conf')
/usr/local/python/2.6.4/lib/python2.6/logging/config.py(84)fileConfig()
-> handlers = _install_handlers(cp, formatters)
/usr/local/python/2.6.4/lib/python2.6/logging/config.py(156)_install_handlers()
-> klass = _resolve(klass)
/usr/local/python/2.6.4/lib/python2.6/logging/config.py(94)_resolve()
-> found = __import__(used)
/root/test1.py(21)<module>()
-> logging.config.fileConfig('/root/test1.conf')
/usr/local/python/2.6.4/lib/python2.6/logging/config.py(84)fileConfig()
-> handlers = _install_handlers(cp, formatters)
/usr/local/python/2.6.4/lib/python2.6/logging/config.py(159)_install_handlers()
-> h = klass(*args)
> /root/test1.py(12)__init__()
-> print "init called"
(Pdb) c
init called
второй звонок:
> /root/test1.py(12)__init__()
-> print "init called"
(Pdb) w
/root/test1.py(21)<module>()
-> logging.config.fileConfig('/root/test1.conf')
/usr/local/python/2.6.4/lib/python2.6/logging/config.py(84)fileConfig()
-> handlers = _install_handlers(cp, formatters)
/usr/local/python/2.6.4/lib/python2.6/logging/config.py(159)_install_handlers()
-> h = klass(*args)
> /root/test1.py(12)__init__()
-> print "init called"
2 ответов
- почему init вызывается дважды?
если следовать коду logging
module, вы увидите, что при загрузке файла конфигурации журнала он создает экземпляры всех обработчиков (первый экземпляр).
в вашем коде вы объявляете свой обработчик как test1.Test1TimedRotatingFileHandler
, поэтому при попытке импортировать обработчик он анализирует код в модуле test1... так он воссоздает обработчик !!
исправленный код будет охранять используя __name__ == '__main__'
:
#!/bin/env python
import logging
import logging.handlers
import logging.config
class Test1TimedRotatingFileHandler(logging.handlers.TimedRotatingFileHandler):
def __init__(self,filename):
print "init called"
logging.handlers.TimedRotatingFileHandler.__init__(self,filename, when='S', interval=86400, backupCount=8, encoding=None)
def __del__(self):
print "del called"
if hasattr(logging.handlers.TimedRotatingFileHandler,"__del__"):
logging.handlers.TimedRotatingFileHandler.__del__(self)
if __name__ == "__main__":
logging.config.fileConfig('./test1.conf')
logger = logging.getLogger("test1")
2 . Почему del называют реже, чем init?
в общем,__del__
оператор вызывается, когда-python-хочет, точнее, он вызывается, когда сборщик мусора решает мусор-собрать объект; это не обязательно сразу после его выпуска.
вам не хватает if __name__ == "__main__":
защитите свой код конфигурации регистрации. Он выполняется во второй раз, когда logging
импортирует test1
модуль для поиска ссылки на класс.
в качестве альтернативы используйте имя __main__.Test1TimedRotatingFileHandler
в конфигурационном файле или же поместите код конфигурации и класс обработчика в разные файлы.