logging中RotatingFileHandler和TimedRotatingFileHandler对于多进程不支持(由于每个进程都保持一个固定的文件句柄,导致在达到条件回滚时,相互之间的rename会相互干扰,比如一个进程已经把worker.log变为worker.log.2016-06-01了,其他进程就跟着写到worker.log.2016-06-01了,其他还有好多问题)
故实现适应多进程的handle,代码如下:
# -*- coding: utf-8 -*-
import logging, os, re, time, datetime
try:
import codecs
except ImportError:
codecs = None
class MyLoggerHandler(logging.FileHandler):
def __init__(self, filename, when=‘D‘, backupCount=0, encoding=None, delay=False):
self.prefix = filename
self.when = when.upper()
# S - Every second a new file
# M - Every minute a new file
# H - Every hour a new file
# D - Every day a new file
if self.when == ‘S‘:
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.suffix = "%Y-%m-%d_%H-%M"
self.extMatch = r"^\d{4}-\d{2}-\d{2}_\d{2}-\d{2}$"
elif self.when == ‘H‘:
self.suffix = "%Y-%m-%d_%H"
self.extMatch = r"^\d{4}-\d{2}-\d{2}_\d{2}$"
elif self.when == ‘D‘:
self.suffix = "%Y-%m-%d"
self.extMatch = r"^\d{4}-\d{2}-\d{2}$"
else:
raise ValueError("Invalid rollover interval specified: %s" % self.when)
self.filefmt = os.path.join("logs", "%s.%s" % (self.prefix, self.suffix))
self.filePath = datetime.datetime.now().strftime(self.filefmt)
_dir = os.path.dirname(self.filePath)
try:
if os.path.exists(_dir) is False:
os.makedirs(_dir)
except Exception:
print "can not make dirs"
print "filepath is " + self.filePath
pass
self.backupCount = backupCount
if codecs is None:
encoding = None
logging.FileHandler.__init__(self, self.filePath, ‘a‘, encoding, delay)
def shouldChangeFileToWrite(self):
_filePath = datetime.datetime.now().strftime(self.filefmt)
if _filePath != self.filePath:
self.filePath = _filePath
return 1
return 0
def doChangeFile(self):
self.baseFilename = os.path.abspath(self.filePath)
if self.stream is not None:
self.stream.flush()
self.stream.close()
if not self.delay:
self.stream = self._open()
if self.backupCount > 0:
for s in self.getFilesToDelete():
os.remove(s)
def getFilesToDelete(self):
dirName, baseName = os.path.split(self.baseFilename)
fileNames = os.listdir(dirName)
result = []
prefix = self.prefix + "."
plen = len(prefix)
for fileName in fileNames:
if fileName[:plen] == prefix:
suffix = fileName[plen:]
if re.compile(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 emit(self, record):
"""
Emit a record.
"""
try:
if self.shouldChangeFileToWrite():
self.doChangeFile()
logging.FileHandler.emit(self, record)
except (KeyboardInterrupt, SystemExit):
raise
except:
self.handleError(record)
使用方式和TimedRotatingFileHandler差不多,如文件配置按下:
[handler_workerFile2] class=log_kit.MyLoggerHandler level=INFO formatter=simpleFormatter args=(r‘worker.log‘, ‘M‘, 5) # 一分钟一个文件,只保留最新的5个 #args=(r‘worker.log‘, ‘D‘, 5) # 一天一个文件,只保留最新的5个
原文:http://my.oschina.net/u/914655/blog/469512