Python 使用logging模块,让日志文件按日期路径保存,按时间滚动切分

因为工作需要,要求写一个能够按日期路径保存,按时间滚动切分的日志方法。所以重写了logging模块中TimedRotatingFileHandler的doRollover方法(实际上只是改了改前人的代码)。

完整代码如下:logUtil.py。

import logging
import os
import datetime
import time
from logging.handlers import TimedRotatingFileHandler

gl_baseDir = ''


class TimeLoggerRolloverHandler(TimedRotatingFileHandler):
    def __init__(self, filename, when='h', interval=1, backupCount=0, encoding=None, delay=False, utc=False,
                 atTime=None):
        super(TimeLoggerRolloverHandler, self).__init__(filename, when, interval, backupCount, encoding, delay, utc, atTime)

    def doRollover(self):
        """
        TimedRotatingFileHandler对日志的切分是在满足设定的时间间隔后,执行doRollover方法,
        将my.log重命名为带有当前时间后缀(my.log.****)的文件,并新建一个my.log,继续记录后续日志。
        (1) 重写TimedRotatingFileHandler的doRollover方法的文件翻转块代码
        做了以下两点改动:
            重定义了新文件名,将日期放在了中间而不是最后
            直接将将baseFilename 指向新文件
        """
        if self.stream:
            self.stream.close()
            self.stream = None
        currentTime = int(time.time())
        dstNow = time.localtime(currentTime)[-1]

        # 重新定义了新文件名
        global gl_baseDir
        _, base_name = os.path.split(self.baseFilename)
        base_name = base_name.split('_')[0]  # 这里要求文件名前缀不能有下滑线
        print(f'baseFilename: {self.baseFilename}')
        print(f'base_name:{base_name}')
        datetime_now = datetime.datetime.now().strftime('%Y-%m-%d_%H:%M:%S').split('_')
        date_now = datetime_now[0]
        time_now = datetime_now[1]
        log_dir = f'{gl_baseDir}/{date_now}_{time_now}'
        if not os.path.exists(log_dir):
            os.makedirs(log_dir, exist_ok=True)
        dfn = f"{log_dir}/{base_name}_{date_now}_{time_now}.log"
        if os.path.exists(dfn):
            os.remove(dfn)
        self.baseFilename = dfn
        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(project_name, log_file_name, when='H', interval=1):
    global gl_baseDir
    gl_baseDir = f"./log_{project_name}"
    datetime_now = datetime.datetime.now().strftime('%Y-%m-%d_%H:%M:%S').split('_')
    date_now = datetime_now[0]
    time_now = datetime_now[1]
    log_dir = f'{gl_baseDir}/{date_now}'
    if not os.path.exists(log_dir):
        os.makedirs(log_dir, exist_ok=True)
    log_file = f"{log_dir}/{log_file_name}_{date_now}_{time_now}.log"

    logger = logging.getLogger('log')  # 创建日志收集器
    logger.setLevel(logging.DEBUG)  # 定义收集级别,低于该级别将被过滤,DEBUG是最低级别

    console_handler = logging.StreamHandler()  # 输出到控制台
    save_handler = TimeLoggerRolloverHandler(log_file, when=when, interval=interval)  # 输出到文件

    console_handler.setLevel(logging.DEBUG)  # 定义控制台输出级别
    save_handler.setLevel(logging.DEBUG)  # 定义文件输出级别

    formatter = logging.Formatter('%(asctime)s-%(levelname)s-%(filename)s-%(module)s-'
                                  '%(funcName)s-%(lineno)s-%(message)s')  # 指定输出格式
    console_handler.setFormatter(formatter)  # 规定日志输出的时候按照formatter格式来打印
    save_handler.setFormatter(formatter)

    logger.addHandler(console_handler)  # 对接,添加输出控制台渠道
    logger.addHandler(save_handler)  # 对接,添加输出文件渠道

    return logger


if __name__ == "__main__":
    my_logger = get_logger("project_name", "log_filename", when='S', interval=1)
    for i in range(10):
        my_logger.error('111')
        time.sleep(1)

如果想要日志方法跨文件全局调用的话,可以创建一个公用的py文件,事先初始化log方法,以后直接从这个文件调用相关方法。
commonObj.py

import logUtil
import os

gl_log = None


def init_log():
    global gl_log
    log_path = 'L0send_log'
    gl_log = logUtil.get_logger(log_path, 'L0send', when='s', interval=1)
    return gl_log


def get_log():
    global gl_log
    return gl_log

main.py

from commonObj import init_log
import time
log = init_log()
for i in range(5):
    log.debug('1')
    log.info('1')
    log.warning('1')
    log.error('1')
    time.sleep(1)

t.py

from commonObj import get_log
import time


def test():
    log = get_log()
    test1 = 'test log'
    print('test log')
    for i in range(5):
        log.debug(test1)
        log.info(test1)
        log.warning(test1)
        log.error(test1)
        time.sleep(1)

参考链接:
python的logging模块使用,以及日志文件按日期路径保存,按时间滚动切分

  • 11
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值