【发布时间】:2015-06-18 14:06:43
【问题描述】:
我需要在 json 中准备一个日志记录配置文件,该文件按时间、大小旋转它并压缩为我的应用程序中的所有模块旋转的 de 文件(我现在卡住了)。我想用一个单独的 json 配置文件来做,这是我当前的文件,但是这个配置只按时间轮换:
{
"version": 1,
"disable_existing_loggers": false,
"formatters": {
"simple": {
"format": "%(asctime)s - %(name)s - %(levelname)s - %(message)s",
"datefmt": "%Y-%m-%d %H:%M:%S"
}
},
"handlers": {
"my_rotate": {
"level": "DEBUG",
"class": "logging.handlers.TimedRotatingFileHandler",
"formatter": "simple",
"when": "D",
"interval": 1,
"backupCount": 5,
"filename": "/var/log/test.log",
"encoding": "utf8"
}
},
"loggers": {
"my_module": {
"level": "DEBUG",
"handlers": ["my_rotate"]
}
},
"root": {
"level": "DEBUG",
"handlers": ["my_rotate"],
"propagate": false
}
}
如果我在处理程序部分 (logging.handlers.RotateFileHandler) 添加其他处理程序以按大小旋转结果日志文件重复所有消息。
我的主程序使用以下方法获取记录器属性:
config_json_file = open(os.path.join(os.path.dirname(os.path.realpath(__file__)), "logging.json"))
logging_data = json.load(config_json_file)
logging.config.dictConfig(logging_data)
我的模块像这样调用记录器:
class StoreData(object):
def __init__(self):
self.logger = logging.getLogger(__name__)
如何在这个文件中混合我的三个要求(按大小和时间旋转,并压缩旋转的文件)?
非常感谢!
更新 1
正如@Bakuriu 建议的那样,我创建了一个新类来覆盖能够压缩旋转文件所需的方法:
class MyRotatingFileHandler(logging.handlers.TimedRotatingFileHandler):
""" My rotating file hander to compress rotated file """
def __init__(self, **kwargs):
logging.handlers.TimedRotatingFileHandler.__init__(self, **kwargs)
def rotate(self, source, dest):
""" Compress rotated log file """
os.rename(source, dest)
f_in = open(dest, 'rb')
f_out = gzip.open("%s.gz" % dest, 'wb')
f_out.writelines(f_in)
f_out.close()
f_in.close()
os.remove(dest)
所以“新”类被称为来自日志记录配置文件,我在其中添加了一个新的处理程序:
"handlers": {
"my_rotate": {
"level": "DEBUG",
"class": "myMainPackage.MyRotatingFileHandler",
"formatter": "simple",
"when": "D",
"interval": 1,
"backupCount": 5,
"filename": "/var/log/test.log",
"encoding": "utf8"
}
在下一次更新中,我将添加一个方法来覆盖所需的方法,并能够将时间和文件大小轮换混合在一起。
更新 2
好吧,我已经覆盖了“shouldRollover”方法,因此我混合了旋转的时间和文件大小。
class MyRotatingFileHandler(logging.handlers.TimedRotatingFileHandler):
""" My rotating file hander to compress rotated file """
def __init__(self, filename, mode='a', maxBytes=0, backupCount=0, encoding=None,
delay=0, when='h', interval=1, utc=False):
if maxBytes > 0:
mode = 'a'
logging.handlers.TimedRotatingFileHandler.__init__(
self, filename, when, interval, backupCount, encoding, delay, utc)
self.maxBytes = maxBytes
self.backupCount = backupCount
def shouldRollover(self, record):
""" Determine if rollover should occur. """
# Check rollover by size
if self.stream is None: # delay was set...
self.stream = self._open()
if self.maxBytes > 0: # are we rolling over?
msg = "%s\n" % self.format(record)
self.stream.seek(0, 2) #due to non-posix-compliant Windows feature
if self.stream.tell() + len(msg) >= self.maxBytes:
return 1
# Check rollover by time
t = int(time.time())
if t >= self.rolloverAt:
return 1
return 0
def rotate(self, source, dest):
""" Compress rotated log file """
os.rename(source, dest)
f_in = open(dest, 'rb')
f_out = gzip.open("%s.gz" % dest, 'wb')
f_out.writelines(f_in)
f_out.close()
f_in.close()
os.remove(dest)
并修改我在 json 中的日志记录配置文件以按天轮换时间,但以秒为单位检查...这意味着 86400s(一天中的秒数)和 5Mb 的大小限制 em>:
"handlers": {
"my_rotate_timed": {
"level": "DEBUG",
"class": "myMainPackage.MyRotatingFileHandler",
"formatter": "simple",
"when": "S",
"interval": 86400,
"backupCount": 5,
"maxBytes": 5242880,
"filename": "/var/log/test.log",
"encoding": "utf8"
}
这种方式重用了 TimedRotationFileHandler 中的其他方法,如果 maxBytes 调用了旋转,那么它使用从 init TimedRotationFileHandler 继承的以秒为单位的后缀方法,格式为: "%Y-%m-%d_%H-%M-%S" 。这就是我使用 "{when="S", interval=86400}" 而不是 "{when="D", interval=1}" 的原因
【问题讨论】:
-
感谢分享,我去测试一下。顺便说一句,init 中的“mode”参数未使用
-
我认为按大小进行的旋转工作不正常。在这种情况下,backupCount 始终为 1,即使它被另外配置。我会努力解决的