解决python logging遇到的坑 日志重复打印问题
python中logging模块假如遇到多线程或者多进程或者在web框架中自定义logging的话(一个请求就是一个独立的线程)非常容易重复打印日志和造成内存崩溃,所以:
解决方法如下:
重写日志方法用类:
classLog(): importlogging def__init__(self): self.logger=logging.getLogger(__name__) #以下三行为清空上次文件 #这为清空当前文件的logging因为logging会包含所有的文件的logging logging.Logger.manager.loggerDict.pop(__name__) #将当前文件的handlers清空 self.logger.handlers=[] #然后再次移除当前文件logging配置 self.logger.removeHandler(self.logger.handlers) #这里进行判断,如果logger.handlers列表为空,则添加,否则,直接去写日志 ifnotself.logger.handlers: #loggger文件配置路径 self.handler=logging.FileHandler(os.getcwd()+'/logger/%s_log/%s_score.log'%(str(dt.date.today()),str(dt.date.today()))) #logger配置等级 self.logger.setLevel(logging.DEBUG) #logger输出格式 formatter=logging.Formatter('%(asctime)s-%(levelname)s-%(name)s-%(message)s') #添加输出格式进入handler self.handler.setFormatter(formatter) #添加文件设置金如handler self.logger.addHandler(self.handler) #以下皆为重写方法并且每次记录后清除logger definfo(self,message=None): self.__init__() self.logger.info(message) self.logger.removeHandler(self.logger.handlers) defdebug(self,message=None): self.__init__() self.logger.debug(message) self.logger.removeHandler(self.logger.handlers) defwarning(self,message=None): self.__init__() self.logger.warning(message) self.logger.removeHandler(self.logger.handlers) deferror(self,message=None): self.__init__() self.logger.error(message) self.logger.removeHandler(self.logger.handlers) defcritical(self,message=None): self.__init__() self.logger.critical(message) self.logger.removeHandler(self.logger.handlers)
亲测有效!
另外模块尤其注意例如web请求的时候在接口处调用然后引导传参千万别做全局变量
补充:python中多个文件共用logger,重复打印问题的解决方案
问题背景&现象
最近在项目中,需要用python的logging库来将日志打印到文件中,然后将python脚本放到crontab中执行。所以写了一个logger的简单封装。
如下:
#!/usr/bin/python #-*-coding:utf-8-*- importlogging importtime importos classLog(object): ''' 封装后的logging ''' def__init__(self,logger=None,log_cate='search'): ''' 指定保存日志的文件路径,日志级别,以及调用文件 将日志存入到指定的文件中 ''' #创建一个logger self.logger=logging.getLogger(logger) self.logger.setLevel(logging.DEBUG) #创建一个handler,用于写入日志文件 self.log_time=time.strftime("%Y_%m_%d") file_dir=os.getcwd()+'/../log' ifnotos.path.exists(file_dir): os.mkdir(file_dir) self.log_path=file_dir self.log_name=self.log_path+"/"+log_cate+"."+self.log_time+'.log' #print(self.log_name) fh=logging.FileHandler(self.log_name,'a')#追加模式这个是python2的 #fh=logging.FileHandler(self.log_name,'a',encoding='utf-8')#这个是python3的 fh.setLevel(logging.INFO) #再创建一个handler,用于输出到控制台 ch=logging.StreamHandler() ch.setLevel(logging.INFO) #定义handler的输出格式 formatter=logging.Formatter( '[%(asctime)s]%(filename)s->%(funcName)sline:%(lineno)d[%(levelname)s]%(message)s') fh.setFormatter(formatter) ch.setFormatter(formatter) #给logger添加handler self.logger.addHandler(fh) self.logger.addHandler(ch) #添加下面一句,在记录日志之后移除句柄 #self.logger.removeHandler(ch) #self.logger.removeHandler(fh) #关闭打开的文件 fh.close() ch.close() defgetlog(self): returnself.logger
目的是让所有用到logger的地方,只import这个封装库就行,然后直接调用。比如调用logger的
a.py
#!/usr/bin/python #-*-coding:utf-8-*- fromcommon.logimportLog log=Log().getlog() log.info("Iama.py")
b.py
#!/usr/bin/python #-*-coding:utf-8-*- fromcommon.logimportLog log=Log().getlog() log.info("Iamb.py")
c.py
#!/usr/bin/python #-*-coding:utf-8-*- importa importb fromcommon.logimportLog log=Log().getlog() log.info("Iamc.py")
此时执行c.py的结果如下:
➜searchgit:(master)✗pythonc.py
[2019-01-1415:58:35,807]a.py->
line:6[INFO]Iama.py [2019-01-1415:58:35,808]b.py->
line:6[INFO]Iamb.py [2019-01-1415:58:35,808]b.py->
line:6[INFO]Iamb.py [2019-01-1415:58:35,809]c.py->
line:8[INFO]Iamc.py [2019-01-1415:58:35,809]c.py->
line:8[INFO]Iamc.py [2019-01-1415:58:35,809]c.py->
line:8[INFO]Iamc.py
可见,a.py,b.py,c.py的logger共用了,出现了重复打印。
问题原因分析
从现象可以得出,不同文件间的log系统是相互影响的,在a.py,b.py,c.py中,我们的调用方式是log=Log().getlog(),即self.logger=logging.getLogger(logger),logger参数并未传递,所以得到的self.logger是RootLogger。
RootLogger是一个python程序内全局唯一的,所有Logger对象的祖先。所以我们对RootLogger的设定,自然会影响到所有的日志输出。简言之,就是先打开的文件中对log的设置,后打开的文件都会受到影响,都会走一遍logger的继承关系。在这个示例中,b.py在a.py之后被import,所以b.py会执行一次自己的logger,再执行一次a.py中打开的RootLogger,以此类推.........
问题解决方式
不用默认的RootLogger,给每个Logger都加个名字。
a.py
fromcommon.logimportLog log=Log(__name__).getlog() log.info("Iama.py")
b.py
fromcommon.logimportLog log=Log(__name__).getlog() log.info("Iamb.py")
c.py
importb importa fromcommon.logimportLog log=Log(__name__).getlog() log.info("Iamc.py")
c.py的最新执行结果:
➜searchgit:(master)✗pythonc.py
[2019-01-1416:24:12,008]b.py->
line:6[INFO]Iamb.py [2019-01-1416:24:12,009]a.py->
line:6[INFO]Iama.py [2019-01-1416:24:12,009]c.py->
line:10[INFO]Iamc.py
没有重复了,符合预期。问题得以解决。
以上为个人经验,希望能给大家一个参考,也希望大家多多支持毛票票。如有错误或未考虑完全的地方,望不吝赐教。
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。