平常使用的是concurrent-log來打印Python項目的日誌,該庫是基於原生logging庫的二次開發,以支持多進程日誌打印,但有個不滿意的地方就是日誌文件的後綴是日期結尾(固然可能有其餘方式能夠設置,但我沒有找到),無論如何能解決本身的需求就行,過程不重要python
class PrivateConcurrentTimedRotatingFileHandler(ConcurrentTimedRotatingFileHandler): # 重寫doRollover方法,用於支撐日誌翻轉的文件命名 def doRollover(self): """ 本方法繼承Python標準庫,修改的部分已在下方使用註釋標記出 """ if self.stream: self.stream.close() self.stream = None # get the time that this sequence started at and make it a TimeTuple currentTime = int(time.time()) dstNow = time.localtime(currentTime)[-1] t = self.rolloverAt - self.interval if self.utc: timeTuple = time.gmtime(t) else: timeTuple = time.localtime(t) dstThen = timeTuple[-1] if dstNow != dstThen: if dstNow: addend = 3600 else: addend = -3600 timeTuple = time.localtime(t + addend) # 天天生成的日誌文件沒有後綴,須要修改源碼:TimedRotatingFileHandler類下的doRollover方法--> # dfn = self.rotation_filename(self.baseFilename + "." + time.strftime(self.suffix, timeTuple)後面拼接後綴名 # dfn = self.rotation_filename(self.baseFilename + "." + time.strftime(self.suffix, timeTuple) + ".log") dfn = self.rotation_filename(self.baseFilename + "." + time.strftime(self.suffix, timeTuple) + ".log") """ 若是翻轉文件已經生成,則說明其餘進程已經處理過翻轉 處理日誌文件已經翻轉當前進程中未寫入文件的日誌副本,修改開始 """ # 直接修改靜態變量,由於代碼執行到此處已經獲取到非重入進程鎖,保證同一時間只有一個線程對變量進行修改 # 因爲Python GIL,同一時間同一進程內只有一個線程運行,線程切換後緩存自動失效,即其餘線程能夠看見修改後的最新值 # 記錄每一次觸發翻轉動做的時間,無論反轉是否真的執行 ConcurrentTimedRotatingFileHandler.before_rollover_at = self.rolloverAt if os.path.exists(dfn): # 由於進程變量不會在內存同步,因此存在其餘進程已經翻轉過日誌文件當時當前進程中還標識爲未翻轉 # 日誌內容建立時間若是小於等於下一個處理翻轉時刻,則將日誌寫入反轉後的日誌文件,而不是當前的baseFilename # 當前磁盤上的baseFilename對於當前進程中的標識副原本說已是翻轉後要寫入的文件 # 因此當文件存在時,本次再也不進行翻轉動做 pass else: self.rotate(self.baseFilename, dfn) """ 處理日誌文件已經翻轉當前進程中未寫入文件的日誌副本,修改結束 """ if self.backupCount > 0: for s in self.getFilesToDelete(): os.remove(s) if not self.delay: self.stream = self._open() 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: dstAtRollover = time.localtime(newRolloverAt)[-1] if dstNow != dstAtRollover: if not dstNow: # DST kicks in before next rollover, so we need to deduct an hour addend = -3600 else: # DST bows out before next rollover, so we need to add an hour addend = 3600 newRolloverAt += addend # 此刻,當前進程中的標識副本已經同步爲最新 self.rolloverAt = newRolloverAt
def get_logger(self): """在logger中添加日誌句柄並返回,若是logger已有句柄,則直接返回 咱們這裏添加兩個句柄,一個輸出日誌到控制檯,另外一個輸出到日誌文件。 兩個句柄的日誌級別不一樣,在配置文件中可設置。 """ if not self.logger.handlers: # 避免重複日誌 console_handler = logging.StreamHandler() console_handler.setFormatter(self.formatter) console_handler.setLevel(self.console_output_level) self.logger.addHandler(console_handler) # 天天從新建立一個日誌文件,最多保留backup_count份 # 天天生成的日誌文件沒有後綴,須要修改源碼:TimedRotatingFileHandler類下的doRollover方法--> # dfn = self.rotation_filename(self.baseFilename + "." + time.strftime(self.suffix, timeTuple)後面拼接後綴名 # dfn = self.rotation_filename(self.baseFilename + "." + time.strftime(self.suffix, timeTuple) + ".log") file_handler = PrivateConcurrentTimedRotatingFileHandler(filename=os.path.join(self.log_path, self.log_file_name), when='MIDNIGHT', interval=1, backupCount=self.backup_count, delay=True, encoding='utf-8' ) file_handler.setFormatter(self.formatter) file_handler.setLevel(self.file_output_level) self.logger.addHandler(file_handler)