python 实现logging动态变更输出日志文件名
python作为一门非常容易上手的脚本语言,日志输出更是简单,logging模块,简单的设置配置和属性,就能实现到控制台输出日志,在basicConfig()设置文件名,就能够将日志信息写入文件,简直是简单到不能再简单。
最近在项目中就遇到一个日志问题,使用python编写的服务程序一直运行,连续处理一些任务,每个任务的关键信息都需要输出到文件中,便于维护人员查看,可是对于简单实用logging来说,日志写入文件非常简单,由于服务程序连续运行,一直向一个文件记录日志信息有些不妥,有常识的开发人员都知道,长时间的日志输出会导致日志文件过大,可是如何在服务运行时,修改日志的输出文件,以当天日期作为日志文件名。
代码编写环境:python3.4.3
1.logging.basicConfig()
首先,想到的是更改logging.basicConfig(filename=logfilename)参数,来实现变更日志文件名的目的。编写代码如下:
log_fmt='%(asctime)s%(filename)s[line:%(lineno)d]%(levelname)s%(message)s' foriinrange(1,4): filename=str.format('mylog%d.txt'%i) logging.basicConfig(format=log_fmt,level=logging.DEBUG,filename=filename) logging.debug('Thisisdebugmessage') logging.info('Thisisinfomessage') logging.warning('Thisiswarningmessage')
运行结果没有达到预期的效果,只有日志文件mylog1.txt被创建,mylog2.txt和mylog3.txt都未被创建,连续3次的输出的内容都写入mylog1.txt中。说明logging.basicConfig()设置属性具有全局性,第一次设置之后,之后再设置将不再生效。查看官方文档,也确实是如此。
logging.basicConfig(**kwargs)
DoesbasicconfigurationfortheloggingsystembycreatingaStreamHandlerwithadefaultFormatterandaddingittotherootlogger.Thefunctionsdebug(),info(),warning(),error()andcritical()willcallbasicConfig()automaticallyifnohandlersaredefinedfortherootlogger.
Thisfunctiondoesnothingiftherootloggeralreadyhashandlersconfiguredforit.
此路不通,只好用其他方法。
2.Handler对象
logging支持添加多个不同类型的handler对象,实现对控制台(logging.StreamHandler)、文件(logging.FileHandler)等不同目标输出日志。
logging支持的日志详情见文档logging.handlers
通过增加多个handler对象,可是实现同时在控制台、文件同时输出不同级别的日志信息。
#默认配置logging写入本地文件 logging.basicConfig(level=logging.DEBUG, format='%(asctime)s%(filename)s[line:%(lineno)d]%(levelname)s%(message)s', datefmt='%a,%d%b%Y%H:%M:%S', filename='myapp2.log', filemode='w') #定义一个StreamHandler,将INFO级别或更高的日志信息打印到标准错误,并将其添加到当前的日志处理对象。 console=logging.StreamHandler() console.setLevel(logging.INFO) formatter=logging.Formatter('%(name)-12s:%(levelname)-8s%(message)s') console.setFormatter(formatter) logging.getLogger('').addHandler(console) logging.debug('Thisisdebugmessage') logging.info('Thisisinfomessage') logging.warning('Thisiswarningmessage')
考虑实现简单又能说明效果,写入文件使用logging.basicConfig()设置,并添加输出指向控制台的流处理(StreamHandler)对象console,实现同时输出日志。当然也可以反过来,默认设置控制台输出日志,之后创建文件对象(logging.FileHandler),并加入处理集合,实现同样的效果。
logging.getLogger('')获取的是名为'root'的默认根节点
同时,logging提供addHandler()的方法,自然也会有管理handler的方法。
延伸之前Handler的思路,我们可以实现对handler的动态管理,变更日志文件。每次需要变更输出文件路径前,使用handler管理清空原先的logging.FileHandler对象,重新创建一个新文件名的logging.FileHandler对象即可。
#默认配置logging写入本地文件 logging.basicConfig(level=logging.DEBUG, format='%(asctime)s%(filename)s[line:%(lineno)d]%(levelname)s%(message)s', datefmt='%a,%d%b%Y%H:%M:%S', filename='myapp2.log', filemode='w') #定义一个StreamHandler,将INFO级别或更高的日志信息打印到标准错误,并将其添加到当前的日志处理对象。 console=logging.StreamHandler() console.setLevel(logging.INFO) formatter=logging.Formatter('%(name)-12s:%(levelname)-8s%(message)s') console.setFormatter(formatter) logging.getLogger('').addHandler(console) logging.debug('Thisisdebugmessage') logging.info('Thisisinfomessage') logging.warning('Thisiswarningmessage')
使用for循环执行3次处理,分别创建日志文件名称为mylog1.txt,mylog2.tx,mylog3.txt,并写入相同的内容。执行结果确实产生不同名称的文件,日志内容也正确写入。
至此,已经实现动态变更输出文件日志名称的功能。至于按照日志输出文件名,只需要按照上述代码的思路,将创建logging.FileHandler()的文件名参数变更就能达成目的。
简单实现方案
浏览官方文档logging.handlers一节内容,python考虑到日志的常规使用场景,已经封装更为简单的实现方案,TimedRotatingFileHandler,只需简单的配置,即可实现对输出日志文件的基本管理,灵活易用,代码如下:
importlogging,logging.handlers importtime ''' TimedRotatingFileHandler构造函数声明 classlogging.handlers.TimedRotatingFileHandler(filename,when='h',interval=1,backupCount=0,encoding=None,delay=False,utc=False,atTime=None) filename日志文件名前缀 when日志名变更时间单位 'S'Seconds 'M'Minutes 'H'Hours 'D'Days 'W0'-'W6'Weekday(0=Monday) 'midnight'Rolloveratmidnight interval间隔时间,是指等待N个when单位的时间后,自动重建文件 backupCount保留日志最大文件数,超过限制,删除最先创建的文件;默认值0,表示不限制。 delay延迟文件创建,直到第一次调用emit()方法创建日志文件 atTime在指定的时间(datetime.time格式)创建日志文件。 ''' deftest_TimedRotatingFileHandler(): #定义日志输出格式 fmt_str='%(asctime)s[level-%(levelname)s][%(name)s]:%(message)s' #初始化 logging.basicConfig() #创建TimedRotatingFileHandler处理对象 #间隔5(S)创建新的名称为myLog%Y%m%d_%H%M%S.log的文件,并一直占用myLog文件。 fileshandle=logging.handlers.TimedRotatingFileHandler('myLog',when='S',interval=5,backupCount=3) #设置日志文件后缀,以当前时间作为日志文件后缀名。 fileshandle.suffix="%Y%m%d_%H%M%S.log" #设置日志输出级别和格式 fileshandle.setLevel(logging.DEBUG) formatter=logging.Formatter(fmt_str) fileshandle.setFormatter(formatter) #添加到日志处理对象集合 logging.getLogger('').addHandler(fileshandle) if__name__=='__main__': test_TimedRotatingFileHandler() #测试在200s内创建文件多个日志文件 foriinrange(0,100): logging.debug("logging.debug") logging.info("logging.info") logging.warning("logging.warning") logging.error("logging.error") time.sleep(2)
补充:使用Python的logging.config.fileConfig配置日志
Python的logging.config.fileConfig方式配置日志,通过解析conf配置文件实现。文件logglogging.conf配置如下:
[loggers] keys=root,fileLogger,rotatingFileLogger [handlers] keys=consoleHandler,fileHandler,rotatingFileHandler [formatters] keys=simpleFormatter [logger_root] level=DEBUG handlers=consoleHandler [logger_fileLogger] level=DEBUG #该logger中配置的handler handlers=fileHandler #logger的名称 qualname=fileLogger propagate=0 [logger_rotatingFileLogger] level=DEBUG #这样配置,rotatingFileLogger中就同时配置了consoleHandler,rotatingFileHandler #consoleHandler负责将日志输出到控制台 #rotatingFileHandler负责将日志输出保存到文件中 handlers=consoleHandler,rotatingFileHandler qualname=rotatingFileLogger propagate=0 [handler_consoleHandler] class=StreamHandler level=DEBUG formatter=simpleFormatter args=(sys.stdout,) [handler_fileHandler] class=FileHandler level=DEBUG formatter=simpleFormatter args=('logs/logging.log','a') [handler_rotatingFileHandler] class=handlers.RotatingFileHandler level=WARNING formatter=simpleFormatter args=("logs/rotating_logging.log","a",1*1024*1024,5) [formatter_simpleFormatter] #format=%(asctime)s-%(name)s-%(levelname)s-%(message)s format=%(asctime)s-%(module)s-%(thread)d-%(levelname)s:%(message)s datefmt=%Y-%m-%d%H:%M:%S
以上配置文件主要包含以下几部分:
loggers:配置logger信息。必须包含一个名字叫做root的logger,当使用无参函数logging.getLogger()时,默认返回root这个logger,其他自定义logger可以通过logging.getLogger("fileLogger")方式进行调用
handlers:定义声明handlers信息。常用的handlers包括StreamHandler(仅将日志输出到kong控制台)、FileHandler(将日志信息输出保存到文件)、RotaRotatingFileHandler(将日志输出保存到文件中,并设置单个日志wenj文件的大小和日志文件个数)
formatter:设置日志格式
logger_xxx:对loggers中声明的logger进行逐个配置,且要一一对应
handler_xxx:对handlers中声明的handler进行逐个配置,且要一一对应
formatter_xxx:对声明的formatterjinx进行配置
代码示例
logging.config.fileConfig(“logging.conf”) #输出日志到控制台,获取的是root对应的logger console_logger=logging.getLogger() #输出日志到单个文件 file_logger=logging.getLogger(name="fileLogger") #rotatingFileLogger中额consoleHandler输出到控制台,rotatingHandler输出日志到文件 rotating_logger=logging.getLogger(name="rotatingFileLogger")
友情提示
进行以上配置后,在项目中需要进行日志输出的地方通过logging.getLogger()方式就可以获取到du应的logger,然后就可以使用logger.info("xxx")jinx进行日志输出了。
使用这种方式配置日志,一定要在项目的入口函数中就调用logging.config.fileConfig(“logging.conf”)函数,因为logging.conf文件中,在handler中配置的是日志文件的相对地址,如果在其他代码文件中进行调用,由于相对地址的原因,将导致日志文件会出现在yixi意想不到的位置。
以上为个人经验,希望能给大家一个参考,也希望大家多多支持毛票票。如有错误或未考虑完全的地方,望不吝赐教。
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。