Python logging库使用详解与实践指南

文章目录

  • 1、前言
  • 2、日志的等级
  • 3、logging的基本应用
  • 4、logging的进阶应用
  • 5、logging的高阶应用
  • 6、简单调用
  • 7、参考
  • 1、前言

      编程代码中,日志的合理使用,能够很好地监控代码的运行过程;在业务部署中,通过日志的记录情况,快速查看代码状态,定位代码运行异常信息,能高效地进行代码维护、管理、执行等。

    2、日志的等级

      日志包含以下等级;设置日志等级之后,日志输出只会包含大于等于设置等级的日志信息。

    3、logging的基本应用

  • 尝试创建一条日志,结果会打印所有的的信息
  • import logging
    # level默认为WARNING级别,不传入参数只会打印logging.waring及以下的日志
    logging.basicConfig(level=logging.DEBUG)
    logging.debug('这是一条debug日志')
    logging.info('这是一条info日志')
    logging.warning('这是一条warning日志')
    logging.error('这是一条error日志')
    logging.critical('这是一条critical日志')
    

      此外,可以设定参数控制日志输出的格式;

    参数 功能
    %(asctime)s 日志事件的发生时间
    %(levelname)s 该日志事件的级别
    %(message)s 日志记录的文本内容
    %(name)s 所使用日志器的名称,默认为’root’
    %(pathname)s 调用日志记录函数的文件全路径
    %(filename)s 调用日志记录函数的函数名
    %(funcname)s 调用日志记录函数的函数名
    %(lineno)d 调用日志记录函数的代码所在的行号
  • 使用以下代码再次尝试,对比不同之处
  • import logging
    logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s', datefmt="%Y-%m-%d %H:%M:%S")
    logging.debug('这是一条debug日志')
    logging.info('这是一条info日志')
    logging.warning('这是一条warning日志')
    logging.error('这是一条error日志')
    logging.critical('这是一条critical日志')
    
  • 在logging.basicConfig中加入filename参数,将日志输出到文件中
  • import logging
    logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s', datefmt="%Y-%m-%d %H:%M:%S", filename='demo.log')
    logging.debug('这是一条debug日志')
    logging.info('这是一条info日志')
    logging.warning('这是一条warning日志')
    logging.error('这是一条error日志')
    logging.critical('这是一条critical日志')
    

    4、logging的进阶应用

  • 相关组件
  • 名称 作用
    Loggers 记录器,提供应用程序代码直接使用的接口
    Handles 处理器,将记录器产生的日志发送到目的地
    Filters 过滤器,提供更好的粒度控制,决定哪些日志会被输出
    Formatters 格式化器,设置日志内容的组成结构和消息字段

    # 标准输出handler, 在终端输出
    console_handler = logging.StreamHandler(stream=None)
    # 文件handler, 将日志输出到文件中
    file_handler = logging.FileHandler(filename,mode='a',encoding=None,delay=False)
    
    # 其它handler
    # BaseRotatingHandler
    # Rotating Filehandler 滚动的多日志输出,按照时间or其他方式去生成多个日志
    # TimedRotatingfilehandler
    
    # ===========================
    # 以下的使用较少
    # Sockethandler
    # Dataaramhandler
    # Smtphandler
    # Sysloghandler
    # Nteventloghandler
    # Httphandler
    # WatchedFilehandler
    # Qutelehandler
    # Nullhandler
    
    属性 格式 描述
    asctime %(asctime)s 日志产生的时间,默认格式为msecs2003-07-0816:49:45,896
    msecs %(msecs)d 日志生成时间的亳秒部分
    created %(created)f 生成的日志创建时间戳
    message %(message)s 具体的日志信息
    filename %(filename)s 生成日志的程序名
    name %(name)s 日志调用者
    funcname %( funcname)s 调用日志的函数名
    levelname %(levelname)s 日志级別( DEBUG,INFO, WARNING, 'ERRORCRITICAL)
    levene %( leveling)s 日志级别对应的数值
    lineno %(lineno)d 日志所针对的代码行号(如果可用的话)
    module %( module)s 生成日志的模块名
    pathname %( pathname)s 生成日志的文件的完整路径
    process %( (process)d 生成日志的进程D(如果可用)
    processname (processname)s 进程名(如果可用)
    thread %(thread)d 生成日志的线程D(如果可用)
    threadname %( threadname)s 线程名(如果可用)
  • 示例
  • #记录器
    logger = logging.getLogger('cn.cccb.applog')
    logger.setLevel(logging.DEBUG)
    #必须设置为两个handler中级别更低的
    
    #处理器handler
    consoleHandler = logging.StreamHandler()
    consoleHandler.setLevel(logging.DEBUG)
    
    #没有给handler指定日志级别,将使用logger的级别
    fileHandler = logging.FileHandler(filename='addDemo.log')
    consoleHandler.setLevel(logging.INFO)
    
    #formatter格式
    formatter = logging.Formatter("%(asctime)s|%(levelname)8s|%(filename)10s%lineno)s|%(message)s")
    #里面的8,10实现了占位对齐
    
    #给处理器设置格式
    consoleHandler.setFormatter(formatter)
    fileHandler.setFormatter(formatter)
    
    #记录器要设置处理器
    logger.addHandler(consoleHandler)
    logger.addHandler(fileHandler)
    
    #定义一个过滤器
    flt = logging.Filter("cn.cccb")
    
    #关联过滤器
    # logger.addFilter(flt)
    fileHandler.addFilter(flt)
    
    #打印日志的代码
    #logging.debug()#不能使用这个了!!!会使用WARNING的版本,不会用之前的记录器
    logger.debug("姓名 %s, 年龄%d",name,age)
    logger.debug("姓名 %s, 年龄%d",% (name,age))
    logger.debug("姓名 {}, 年龄{}"。format(name,age))
    logger.debug(f"姓名{name}, 年龄{age}")
    
    

    5、logging的高阶应用

  • logging的配置文件形式 .conf
  • #./logging.conf
    
    #记录器:提供应用程序代码直接使用的接口
    #设置记录器名称,root必须存在!!!
    [loggers]
    keys=root,applog
    
    #处理器,将记录器产生的日志发送至目的地
    #设置处理器类型
    [handlers]
    keys=fileHandler,consoleHandler
    
    #格式化器,设置日志内容的组成结构和消息字段
    #设置格式化器的种类
    [formatters]
    keys=simpleFormatter
    
    #设置记录器root的级别与种类
    [logger_root]
    level=DEBUG
    handlers=consoleHandler
    
    #设置记录器applog的级别与种类
    [logger_applog]
    level=DEBUG 
    handlers=fileHandler,consoleHandler
    #起个对外的名字
    qualname=applog
    #继承关系
    propagate=0
    
    #设置
    [handler_consoleHandler]
    class=StreamHandler
    args=(sys.stdout,)
    level=DEBUG
    formatter=simpleFormatter
    
    [handler_fileHandler]
    class=handlers.TimedRotatingFileHandler
    #在午夜1点(3600s)开启下一个log文件,第四个参数0表示保留历史文件
    args=('applog.log','midnight',3600,0)
    level=DEBUG
    formatter=simpleFormatter
    
    [formatter_simpleFormatter]
    format=%(asctime)s|%(levelname)8s|%(filename)s[:%(lineno)d]|%(message)s
    #设置时间输出格式
    datefmt=%Y-%m-%d %H:%M:%S
    
  • logging的字典配置形式
  • # logging_config.py
    LOGGING_CONFIG = {
        'version': 1,
        'disable_existing_loggers': False,
        'formatters': {
            'simpleFormatter': {
                'format': '%(asctime)s|%(levelname)8s|%(filename)s[:%(lineno)d]|%(message)s',
                'datefmt': '%Y-%m-%d %H:%M:%S'
            }
        },
        'handlers': {
            'consoleHandler': {
                'class': 'logging.StreamHandler',
                'stream': 'ext://sys.stdout',
                'level': 'DEBUG',
                'formatter': 'simpleFormatter'
            },
            'fileHandler': {
                'class': 'logging.handlers.TimedRotatingFileHandler',
                'filename': 'applog.log',
                'when': 'midnight',
                'interval': 1,
                'backupCount': 0,
                'level': 'DEBUG',
                'formatter': 'simpleFormatter'
            }
        },
        'loggers': {
            'root': {
                'handlers': ['consoleHandler'],
                'level': 'DEBUG',
                'propagate': False
            },
            'applog': {
                'handlers': ['fileHandler', 'consoleHandler'],
                'level': 'DEBUG',
                'propagate': False
            }
        }
    }
    
  • 配置文件加载、调用
  • import logging
    import logging.config
    from logging_config import LOGGING_CONFIG
    
    logging.config.fileConfig('logging.conf')
    #使用字典就能从任意格式文件进行配置,字典是一种接口格式
    # logging.config.dictConfig(LOGGING_CONFIG)
    
    rootLogger = logging.getLogger('applog')
    rootLogger.debug("This is root Logger, debug")
    
    logger = logging.getLogger('cn.cccb.applog')
    logger.debug("This is applog, debug")
    
    try:
        int(a)
    except Exception as e:
        logger.exception(e)
    

    6、简单调用

  • 使用以上配置文件过程中,想要进行每天日志输出,输出日志的文件名每天不一样,发现总有些问题。问题是我在只使用root_logger记录器时,依然生成了datetime.now().strftime(‘applog_%Y-%m-%d.log’)命名的日志文件,代码如下:
  • import os
    import logging
    import logging.config
    from datetime import datetime
    
    # 确保日志目录存在
    log_dir = 'logs'
    if not os.path.exists(log_dir):
        os.makedirs(log_dir)
    
    LOGGING_CONFIG = {
        'version': 1,
        'disable_existing_loggers': False,
        'formatters': {
            'standardFormatter': {
                'format': '%(asctime)s | %(levelname)8s | %(name)s | %(filename)s[:%(lineno)d] | %(message)s',
                'datefmt': '%Y-%m-%d %H:%M:%S'
            }
        },
        'handlers': {
            'consoleHandler': {
                'class': 'logging.StreamHandler',
                'stream': 'ext://sys.stdout',
                'level': 'DEBUG',
                'formatter': 'standardFormatter'
            },
            'fileHandler': {
                'class': 'logging.FileHandler',
                'filename': os.path.join(log_dir, datetime.now().strftime('applog_%Y-%m-%d.log')),
                'level': 'INFO',
                'formatter': 'standardFormatter',
                'encoding': 'utf-8'  # 指定编码
            }
        },
        'loggers': {
            'root': {  # root logger
                'handlers': ['consoleHandler'],  # 只包含控制台处理器
                'level': 'DEBUG',
                'propagate': False
            },
            'MyLogger': {
                'handlers': ['fileHandler', 'consoleHandler'],  # 包含文件和控制台处理器
                'level': 'INFO',
                'propagate': False
            }
        }
    }
    
    # 应用配置
    logging.config.dictConfig(LOGGING_CONFIG)
    
    # 使用root logger
    root_logger = logging.getLogger('root')
    root_logger.debug("This is a DEBUG message from root logger")
    root_logger.info("This is an INFO message from root logger")
    
    # 使用MyLogger logger
    my_logger = logging.getLogger('MyLogger')
    my_logger.debug("This is a DEBUG message from MyLogger")  # 不会显示,因为level是INFO
    my_logger.info("This is an INFO message from MyLogger")
    my_logger.error("This is an ERROR message from MyLogger")
    
  • 所以,采用了以下方法实现
  • import logging
    import os
    from datetime import datetime
    
    
    def setup_logger(config):
        """
        使用配置字典创建并返回一个定制化的logger。
        :param config: 包含日志配置的字典
        """
        # 创建日志目录
        log_dir = config.get('log_dir', 'logs')
        if not os.path.exists(log_dir):
            os.makedirs(log_dir)
    
        # 创建logger
        logger = logging.getLogger(config.get('name', 'PIESAT'))
        logger.setLevel(config.get('log_level', logging.INFO))
    
        # 创建日志格式
        formatter_config = config.get('formatter', {})
        formatter = logging.Formatter(formatter_config.get('format', '%(asctime)s - %(name)s - %(levelname)s - %(message)s'))
    
        # 创建文件处理器
        file_handler_config = config.get('file_handler', {})
        if file_handler_config:
            log_filename = datetime.now().strftime(
                file_handler_config.get('filename_format', "log_%Y-%m-%d_%H-%M-%S.log"))  # 修改这里
            file_handler = logging.FileHandler(os.path.join(log_dir, log_filename))
            # 设置等级
            file_handler.setLevel(file_handler_config.get('level', logging.DEBUG))
            # 设置格式
            file_handler.setFormatter(formatter)
            # 添加处理器
            logger.addHandler(file_handler)
    
        # 创建终端处理器
        console_handler_config = config.get('console_handler', {})
        console_handler = logging.StreamHandler()
        console_handler.setLevel(console_handler_config.get('level', logging.DEBUG))
        console_handler.setFormatter(formatter)
        logger.addHandler(console_handler)
    
        return logger
    
    
    # 使用示例
    logger_config = {
        'log_dir': 'logs',
        'name': 'MuYe',
        'log_level': logging.INFO,
        'file_handler': {
            'filename_format': "log_%Y-%m-%d_%H-%M.log",  # 修改这里
            'level': logging.INFO,
        },
        'console_handler': {
            'level': logging.DEBUG,
        },
        'formatter': {
            'format': '%(asctime)s - %(name)s - %(levelname)s - %(message)s',
        }
    }
    
    logger = setup_logger(logger_config)
    logger.info("This is an info message")
    
    

    7、参考

    Python基础之标准库logging
    标准库系列:logging 日志打印

    作者:木叶清风666

    物联沃分享整理
    物联沃-IOTWORD物联网 » Python logging库使用详解与实践指南

    发表回复