python之日志模板

1、什么是日志

日志是一种可以追踪某些软件运行时所发生事件的方法,可以在程序的关键部分调用日志记录程序运行的状态与结果。

在Python中打印功能只能在控制台显示,某个节点的数据无法保存在文件中。当一个程序上线之后,我们需要记录用户的一些相关操作,和程序的运行状态,重要信息的打印,后期的查询与数据分析,日志记录就非常重要了。

日志的主要功能:

  • 程序调试
  • 用户操作行为记录
  • 程序运行故障分析与问题定位

 

2、日志级别

由于日志消息的重要性的不同,方面信息的查询与快速定位,日志信息的保存分成不同的等级,根据等级的不同,我们可以把日志保存到不同的文件中

日志级别:DEBUG < INFO < WARNING < ERROR < CRITICAL

日志等级(level)描述
DEBUG 最详细的日志信息,典型应用场景是 问题诊断,用于记录不重要的信息
INFO 通常只记录关键节点信息,用于确认一切都是按照我们预期的那样进行工作,操作行为记录,重要信息打印
WARNING 当某些不期望的事情发生时记录的信息,但是此时应用程序还是正常运行的
ERROR 由于一个更严重的问题导致某些功能不能正常运行时记录的信息
CRITICAL 当发生严重错误,导致应用程序不能继续运行时记录的信息

开发应用程序或部署开发环境时,可以使用DEBUG或INFO级别的日志获取尽可能详细的日志信息来进行开发或部署调试;应用上线或部署生产环境时,应该使用WARNING或ERROR或CRITICAL级别的日志来降低机器的I/O压力和提高获取错误日志信息的效率。

 

3、日志模块logging的使用

3.1 logging模块的级别:

#默认级别是WARNING ,低于这个级别的信息不打印,可以设置,level=10 
#或 level=logging.DEBUG (日志的级别需要大写)
CRITICAL = 50 #FATAL = CRITICAL
ERROR = 40
WARNING = 30 #WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0 #不设置

 

3.2日志模块的高级配置

logger

产生日志的对象
Filter 过滤日志的对象
Handler 接收日志然后控制打印到不同的地方,FileHandler用来打印到文件中,StreamHandler用来打印到终端
Formatter 可以定制不同的日志格式对象,然后绑定给不同的Handler对象使用,以此来控制不同的Handler的日志格式

 

 3.3 日志配置文件的使用,直接使用模板就行

使用时候:你可以自己配置相关参数,在其他模块中,直接导入load_logger使用

# -*- coding: utf-8 -*-
# @Time : 2021/7/28 15:34
# @Author : March
# @File : config.py

#配置日志文件
"""
logging配置
"""

import os
import time
import logging.config
# 1、定义三种日志输出格式,日志中可能用到的格式化串如下
# %(name)s Logger的名字   getLogger('name') 默认__name__  或者空值。区分日志种类
# %(levelno)s 数字形式的日志级别
# %(levelname)s 文本形式的日志级别,推荐使用
# %(pathname)s 调用日志输出函数的模块的完整路径名,可能没有
# %(filename)s 调用日志输出函数的模块的文件名
# %(module)s 调用日志输出函数的模块名
# %(funcName)s 调用日志输出函数的函数名
# %(lineno)d 调用日志输出函数的语句所在的代码行
# %(created)f 当前时间,用UNIX标准的表示时间的浮 点数表示
# %(relativeCreated)d 输出日志信息时的,自Logger创建以 来的毫秒数
# %(asctime)s 字符串形式的当前时间。默认格式是 “2003-07-08 16:49:45,896”。逗号后面的是毫秒
# %(thread)d 线程ID。可能没有
# %(threadName)s 线程名。可能没有
# %(process)d 进程ID。可能没有
# %(message)s用户输出的消息

# 2、强调:其中的%(name)s为getlogger时指定的名字,一行太长了,可以加\换行
#这个格式是我常用的格式,需要的话可以自己设定
standard_format = '[%(asctime)s:%(levelname)s:task_id:%(name)s in %(filename)s:%(pathname)s:%(lineno)d]' \
                  '>>>:%(message)s'
#[2021-09-14 23:31:45,667:INFO:task_id:root in 日志模块测试.py:E:/pythonweb/python_study/日志模块测试.py:131]>>>:日志文件启动

simple_format = '[%(levelname)s][%(asctime)s][%(filename)s:%(lineno)d]%(message)s'
#[INFO][2021-09-14 23:31:45,667][日志模块测试.py:131]日志文件启动

error_format = '%(asctime)s %(levelname)s: %(message)s [in %(pathname)s:%(lineno)d]'
#2021-09-14 23:31:45,669 ERROR: 我这里保存了错误信息 [in E:/pythonweb/python_study/日志模块测试.py:136]

#设置日志文件
logfile_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))  #项目的更目录
#这里设置了两个日志文件,一个用于保存正常的数据,一个记录程序错误数据记录
logfile_name =time.strftime('%Y-%m-%d')+'_info.log'
logfile_error =time.strftime('%Y-%m-%d')+'_error.log'

# log文件的路径
logfile_path = os.path.join(logfile_dir, 'log',logfile_name)
error_logfile_path = os.path.join(logfile_dir, 'log',logfile_error)

# 如果不存在定义的日志目录就创建一个
if not os.path.isdir(os.path.join(logfile_dir, 'log')):
    os.mkdir(os.path.join(logfile_dir, 'log'))

# 3、日志配置字典
LOGGING_DIC = {
    #默认设置
    'version': 1,
    'disable_existing_loggers': False,
    #日志信息的格式
    #standard,simple,error可改,需要与handlers中的formatter对应,formatters,format关键字无法修改
    'formatters': {
        'standard': {
            'format': standard_format
        },
        'simple': {
            'format': simple_format
        },
        'error': {
            'format': error_format
        },
    },
    #暂时不需要
    'filters': {},
    #日志的接受者,根据不同的配置,保存文件到不同的位置
    'handlers': {
        #console,default,error关键字可以自己修改,需要与logger中的handlers对应
        #打印到终端的日志
        'console': {
            'level': 'DEBUG', #日志的级别
            'class': 'logging.StreamHandler',  # 打印到屏幕
            'formatter': 'simple'#需要的日志格式
        },
        #打印到文件的日志,收集info及以上的日志
        'default': {
            'level': 'DEBUG',
            'class': 'logging.handlers.RotatingFileHandler',  # 保存到文件,日志轮转
            'formatter': 'standard',
            # 可以定制日志文件路径
            'filename': logfile_path,  # 日志文件
            'maxBytes': 1024*1024*100,  # 日志大小 文件最大为100M,超过之后会分割文件
            'backupCount': 15,  #文件最多保留15个
            'encoding': 'utf-8',  # 日志文件的编码,再也不用担心中文log乱码了
        },
        #只保存出现错误及以上的日志,数据很少
        'error': {
            'level': 'ERROR',
            'class': 'logging.FileHandler',  # 保存到文件,没有分割文件的功能
            'formatter': 'error',
            'filename': error_logfile_path,
            'encoding': 'utf-8',
        },
    },
    #日志的生产者
    'loggers': {
        #logging.getLogger(__name__)拿到的logger配置,
        #空的指定对象,在不指定的情况下,默认使用该对象中的handlers
        '': {
            'handlers': ['default', 'console'],  # 这里把上面定义的两个handler都加上,即log数据既写入文件又打印到屏幕
            'level': 'DEBUG', # loggers(第一层日志级别关限制)--->handlers(第二层日志级别关卡限制)
            'propagate': False,  # 默认为True,向上(更高level的logger)传递,通常设置为False即可,否则会一份日志向上层层传递
        },
        'error': {
            'handlers': ['error',],
            'level': 'DEBUG',  #可以使用数字10
            'propagate': False,
        },
    },
}

#调用日志对象
def load_logger(logger_name=''):    #传入一个日志的类型,名称为loggers中的,如果没有默认''
    logging.config.dictConfig(LOGGING_DIC)  # 导入上面定义的logging配置
    #logger_name可以设置为执行文件名,当不存在的时候默认都是使用''loggers对象
    logger = logging.getLogger(logger_name)  # 生成一个log实例变量对应日志配置中的%(name)s
    return logger  #返回一个日志对象,可以直接调用


# load_my_logging_cfg()
if __name__ == '__main__':
    logger=load_logger()  #该函数返回一个对象
    logger.info('日志文件启动')
    logger.info('由于我没有传logger的名字,或者传了一个不存在的,所以我使用默认空的配置')

    #由于error名称的logger存在,所以会直接调用error对应的相关配置
    error_logger = load_logger('error')
    error_logger.error('我这里保存了错误信息')   #只能保存error上的级别

 修改成类使用的方式:

"""
 #配置日志文件
 """
# 日志文件不存在,创建
if not os.path.isdir(os.path.join(os.path.dirname(os.path.abspath(__file__)), 'logs')):
    os.mkdir(os.path.join(os.path.dirname(os.path.abspath(__file__)), 'logs'))

class Logger():

    standard_format = '[%(asctime)s:%(levelname)s:task_id:%(name)s in %(filename)s:%(pathname)s:%(lineno)d]' \
                      '>>>:%(message)s'
    simple_format = '[%(levelname)s][%(asctime)s][%(filename)s:%(lineno)d]%(message)s'

    error_format = '%(asctime)s %(levelname)s: %(message)s [in %(pathname)s:%(lineno)d]'

    # log文件的全路径
    logfile_dir = os.path.dirname(os.path.abspath(__file__))  # logs文件的目录
    logfile_path = os.path.join(logfile_dir, 'logs', 'info.log')
    error_logfile_path = os.path.join(logfile_dir, 'logs', 'error.log')

    logging_dic = {
        'version': 1,
        'disable_existing_loggers': False,
        'formatters': {
            'standard': {
                'format': standard_format
            },
            'simple': {
                'format': simple_format
            },
            'error': {
                'format': error_format
            },
        },
        'filters': {},
        # 日志的执行者
        'handlers': {
            # 打印到终端的日志
            'console': {
                'level': 'DEBUG',
                'class': 'logging.StreamHandler',  # 打印到屏幕
                'formatter': 'simple'
            },
            # 打印到文件的日志,收集info及以上的日志
            'default': {
                'level': 'DEBUG',
                'class': 'logging.handlers.RotatingFileHandler',  # 保存到文件,日志轮转
                'formatter': 'standard',
                'filename': logfile_path,  # 日志文件
                'maxBytes': 1024 * 1024 * 20,  # 日志大小 5M
                'backupCount': 15,
                'encoding': 'utf-8',  # 日志文件的编码,再也不用担心中文log乱码了
            },
            # 只保存出现错误及以上的日志
            'error': {
                'level': 'ERROR',
                'class': 'logging.FileHandler',  # 保存到文件,没有分割文件的功能
                'formatter': 'error',
                'filename': error_logfile_path,
                'encoding': 'utf-8',
            },
        },
        # 日志的生产者
        'loggers': {
            # logging.getLogger(__name__)拿到的logger配置,
            # 空的指定对象,在不指定的情况下,默认使用该对象中的handlers
            '': {
                'handlers': ['default', 'console'],  # 这里把上面定义的两个handler都加上,即log数据既写入文件又打印到屏幕
                'level': 'INFO',  # loggers(第一层日志级别关限制)--->handlers(第二层日志级别关卡限制)
                'propagate': False,  # 默认为True,向上(更高level的logger)传递,通常设置为False即可,否则会一份日志向上层层传递
            },
            'error': {
                'handlers': ['error', ],
                'level': 'DEBUG',
                'propagate': False,
            },
        },
    }

    #调用日志对象
    @classmethod
    def load_logger(cls,logger_name=None):    #传入一个日志的类型,名称为loggers中的,如果没有默认''
        logging.config.dictConfig(cls.logging_dic)  # 导入上面定义的logging配置
        logger = logging.getLogger(logger_name)  # 生成一个log实例变量对应日志配置中的%(name)s
        return logger  #返回一个日志对象,可以直接调用
View Code

 

posted @ 2021-09-14 23:40  三月减肥的猫  阅读(321)  评论(0编辑  收藏  举报