在使用 Python 的 logging 模块记录日志时,我们通常希望日志文件包含当前日期,以便于追踪和分析日志。然而,如果我们使用 TimedRotatingFileHandler 处理器,则无法指定日志文件的文件名,该处理器会根据时间自动滚动日志文件。
此外,如果我们的进程每天重新启动,那么 TimedRotatingFileHandler 就无法正常工作,因为它无法识别新的日志文件。
2、解决方案
1. 手动指定日志文件的文件名
我们可以通过手动指定日志文件的文件名来解决这个问题,这样就可以包含当前日期。
import logging
import logging.handlers
LOG_FILENAME = '/tmp/log-{}.txt'.format(datetime.date.today())
log = logging.getLogger(__name__)
log.setLevel(logging.DEBUG)
handler = logging.FileHandler(LOG_FILENAME)
log.addHandler(handler)
# python script
from datetime import datetime
import logging
import logging.handlers
# define a new Handler that formats and writes to a log file
# logfile will be rotated every day at midnight
class DailyRotatingFileHandler(logging.handlers.TimedRotatingFileHandler):
def __init__(self, filename, when="midnight", backupCount=7):
logging.handlers.TimedRotatingFileHandler.__init__(self, filename, when=when, backupCount=backupCount)
def doRollover(self):
if self.stream:
self.stream.close()
# get the time that this sequence started at and make it a TimeTuple
t = time.time()
current_time = time.gmtime(t)
d, _, h = self.when_to_rollover(current_time)
dt = datetime(current_time.tm_year, current_time.tm_mon, d, h, 0, 0)
new_rollover_at = self.computeRollover(dt)
while new_rollover_at <= t:
new_rollover_at = self.computeRollover(dt)
dt += timedelta(days=1)
# if we are rolling over at xxx Midnight, then the new file to open is
# xxx YYYYMMDD.log
target_time = dt.timetuple()
filename = self.baseFilename + "." + \
time.strftime(self.suffix, target_time)
# compute filename for new file
# if self.utc then we set self.baseFilename to UTC time, while we use
# local time for the rolled over files
if self.utc:
# if we are in UTC, the filename is in UTC, but we use the local
# time zone for the rollover computations.
time_str = time.strftime(self.prefix + "%Y-%m-%d_%H-%M-%S", self.utcnow())
else:
# if we are in local time, the filename is in local time, and likewise
# for the rollover computations.
time_str = time.strftime(self.prefix + "%Y-%m-%d_%H-%M-%S", current_time)
dfn = self.baseFilename + "." + time_str
dfn = os.path.join(self.directory, dfn)
# when DST ends, the next day the file should have today's date
# instead of yesterday's
if self.utc:
yearday = datetime.now(tz=datetime.timezone.utc).timetuple().tm_yday
else:
yearday = datetime.now().timetuple().tm_yday
# remove the old files
self.removeOldFiles(yearday)
# open the new file and make sure it's writable
stream = open(dfn, "w", encoding=self.encoding, errors=self.errors)
# make sure that the file has good permissions (in case we're not root)
try:
os.chmod(dfn, stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP |
stat.S_IROTH)
except OSError:
pass # TODO - warn here
if self.mode == "a":
stream.write(self.stream.read())
self.stream = stream
current_time = time.localtime(t) # don't use localtime() above, as we may
# miss a rollover
new_rollover_at = self.computeRollover(current_time)
self.rolloverAt = new_rollover_at
2. 使用自定义 RotatingFileHandler
也可以使用自定义的 RotatingFileHandler,该处理器允许我们指定日志文件的文件名,并根据需要对其进行滚动。
import logging
import logging.handlers
LOG_FILENAME = '/tmp/log-{}.txt'.format(datetime.date.today())
log = logging.getLogger(__name__)
log.setLevel(logging.DEBUG)
handler = logging.handlers.RotatingFileHandler(LOG_FILENAME, maxBytes=1024 * 1024, backupCount=5)
log.addHandler(handler)
这种方法允许我们指定日志文件的最大大小和备份文件数量,当日志文件达到最大大小时,它会自动滚动到一个新的日志文件,同时保留指定数量的备份文件。