import datetime
import logging
import os
import re
import time
class ScheduledDeletionDayHandler(logging.FileHandler):
"""
删除过多log文件handler
"""
def __init__(self, filepath, suffix, ext_match, mode='a', back_count=10, encoding=None, delay=False):
"""
:param filepath: 文件路径
:param suffix:时间格式
:param ext_match:文件名匹配正则表达式
:param mode:模式
:param back_count:备份数量
:param encoding:
:param delay:
"""
logging.FileHandler.__init__(self, filepath, mode, encoding=encoding, delay=delay)
self.suffix = suffix
self.back_count = back_count
self.ext_match = re.compile(ext_match)
self.suffix_time = ""
def emit(self, record):
"""
复写FileHandler的emit方法
:param record:
"""
try:
if self.check_base_filename():
self.build_base_filename()
logging.FileHandler.emit(self, record)
except (KeyboardInterrupt, SystemExit):
raise
except BaseException:
self.handleError(record)
def find_remove_files(self):
"""
找出超出备份数量待删除的日志路径
:return:
"""
dir_path = os.path.dirname(self.baseFilename)
file_names = os.listdir(dir_path)
file_list = list()
for file_name in file_names:
if self.ext_match.search(file_name):
file_list.append((os.path.join(dir_path, file_name)))
file_list.sort()
files_count = len(file_list)
if files_count > self.back_count:
return file_list[:files_count - self.back_count]
return file_list
@classmethod
def remove_file(cls, remove_files):
"""
删除日志
:param remove_files:
"""
for file in remove_files:
try:
os.remove(file)
except PermissionError:
pass
def check_base_filename(self):
"""
检查日志文件输入流是否指向当前时间段的日志文件,是否需要修改文件输入流
"""
time_tuple = time.localtime()
if self.suffix_time != time.strftime(self.suffix, time_tuple) or not os.path.exists(self.baseFilename):
return True
return False
def build_base_filename(self):
"""
修改文件输入流,指向当前时间段的日志文件,判断并删除超出备份数量的日志文件
"""
if self.stream:
self.stream.close()
self.stream = None
remove_files = self.find_remove_files()
if remove_files:
self.remove_file(remove_files)
current_time_tuple = time.localtime()
self.suffix_time = time.strftime(self.suffix, current_time_tuple)
prefix = re.split(self.ext_match, self.baseFilename)[0]
self.baseFilename = "{0}{1}.log".format(prefix, self.suffix_time)
self.mode = "a"
class Logger:
level_relation = {
"debug": logging.DEBUG,
"info": logging.INFO,
"warning": logging.WARNING,
"error": logging.ERROR,
"critical": logging.CRITICAL
}
def __init__(self, level='info', back_count=10,
fmt='%(asctime)s - %(pathname)s[line:(lineno)d] - %(levelname)s: %(message)s'):
file_path = '{0}/../../logs/{1}'.format(
__file__, 'all-{0}'.format(datetime.datetime.now().strftime("%Y-%m-%d")))
logs_dir = os.path.dirname(os.path.abspath(file_path))
if not os.path.exists(logs_dir):
os.makedirs(logs_dir, exist_ok=True)
self.logger = logging.getLogger()
if not self.logger.handlers:
format_str = logging.Formatter(fmt)
self.logger.setLevel(self.level_relation.get(level))
sh_out = logging.StreamHandler()
sh_out.setFormatter(format_str)
time_handler = ScheduledDeletionDayHandler(
file_path, "%Y-%m-%d", r"\d{4}-\d{2}-\d{2}.log", back_count=back_count)
time_handler.setFormatter(format_str)
self.logger.addHandler(time_handler)
self.logger.addHandler(sh_out)