2. Python logging模块入门:基本使用、配置日志格式、输出到控制台

好,咱们正式开始动手了。这一节我带你快速上手 Python 的 logging 模块。说实话,很多新手写代码时习惯用 print 来调试,项目一大了就抓瞎。我个人习惯从一开始就把日志框架搭好,后面省心太多。

2.1 最简单的日志输出

先看一个最基础的例子。你什么都不用配置,直接导入 logging 模块就能用:

import logging

logging.debug("这是 debug 级别的消息")
logging.info("这是 info 级别的消息")
logging.warning("这是 warning 级别的消息")
logging.error("这是 error 级别的消息")
logging.critical("这是 critical 级别的消息")

运行一下,你会发现控制台只输出了后面三条。为什么?因为 logging 模块默认的日志级别是 WARNING,低于这个级别的消息会被过滤掉。嗯,这里要注意,debug 和 info 默认是不显示的。

小技巧: 我刚开始学的时候也纳闷,为什么 debug 信息不打印?后来才明白,这是设计上的考虑——生产环境里你通常只关心警告和错误,调试信息太多反而干扰。

2.2 配置日志级别

想看到所有日志?很简单,设置一下级别就行:

import logging

logging.basicConfig(level=logging.DEBUG)

logging.debug("这下能看到我了")
logging.info("info 也能看到了")

basicConfig 是 logging 模块最常用的配置函数。你可以在程序入口处调用一次,全局生效。我曾经在项目里忘了设置 level,结果排查了半天问题,最后发现是日志没打出来——从那以后我写任何脚本第一件事就是配日志级别。

2.3 配置日志格式

默认的日志格式太简陋了,只有级别和消息。实际项目中,我们需要时间、文件名、行号等信息。来看怎么自定义格式:

import logging

logging.basicConfig(
    level=logging.DEBUG,
    format='%(asctime)s - %(name)s - %(levelname)s - %(filename)s:%(lineno)d - %(message)s',
    datefmt='%Y-%m-%d %H:%M:%S'
)

logging.info("系统启动成功")

输出效果类似这样:

2025-01-15 14:30:22 - root - INFO - test.py:10 - 系统启动成功

format 字符串里的占位符有很多,我常用的几个列出来:

占位符 含义 示例输出
%(asctime)s 时间戳 2025-01-15 14:30:22
%(name)s 日志器名称 root
%(levelname)s 日志级别 INFO
%(filename)s 文件名 test.py
%(lineno)d 行号 10
%(message)s 日志消息 系统启动成功
重点: datefmt 参数控制时间的显示格式。如果你不指定,默认会带毫秒和时区信息,有时候看着太啰嗦。我个人习惯用 '%Y-%m-%d %H:%M:%S',简洁明了。

2.4 输出到控制台

其实上面所有的例子,默认就是输出到控制台(标准错误流 stderr)。但如果你想更精细地控制,可以显式添加一个 StreamHandler:

import logging

# 创建一个日志器
logger = logging.getLogger('my_logger')
logger.setLevel(logging.DEBUG)

# 创建控制台处理器
console_handler = logging.StreamHandler()
console_handler.setLevel(logging.DEBUG)

# 定义格式
formatter = logging.Formatter(
    '%(asctime)s - %(name)s - %(levelname)s - %(message)s',
    datefmt='%Y-%m-%d %H:%M:%S'
)
console_handler.setFormatter(formatter)

# 把处理器加到日志器上
logger.addHandler(console_handler)

logger.info("这条日志通过自定义处理器输出")

你可能会问,直接用 basicConfig 不就行了?为什么还要手动创建 Handler?说白了,basicConfig 是一次性的,而且只能做简单配置。当你需要同时输出到控制台和文件,或者不同级别用不同格式时,就得手动管理 Handler 了。

避坑指南: 我曾经在同一个脚本里调用了两次 basicConfig,结果第二次调用完全没生效。因为 basicConfig 只有在日志系统未初始化时才会起作用。如果你需要动态修改配置,建议直接操作 Handler 和 Formatter。

2.5 一个完整的入门示例

最后,我给你一个可以直接复制用的模板。这个模板包含了控制台输出、时间格式、日志级别配置:

import logging

def setup_logger():
    """初始化日志配置"""
    logging.basicConfig(
        level=logging.DEBUG,
        format='%(asctime)s | %(levelname)-8s | %(filename)s:%(lineno)d | %(message)s',
        datefmt='%H:%M:%S'
    )
    return logging.getLogger(__name__)

logger = setup_logger()

if __name__ == '__main__':
    logger.debug("调试信息")
    logger.info("普通信息")
    logger.warning("警告信息")
    logger.error("错误信息")

这个模板我用了好几年,基本没改过。你想想看,每次写新脚本都要配一遍日志,多麻烦?不如直接把这个片段存起来,随用随取。

我的习惯: 在团队项目中,我会把日志配置放在一个单独的 config.py 文件里,所有模块都通过 getLogger(__name__) 来获取自己的日志器。这样既能统一格式,又能通过日志器名称快速定位问题来源。

好了,这一节的内容就到这里。你学会了 logging 模块的基本用法、如何配置格式、以及如何输出到控制台。下一节我们会深入文件日志和轮转策略,那才是日志管理的重头戏。