python将logging模块封装成单独模块并实现动态切换Level方式
查找了很多资料,但网上给出的教程都是大同小异的,而我想将代码进一步精简,解耦,想实现如下两个目标
1.将logging模块的初始化,配置,设置等代码封装到一个模块中;
2.能根据配置切换logging.level,网上给出的教程都是写死的,如果我在线上之前使用了logging.info(msg),现在想切换为logging.debug(msg)怎么办?需要能够根据配置文件中的设置配置logging.level
两个文件:
logging_class:将logging模块的初始化,配置,设置等代码封装到一此模块中,读取配置文件中对于log等级的设置项;需要使用log功能的模块import这个模块
applogconfig.ini:配置文件
logging_class:
importlogging importsys importConfigParser deflog_building(log_file): try: #setformat format_str=logging.Formatter("%(asctime)s%(filename)s[line:%(lineno)d]%(levelname)s%(message)s") #createstanderoutputhandler crit_hand=logging.StreamHandler(sys.stderr) crit_hand.setFormatter(format_str) #createfilehandler file_hand=logging.FileHandler(log_file,'a') file_hand.setFormatter(format_str) app_log=logging.getLogger(__name__) app_log.addHandler(crit_hand) app_log.addHandler(file_hand) #必须设置,否则无法输出 app_log.setLevel(logging.NOTSET) returnapp_log exceptExceptionase: logging.shutdown() raisee defconfig_file_get(fpath): try: cnf_dict={} cfg=ConfigParser.SafeConfigParser() cfg.read(fpath) forsectionincfg.sections(): #将ini中的item组合到字典中,key=section+_option foritemincfg.items(section): key=section+'_'+item[0] value=item[1] ifcnf_dict.get(key,None)==None: cnf_dict[key]=value returncnf_dict exceptExceptionase: raisee deflog_level_get(level): DEBUG_LEVEL={'CRITICAL':logging.CRITICAL,'ERROR':logging.ERROR,'WARNING':logging.WARNING, 'INFO':logging.INFO,'DEBUG':logging.DEBUG } try: returnDEBUG_LEVEL.get(level.upper()) exceptExceptionase: raisee
applogconfig.ini内容:
[log] log_level=ERROR dir=log
以下为unittest内容:
importunittest importlogging_class importos importlogging classTest(unittest.TestCase): cfg={} defsetUp(self): print'testbegin' self.cfg={} deftearDown(self): print'testend' deftestlog_level_get(self): currentWorkingPath=r'E:\Myworkspace\python\logging_module\logging_module' ini_file=os.path.normpath(os.path.abspath(os.path.join(currentWorkingPath,'applogconfig.ini'))) self.cfg=logging_class.config_file_get(ini_file) self.assertEqual(self.cfg['log_log_level'].upper(),'ERROR','OK') deftestlog_level_set(self): currentWorkingPath=r'E:\Myworkspace\python\logging_module\logging_module' ini_file=os.path.normpath(os.path.abspath(os.path.join(currentWorkingPath,'applogconfig.ini'))) self.cfg=logging_class.config_file_get(ini_file) #printself.cfg['log_log_level'] self.assertEqual(logging_class.log_level_get(self.cfg['log_log_level']),logging.ERROR,'OK') deftestlog_building(self): currentWorkingPath=r'E:\Myworkspace\python\logging_module\logging_module' ini_file=os.path.normpath(os.path.abspath(os.path.join(currentWorkingPath,'applogconfig.ini'))) log_file=os.path.normpath(os.path.abspath(os.path.join(currentWorkingPath,'b.log'))) self.cfg=logging_class.config_file_get(ini_file) #printself.cfg['log_log_level'] level=logging_class.log_level_get(self.cfg['log_log_level']) log=logging_class.log_building(log_file) log.log(level,'dddds') log.debug('msg') if__name__=="__main__": #importsys;sys.argv=['','Test.testName'] unittest.main()
输出:
Findingfiles...done. Importingtestmodules...done. testbegin testend testbegin testend testbegin 2016-12-1517:59:04,059logging_module_test.py[line:48]ERRORdddds testend ---------------------------------------------------------------------- Ran3testsin0.004s
补充知识:一种logging封装方法,不会产生重复log
在调试logging的封装的时候,发现已经调用了logging封装的函数,在被其它函数再调用时,会出现重复的logging。原因是不同的地方创建了不同的handler,所以会重复,可以使用暴力方法解决
暴力方式就是每次创建新的对象就清空logger.handlers
我常用的封装如下
importlogging importtime,os ''' 使用方法: importmylog log=mylog.Log().getlog() log.debug("###") ''' classLog(): def__init__(self,logger="mylog"): self.logger=logging.getLogger(logger) self.logger.setLevel(logging.DEBUG) self.log_time="\\"+time.strftime("%Y-%m-%d_%H_%M",time.localtime())+".log" #在进程路径创建log文件夹 #self.log_path=os.path.join(os.getcwd()+"\\log") #固定在mylog上一级创建 self.log_path=os.path.join(os.path.dirname(os.path.dirname(__file__))+"\\log") ifos.path.exists(self.log_path)andos.path.isdir(self.log_path): pass else: os.makedirs(self.log_path) self.log_name=os.path.join(self.log_path+self.log_time) #因为多出调用logger会生成多个handlers,所以每次调用清空handler self.logger.handlers=[] fh=logging.FileHandler(self.log_name,'a',encoding='utf-8') formatter=logging.Formatter('[%(levelname)s][%(asctime)s][%(filename)s]->[%(funcName)s]line:%(lineno)d--->%(message)s') fh.setLevel(logging.DEBUG) fh.setFormatter(formatter) self.logger.addHandler(fh) ch=logging.StreamHandler() ch.setLevel(logging.DEBUG) ch.setFormatter(formatter) self.logger.addHandler(ch) fh.close() defgetlog(self): returnself.logger if__name__=="__main__": log=Log().getlog() log.debug("hello")
以上这篇python将logging模块封装成单独模块并实现动态切换Level方式就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持毛票票。