Python日志记录:为什么__init__被调用两次?

时间:2011-05-17 14:08:55

标签: python logging handler config init

我正在尝试使用配置文件和自己的处理程序进行python日志记录。这在某种程度上起作用。让我感到困惑的是__init__被调用两次而__del__被调用一次。当我删除整个配置文件并在代码__init__内直接创建处理程序时,调用一次,__del__永远不会被调用。

我的问题:

  1. 为什么__init__被调用两次?
  2. 为什么__del__的调用频率低于__init__
  3. 代码:

    #!/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 个答案:

答案 0 :(得分:12)

  
      
  1. 为什么init被调用两次?
  2.   

如果您遵循logging模块的代码,您将看到当您加载日志记录配置文件时,它会实例化所有处理程序(第一次实例化)。

在你的代码中,你将你的处理程序声明为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更少被调用?

通常,在-python-want时调用__del__运算符,更确切地说,当垃圾收集器决定垃圾收集对象时调用它;这不一定就在你发布之后。

答案 1 :(得分:5)

您在日志记录配置代码中缺少if __name__ == "__main__":警卫。当logging导入test1模块以查找类引用时,它将再次执行。

或者,在配置文件中使用名称__main__.Test1TimedRotatingFileHandler,或者将配置代码和处理程序类放在不同的文件中。