python按照日志等级将日志输出至不同的日志文件

将日志按照等级分别保存在不同的文件中,并在控制台同步输出。

import os
import sys
import logging
from logs.multiprocessloghandler import MultiprocessHandler


def loggerDefine(platform, log_name):
    base_dir = "F:\PythonProject\\xiao_new_resources\logs"

    info_dir_path = base_dir + "\\info\\{}".format(platform)
    error_dir_path = base_dir + "\\error\\{}".format(platform)

    # 判断响应的文件是否存在
    if not os.path.exists(info_dir_path):
        os.makedirs(info_dir_path)
    info_dir = os.path.join(info_dir_path, log_name)

    if not os.path.exists(error_dir_path):
        os.makedirs(error_dir_path)
    error_dir = os.path.join(error_dir_path, log_name)

    # 返回一个logger对象,如果没有指定名字将返回root logger
    log = logging.getLogger('test')

    # 定义日志输出格式
    formattler = '%(asctime)s|%(processName)s|%(threadName)s|%(levelname)s|%(filename)s:%(lineno)d|%(funcName)s|%(message)s'
    fmt = logging.Formatter(formattler)

    # 设置日志控制台输出
    stream_handler = logging.StreamHandler(sys.stdout)
    stream_handler.setLevel(logging.INFO)

    # 设置控制台文件输出
    log_handler_info = MultiprocessHandler(info_dir)
    log_handler_err = MultiprocessHandler(error_dir)

    # 设置日志输出格式:
    stream_handler.setFormatter(fmt)
    log_handler_info.setFormatter(fmt)
    log_handler_err.setFormatter(fmt)

    # 设置过滤条件
    info_filter = logging.Filter()
    info_filter.filter = lambda record: record.levelno < logging.WARNING  # 设置过滤等级
    err_filter = logging.Filter()
    err_filter.filter = lambda record: record.levelno >= logging.WARNING

    # 对文件输出日志添加过滤条件
    log_handler_info.addFilter(info_filter)
    log_handler_err.addFilter(err_filter)

    # 对logger增加handler日志处理器
    log.addHandler(log_handler_info)
    log.addHandler(log_handler_err)
    log.addHandler(stream_handler)

    log.setLevel("INFO")
    return log


if __name__ == '__main__':
    logg = loggerDefine("youtube", "youtube.log")
    logg.info("info")
    logg.warning("warning")
    logg.error("error")

multiprocessloghandler源码:

import datetime
import logging
import os
import re

try:
    import codecs
except ImportError:
    codecs = None


class MultiprocessHandler(logging.FileHandler):
    """支持多进程的TimedRotatingFileHandler"""

    def __init__(self, filename, when='D', backupCount=7, encoding="utf-8", delay=False):
        """
        filename 日志文件名,when 时间间隔的单位,backupCount 保留文件个数
        delay 是否开启 OutSteam缓存
        True 表示开启缓存,OutStream输出到缓存,待缓存区满后,刷新缓存区,并输出缓存数据到文件。
        False表示不缓存,OutStrea直接输出到文件
        """
        self.prefix = filename
        self.backupCount = backupCount
        self.when = when.upper()
        # 正则匹配 年--日
        # 正则写到这里就对了
        self.extMath = r"\d{4}-\d{2}-\d{2}"

        # S 每秒建立一个新文件
        # M 每分钟建立一个新文件
        # H 每天建立一个新文件
        # D 每天建立一个新文件
        self.when_dict = {
            'S': "%Y-%m-%d-%H-%M-%S",
            'M': "%Y-%m-%d-%H-%M",
            'H': "%Y-%m-%d-%H",
            'D': "%Y-%m-%d"
        }
        # 日志文件日期后缀
        self.suffix = self.when_dict.get(when)
        # 源码中self.extMath写在这里
        # 这个正则匹配不应该写到这里,不然非D模式下 会造成 self.extMath属性不存在的问题
        # 不管是什么模式都是按照这个正则来搜索日志文件的。
        # if self.when == 'D':
        #    正则匹配 年--日
        #    self.extMath = r"^\d{4}-\d{2}-\d{2}"
        if not self.suffix:
            raise ValueError(u"指定的日期间隔单位无效: %s" % self.when)
        # 拼接文件路径 格式化字符串
        self.filefmt = os.path.join(os.getcwd(), "%s.%s" % (self.prefix, self.suffix))
        a = "%s.%s" % (self.prefix, self.suffix)
        # 使用当前时间,格式化文件格式化字符串
        self.filePath = datetime.datetime.now().strftime(self.filefmt)
        # 获得文件夹路径
        _dir = os.path.dirname(self.filefmt)
        try:
            # 如果日志文件夹不存在,则创建文件夹
            if not os.path.exists(_dir):
                os.makedirs(_dir)
        except Exception:
            print("创建文件夹失败")
            print("文件夹路径:" + self.filePath)
            pass
        if codecs is None:
            encoding = None
            # 调用FileHandler
        logging.FileHandler.__init__(self, self.filePath, 'a+', encoding, delay)

    def shouldChangeFileToWrite(self):
        """更改日志写入目的写入文件
        return True 表示已更改,False 表示未更改"""
        # 以当前时间获得新日志文件路径
        _filePath = datetime.datetime.now().strftime(self.filefmt)
        # 新日志文件日期 不等于 旧日志文件日期,则表示 已经到了日志切分的时候
        #   更换日志写入目的为新日志文件。
        # 例如 按 天 (D)来切分日志
        #   当前新日志日期等于旧日志日期,则表示在同一天内,还不到日志切分的时候
        #   当前新日志日期不等于旧日志日期,则表示不在
        # 同一天内,进行日志切分,将日志内容写入新日志内。
        if _filePath != self.filePath:
            self.filePath = _filePath
            return True
        return False

    def doChangeFile(self):
        """输出信息到日志文件,并删除多于保留个数的所有日志文件"""
        # 日志文件的绝对路径
        self.baseFilename = os.path.abspath(self.filePath)
        # stream == OutStream
        # stream is not None 表示 OutStream中还有未输出完的缓存数据
        if self.stream:
            # self.stream.flush()
            self.stream.close()
            self.stream = None
        # delay 为False 表示 不OutStream不缓存数据 直接输出
        #   所有,只需要关闭OutStream即可
        if not self.delay:
            # self.stream.close()
            self.stream = self._open()

        # 删除多于保留个数的所有日志文件
        if self.backupCount > 0:
            for s in self.getFilesToDelete():
                # print s
                os.remove(s)

    def getFilesToDelete(self):
        """获得过期需要删除的日志文件"""
        # 分离出日志文件夹绝对路径
        # split返回一个元组(absFilePath,fileName)
        # 例如:split('I:\ScripPython\char4\mybook\util\logs\mylog.2017-03-19)
        # 返回(I:\ScripPython\char4\mybook\util\logs, mylog.2017-03-19)
        # _ 表示占位符,没什么实际意义,
        dirName, _ = os.path.split(self.baseFilename)
        fileNames = os.listdir(dirName)
        result = []
        # self.prefix 为日志文件名 列如:mylog.2017-03-19 中的 mylog
        # 加上 点号 . 方便获取点号后面的日期
        prefix = self.prefix
        prefix = _.rsplit(".", 1)[0] + "."
        plen = len(prefix)
        for fileName in fileNames:
            if fileName[:plen] == prefix:
                # 日期后缀 mylog.2017-03-19 中的 2017-03-19
                suffix = fileName[plen:]
                # 匹配符合规则的日志文件,添加到result列表中
                if re.compile(self.extMath).match(suffix):
                    result.append(os.path.join(dirName, fileName))
        result.sort()

        # 返回  待删除的日志文件
        #   多于 保留文件个数 backupCount的所有前面的日志文件。
        if len(result) < self.backupCount:
            result = []
        else:
            result = result[:len(result) - self.backupCount]
        return result


    def emit(self, record):
        """发送一个日志记录
        覆盖FileHandler中的emit方法,logging会自动调用此方法"""
        try:
            if self.shouldChangeFileToWrite():
                self.doChangeFile()
            logging.FileHandler.emit(self, record)
        except (KeyboardInterrupt, SystemExit):
            raise
        except:
            self.handleError(record)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值