Python 的 logging 模块是一个功能强大的日志记录工具,可以替代简单的 print(),支持不同级别、输出到文件/控制台、自动格式化等。下面从基础到进阶介绍常用用法。

1 基本配置

import logging

# 基本配置: 级别, 格式, 输出位置
# basicConfig() 必须在任何日志记录前调用一次,且只能生效一次。
logging.basicConfig(
    level = logging.INFO, # 记录INFO及其以上级别
    format='%(asctime)s - %(name)s %(levelname)s - %(message)s',
    handlers=[
    logging.StreamHandler(),
    logging.FileHandler('my.log')
    ]
)

# 使用不同级别记录日志
logging.debug('这是调试信息, 默认不显示')
logging.info('这是程序启动信息')
logging.warning('这是警告信息: CPU负载高')
logging.error('这是错误信息: 程序启动失败')
logging.critical('这是非常重要的信息')

运行后, 在执行这个脚本的目录中产生一个my.log的文件, 控制台和这个文件中都会产生以下信息:

2026-04-14 15:35:22,555 - root INFO - 这是程序启动信息
2026-04-14 15:35:22,557 - root WARNING - 这是警告信息: CPU负载高
2026-04-14 15:35:22,557 - root ERROR - 这是错误信息: 程序启动失败
2026-04-14 15:35:22,557 - root CRITICAL - 这是非常重要的信息

2. 日志级别

级别 数值 用途
DEBUG 10 详细的调试信息
INFO 20 正常操作信息
WARNING 30 潜在问题警告(默认级别)
ERROR 40 错误,部分功能失效
CRITICAL 50 严重错误,程序可能中止

设置 level=logging.DEBUG 后,所有级别都会被记录。

3. 记录变量信息

beamline = "XPS"
devices = 25
logging.info(f"station {beamline} devices {devices}")          # f-string 方式(推荐)
logging.info("station name:  %s devices: %d" % (beamline, devices))       # 旧式格式化(延迟计算,性能更好)

运行后:

2026-04-14 15:43:35,148 - root INFO - station XPS devices 25
2026-04-14 15:43:35,148 - root INFO - station name:  XPS devices: 25

4. 更灵活的结构:Logger、Handler、Formatter

basicConfig() 适用于简单场景。复杂需求(不同模块不同级别、多个输出目标、不同格式)需手动配置。

import logging

# 1. 创建 Logger, 设置日志级别
logger = logging.getLogger('__name__')
logger.setLevel(logging.DEBUG)

# 2. 创建 Handler(控制台)
console_handler = logging.StreamHandler()
 # 控制台只显示 WARNING 及以上
console_handler.setLevel(logging.WARNING)     

# 3. 创建 Handler(文件)
file_handler = logging.FileHandler('all.log')
 # 文件记录所有级别
file_handler.setLevel(logging.DEBUG)          

# 4. 定义格式
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
console_handler.setFormatter(formatter)
file_handler.setFormatter(formatter)

# 5. 添加 Handler 到 Logger
logger.addHandler(console_handler)
logger.addHandler(file_handler)

# 使用
logger.debug('调试信息只写入文件,不显示控制台')     
logger.warning('警告信息,  同时写入文件和显示控制台') 

5. 常用格式化字段

字段 含义
%(asctime)s 时间(可配置 datefmt)
%(name)s Logger 名称
%(levelname)s 日志级别文本
%(message)s 日志消息
%(filename)s 文件名
%(lineno)d 行号
%(funcName)s 函数名
%(process)d 进程ID
%(thread)d 线程ID

6.在多个模块中使用

主模块:

import logging
import submodule

logging.basicConfig(level=logging.INFO, format='%(name)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)

logger.info('主程序启动')
submodule.do_something()

被调用模块submodule.py:

import logging

# 名称自动为 'submodule'
logger = logging.getLogger(__name__)   

def do_something():
    logger.info('模块内信息')

调用结果为:

__main__ - INFO - 主程序启动
submodule - INFO - 模块内信息

7. 配置文件方式(推荐用于生产)

使用 fileConfig 或 dictConfig 可以分离配置与代码。

配置文件:

[loggers]
keys=root,myapp

[handlers]
keys=consoleHandler,fileHandler

[formatters]
keys=simpleFormatter

[logger_root]
level=WARNING
handlers=consoleHandler

[logger_myapp]
level=DEBUG
handlers=consoleHandler,fileHandler
qualname=myapp
propagate=0

[handler_consoleHandler]
class=StreamHandler
level=DEBUG
formatter=simpleFormatter
args=(sys.stdout,)

[handler_fileHandler]
class=FileHandler
level=DEBUG
formatter=simpleFormatter
args=('app.log', 'a')

[formatter_simpleFormatter]
format=%(asctime)s - %(name)s - %(levelname)s - %(message)s

整体结构

配置文件分为多个节(section):

  • [loggers]:声明有哪些 logger 实例。
  • [handlers]:声明有哪些 handler 实例。
  • [formatters]:声明有哪些 formatter 实例。

然后分别定义每个 logger、handler、formatter 的具体属性。

1. [loggers] 节

作用:列出配置文件中定义的所有 logger 名称。

[loggers]
keys=root,myapp
  • keys:逗号分隔的 logger 标识符。这里有两个 logger:
  • root:根 logger,是日志系统的顶层,所有未指定父级的 logger 默认继承它。

myapp:自定义的 logger,名为 myapp。

注意:keys 中的名称只是引用,真正的 logger 名称由后面的 [logger_xxx] 节中的 qualname 指定(对于 root 例外,它固定为根)。

2. [handlers]节

作用:列出所有 handler 的名称。

[handlers]
keys=consoleHandler,fileHandler

keys:这里定义了两种处理器:

  • consoleHandler:输出到控制台(标准输出)。
  • fileHandler:输出到文件。

3. [formatters]节

作用:列出所有 formatter 的名称。

[formatters]
keys=simpleFormatter

keys:这里只有一个格式化器 simpleFormatter,用于定义日志消息的输出格式。

4 . [logger_root]节

[logger_root]
level=WARNING
handlers=consoleHandler

作用:配置根 logger。

  • level:根 logger 的日志级别为 WARNING。这意味着只有级别 ≥ WARNING 的日志(WARNING、ERROR、CRITICAL)才会被处理,更低级别(DEBUG、INFO)会被忽略。
  • handlers:根 logger 关联的 handler 列表(此处只有 consoleHandler)。所有传递给根 logger 的日志消息都会交给这些 handler 处理。

注意:根 logger 没有 qualname 和 propagate 属性,因为它就是日志树的根,不存在父级。

5. [logger_myapp]节

[logger_myapp]
level=DEBUG
handlers=consoleHandler,fileHandler
qualname=myapp
propagate=0

作用:配置名为 myapp 的自定义 logger。

  • level:该 logger 的日志级别为 DEBUG,会接收所有 DEBUG 及以上级别的日志。
  • handlers:该 logger 关联两个 handler:consoleHandler 和 fileHandler。日志消息会同时输出到控制台和文件。
  • qualname:真正的 logger 名称。程序中使用 logging.getLogger('myapp') 获取的就是这个 logger。qualname 可以包含点号表示层级(如 myapp.sub),但这里只是简单字符串。
  • propagate:是否将日志消息传播给父级 logger。
    1. propagate=0(或 False)表示禁止传播。即 myapp 的日志消息不会传递给根 logger 或其他父级 logger。
    2. 如果 propagate=1(默认),则除了自己关联的 handler 外,消息还会向上传递给父级(最终到根)的 handler,可能导致重复输出。

因为这里 propagate=0,所以 myapp 的日志只会由它自己的两个 handler 处理,根 logger 的 consoleHandler 不会收到这些日志(即使它们同名也不会重复)

6. [handler_consoleHandler]节

[handler_consoleHandler]
class=StreamHandler
level=DEBUG
formatter=simpleFormatter
args=(sys.stdout,)

作用:配置名为 consoleHandler 的处理器。

  • class:处理器的类名。StreamHandler 表示输出到流(如控制台)。Python 会从 logging 模块中导入这个类。
  • level:该 handler 自身的日志级别过滤器。只有级别 ≥ DEBUG 的日志才会被这个 handler 处理。这里设为 DEBUG,意味着所有级别的日志都能通过。
  • formatter:指定使用哪个格式化器。这里使用 simpleFormatter(定义在后面)。
  • args:传递给 handler 类的构造参数。StreamHandler 的构造函数接受一个流对象,sys.stdout 表示标准输出(控制台)。args=(sys.stdout,) 是一个元组,对应 __init__(self, stream=None) 的参数。

注意:虽然 myapp logger 的级别是 DEBUG,但 handler 的级别也是 DEBUG,所以两者一致。如果 handler 级别设为 INFO,则即使 logger 收到 DEBUG 日志,handler 也会丢弃它。

7. [handler_fileHandler]节

作用:配置名为 fileHandler 的处理器。

[handler_fileHandler]
class=FileHandler
level=DEBUG
formatter=simpleFormatter
args=('app.log', 'a')
  • class:FileHandler 表示输出到文件。
  • level:同样为 DEBUG,接收所有级别日志。
  • formatter:使用相同的 simpleFormatter。
  • args:FileHandler 构造参数:
  1. 'app.log':文件名。
  2. 'a':文件打开模式,'a' 表示追加(append)。如果文件已存在,新日志追加到末尾;如果不存在则创建。

作用:定义日志消息的格式。

8. [formatter_simpleFormatter]节

[formatter_simpleFormatter]
format=%(asctime)s - %(name)s - %(levelname)s - %(message)s

format:字符串模板,包含变量(由 LogRecord 属性填充):

  • %(asctime)s:日志产生的时间(默认格式为 YYYY-MM-DD HH:MM:SS,mmm,可单独设置 datefmt 修改)。
  • %(name)s:logger 的名称(例如 'myapp' 或 'root')。
  • %(levelname)s:日志级别文本(如 DEBUG, INFO)。
  • %(message)s:实际的日志消息内容。

配置生效

在python程序中,像如下加载配置文件:

import logging
from logging import config
import os

dir_name = os.path.dirname(os.path.abspath(__file__))
config_file_path = os.path.join(dir_name, 'logging.conf')

print(f"config file path:{config_file_path}")

config.fileConfig(config_file_path)
logger = logging.getLogger('myapp')   # 获取名为 myapp 的 logger
logger.debug('调试信息')               # 会输出到控制台和 app.log

运行结果, 在控制台和app.log文件中都会有以下信息:

2026-04-14 21:55:41,584 - myapp - DEBUG - 调试信息

总结:整个配置的工作流程

1. 程序启动时加载配置文件,创建 root 和 myapp 两个 logger 实例。

2. 创建两个 handler:consoleHandler(输出到 sys.stdout)和 fileHandler(追加到 app.log)。

3. 创建格式化器 simpleFormatter,并附加到两个 handler 上。

4. 根 logger 的级别为 WARNING,关联 consoleHandler。

5. myapp logger 的级别为 DEBUG,关联两个 handler,并且禁止向上传播(propagate=0)。

6. 当代码中通过 logging.getLogger('myapp') 获取 logger 并记录日志时:

  • 日志消息被 myapp logger 接收。
  • 因为 level=DEBUG,所以所有级别日志都通过。
  • 日志消息交给 consoleHandler 和 fileHandler,两个 handler 的级别也是 DEBUG,都会处理。
  • 每个 handler 使用 simpleFormatter 格式化消息,然后分别输出到控制台和文件。
  • 由于 propagate=0,消息不会发送给根 logger,因此根 logger 的 consoleHandler 不会再次输出(避免重复)。

如果某个日志级别低于 DEBUG(如 NOTSET),则不会被任何地方处理。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐