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:

import logging

import sys

import ConfigParser

def log_building(log_file):

try:

#set format

format_str=logging.Formatter("%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s")

#create stander output handler

crit_hand=logging.StreamHandler(sys.stderr)

crit_hand.setFormatter(format_str)

#create file handler

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)

return app_log

except Exception as e:

logging.shutdown()

raise e

def config_file_get(fpath):

try:

cnf_dict={}

cfg=ConfigParser.SafeConfigParser()

cfg.read(fpath)

for section in cfg.sections():

#将ini中的item组合到字典中,key=section+_option

for item in cfg.items(section):

key= section+'_'+item[0]

value=item[1]

if cnf_dict.get(key,None)==None:

cnf_dict[key]=value

return cnf_dict

except Exception as e:

raise e

def log_level_get(level):

DEBUG_LEVEL={'CRITICAL':logging.CRITICAL,'ERROR':logging.ERROR,'WARNING':logging.WARNING,

'INFO':logging.INFO,'DEBUG':logging.DEBUG

}

try:

return DEBUG_LEVEL.get(level.upper())

except Exception as e:

raise e

applogconfig.ini内容:

[log]

log_level=ERROR

dir=log

以下为unittest内容:

import unittest

import logging_class

import os

import logging

class Test(unittest.TestCase):

cfg={}

def setUp(self):

print 'test begin'

self.cfg={}

def tearDown(self):

print 'test end'

def testlog_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')

def testlog_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)

#print self.cfg['log_log_level']

self.assertEqual(logging_class.log_level_get(self.cfg['log_log_level']), logging.ERROR, 'OK')

def testlog_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)

#print self.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__":

#import sys;sys.argv = ['', 'Test.testName']

unittest.main()

输出:

Finding files... done.

Importing test modules ... done.

test begin

test end

test begin

test end

test begin

2016-12-15 17:59:04,059 logging_module_test.py[line:48] ERROR dddds

test end

----------------------------------------------------------------------

Ran 3 tests in 0.004s

补充知识:一种logging封装方法,不会产生重复log

在调试logging的封装的时候,发现已经调用了logging封装的函数,在被其它函数再调用时,会出现重复的logging。原因是不同的地方创建了不同的handler,所以会重复,可以使用暴力方法解决

暴力方式就是每次创建新的对象就清空logger.handlers

我常用的封装如下

import logging

import time,os

'''

使用方法:

import mylog

log = mylog.Log().getlog()

log.debug("###")

'''

class Log():

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")

if os.path.exists(self.log_path) and os.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()

def getlog(self):

return self.logger

if __name__ == "__main__":

log = Log().getlog()

log.debug("hello")

以上这篇python将logging模块封装成单独模块并实现动态切换Level方式就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持。

以上是 python将logging模块封装成单独模块并实现动态切换Level方式 的全部内容, 来源链接: utcz.com/z/311963.html

回到顶部