python 的 logging 模块, 在多线程应用中, logging.hanlders.TimedRotatingFileHandler 不能正常按日期分割。
解决办法为:重写FileHandler类,用于多线程中日志按天分割。
# 重写FileHandler类,用于多线程中日志按天分割
class SafeFileHandler(logging.FileHandler):
def __init__(self, filename, mode, encoding=None, delay=0):
"""
Use the specified filename for streamed logging
"""
encoding = None
logging.FileHandler.__init__(self, filename, mode='a', encoding=None, delay=False)
self.mode = mode
self.encoding = encoding
self.suffix = "%Y-%m-%d"
self.suffix_time = ""
def emit(self, record):
"""
Emit a record.
Always check time
"""
try:
if self.check_baseFilename(record):
self.build_baseFilename()
logging.FileHandler.emit(self, record)
except (KeyboardInterrupt, SystemExit):
raise
except:
self.handleError(record)
def check_baseFilename(self, record):
"""
Determine if builder should occur.
record is not used, as we are just comparing times,
but it is needed so the method signatures are the same
"""
timeTuple = time.localtime()
if self.suffix_time != time.strftime(self.suffix, timeTuple) or not os.path.exists(self.baseFilename+'.'+self.suffix_time):
return 1
else:
return 0
def build_baseFilename(self):
"""
do builder; in this case,
old time stamp is removed from filename and
a new time stamp is append to the filename
"""
if self.stream:
self.stream.close()
self.stream = None
# remove old suffix
if self.suffix_time != "":
index = self.baseFilename.find("."+self.suffix_time)
if index == -1:
index = self.baseFilename.rfind(".")
self.baseFilename = self.baseFilename[:index]
# add new suffix
currentTimeTuple = time.localtime()
self.suffix_time = time.strftime(self.suffix, currentTimeTuple)
self.baseFilename = self.baseFilename + "." + self.suffix_time
self.mode = 'a'
if not self.delay:
self.stream = self._open()
之后,Logger定义日志的各种参数(格式等):
class Logger(object):
# 日志级别关系映射
level_relations = {
'debug':logging.DEBUG,
'info':logging.INFO,
'warning':logging.WARNING,
'error':logging.ERROR,
'critical':logging.CRITICAL
}
def __init__(self, filename, level='info', when='D', backCount=7,
fmt= '%(asctime)s - %(pathname)s [line:%(lineno)d] - %(levelname)s: %(message)s'):
self.logger = logging.getLogger('mylogger')
# 创建日志目录(路径logdir可从自定义配置文件导入,或实例化时传入)
self.mkdir(logdir)
# 设置日志格式
format_str = logging.Formatter(fmt)
self.logger.setLevel(self.level_relations.get(level))#设置日志级别
# 指定间隔时间自动生成文件的处理器(用于debug)
th = SafeFileHandler(filename=filename, mode='a')
# 设置文件里写入的格式
th.setFormatter(format_str)
# 把对象加到logger里
self.logger.addHandler(th)
def mkdir(self, path) -> None:
# 如果不存在则创建目录
if not os.path.exists(path):
os.makedirs(path)
实例化日志:
mylogger = Logger(filename='all.log', level='debug')
网友评论