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方式就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持毛票票。