Python之logging.handlers.TimedRotatingFileHandler

..

import os
import logging
import sys
from logging.handlers import TimedRotatingFileHandler
import time
 
LOG_PATH = "logs"
 
 
def get_logger(name):
    logger = logging.getLogger(name)
    if os.path.exists(LOG_PATH):
        pass
    else:
        os.mkdir(LOG_PATH)
    # 设置日志基础级别
    logger.setLevel(logging.DEBUG)
    # 日志格式
    formatter = '%(asctime)s | %(levelname)s | %(thread)d | %(filename)s - %(funcName)s : %(message)s'
 
    log_formatter = logging.Formatter(formatter)
    # 控制台日志
    console_handler = logging.StreamHandler(sys.stdout)
    console_handler.setFormatter(log_formatter)
    # info日志文件名
    info_file_name = 'info-' + time.strftime(
        '%Y-%m-%d', time.localtime(time.time())) + '.log'
    # info日志处理器
    # filename:日志文件名
    # when:日志文件按什么维度切分。'S'-秒;'M'-分钟;'H'-小时;'D'-天;'W'-周
    #       这里需要注意,如果选择 D-天,那么这个不是严格意义上的'天',而是从你
    #       项目启动开始,过了24小时,才会从新创建一个新的日志文件,
    #       如果项目重启,这个时间就会重置。所以这里选择'MIDNIGHT'-是指过了午夜
    #       12点,就会创建新的日志。
    # interval:是指等待多少个单位 when 的时间后,Logger会自动重建文件。
    # backupCount:是保留日志个数。默认的0是不会自动删除掉日志。
    info_handler = TimedRotatingFileHandler(filename='logs/info/' +
                                            info_file_name,
                                            when='MIDNIGHT',
                                            interval=1,
                                            backupCount=7,
                                            encoding='utf-8')
    info_handler.setFormatter(log_formatter)
    info_handler.setLevel(logging.INFO)
    # error日志文件名
    error_file_name = 'error-' + time.strftime(
        '%Y-%m-%d', time.localtime(time.time())) + '.log'
    # 错误日志处理器
    err_handler = TimedRotatingFileHandler(filename='logs/error/' +
                                           error_file_name,
                                           when='MIDNIGHT',
                                           interval=1,
                                           backupCount=7,
                                           encoding='utf-8')
    err_handler.setFormatter(log_formatter)
    err_handler.setLevel(logging.ERROR)
    # 添加日志处理器
    logger.addHandler(info_handler)
    logger.addHandler(err_handler)
    logger.addHandler(console_handler)
    return logger

重写`logging.handlers.TimedRotatingFileHandler`类可以让你自定义日志文件的轮转策略。在多进程环境中,如使用Gunicorn运行Flask应用时,你可能需要处理多个工作进程写入同一个日志文件的问题。默认情况下,`TimedRotatingFileHandler`不支持多进程写入,因此你需要确保日志系统能够在多进程环境下正确地轮转日志文件。 以下是一个简单的例子,展示了如何在Flask项目中重写`TimedRotatingFileHandler`来实现多进程日期分割的日志轮转: ```python import logging.handlers import os class MultiProcessTimedRotatingFileHandler(logging.handlers.TimedRotatingFileHandler): def __init__(self, filename, when='H', interval=1, backupCount=0, encoding=None, delay=False): super().__init__(filename, when, interval, backupCount, encoding, delay) # 确保父进程打开文件时,子进程能够正确复制文件描述符 selfFH = None def getFilesToDelete(self): # 获取需要删除的旧日志文件列表 dirName, baseName = os.path.split(self.baseFilename) fileNames = os.listdir(dirName) result = [os.path.join(dirName, fileName) for fileName in fileNames if fileName.startswith(baseName + ".")] result.sort() return result[-self.backupCount:] def doRollover(self): # 多进程环境下,确保日志文件的轮转 if self.stream: self.stream.close() self.stream = None if self.backupCount > 0: for s in self.getFilesToDelete(): os.remove(s) # 这里不需要重新打开文件,因为我们将通过 reopen() 方法来处理它 self.reopen() def reopen(self): # 重新打开文件,确保可以写入新的日志文件 if self.encoding is None: mode = 'a' else: mode = 'a' self.stream = self._open() if self.delay: self.stream.close() self.stream = None class MyRotatingFileHandler(MultiProcessTimedRotatingFileHandler): def __init__(self, filename, when='H', interval=1, backupCount=0, encoding=None, delay=False): super().__init__(filename, when, interval, backupCount, encoding, delay) # 可以在这里添加更多自定义的逻辑 ``` 在Flask应用中使用自定义的日志处理器: ```python from flask import Flask import logging from myrotatingfilehandler import MyRotatingFileHandler app = Flask(__name__) # 创建logger对象 logger = logging.getLogger() logger.setLevel(logging.DEBUG) # 设置日志级别 # 创建自定义的多进程日志处理器 handler = MyRotatingFileHandler('app.log', when='D', interval=1, backupCount=7, encoding='utf-8', delay=False) # 设置处理器的日志级别和格式 handler.setLevel(logging.DEBUG) formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') handler.setFormatter(formatter) # 添加处理器到logger对象 logger.addHandler(handler) # 使用logger @app.route('/') def index(): logger.debug('debug message') logger.info('info message') logger.warning('warning message') logger.error('error message') logger.critical('critical message') return 'Hello, World!' if __name__ == '__main__': app.run(host='0.0.0.0', port=5000) ``` 使用这个自定义的`MyRotatingFileHandler`,你可以确保在多进程的Flask应用中,日志文件能够按照指定的策略进行日期分割轮转,同时处理多进程的写入问题。
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

往事如yan

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值