平常使用的是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)