如何使用python';什么是TimedRotatingFileHandler?
我正在尝试使用将每日日志保存在单独的日志文件中。 旋转工作完全符合预期,但我不喜欢它的工作方式是文件的命名 如果我将日志文件设置为my_log_file.log,这将是“今天”的日志文件,当它在午夜更改日期时,将重命名为如何使用python';什么是TimedRotatingFileHandler?,python,logging,filehandler,Python,Logging,Filehandler,我正在尝试使用将每日日志保存在单独的日志文件中。 旋转工作完全符合预期,但我不喜欢它的工作方式是文件的命名 如果我将日志文件设置为my_log_file.log,这将是“今天”的日志文件,当它在午夜更改日期时,将重命名为my_log_file.log.2014-07-08,末尾没有.log扩展名,并且将为新的一天创建一个新的my_log_file.log 我想得到的是旧文件被重命名为 MyLogLogyField.2014-0708.日志或甚至 MyLogLogyFiel-2014-0708.
my_log_file.log.2014-07-08
,末尾没有.log扩展名,并且将为新的一天创建一个新的my_log_file.log
我想得到的是旧文件被重命名为<代码> MyLogLogyField.2014-0708.日志或甚至<代码> MyLogLogyFiel-2014-0708. log ,主要是.log结尾,不在中间。 另外,我希望“今天”日志文件已经用今天的日期命名,就像旧的一样
有什么办法吗 我发现我可以通过以下方式对后缀进行个性化设置: handler.suffix=“%Y-%m-%d”但是我没有办法删除内部.log部分并强制当前日志文件添加后缀。据我所知,没有办法直接实现这一点 您可以尝试的一种解决方案是覆盖默认行为
- 创建自己的
并重写TimedRotatingFileHandler类
doRollover()函数。
- 检查python安装中的源代码
/Lib/logging/handlers.py
class MyTimedRotatingFileHandler(TimedRotatingFileHandler):
def __init__(self, **kwargs):
TimedRotatingFileHandler.__init__(self, **kwargs)
def doRollover(self):
# Do your stuff, rename the file as you want
我创建了一个类ParallelTimedRotatingFileHandler,主要目的是允许多个进程并行写入日志文件。 此类解决的并行过程问题包括:
- 当所有进程都试图同时复制或重命名同一文件时,会出现错误
- 这个问题的解决方案正是您建议的命名约定。因此,对于您在处理程序中提供的文件名
,日志记录不会转到例如Service
,而是今天转到Service.log
,明天转到Service.2014-08-18.log
李>Service.2014-08-19.log
- 另一种解决方案是以
(append)模式而不是a
打开文件,以允许并行写入w
- 删除备份文件时也需要小心,因为多个并行进程同时删除相同的文件
- 此实现不考虑闰秒(这对于Unix来说不是问题)。在其他操作系统中,翻滚时刻可能仍然是30/6/2008 23:59:60,因此日期没有更改,因此,我们采用与昨天相同的文件名
- 我知道Python的标准建议是,
模块不适用于并行进程,我应该使用SocketHandler,但至少在我的环境中,这是可行的日志记录
import logging
import logging.handlers
import os
import time
import re
class ParallelTimedRotatingFileHandler(logging.handlers.TimedRotatingFileHandler):
def __init__(self, filename, when='h', interval=1, backupCount=0, encoding=None, delay=False, utc=False, postfix = ".log"):
self.origFileName = filename
self.when = when.upper()
self.interval = interval
self.backupCount = backupCount
self.utc = utc
self.postfix = postfix
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}$"
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}$"
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}$"
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}$"
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}$"
else:
raise ValueError("Invalid rollover interval specified: %s" % self.when)
currenttime = int(time.time())
logging.handlers.BaseRotatingHandler.__init__(self, self.calculateFileName(currenttime), 'a', encoding, delay)
self.extMatch = re.compile(self.extMatch)
self.interval = self.interval * interval # multiply by units requested
self.rolloverAt = self.computeRollover(currenttime)
def calculateFileName(self, currenttime):
if self.utc:
timeTuple = time.gmtime(currenttime)
else:
timeTuple = time.localtime(currenttime)
return self.origFileName + "." + time.strftime(self.suffix, timeTuple) + self.postfix
def getFilesToDelete(self, newFileName):
dirName, fName = os.path.split(self.origFileName)
dName, newFileName = os.path.split(newFileName)
fileNames = os.listdir(dirName)
result = []
prefix = fName + "."
postfix = self.postfix
prelen = len(prefix)
postlen = len(postfix)
for fileName in fileNames:
if fileName[:prelen] == prefix and fileName[-postlen:] == postfix and len(fileName)-postlen > prelen and fileName != newFileName:
suffix = fileName[prelen:len(fileName)-postlen]
if self.extMatch.match(suffix):
result.append(os.path.join(dirName, fileName))
result.sort()
if len(result) < self.backupCount:
result = []
else:
result = result[:len(result) - self.backupCount]
return result
def doRollover(self):
if self.stream:
self.stream.close()
self.stream = None
currentTime = self.rolloverAt
newFileName = self.calculateFileName(currentTime)
newBaseFileName = os.path.abspath(newFileName)
self.baseFilename = newBaseFileName
self.mode = 'a'
self.stream = self._open()
if self.backupCount > 0:
for s in self.getFilesToDelete(newFileName):
try:
os.remove(s)
except:
pass
newRolloverAt = self.computeRollover(currentTime)
while newRolloverAt <= currentTime:
newRolloverAt = newRolloverAt + self.interval
#If DST changes and midnight or weekly rollover, adjust for this.
if (self.when == 'MIDNIGHT' or self.when.startswith('W')) and not self.utc:
dstNow = time.localtime(currentTime)[-1]
dstAtRollover = time.localtime(newRolloverAt)[-1]
if dstNow != dstAtRollover:
if not dstNow: # DST kicks in before next rollover, so we need to deduct an hour
newRolloverAt = newRolloverAt - 3600
else: # DST bows out before next rollover, so we need to add an hour
newRolloverAt = newRolloverAt + 3600
self.rolloverAt = newRolloverAt
导入日志
导入日志记录处理程序
导入操作系统
导入时间
进口稀土
类ParallelTimedRotatingFileHandler(logging.handlers.TimedRotatingFileHandler):
def _uinit _;(self,filename,when='h',interval=1,backupCount=0,encoding=None,delay=False,utc=False,postfix=“.log”):
self.origFileName=文件名
self.when=when.upper()
self.interval=间隔
self.backupCount=备份计数
self.utc=utc
self.postfix=后缀
如果self.when==“S”:
self.interval=1#1秒
self.suffix=“%Y-%m-%d\u%H-%m-%S”
self.extMatch=r“^\d{4}-\d{2}-\d{2}-\d{2}-\d{2}-\d{2}$”
elif self.when==“M”:
self.interval=60#一分钟
self.suffix=“%Y-%m-%d\u%H-%m”
self.extMatch=r“^\d{4}-\d{2}-\d{2}-\d{2}-\d{2}$”
elif self.when==“H”:
self.interval=60*60#一小时
self.suffix=“%Y-%m-%d\uh”
self.extMatch=r“^\d{4}-\d{2}-\d{2}-\d{2}$”
elif self.when==“D”或self.when==“午夜”:
self.interval=60*60*24#一天
self.suffix=“%Y-%m-%d”
self.extMatch=r“^\d{4}-\d{2}-\d{2}$”
elif self.when.startswith('W'):
自我间隔=60*60*24*7#一周
如果len(self.when)!=2:
raise VALUERROR(“您必须指定从0到6的每周滚动日(0是星期一):%s”%self.when)
如果self.when[1]<“0”或self.when[1]>“6”:
raise VALUERROR(“为每周滚动指定的日期无效:%s”%self.when)
self.dayOfWeek=int(self.when[1])
self.suffix=“%Y-%m-%d”
self.extMatch=r“^\d{4}-\d{2}-\d{2}$”
其他:
raise VALUERROR(“指定的滚动间隔无效:%s”%self.when)
currenttime=int(time.time())
logging.handlers.BaseRotatingHandler.\uuuuu init\uuuuuuuu(self,self.calculateFileName(currenttime),'a',编码,延迟)
self.extMatch=re.compile(self.extMatch)
self.interval=self.interval*interval#乘以请求的单位
self.rolloverAt=self.computeRollover(当前时间)
def calculateFileName(自身,当前时间):
如果self.utc:
timeTuple=time.gmtime(currenttime)
其他:
timeTuple=time.localtime(currenttime)
返回self.origFileName+““+time.strftime(self.suffix,timeTuple)+self.postfix
def getFilesToDelete(self,newFileName):
dirName,fName=os.path.split(self.origFileName)
dName,newFileName=os.path.split(newFileName)
filename=os.listdir(dirName)
结果=[]
前缀=fName+”
后缀=self.postfix
prelen=len(前缀)
postlen=len(后缀)
对于文件名中的文件名:
如果文件名[:prelen]==前缀和文件名[-postlen:]==后缀
def __init__(self, filename, when='h', interval=1, backupCount=0,
encoding=None, delay=False, utc=False, atTime=None, postfix = ".log"):
self.postfix = postfix
def namer(name):
return name.replace(".log", "") + ".log"
handler.namer = namer
import os
import logging
from logging.handlers import TimedRotatingFileHandler
from config import constants
def namer(name):
return name.replace(".log", "") + ".log"
def init(baseFilename):
logPath = constants.LOGGING_DIR
envSuffix = '-prod' if constants.ENV == 'prod' else '-dev'
logFilename = os.path.join(logPath, baseFilename + envSuffix + '.log')
print(f"Logging to {logFilename}")
handler = TimedRotatingFileHandler(logFilename,
when = "midnight",
backupCount = 30,
encoding = 'utf8')
handler.setLevel(logging.DEBUG)
handler.suffix = "%Y%m%d"
handler.namer = namer # <-- Here's where I assign the custom namer.
formatter = logging.Formatter('%(asctime)s %(levelname)s %(message)s [%(module)s:%(lineno)d]')
handler.setFormatter(formatter)
logging.basicConfig(
handlers = [handler],
format = '%(asctime)s %(levelname)s %(message)s [%(module)s:%(lineno)d]',
level = logging.DEBUG,
datefmt = '%Y-%m-%d %H:%M:%S')
if __name__ == '__main__':
init('testing')
logging.error("ohai")
logging.debug("ohai debug")
logging.getLogger().handlers[0].doRollover()
logging.error("ohai next day")
logging.debug("ohai debug next day")