Python日志模块全面解析


文章目录

  • 前言:为什么不用print而要用logging?
  • 一、logging模块的五大核心优势
  • 1. 分级管理
  • 2. 格式定制
  • 3. 多路输出
  • 4. 异常捕获
  • 5. 动态控制
  • 二、logging模块核心组件
  • 1. Logger(记者)
  • 2. Handler(发布渠道)
  • 3. Filter(过滤器)
  • 4. Formatter(排版工具)
  • 三、怎么使用logging模块
  • 1.基础使用:控制台日志
  • 2.将日志写到文件
  • format
  • style
  • 3. 记录变量
  • 总结
  • 参考链接:

  • 前言:为什么不用print而要用logging?

    日常的开发离不开日志,打印日志可以帮助我们排查问题、熟悉代码框架。打印一条日志,简单的print就行,那为什么还要用logging模块呢?print的确能够打印日志,但是当遇到复杂的工业场景,print就显得力不从心了。

    一、logging模块的五大核心优势

    1. 分级管理

    日志分为五级(DEBUG/INFO/WARNING/ERROR/CRITICAL),可动态控制输出。比如:

  • 开发时开启DEBUG,看到所有细节
  • 上线后只保留WARNING及以上级别,避免日志爆炸
  • 2. 格式定制

    自动添加时间、模块名、行号等信息,告别手动拼接字符串的麻烦。

    # 示例格式:2023-10-01 12:00:00 - WARNING - main.py (Line 10) - 文件内容为空
    

    3. 多路输出

    一条日志可同时输出到控制台、文件、甚至发送邮件给运维人员。想象这样一个场景:将ERROR级日志实时发送到运维群聊,而DEBUG日志持久化到数据库。

    4. 异常捕获

    无需修改代码,通过配置文件即可调整日志行为,适合微服务环境。

    5. 动态控制

    无需修改代码,通过logging.config模块或字典配置就能动态调整日志行为。这在微服务架构中尤为重要,可以通过热更新配置实现日志策略切换。

    二、logging模块核心组件

    1. Logger(记者)

  • 负责收集日志,通过logging.getLogger(name)获取
  • Logger对象是线程安全的,且采用单例模式,因此在程序中可以多次调用getLogger(name)获取同一个Logger实例
  • 不同模块建议用不同名称(如__name__),方便追踪来源
  • 2. Handler(发布渠道)

  • 决定日志发到哪:文件、控制台等。
  • 一个Logger可绑定多个Handler,比如同时输出到文件和邮件
  • 3. Filter(过滤器)

  • 过滤不重要的日志,比如只记录包含特定关键词的ERROR日志
  • 它可以在Logger和Handler级别上设置,用于过滤日志消息
  • 4. Formatter(排版工具)

  • 定义日志格式,可自定义,包括时间、日志级别、日志内容等
  • 三、怎么使用logging模块

    1.基础使用:控制台日志

    import logging
    
    import logging
    logging.debug("this is a debug message.")
    logging.info("this is a info message.")
    logging.warning("this is a warning message!")
    logging.error("this is a error message!")
    logging.critical("this is a critical message!")
    

    输出如下:

    WARNING:root:this is a warning message!
    ERROR:root:this is a error message!
    CRITICAL:root:this is a critical message!

    为什么debug和info级别的日志都没输出呢?这是因为logging默认的输出级别就是warning,即只输出warning级别或更高级别的日志。

    这里,介绍一下日志的分级,按照严重性,由低到高为:

    级别 使用场景
    DEBUG 记录详细信息,通常在诊断问题时使用
    INFO 记录常规信息,确认一切按期进行
    WARNING 表示发生了意外情况,或在不久的将来会出现某些问题(例如“磁盘空间不足”)。程序仍按预期工作。
    ERROR 发生了更严重的问题,程序无法执行某些功能
    CRITICAL 发生了严重错误,程序本身可能无法继续运行

    2.将日志写到文件

    上面只是在控制台输出日志,在生产开发环境中,往往需要将日志打印到文件中保存起来,以便日后使用。实现如下:

    import logging
    logger = logging.getLogger(__name__)
    logging.basicConfig(filename='test.log', encoding='utf-8', level=logging.INFO)
    logger.debug("this is a debug message.")
    logger.info("this is a info message.")
    logger.warning("this is a warning message!")
    logger.error("this is a error message!")
    logger.critical("this is a critical message!")
    

    这样,日志就打印到了文件test.log中,如下:

    INFO:__main__:this is a info message.
    WARNING:__main__:this is a warning message!
    ERROR:__main__:this is a error message!
    CRITICAL:__main__:this is a critical message!

    在上面,第二行创建了一个记录器logger,并直接使用模块的名字作为记录器的名字(在日志中体现为__main__),如果不设置,系统会默认创建名为root的根记录器(在日志中体现为root,如1简单使用中的输出)。

    第三行对记录器进行一些基本的配置,设置了日志文件名、编码方式和日志级别,这都是通过logging.basicConfig配置的,其支持的所有配置有:

  • filename:日志文件名
  • filemode:上述文件打开的方式,默认为 ‘a’,表示在文件末尾追加。如需覆盖之前写的,可以使用’w’
  • format:指定日志打印的格式,默认格式为levelname:name:message
  • datefmt:指定日期/时间格式,它使用与 time.strftime() 函数相同的格式化代码
  • style(3.2新增):format字段使用的格式化风格,包括’%‘, ‘{’ or ‘$’,默认使用’%’
  • level:打印日志的最低级别,默认warning
  • stream:用来给StreamHandler初始化,和filename参数不可同时使用
  • handlers(3.3新增):如果指定,需要是创建好的可迭代对象,和filename或stream参数不可同时使用
  • force(3.8新增):
  • encoding(3.9新增):指定编码
  • errors(3.9新增):
  • 下面详细介绍下一些重要的字段

    format

    它接受一个字符串,其中可以包含各种日志记录的字段占位符,这些占位符会在日志记录时被实际的值替换。常用占位符有:

    占位符 含义
    %(asctime)s 日志记录的时间,格式默认为 YYYY-MM-DD HH:MM:SS,sss
    %(levelname)s 日志级别,如 DEBUG、INFO、WARNING、ERROR、CRITICAL
    %(name)s 日志记录器的名称
    %(message)s 日志消息内容
    %(filename)s 包含日志记录调用的源文件的文件名
    %(lineno)s 日志记录调用所在的源文件的行号

    该字段默认格式为levelname:name:message,比如上面的日志中,

    levelname是INFO,name是__main__,message是this is a info message.,这三者之间用冒号分隔

    如下,使用上面提到的6个常用占位符,打印一条日志:

    logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(name)s - %(filename)s - %(lineno)s - %(message)s')
    logging.info("this is a info message.")
    

    2025-03-17 15:30:54,006 – INFO – root – test.py – 3 – this is a info message.

    style

    支持’%', ‘{’ 或 '$'三种风格:

    # 使用 % 风格配置日志
    logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s', style='%')
    
    # 使用 { 风格配置日志
    logging.basicConfig(level=logging.INFO, format='{asctime} - {levelname} - {message}', style='{')
    
    # 使用 $ 风格配置日志
    logging.basicConfig(level=logging.INFO, format='$asctime - $levelname - $message', style='$')
    

    3. 记录变量

    logging也支持记录变量,支持’%', ‘{’ 或 '$'三种风格格式化的方式

    logging.warning('It is %s, %d years old, %.2fm high', 'Tom', 6, 1.2)
    

    WARNING:root:It is Tom, 6 years old, 1.20m high

    总结

  • 为什么用logging?:专业分级、灵活输出、规范管理。

  • 核心四件套:Logger(收集)、Handler(输出)、Filter(过滤)、Formatter(排版)。

  • 避坑指南

  • 优先使用Logger对象而非全局的logging.xxx()。

  • 生产环境避免日志文件无限增长(用RotatingFileHandler)。

  • 通过合理配置logging模块,你的程序将拥有清晰的“诊断报告”,问题排查效率提升10倍!

    参考链接:

    https://docs.python.org/3/howto/logging.html#logging-basic-tutorial

    作者:程序员出道

    物联沃分享整理
    物联沃-IOTWORD物联网 » Python日志模块全面解析

    发表回复