通常在运行代码时,我们往往需要使用logging模块记录代码在运行过程中的一些信息作为日志,方便在代码运行完成后进行判断和检查。但是如果将所有级别(python 日志处理 logging模块 使用 详细解析 整理 参考文档_logging.info-CSDN博客)的日志都写在一个文件中,往往会使得日志文件大小庞大,及时使用日志分割(python 日志处理 logging模块 日志切分_logging 文件分割-CSDN博客)也会因为无法区分正常级别日志和错误级别日志从而给调试代码、定问问题带来麻烦。因此,为了方便快速的定位错误信息及其问题,需要将错误及以上级别的日志输出单独记录到新的日志文件进行区分。
代码功能:
提供日志记录的工具类代码,可直接调用 HandleLog 记录全部五种级别的日志。在添加日志时,正常使用对应五种级别的函数,这些日志将被记录到两个文件中,一个文件为all.log,保存所有的日志信息,另一个为error.log,仅保存错误及以上等级的日志信息,便于调试。
代码初始化设置说明:
- 日志文件保存位置:代码所在文件的同级目录下的logs文件夹下,即“ ./logs ”
- 保存全部日志的日志文件名为:
[日志名称] 日期-all.log 例如:“ test 2020-01-01-all.log ”
- 保存错误及致命等级日志的日志文件名为:
[日志名称] 日期-error.log 例如:“ test 2020-01-01-error.log ”
- 日志的记录格式为:“ 2021-03-11 14:43:01,389 - root - HandleLog.py - [line:132] - INFO - [日志信息]: 程序启动 ”(示例)
- 文件超过1M大小时,切割日志文件,日志不会回滚
- error和critical等级的日志在记录用户传入的message信息之外还会将程序当前的堆栈信息作为日志进行记录,即:
exc_info=True, stack_info=True
- 代码除了将日志输出到文件中,还会在屏幕(console)上打印输出日志信息
所有的参数配置可在代码中进行修改,对应位置均有注释说明。
源码实现:
#!/usr/bin/env python
# encoding: utf-8
'''
@Author : Dylan
@License : (C) Copyright 2015-2021.
@Contact : @bupt.edu.cn
@Software : PyCharm
@File : HandleLog.py
@Time : 2021/3/11 13:30
@Description:
'''
import logging
import os
import colorlog
from logging.handlers import RotatingFileHandler
from datetime import datetime
# 配置日志文件名称及路径
cur_path = os.path.dirname(os.path.realpath(__file__)) # 当前项目路径
log_path = os.path.join(cur_path, 'logs') # log_path为存放日志的路径
if not os.path.exists(log_path): os.mkdir(log_path) # 若不存在logs文件夹,则自动创建
log_colors_config = {
# 终端输出日志颜色配置
'DEBUG': 'white',
'INFO': 'cyan',
'WARNING': 'yellow',
'ERROR': 'red',
'CRITICAL': 'bold_red',
}
default_formats = {
# 终端输出格式
'color_format': '%(log_color)s%(asctime)s-%(name)s-%(filename)s-[line:%(lineno)d]-%(levelname)s-[日志信息]: %(message)s',
# 日志输出格式
'log_format': '%(asctime)s - %(name)s - %(filename)s - [line:%(lineno)d] - %(levelname)s - [日志信息]: %(message)s'
}
class HandleLog():
"""
先创建日志记录器(logging.getLogger),然后再设置日志级别(logger.setLevel),
接着再创建日志文件,也就是日志保存的地方(logging.FileHandler),然后再设置日志格式(logging.Formatter),
最后再将日志处理程序记录到记录器(addHandler)
"""
def __init__(self, log_name):
self.__now_time = datetime.now().strftime('%Y-%m-%d') # 当前日期格式化
# 收集所有日志文件,名称为:[日志名称] 2020-01-01-all.log;收集错误日志信息文件,名称为:[日志名称] 2020-01-01-error.log
# 其中,[日志名称]为调用日志时的传入参数
self.__all_log_path = os.path.join(log_path, log_name + " " + self.__now_time + "-all" + ".log") # 收集所有日志信息文件
self.__error_log_path = os.path.join(log_path, log_name + " " + self.__now_time + "-error" + ".log") # 收集错误日志信息文件
# 配置日志记录器及其级别 设置默认日志记录器记录级别为DEBUG
self.__logger = logging.getLogger() # 创建日志记录器
self.__logger.setLevel(logging.DEBUG) # 设置默认日志记录器记录级别
@staticmethod
def __init_logger_handler(log_path):
"""
创建日志记录器handler,用于收集日志
:param log_path: 日志文件路径
:return: 日志记录器
"""
# 写入文件,如果文件超过1M大小时,切割日志文件
logger_handler = RotatingFileHandler(filename=log_path, maxBytes=1 * 1024 * 1024, encoding='utf-8') # 可以设置 backupCount=3 在切割日志文件后仅保留3个文件
return logger_handler
@staticmethod
def __init_console_handle():
"""创建终端日志记录器handler,用于输出到控制台"""
console_handle = colorlog.StreamHandler()
return console_handle
def __set_log_handler(self, logger_handler, level=logging.DEBUG):
"""
设置handler级别并添加到logger收集器
:param logger_handler: 日志记录器
:param level: 日志记录器级别
"""
logger_handler.setLevel(level=level)
self.__logger.addHandler(logger_handler) # 添加到logger收集器
def __set_color_handle(self, console_handle):
"""
设置handler级别并添加到终端logger收集器
:param console_handle: 终端日志记录器
:param level: 日志记录器级别
"""
console_handle.setLevel(logging.DEBUG)
self.__logger.addHandler(console_handle)
@staticmethod
def __set_color_formatter(console_handle, color_config):
"""
设置输出格式-控制台
:param console_handle: 终端日志记录器
:param color_config: 控制台打印颜色配置信息
:return:
"""
formatter = colorlog.ColoredFormatter(default_formats["color_format"], log_colors=color_config)
console_handle.setFormatter(formatter)
@staticmethod
def __set_log_formatter(file_handler):
"""
设置日志输出格式-日志文件
:param file_handler: 日志记录器
"""
formatter = logging.Formatter(default_formats["log_format"], datefmt='') # datefmt用于设置asctime的格式,例如:%a, %d %b %Y %H:%M:%S 或者 %Y-%m-%d %H:%M:%S
file_handler.setFormatter(formatter)
@staticmethod
def __close_handler(file_handler):
"""
关闭handler
:param file_handler: 日志记录器
"""
file_handler.close()
def __console(self, level, message):
"""构造日志收集器"""
# 创建日志文件
all_logger_handler = self.__init_logger_handler(self.__all_log_path) # 收集所有日志文件
error_logger_handler = self.__init_logger_handler(self.__error_log_path) # 收集错误日志信息文件
console_handle = self.__init_console_handle()
# 设置日志文件格式
self.__set_log_formatter(all_logger_handler)
self.__set_log_formatter(error_logger_handler)
self.__set_color_formatter(console_handle, log_colors_config)
self.__set_log_handler(all_logger_handler) # 设置handler级别并添加到logger收集器
self.__set_log_handler(error_logger_handler, level=logging.ERROR)
self.__set_color_handle(console_handle)
if level == 'info':
self.__logger.info(message)
elif level == 'debug':
self.__logger.debug(message)
elif level == 'warning':
self.__logger.warning(message)
elif level == 'error':
self.__logger.error(message, exc_info=True, stack_info=True) # exc_info=True, stack_info=True 用于在日志中记录堆栈信息,方便查看日志进行调试
elif level == 'critical':
self.__logger.critical(message, exc_info=True, stack_info=True) # exc_info=True, stack_info=True 用于在日志中记录堆栈信息,方便查看日志进行调试
self.__logger.removeHandler(all_logger_handler) # 避免日志输出重复问题
self.__logger.removeHandler(error_logger_handler)
self.__logger.removeHandler(console_handle)
self.__close_handler(all_logger_handler) # 关闭handler
self.__close_handler(error_logger_handler)
def debug(self, message):
self.__console('debug', message)
def info(self, message):
self.__console('info', message)
def warning(self, message):
self.__console('warning', message)
def error(self, message):
self.__console('error', message)
def critical(self, message):
self.__console('critical', message)
if __name__ == '__main__':
log = HandleLog(os.path.split(__file__)[-1].split(".")[0])
log.info("这是日志信息")
log.debug("这是debug信息")
log.warning("这是警告信息")
log.error("这是错误日志信息")
log.critical("这是严重级别信息")
说明:
1.在相同代码文件中调用时,方式为:
log = HandleLog(os.path.split(__file__)[-1].split(".")[0])
log.info("这是日志信息")
log.debug("这是debug信息")
log.warning("这是警告信息")
log.error("这是错误日志信息")
log.critical("这是严重级别信息")
在其他文件中调用时,方式为:
import HandleLog
log = HandleLog.HandleLog(os.path.split(__file__)[-1].split(".")[0])
log.info("这是日志信息")
log.debug("这是debug信息")
log.warning("这是警告信息")
log.error("这是错误日志信息")
log.critical("这是严重级别信息")
其中,os.path.split(__file__)[-1].split(".")[0]为当前文件的文件名(不懂请看:python 获取当前 代码 脚本 文件 文件名_python程序如何获取自己py程序名称-CSDN博客),也可以改为其他值。
代码调用可能会影响日志文件的保存位置!
2.使用时,info 、 debug 、 warning 、 error 、 critical五个函数只能使用小写,且输入参数唯一(即要记录的message信息)。
3.使用代码除了python自带的 logging 库,还需要安装 colorlog 库,用于在屏幕输出带颜色的日志信息,分别用不同颜色区分不同等级的日志。
代码如有疑问或讨论交流,可在评论区留言哦!
参考教程:
https://www.cnblogs.com/xyztank/articles/13599302.html
https://www.cnblogs.com/yanjieli/p/10179626.html
https://blog.csdn.net/qq_35556064/article/details/103995651
https://blog.csdn.net/weixin_30254435/article/details/96173364