最好在午夜更新
import os
import logging
from logging.handlers import TimedRotatingFileHandler
# 这个只能指定文件大小进行切割?
# from concurrent_log_handler import ConcurrentRotatingFileHandler
class MyTimedRotatingFileHandler(TimedRotatingFileHandler):
def rotate(self, source, destination):
if not callable(self.rotator):
# Issue 18940: A file may not have been created if delay is True.
self.new_rename(destination, source)
else:
self.rotator(source, destination)
@staticmethod
def new_rename(destination, source):
"""整体思路避免直接rename当前日志文件,我们先创建新的rotate备份文件,
将当前日志文件内容复制到这个备份文件中去,然后清空当前日志文件
缺点是读写过程中的日志可能会漏掉,建议午夜时间进行rotate备份
"""
if os.path.exists(source):
with open(destination, "wb+") as fw:
with open(source, "rb+") as fr:
fw.write(fr.read())
with open(source, "w+") as fw:
fw.write("###\n")
class Logger:
def __init__(self, name=None, filename="./log"):
self.logger = logging.getLogger(name)
self.logger.setLevel(level=logging.DEBUG)
# 防止动态加载或多模块导入时重复加载此模块导致的打印重复日志的问题
if self.logger.hasHandlers():
self.logger.handlers.clear()
formatter = logging.Formatter(
'%(asctime)s-[P]%(process)s-%(filename)s:%('
'funcName)s:%(lineno)s-%(levelname)s-[msg]%(message)s')
# 添加文件打印handler
# 创建TimedRotatingFileHandler处理对象
file_handler = MyTimedRotatingFileHandler(
filename=filename, when='midnight', backupCount=30, encoding="utf-8")
# 设置日志文件后缀,以当前时间作为日志文件后缀名,
# 一定要符合如下的时间格式,精确到秒的就when的最小单位就只能是S,同理
file_handler.suffix = "%Y-%m-%d_%H-%M-%S"
file_handler.setLevel(logging.DEBUG)
file_handler.setFormatter(formatter)
self.logger.addHandler(file_handler)
# 添加console打印handler
console_handler = logging.StreamHandler()
console_handler.setFormatter(formatter)
console_handler.setLevel(logging.DEBUG)
self.logger.addHandler(console_handler)
logger = Logger(name="test", filename="log_test.log").logger
if __name__ == "__main__":
logger.info("Start print log")
logger.debug("Do something")
logger.warning("Something maybe fail.")
时间后缀格式和when对应如下:
if self.when == 'S':
self.interval = 1 # one second
self.suffix = "%Y-%m-%d_%H-%M-%S"
self.extMatch = r"^\d{4}-\d{2}-\d{2}_\d{2}-\d{2}-\d{2}(\.\w+)?$"
elif self.when == 'M':
self.interval = 60 # one minute
self.suffix = "%Y-%m-%d_%H-%M"
self.extMatch = r"^\d{4}-\d{2}-\d{2}_\d{2}-\d{2}(\.\w+)?$"
elif self.when == 'H':
self.interval = 60 * 60 # one hour
self.suffix = "%Y-%m-%d_%H"
self.extMatch = r"^\d{4}-\d{2}-\d{2}_\d{2}(\.\w+)?$"
elif self.when == 'D' or self.when == 'MIDNIGHT':
self.interval = 60 * 60 * 24 # one day
self.suffix = "%Y-%m-%d"
self.extMatch = r"^\d{4}-\d{2}-\d{2}(\.\w+)?$"
elif self.when.startswith('W'):
self.interval = 60 * 60 * 24 * 7 # one week
if len(self.when) != 2:
raise ValueError("You must specify a day for weekly rollover from 0 to 6 (0 is Monday): %s" % self.when)
if self.when[1] < '0' or self.when[1] > '6':
raise ValueError("Invalid day specified for weekly rollover: %s" % self.when)
self.dayOfWeek = int(self.when[1])
self.suffix = "%Y-%m-%d"
self.extMatch = r"^\d{4}-\d{2}-\d{2}(\.\w+)?$"