需求:
一个Python服务器程序,可能会连续运行几个月,现在需要把每天产生的log信息写入到当天的文件中,即每天产生一个log文件。
使用logging模块编写程序,第一个版本如下:
import logging
import time
class LogSingleton(object):
@classmethod
def get_logger_v1(cls):
"""
获取一个最新设置的logger对象,使用当前时间(年-月-日)作为文件名
:return:
"""
logger = logging.getLogger()
logger.setLevel(level=logging.INFO)
handler = logging.FileHandler('%s_log.txt' % time.strftime("%Y-%m-%d"), mode='a')
handler.setLevel(logging.INFO)
formatter = logging.Formatter('%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s')
handler.setFormatter(formatter)
for h in logger.handlers:
logger.removeHandler(h) # 移除其他所有的handler
logger.addHandler(handler) # 设置新的handler
return logger
if __name__ == '__main__':
logger = LogSingleton.get_logger_v1()
logger.info('xxx')
需要说明的是,logging.getLogger()是一个单例函数,当getLogger不传参数或者传入同一个字符串时,获得的log对象是同一个对象,可以通过id()函数验证。
上述代码中每次调用get_logger_v1()就会更新log对象的handler,已达到更新log文件名的目的,当被设置了新的log文件名后,logging模块会帮我们创建这个文件(前提是其路径无误),后续的log信息就会写入到这个最新handler指定的log文件中。
关于性能的思考
如果程序中调用的地方比较多,那我们不得不考虑他的运行性能好不好。优化的基本思路是判断当前的handler中的文件名是否是当天的,如果是,直接返回;如果不是,再设置一个新的handler返回。
下面是优化后版本:
import logging
import time
from pathlib import Path
class LogSingleton(object):
@classmethod
def get_logger_v2(cls):
"""
获取一个最新设置的logger对象,使用当前时间(年-月-日)作为文件名
:return:
"""
logger = logging.getLogger()
logger.setLevel(level=logging.INFO)
if logger.hasHandlers():
if '%s_log.txt' % time.strftime("%Y-%m-%d") == Path(logger.handlers[0].baseFilename).name:
return logger
handler = logging.FileHandler('%s_log.txt' % time.strftime("%Y-%m-%d"), mode='a')
handler.setLevel(logging.INFO)
formatter = logging.Formatter('%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s')
handler.setFormatter(formatter)
for h in logger.handlers:
logger.removeHandler(h) # 移除其他所有的handler,如果不移除之前的handler,可能会同时把log写入到不同的log文件中。
logger.addHandler(handler) # 设置新的handler
return logger
性能分析
if __name__ == '__main__':
i = 0
t = time.time()
while i < 10000:
logger = LogSingleton.get_logger_v2()
i += 1
print('v2: %.3fs' % (time.time() - t))
i = 0
t = time.time()
while i < 10000:
logger = LogSingleton.get_logger_v1()
i += 1
print('v1: %.3fs' % (time.time() - t))
耗时如下:
v2: 0.106s
v1: 1.394s
Process finished with exit code 0
一万次耗时,可以相差近14倍,这次优化效果还是很可观的。
End