Python中利用logger进行日志格式输出

本文主要是针对python程序员小白在写项目代码时的焦虑:什么时候打印日志?日志打印格式是什么样的?打印日志怎么存?等等这些问题都是刚开始需要考虑的。

本文就这些问题设计了一个python项目的目录结构,大致常用的目录如下:

其中logs文件夹是专门存储日志文件的,对日志文件的输出要求是:
1. logs文件夹下包括三种类型:log.log、error.log、历史日志文件夹。其中log.log是当前程序运行输出的所有日志(包括warnings),error.log是当前程序运行输出的所有错误日志。结构如下:

2. 要求每次重新执行程序都会生成新的log.log和error.log,之前的相应日志文件按照日期存储到对应日期文件夹下,要求一天存储一个日志文件(除非日志文件超过最大限制)
 

完整的项目已经放到github上,需要的可以自由下载,地址是(https://github.com/Trisyp/logger)。

下面附上部分代码做解释:

首先是logger模块:

class Log(metaclass=SingletonType):
    def __init__(self):
        # 文件的命名
        self.info_log_name = os.path.join(log_path, 'log') + '.log'
        self.error_log_name = os.path.join(log_path, 'error') + '.log'
        self.logger = logging.getLogger()

        # 设置日志级别,其中log_level提前在config文件夹下配置好
        if log_level == "DEBUG":
            self.logger.setLevel(logging.DEBUG)
        elif log_level == "CRITICAL":
            self.logger.setLevel(logging.CRITICAL)
        elif log_level == "WARNING":
            self.logger.setLevel(logging.WARNING)
        else:
            self.logger.setLevel(logging.INFO)

        # 日志输出格式(这里主要打印的是:时间-线程id-进程id-级别名称-日志消息)
        self.formatter = logging.Formatter('[%(asctime)s] - thread_id:%(thread)d - process_id:%(process)d - %(levelname)s: %(message)s')

    def __console(self, level, log_name, message, Handler_flag=True):
        # 创建一个FileHandler,用于写到本地
        os.makedirs(log_path, exist_ok=True)
        fh = logging.FileHandler(log_name, 'a')  # 追加模式
        fh.setLevel(logging.DEBUG)
        fh.setFormatter(self.formatter)
        self.logger.addHandler(fh)

        # 创建一个StreamHandler,用于输出到控制台
        ch = logging.StreamHandler()
        ch.setLevel(logging.DEBUG)
        ch.setFormatter(self.formatter)
        self.logger.addHandler(ch)

        # 根据日志等级来打印日志内容
        if level == 'info':
            self.logger.info(message)
        elif level == 'debug':
            self.logger.debug(message)
        elif level == 'warning':
            self.logger.warning(message)
        elif level == 'error':
            if not Handler_flag:
                self.logger.removeHandler(ch)
                ch.close()
            self.logger.error(message)
        # 这两行代码是为了避免日志输出重复问题
        self.logger.removeHandler(ch)
        self.logger.removeHandler(fh)
        # 关闭打开的文件
        fh.close()
        ch.close()

    def debug(self, message):
        self.__console('debug', self.info_log_name, message, True)

    def info(self, message):
        self.__console('info', self.info_log_name, message, True)

    def warning(self, message):
        self.__console('warning', self.info_log_name, message, True)

    def error(self, message):
        self.__console('error', self.info_log_name, message, True)
        self.__console('error', self.error_log_name, message, False)

然后是logger模块下的存储格式设置模块log_subarea:

def merge_logs(file_path, new_file):  # 将历史日志文件合并到一个文件里
    k = open(new_file, 'a+')
    f = open(file_path)
    k.write(f.read()+"\n")  # 换行拼接到后面
    k.close()


def log_to_folder(from_path, file_name, file_type=".log"):
    from_path = Path(from_path)
    folder = Path(from_path)
    cnt = 1
    src_file = from_path / (file_name + file_type)  # 先查看是否有已存在日志文件
    # src_file = Path(src_file)
    if src_file.exists():
        file_date = datetime.datetime.fromtimestamp(os.stat(src_file).st_mtime).date()  # 获取日志文件生成日期
        folder = folder / str(file_date)  
        os.makedirs(folder, exist_ok=True)  # 创建日期文件夹
        shutil.move(str(src_file), str(folder))  # 将文件移动到对应日期文件夹
        src_file2 = folder / (file_name + file_type)
        
        # 若文件大小超过最大值则新建文件进行存储
        new_name = file_name+str(file_date)  
        new_file = Path(f"{folder}/{new_name}-{cnt}" + file_type)
        if src_file2.exists():
            if new_file.exists():
                while os.path.getsize(new_file)/float(1024**2) > max_log_size:
                    cnt += 1
                    new_file = Path(f"{new_name}-{cnt}" + file_type)
                merge_logs(src_file2, new_file)
                os.remove(src_file2)
            else:
                merge_logs(src_file2, new_file)
                os.remove(src_file2)

最后以python读取json文件为例来打印日志:

def read_txt_file(file_name):
    log_to_folder(f"{root_dir}/logs", "log")  # 判断是否存在日志文件存在的话就移动到对应日期文件夹下
    log_to_folder(f"{root_dir}/logs", "error")
    try:
        with open(file_name, encoding="UTF-8") as file:
            js_data = json.load(file)
        log.info("json data has read successfully")  # info级别日志
    except Exception as e:
        log.error(e.__str__())  # erro级别日志
    return js_data

输出日志文件的内容效果如下:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Trisyp

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

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

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

打赏作者

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

抵扣说明:

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

余额充值