博客引言
2023 年我负责的某电商系统线上故障排查,让我深刻体会到「Python Logging 模块是开发中最容易被轻视、却最影响线上稳定性的组件」:
当时系统突然出现订单支付失败,但监控系统未报警,服务器也无异常指标。我们花了 4 小时排查,才发现开发人员用print()代替了logging输出支付日志,而容器重启后print日志被清空,导致完全无法定位根因。
类似的「日志配置错误导致故障定位困难」「日志太多导致磁盘爆满」「多模块日志混乱」等问题,在 Python 开发者中比比皆是。本文将用15000字 + 的篇幅,从基础组件、配置方式、进阶特性、生产实战、踩坑避坑、最佳实践6 大维度,彻底讲透 Python Logging 模块的所有核心知识点与落地经验。
第一章 Python Logging 模块核心组件与基础概念
1.1 Logging 模块的 4 大核心组件
Logging 模块的本质是「日志生产 - 过滤 - 格式化 - 输出」的流水线,核心由 4 个组件构成:
- Logger(日志器):日志的「生产入口」,负责生成日志、设置日志级别、传递日志到 Handler;
- Handler(处理器):日志的「输出目标」,负责将日志发送到控制台、文件、网络等;
- Formatter(格式化器):日志的「样式定义」,负责将日志记录格式化为可读字符串;
- Filter(过滤器):日志的「过滤规则」,负责按条件过滤日志(比级别更灵活)。
1.2 日志级别体系
Logging 模块定义了 5 种递增的日志级别,用于控制日志的输出粒度(默认只输出 WARNING 及以上级别):
| 级别名称 | 数值 | 含义 |
|---|---|---|
| DEBUG | 10 | 调试信息(开发阶段) |
| INFO | 20 | 常规信息(运行状态) |
| WARNING | 30 | 警告信息(潜在问题) |
| ERROR | 40 | 错误信息(功能异常) |
| CRITICAL | 50 | 致命信息(系统崩溃) |
1.3 模块级函数的陷阱(新手必踩)
很多新手会直接使用 Logging 模块的模块级函数(如logging.info()),但这隐藏了巨大的陷阱:
# 新手踩坑代码:直接调用模块级函数
import logging
logging.info("这是一条INFO日志") # 无任何输出!
logging.warning("这是一条WARNING日志") # 输出:WARNING:root:这是一条WARNING日志
陷阱原因:
- 模块级函数默认使用「根 Logger(名称为
root)」; - 根 Logger 的默认级别是
WARNING,因此INFO级别日志会被过滤; - 根 Logger 默认只配置了StreamHandler(输出到控制台),且无格式化。
1.4 正确的基础使用姿势
使用 Logging 模块的标准流程是:
- 创建 / 获取 Logger 实例(用
__name__作为 Logger 名称,自动继承模块层级); - 配置 Handler(指定输出目标、级别、格式化);
- 将 Handler 添加到 Logger;
- 生成日志。
# 标准基础使用代码
import logging
# 1. 创建/获取Logger(名称为当前模块名,如"__main__")
logger = logging.getLogger(__name__)
# 设置Logger级别为DEBUG(默认是NOTSET,继承父Logger的级别)
logger.setLevel(logging.DEBUG)
# 2. 配置Handler:输出到控制台的StreamHandler
console_handler = logging.StreamHandler()
console_handler.setLevel(logging.INFO) # Handler级别:仅输出INFO及以上
# 3. 配置Formatter:日志格式包含时间、模块名、级别、内容
console_formatter = logging.Formatter(
"%(asctime)s - %(name)s - %(levelname)s - %(message)s"
)
console_handler.setFormatter(console_formatter)
# 4. 将Handler添加到Logger
logger.addHandler(console_handler)
# 5. 生成日志
logger.debug("这是DEBUG日志(不会输出到控制台)") # 级别低于Handler的INFO
logger.info("这是INFO日志(会输出到控制台)") # 符合Handler级别
logger.warning("这是WARNING日志(会输出到控制台)") # 符合Handler级别
运行结果:
2024-05-20 15:30:00,123 - __main__ - INFO - 这是INFO日志
2024-05-20 15:30:00,124 - __main__ - WARNING - 这是WARNING日志
1.5 核心组件的继承关系
Logger 的名称支持层级结构(用.分隔),如app.module1是app的子 Logger,app是根 Logger 的子 Logger。继承规则如下:
- 子 Logger 默认继承父 Logger 的级别、Handler、Filter;
- 若子 Logger 设置了自己的级别,则不再继承父 Logger 的级别;
- 若子 Logger 的
propagate属性设为False,则不再将日志传播给父 Logger 的 Handler。
第二章 Logging 模块的配置方式
Logging 模块支持4 种主流配置方式,其中「字典配置(dictConfig)」是生产环境的推荐方式:
2.1 基础配置函数:basicConfig()
basicConfig()是 Logging 模块提供的快速配置根 Logger的函数,适合开发调试阶段:
import logging
import logging.handlers
# 配置根Logger:输出到文件+控制台,同时开启日志滚动
logging.basicConfig(
level=logging.DEBUG, # 根Logger级别
format="%(asctime)s - %(name)s - %(levelname)s - %(module)s:%(lineno)d - %(message)s", # 日志格式
datefmt="%Y-%m-%d %H:%M:%S", # 时间格式
handlers=[
logging.FileHandler("app.log", mode="a", encoding="utf-8"), # 输出到文件(追加模式)
logging.StreamHandler(), # 输出到控制台
logging.handlers.RotatingFileHandler( # 日志滚动:最大100MB,保留10个备份
"app_roll.log", maxBytes=100*1024*1024, backupCount=10, encoding="utf-8"
)
]
)
# 测试日志
logger = logging.getLogger(__name__)
logger.debug("这是DEBUG日志")
logger.info("这是INFO日志")
logger.error("这是ERROR日志")
basicConfig()的限制:
- 仅能配置根 Logger,无法配置子 Logger;
- 只能配置一次,第二次调用会被忽略;
- 无法灵活配置多个 Handler 的级别和过滤器。
2.2 文件配置:fileConfig()
fileConfig()支持从INI 格式文件读取配置,适合需要动态修改配置的场景:
# logging_config.ini(INI格式配置文件)
[loggers]
keys=root,app,lib
[handlers]
keys=consoleHandler,fileHandler
[formatters]
keys=simpleFormatter,detailedFormatter
# 根Logger配置
[logger_root]
level=DEBUG
handlers=consoleHandler
# app模块Logger配置
[logger_app]
level=INFO
handlers=fileHandler
qualname=app # Logger名称
propagate=0 # 不传播给父Logger
# lib模块Logger配置
[logger_lib]
level=WARNING
handlers=fileHandler
qualname=lib
propagate=0
# 控制台Handler配置
[handler_consoleHandler]
class=StreamHandler
level=INFO
formatter=simpleFormatter
args=(sys.stdout,)
# 文件Handler配置
[handler_fileHandler]
class=logging.handlers.RotatingFileHandler
level=DEBUG
formatter=detailedFormatter
args=("app.log", "a", 100*1024*1024, 10, "utf-8")
# 简单格式
[formatter_simpleFormatter]
format=%(asctime)s - %(name)s - %(levelname)s - %(message)s
# 详细格式
[formatter_detailedFormatter]
format=%(asctime)s - %(name)s - %(levelname)s - %(process)d:%(threadName)s - %(module)s:%(funcName)s:%(lineno)d - %(message)s
# 加载INI配置文件
import logging
import logging.config
logging.config.fileConfig("logging_config.ini")
logger = logging.getLogger("app")
logger.info("app模块的INFO日志")
2.3 字典配置:dictConfig()(生产环境推荐)
dictConfig()支持从Python 字典或JSON/YAML 文件读取配置,是 Logging 模块最灵活、最适合生产环境的配置方式。以下是一个生产级完整配置示例:
import logging.config
import os
import uuid
from flask import g, request
# 1. 自定义请求ID过滤器(用于Web应用追踪请求)
class RequestIdFilter(logging.Filter):
def filter(self, record):
# 从Flask的g对象中获取请求ID,若没有则生成
record.request_id = getattr(g, "request_id", uuid.uuid4().hex)
return True
# 2. 生产级字典配置
LOGGING_CONFIG = {
"version": 1, # 配置版本(固定为1)
"disable_existing_loggers": False, # 不禁用已存在的Logger
"formatters": {
# 控制台日志格式
"console": {
"format": "%(asctime)s - %(request_id)s - %(name)s - %(levelname)s - %(message)s",
"datefmt": "%Y-%m-%d %H:%M:%S"
},
# 文件日志格式(包含进程/线程/模块/行号)
"file": {
"format": "%(asctime)s - %(request_id)s - %(name)s - %(levelname)s - PID:%(process)d TID:%(threadName)s - %(module)s:%(funcName)s:%(lineno)d - %(message)s"
}
},
"filters": {
# 注册自定义请求ID过滤器
"request_id": {"()": lambda: RequestIdFilter()}
},
"handlers": {
# 控制台Handler(仅输出INFO及以上)
"console": {
"class": "logging.StreamHandler",
"level": "INFO",
"formatter": "console",
"filters": ["request_id"]
},
# 错误日志Handler(仅输出ERROR及以上,单独存储)
"error_file": {
"class": "logging.handlers.RotatingFileHandler",
"level": "ERROR",
"formatter": "file",
"filename": os.path.join("logs", "error.log"),
"maxBytes": 100 * 1024 * 1024, # 100MB
"backupCount": 20, # 保留20个备份
"encoding": "utf-8",
"delay": True # 延迟创建文件(避免多进程竞争)
},
# 所有日志Handler(输出DEBUG及以上,滚动存储)
"all_file": {
"class": "logging.handlers.TimedRotatingFileHandler",
"level": "DEBUG",
"formatter": "file",
"filename": os.path.join("logs", "app.log"),
"when": "D", # 每天滚动
"interval": 1, # 滚动间隔1天
"backupCount": 30, # 保留30天日志
"encoding": "utf-8",
"atTime": "00:00:00" # 每天零点滚动
},
# Syslog Handler(输出到日志服务器,用于监控)
"syslog": {
"class": "logging.handlers.SysLogHandler",
"level": "WARNING",
"formatter": "console",
"address": ("192.168.1.100", 514), # 日志服务器地址
"facility": logging.handlers.SysLogHandler.LOG_USER
}
},
"loggers": {
# 根Logger
"": {
"level": "DEBUG",
"handlers": ["console", "all_file", "error_file"]
},
# 应用模块Logger(如Flask的app)
"app": {
"level": "INFO",
"handlers": ["syslog"],
"propagate": True # 日志传播到根Logger
},
# 第三方库Logger(如requests)
"requests": {
"level": "WARNING", # 屏蔽requests的DEBUG日志
"handlers": ["all_file"],
"propagate": False
},
# 数据库模块Logger
"sqlalchemy": {
"level": "WARNING", # 屏蔽SQLAlchemy的DEBUG日志
"handlers": ["all_file"],
"propagate": False
}
}
}
# 3. 加载字典配置
logging.config.dictConfig(LOGGING_CONFIG)
dictConfig()的优势:
- 支持配置所有组件(Logger、Handler、Formatter、Filter);
- 支持自定义组件(如请求 ID 过滤器);
- 可通过 JSON/YAML 文件动态修改配置;
- 支持多环境配置(开发 / 测试 / 生产)。
第三章 Logging 模块进阶特性
3.1 日志滚动机制(生产环境必须配置)
日志文件若不滚动,会导致磁盘空间耗尽,Logging 模块提供了 2 种滚动 Handler:
3.1.1 大小滚动:RotatingFileHandler
当日志文件达到指定大小后,自动创建新文件(文件名加数字后缀,如app.log.1):
import logging.handlers
from logging import Formatter
logger = logging.getLogger("app")
logger.setLevel(logging.DEBUG)
# 配置大小滚动Handler:最大100MB,保留10个备份
rotating_handler = logging.handlers.RotatingFileHandler(
filename="app.log",
maxBytes=100*1024*1024, # 单个日志文件最大大小
backupCount=10, # 保留的备份文件数
encoding="utf-8",
delay=True # 延迟创建文件,避免多进程竞争
)
rotating_handler.setFormatter(Formatter("%(asctime)s - %(message)s"))
logger.addHandler(rotating_handler)
3.1.2 时间滚动:TimedRotatingFileHandler
按时间间隔自动创建新文件(支持年 / 月 / 日 / 时 / 分 / 秒):
import logging.handlers
from datetime import time
logger = logging.getLogger("app")
logger.setLevel(logging.DEBUG)
# 配置时间滚动Handler:每天零点滚动,保留30天
timed_handler = logging.handlers.TimedRotatingFileHandler(
filename="app.log",
when="D", # 滚动间隔:Y=年,M=月,D=日,H=时,m=分,s=秒
interval=1, # 间隔倍数(如when="H",interval=6则每6小时滚动)
backupCount=30, # 保留30天日志
encoding="utf-8",
atTime=time(0, 0, 0) # 滚动时间点(每天零点)
)
# 配置文件名后缀:%Y-%m-%d → app.log.2024-05-20
timed_handler.suffix = "%Y-%m-%d"
timed_handler.setFormatter(Formatter("%(asctime)s - %(message)s"))
logger.addHandler(timed_handler)
3.2 自定义过滤器(Filter)
过滤器可以实现比级别更灵活的日志过滤,如按日志内容、模块名、请求 ID 等过滤:
3.2.1 按模块名过滤
# 只允许来自app模块的日志通过
class ModuleFilter(logging.Filter):
def __init__(self, module_name):
self.module_name = module_name
def filter(self, record):
# record.name是Logger的名称
return record.name.startswith(self.module_name)
# 使用过滤器
logger = logging.getLogger("app")
filter = ModuleFilter("app")
handler.addFilter(filter)
3.2.2 按日志内容过滤
# 只允许包含"pay"关键字的日志通过(用于过滤支付相关日志)
class ContentFilter(logging.Filter):
def __init__(self, keyword):
self.keyword = keyword
def filter(self, record):
return self.keyword in record.getMessage()
3.3 日志上下文信息(LoggerAdapter)
在 Web 应用或异步场景中,需要将请求 ID、用户 ID、设备 ID等上下文信息添加到所有日志中,LoggerAdapter可以实现这一点:
import logging
import uuid
# 创建基础Logger
logger = logging.getLogger("app")
logger.setLevel(logging.INFO)
handler = logging.StreamHandler()
handler.setFormatter(logging.Formatter("%(asctime)s - %(request_id)s - %(user_id)s - %(message)s"))
logger.addHandler(handler)
# 1. 创建LoggerAdapter,添加上下文信息
context = {"request_id": uuid.uuid4().hex, "user_id": "12345"}
adapter = logging.LoggerAdapter(logger, extra=context)
# 2. 生成带上下文的日志
adapter.info("用户登录成功") # 输出:2024-05-20 16:00:00 - xxxxxxx - 12345 - 用户登录成功
adapter.warning("用户登录失败") # 输出带上下文的警告日志
# 3. 动态更新上下文信息
adapter.extra["user_id"] = "67890"
adapter.info("用户修改密码") # 输出:2024-05-20 16:00:01 - xxxxxxx - 67890 - 用户修改密码
3.4 日志的异常捕获
Logging 模块的 **exception()方法可以自动捕获当前异常并打印堆栈信息 **,是排查错误的利器:
import logging
logger = logging.getLogger(__name__)
logger.setLevel(logging.ERROR)
logger.addHandler(logging.StreamHandler())
try:
# 模拟异常
a = 1 / 0
except Exception:
# exception()会自动记录异常类型、错误信息和堆栈
logger.exception("除法运算错误")
运行结果:
ERROR:__main__:除法运算错误
Traceback (most recent call last):
File "/path/to/script.py", line 9, in <module>
a = 1 / 0
ZeroDivisionError: division by zero
注意:exception()方法只能在except块中使用,且默认级别是ERROR。
3.5 异步日志处理(高并发场景必须)
同步日志在高并发场景下会导致IO 阻塞,Logging 模块提供了QueueHandler和QueueListener实现异步日志:
import logging
import logging.handlers
import multiprocessing
import threading
import time
# 1. 创建日志队列(用于存储日志消息)
log_queue = multiprocessing.Queue()
# 2. 创建QueueHandler(将日志发送到队列)
queue_handler = logging.handlers.QueueHandler(log_queue)
root_logger = logging.getLogger()
root_logger.addHandler(queue_handler)
root_logger.setLevel(logging.DEBUG)
# 3. 创建QueueListener(从队列读取日志并输出到文件/控制台)
file_handler = logging.FileHandler("async.log", encoding="utf-8")
file_formatter = logging.Formatter("%(asctime)s - %(name)s - %(message)s")
file_handler.setFormatter(file_formatter)
console_handler = logging.StreamHandler()
console_handler.setFormatter(file_formatter)
# 初始化QueueListener:监听队列,将日志输出到多个Handler
listener = logging.handlers.QueueListener(
log_queue,
file_handler,
console_handler,
respect_handler_level=True # 尊重Handler的级别设置
)
# 4. 启动Listener(在子线程或子进程中运行)
listener.start()
# 5. 高并发场景模拟:100个线程同时生成日志
def generate_logs():
for i in range(10):
logging.info(f"线程{threading.current_thread().name}生成日志{i}")
time.sleep(0.01)
threads = []
for _ in range(100):
t = threading.Thread(target=generate_logs)
threads.append(t)
t.start()
# 6. 等待所有线程结束
for t in threads:
t.join()
# 7. 停止Listener
listener.stop()
异步日志的优势:
- 主线程 / 进程无需等待日志 IO,提高系统并发能力;
- 避免多进程写入同一日志文件的竞争问题。
第四章 生产环境实战场景
4.1 Flask/Django Web 应用中的日志配置
在 Web 应用中,需要将请求 ID、IP 地址、请求方法、路径等信息添加到日志中,以下是 Flask 应用的配置示例:
from flask import Flask, g, request
import logging
import logging.config
import uuid
import os
# 1. 自定义请求ID过滤器
class RequestIdFilter(logging.Filter):
def filter(self, record):
record.request_id = getattr(g, "request_id", "N/A")
record.remote_ip = request.remote_addr if request else "N/A"
record.request_method = request.method if request else "N/A"
record.request_path = request.path if request else "N/A"
return True
# 2. Flask应用初始化
app = Flask(__name__)
# 3. 应用请求钩子:生成请求ID
@app.before_request
def before_request():
g.request_id = uuid.uuid4().hex
logging.info(f"请求开始:{request.method} {request.path}")
# 4. 应用请求钩子:记录请求结束
@app.after_request
def after_request(response):
logging.info(f"请求结束:{request.method} {request.path},响应状态:{response.status_code}")
return response
# 5. 日志配置
LOGGING_CONFIG = {
"version": 1,
"disable_existing_loggers": False,
"formatters": {
"web": {
"format": "%(asctime)s - %(request_id)s - %(remote_ip)s - %(request_method)s %(request_path)s - %(name)s - %(levelname)s - %(message)s"
}
},
"filters": {
"request": {"()": lambda: RequestIdFilter()}
},
"handlers": {
"console": {
"class": "logging.StreamHandler",
"level": "INFO",
"formatter": "web",
"filters": ["request"]
},
"file": {
"class": "logging.handlers.TimedRotatingFileHandler",
"level": "DEBUG",
"formatter": "web",
"filename": "flask_app.log",
"when": "D",
"backupCount": 30,
"encoding": "utf-8"
}
},
"loggers": {
"": {
"level": "DEBUG",
"handlers": ["console", "file"]
},
"flask": {
"level": "WARNING",
"handlers": ["file"]
}
}
}
# 6. 加载日志配置
logging.config.dictConfig(LOGGING_CONFIG)
# 7. 测试API
@app.route("/")
def index():
logging.debug("处理根路径请求")
return "Hello, Flask!"
if __name__ == "__main__":
app.run()
访问 API 后的日志:
2024-05-20 16:30:00 - xxxxxxx - 127.0.0.1 - GET / - __main__ - INFO - 请求开始:GET /
2024-05-20 16:30:00 - xxxxxxx - 127.0.0.1 - GET / - __main__ - DEBUG - 处理根路径请求
2024-05-20 16:30:00 - xxxxxxx - 127.0.0.1 - GET / - __main__ - INFO - 请求结束:GET /,响应状态:200
4.2 多模块项目的日志配置
在多模块项目中,需要为业务模块、工具模块、第三方模块配置不同的日志级别和输出方式:
# 项目结构
myproject/
├── app/
│ ├── __init__.py
│ ├── module1.py
│ └── module2.py
├── lib/
│ ├── __init__.py
│ └── utils.py
└── main.py
# app/__init__.py 中的日志配置
import logging.config
LOGGING_CONFIG = {
"version": 1,
"loggers": {
"app": { # 业务模块日志:INFO级别,输出到文件
"level": "INFO",
"handlers": ["app_file"],
"propagate": False
},
"lib": { # 工具模块日志:DEBUG级别,输出到文件+控制台
"level": "DEBUG",
"handlers": ["lib_file", "console"],
"propagate": False
},
"requests": { # 第三方模块日志:WARNING级别,屏蔽DEBUG
"level": "WARNING",
"handlers": ["thirdparty_file"],
"propagate": False
}
}
# 省略其他配置(Handler、Formatter)
}
logging.config.dictConfig(LOGGING_CONFIG)
# app/module1.py 中的日志使用
import logging
logger = logging.getLogger(__name__) # Logger名称为"app.module1",自动继承"app"的配置
def func():
logger.info("module1的业务日志")
4.3 日志的监控与分析
生产环境的日志需要集中收集、检索、监控,常用的方案是ELK Stack(Elasticsearch+Logstash+Kibana)或Loki+Grafana。以下是将 Logging 日志输出到 ELK 的示例:
import logging
import logging.handlers
# 配置SysLogHandler输出到Logstash
logstash_handler = logging.handlers.SysLogHandler(
address=("logstash-server", 514),
facility=logging.handlers.SysLogHandler.LOG_LOCAL0
)
logstash_handler.setFormatter(logging.Formatter("%(asctime)s - %(name)s - %(message)s"))
logger = logging.getLogger("app")
logger.addHandler(logstash_handler)
logger.setLevel(logging.INFO)
# 生成日志
logger.info("支付订单成功,订单号:123456")
监控告警:可以在 Kibana/Grafana 中配置告警规则,当 ERROR 级别日志数量超过阈值时,自动发送邮件 / 短信告警。
第五章 常见踩坑点与避坑指南
5.1 坑点 1:日志不输出
原因:
- Logger/Handler 的级别设置过高;
- 未配置 Handler 或 Handler 未添加到 Logger;
basicConfig()被覆盖或未生效;propagate属性设为False且未配置 Handler。避坑:
- 检查 Logger 和 Handler 的级别;
- 使用
logger.handlers查看是否有 Handler; - 确保
basicConfig()在第一次调用 Logger 前执行。
5.2 坑点 2:重复日志
原因:
- 子 Logger 的
propagate属性为True,且父 Logger 和子 Logger 都配置了 Handler; - 重复调用
addHandler()添加同一 Handler。避坑:
- 关闭子 Logger 的
propagate属性; - 添加 Handler 前检查是否已存在:
if handler not in logger.handlers: logger.addHandler(handler)。
5.3 坑点 3:日志滚动不生效
原因:
maxBytes或backupCount参数设置错误;TimedRotatingFileHandler的when参数与interval参数不匹配;- 日志文件路径不存在或无写入权限。避坑:
- 检查参数是否正确(如
maxBytes=100*1024*1024而不是100MB); - 确保日志文件路径存在:
os.makedirs(os.path.dirname(log_file), exist_ok=True)。
5.4 坑点 4:多进程日志混乱
原因:
- 多个进程同时写入同一日志文件,导致文件内容被覆盖;
- 未设置
RotatingFileHandler的delay=True参数。避坑:
- 每个进程使用不同的日志文件名(如包含进程 ID:
app_{}.log.format(os.getpid())); - 使用
QueueHandler+QueueListener实现异步日志; - 使用第三方库
concurrent-log-handler(线程 / 进程安全的日志 Handler)。
5.5 坑点 5:日志格式占位符错误
原因:
- 使用了 Logging 模块不支持的占位符(如
%(time)s而不是%(asctime)s); - 自定义 Formatter 时未包含
%(message)s。避坑:
- 参考 Logging 模块文档使用正确的占位符;
- 确保 Formatter 包含
%(message)s(日志内容)。
第六章 Logging 模块最佳实践
6.1 永远不要用print()代替logging
print()的输出无法控制级别,会淹没关键日志;print()的输出没有时间、模块、线程等上下文信息;print()的输出在容器 / 生产环境中容易丢失。
6.2 生产环境禁用 DEBUG 日志
- DEBUG 日志会产生大量冗余信息,占用磁盘空间;
- DEBUG 日志可能包含敏感信息(如密码、密钥)。
6.3 用dictConfig()做集中配置
- 避免在代码中硬编码日志配置;
- 支持多环境配置(开发 / 测试 / 生产);
- 便于动态修改和维护。
6.4 配置日志滚动和过期清理
- 使用
RotatingFileHandler或TimedRotatingFileHandler; - 定期清理旧日志(如保留 30 天),避免磁盘空间耗尽。
6.5 为不同模块设置不同日志级别
- 业务模块:INFO 级别;
- 工具模块:DEBUG 级别;
- 第三方模块:WARNING 级别(屏蔽无关日志)。
6.6 添加上下文信息(如请求 ID)
- 在 Web 应用中添加请求 ID,便于追踪完整请求链路;
- 在异步任务中添加任务 ID,便于定位任务执行情况。
6.7 异步日志处理(高并发场景)
- 使用
QueueHandler+QueueListener实现异步日志; - 避免同步日志的 IO 阻塞。
6.8 监控日志并配置告警
- 集中收集日志到 ELK/Loki;
- 配置 ERROR 级别日志的告警规则;
- 定期分析日志,发现潜在问题。
6.9 测试日志配置
- 在开发环境测试日志的输出格式和级别;
- 测试日志滚动和过期清理功能;
- 测试异常日志的堆栈输出。
博客结语
Python Logging 模块看似简单,但要配置好生产环境的日志系统,需要理解其核心组件、配置方式、进阶特性和最佳实践。本文通过 15000 字 + 的内容,覆盖了从入门到生产的所有知识点,包括真实踩坑案例、代码示例、避坑指南。希望读者能将这些经验应用到实际开发中,构建稳定、可维护、可监控的日志系统,避免因日志问题导致的线上故障排查困难。


被折叠的 条评论
为什么被折叠?



