【发布时间】:2011-10-24 00:41:47
【问题描述】:
我在 Python 中使用标准记录器库。例如,有 RotatingFileHandler,可以每天轮换日志文件。
但它只是重命名它们。如果它不仅可以重命名,而且还可以将旧文件放入 zip(或 gz、bzip 等)存档中,那就太好了。
有没有简单的方法来实现这一点?
【问题讨论】:
-
子类化并实现它。
我在 Python 中使用标准记录器库。例如,有 RotatingFileHandler,可以每天轮换日志文件。
但它只是重命名它们。如果它不仅可以重命名,而且还可以将旧文件放入 zip(或 gz、bzip 等)存档中,那就太好了。
有没有简单的方法来实现这一点?
【问题讨论】:
我认为您最好的选择是扩展 RotatingFileHandler 类似的东西(未测试):
import os
from logging.handlers import RotatingFileHandler
COMPRESSION_SUPPORTED = {}
try:
import gzip
COMPRESSION_SUPPORTED['gz'] = gzip
except ImportError:
pass
try:
import zipfile
COMPRESSION_SUPPORTED['zip'] = zipfile
except ImportError:
pass
class NewRotatingFileHandler(RotatingFileHandler):
def __init__(self, *args, **kws):
compress_mode = kws.pop('compress_mode')
try:
self.compress_cls = COMPRESSION_SUPPORTED[compress_mode]
except KeyError:
raise ValueError('"%s" compression method not supported.' % compress_mode)
super(NewRotatingFileHandler, self).__init__(self, *args, **kws)
def doRollover(self):
super(NewRotatingFileHandler, self).doRollover()
# Compress the old log.
old_log = self.baseFilename + ".1"
with open(old_log) as log:
with self.compress_cls.open(old_log + '.gz', 'wb') as comp_log:
comp_log.writelines(log)
os.remove(old_log)
【讨论】:
".1" 是什么意思?
backupCount > 1,因为压缩文件没有正确重命名
接受的答案将仅存档 1 个文件-(basefile.log.1) 。其他文件未存档。 此代码将归档除基本文件之外的所有日志文件。
import os
import gzip
import logging.handlers
class NewRotatingFileHandler(logging.handlers.RotatingFileHandler):
def __init__(self, filename, **kws):
backupCount = kws.get('backupCount', 0)
self.backup_count = backupCount
logging.handlers.RotatingFileHandler.__init__(self, filename, **kws)
def doArchive(self, old_log):
with open(old_log) as log:
with gzip.open(old_log + '.gz', 'wb') as comp_log:
comp_log.writelines(log)
os.remove(old_log)
def doRollover(self):
if self.stream:
self.stream.close()
self.stream = None
if self.backup_count > 0:
for i in range(self.backup_count - 1, 0, -1):
sfn = "%s.%d.gz" % (self.baseFilename, i)
dfn = "%s.%d.gz" % (self.baseFilename, i + 1)
if os.path.exists(sfn):
if os.path.exists(dfn):
os.remove(dfn)
os.rename(sfn, dfn)
dfn = self.baseFilename + ".1"
if os.path.exists(dfn):
os.remove(dfn)
if os.path.exists(self.baseFilename):
os.rename(self.baseFilename, dfn)
self.doArchive(dfn)
if not self.delay:
self.stream = self._open()
【讨论】:
你可以通过encoding='bz2-codec'初始化RotatingFileHandler来自动写入bz2压缩日志文件:
import logging
import logging.handlers as handlers
if __name__=='__main__':
log_filename='log_rotate.bz2'
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)
handler = handlers.RotatingFileHandler(
log_filename, maxBytes=20, backupCount=5, encoding='bz2-codec')
logger.addHandler(handler)
for i in range(20):
logger.debug('i = %d' % i)
PS。 Python3 removed 'bz2-codec' 来自有效编码集,因此此解决方案特定于 Python2。
【讨论】: