Last active
January 11, 2021 06:07
-
-
Save tawateer/b33ff85bdcbe9cf1bcb1 to your computer and use it in GitHub Desktop.
重写 Python logging 的 TimedRotatingFileHandler doRollover 方法,解决多进程切割日志的问题。
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/env python | |
# -*- coding: utf-8 -*- | |
import os | |
import time | |
import logging | |
from logging.handlers import TimedRotatingFileHandler | |
LOG_DIR = "/tmp/" | |
LOG_NAME = "test" | |
if not os.path.isdir(LOG_DIR): | |
os.makedirs(LOG_DIR) | |
class ParallelTimedRotatingHandler(TimedRotatingFileHandler): | |
def doRollover(self): | |
""" | |
do a rollover; in this case, a date/time stamp is appended to the | |
filename when the rollover happens. However, you want the file to | |
be named for the start of the interval, not the current time. | |
If there is a backup count, then we have to get a list of matching | |
filenames, sort them and remove the one with the oldest suffix. | |
""" | |
if self.stream: | |
self.stream.close() | |
# get the time that this sequence started at and make it a TimeTuple | |
t = self.rolloverAt - self.interval | |
if self.utc: | |
timeTuple = time.gmtime(t) | |
else: | |
timeTuple = time.localtime(t) | |
dfn = self.baseFilename + "." + time.strftime(self.suffix, timeTuple) | |
if not os.path.exists(dfn): | |
os.rename(self.baseFilename, dfn) | |
if self.backupCount > 0: | |
# find the oldest log file and delete it | |
for s in self.getFilesToDelete(): | |
os.remove(s) | |
self.mode = 'a' | |
self.stream = self._open() | |
currentTime = int(time.time()) | |
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: | |
# DST kicks in before next rollover, so we need to deduct an hour | |
if not dstNow: | |
newRolloverAt = newRolloverAt - 3600 | |
# DST bows out before next rollover, so we need to add an hour | |
else: | |
newRolloverAt = newRolloverAt + 3600 | |
self.rolloverAt = newRolloverAt | |
def singleton(cls): | |
instances = {} | |
def _singleton(*args, **kw): | |
if cls not in instances: | |
instances[cls] = cls(*args, **kw) | |
return instances[cls] | |
return _singleton | |
@singleton | |
class LogHandler(object): | |
WHEN = "midnight" | |
BACKUPCOUNT = 7 | |
logger = logging.getLogger() | |
logger.setLevel(logging.DEBUG) | |
# 格式. | |
formatter = logging.Formatter( | |
'[%(asctime)s] [%(levelname)-8s] [%(name)-16s] [%(filename)s] [%(funcName)s] [%(lineno)d] %(message)s', | |
'%Y-%m-%d %H:%M:%S',) | |
# info 日志. | |
info_handler = ParallelTimedRotatingHandler(LOG_DIR + LOG_NAME + "-info.log", | |
WHEN, backupCount=BACKUPCOUNT) | |
info_handler.propagate = 0 | |
info_handler.setFormatter(formatter) | |
info_handler.setLevel(logging.INFO) | |
logger.addHandler(info_handler) | |
# warning 日志. | |
warning_handler = ParallelTimedRotatingHandler(LOG_DIR + LOG_NAME + "-warning.log", | |
WHEN, backupCount=BACKUPCOUNT) | |
info_handler.propagate = 0 | |
warning_handler.setFormatter(formatter) | |
warning_handler.setLevel(logging.WARNING) | |
logger.addHandler(warning_handler) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
你好,我目前也遇到了多进程切割日志的问题,对比了源码和你的修改以后,发现主要是这句
self.mode = 'a'
,源码里面是self.mode = 'w'
,请问为什么要这么改呢?还有你的代码里面singleton
是用来干什么的呢?