python日志记录模块实例及改进
python打印对象的所有属性值:
defprn_obj(obj): print'\n'.join(['%s:%s'%itemforiteminobj.__dict__.items()])
Pythonlogger对象属性(由上述函数获取的)
name:get_data parent:<logging.RootLoggerinstanceat0x1d8bd88> handlers:[<logging.FileHandlerinstanceat0x21bcc68>] level:10 disabled:1#当前的logger是否有效,默认为0 manager:<logging.Managerinstanceat0x1d8bea8> propagate:0#是否将本级日志 filters:[]
部分日志无法输出
File:logger.conf
[formatters] keys=default [formatter_default] format=%(asctime)s-%(name)s-%(levelname)s-%(message)s class=logging.Formatter [handlers] keys=console,error_file [handler_console] class=logging.StreamHandler formatter=default args=tuple() [handler_error_file] class=logging.FileHandler level=INFO formatter=default args=("logger.log","a") [loggers] keys=root [logger_root] level=DEBUG formatter=default handlers=console,error_file
File:logger.py
#!/bin/envpython importlogging fromlogging.configimportlogging classTest(object): """docstringforTest""" def__init__(self): logging.config.fileConfig("logger.conf") self.logger=logging.getLogger(__name__) deftest_func(self): self.logger.error('test_funcfunction') classWorker(object): """docstringforWorker""" def__init__(self): logging.config.fileConfig("logger.conf") self.logger=logging.getLogger(__name__) data_logger=logging.getLogger('data') handler=logging.FileHandler('./data.log') fmt=logging.Formatter('%(asctime)s|%(message)s') handler.setFormatter(fmt) data_logger.addHandler(handler) data_logger.setLevel(logging.DEBUG) self.data_logger=data_logger deftest_logger(self): self.data_logger.error("test_loggerfunction") instance=Test() self.data_logger.error("test_loggeroutput") instance.test_func() defmain(): worker=Worker() worker.test_logger() if__name__=='__main__': main()
问题一:测试过程中,只能打印出test_loggerfunction一条语句
问题二:明明只在data_logger中打印出语句,但是logger的日志中也出现了相关的日志。
问题一解决方案:
利用python-mpdblogger.py语句对脚本进行调试发现,在执行instance=Test()语句后,通过print'\n'.join(['%s:%s'%itemforiteminself.data_logger.__dict__.items()])调试语句看到data_logger的disable属性值由0变成了True,此时logger的对应属性也发生了相同的变化。这种变化导致了logger对象停止记录日志。参考python logging模块的相关手册发现“ThefileConfig()functiontakesadefaultparameter,disable_existing_loggers,whichdefaultstoTrueforreasonsofbackwardcompatibility.Thismayormaynotbewhatyouwant,sinceitwillcauseanyloggersexistingbeforethefileConfig()calltobedisabledunlessthey(oranancestor)areexplicitlynamedintheconfiguration.”的说明,即调用fileconfig()函数会将之前存在的所有logger禁用。在python2.7版本该fileConfig()函数添加了一个参数,logging.config.fileConfig(fname,defaults=None,disable_existing_loggers=True),可以显式的将disable_existing_loggers设置为FALSE来避免将原有的logger禁用。将上述代码中的Test类中的logging.config.fileConfig函数改成logging.config.fileConfig("./logger.conf",disable_existing_loggers=0)就可以解决问题。不过该代码中由于位于同一程序内,可以直接用logging.getLogger(LOGGOR_NAME)函数引用同一个logger,不用再调用logging.config.fileConfig函数重新加载一遍了。
问题二解决方案:
logger对象有个属性propagate,如果这个属性为True,就会将要输出的信息推送给该logger的所有上级logger,这些上级logger所对应的handlers就会把接收到的信息打印到关联的日志中。logger.conf配置文件中配置了相关的rootlogger的属性,这个rootlogger就是默认的logger日志。
修改后的如下:
File:logger.conf
[formatters] keys=default,data [formatter_default] format=%(asctime)s-%(name)s-%(levelname)s-%(message)s class=logging.Formatter [formatter_data] format=%(asctime)s|%(message)s class=logging.Formatter [handlers] keys=console,error_file,data_file [handler_console] class=logging.StreamHandler formatter=default args=tuple() [handler_error_file] class=logging.FileHandler level=INFO formatter=default args=("logger.log","a") [handler_data_file] class=logging.FileHandler level=INFO formatter=data args=("data_new.log","a") [loggers] keys=root,data [logger_root] level=DEBUG handlers=console,error_file [logger_data] level=DEBUG handlers=data_file qualname=data propagate=0
File:logger.py
#!/bin/envpython importlogging fromlogging.configimportlogging classTest(object): """docstringforTest""" def__init__(self): self.logger=logging.getLogger(__name__) deftest_func(self): self.logger.error('test_funcfunction') classWorker(object): """docstringforWorker""" def__init__(self): logging.config.fileConfig("logger.conf") self.logger=logging.getLogger(__name__) self.data_logger=logging.getLogger('data') deftest_logger(self): self.data_logger.error("test_loggerfunction") instance=Test() self.data_logger.error("test_loggeroutput") instance.test_func() defmain(): worker=Worker() worker.test_logger() if__name__=='__main__': main()