【Hackathon 9th No.88】为FastDeploy重构log日志打印范式设计文档#1220
【Hackathon 9th No.88】为FastDeploy重构log日志打印范式设计文档#1220cloudforge1 wants to merge 1 commit intoPaddlePaddle:masterfrom
Conversation
📎 附录:D1 调研文档 (Current State Analysis)
点击展开完整调研文档 (Click to expand full D1 document)FastDeploy 日志打印现状分析文档
1. 概述 (Overview)本文档对 FastDeploy 框架中模型推理全环节各模块的日志打印现状进行全面调研,梳理仓库源码结构,分析当前日志系统的优势与不足,为后续日志范式重构提供依据。 This document provides a comprehensive survey of the current logging state across all modules in FastDeploy's model inference pipeline, organizes the repository source code structure, and analyzes the strengths and weaknesses of the current logging system to inform the subsequent log paradigm refactoring. 2. 仓库源码结构梳理 (Repository Source Code Organization)2.1 推理流水线模块结构 (Inference Pipeline Module Structure)FastDeploy 的 LLM 推理流水线由以下核心模块组成: 2.2 推理执行流程 (Inference Execution Flow)大模型推理的完整执行流程如下: 3. 日志基础设施现状 (Current Logging Infrastructure)3.1
|
| 文件 | 行数 | 功能 |
|---|---|---|
logger.py |
~255 | FastDeployLogger 单例类,统一+legacy双接口 |
setup_logging.py |
~154 | dictConfig日志配置,文件handler定义 |
formatters.py |
~100 | ColoredFormatter (彩色终端), CustomFormatter |
handlers.py |
~400 | DailyRotatingFileHandler, LazyFileHandler, IntervalRotatingFileHandler |
deterministic_logger.py |
~200 | Tensor哈希日志,确定性调试 |
__init__.py |
~46 | 模块公开API (get_logger, FastDeployLogger) |
FastDeployLogger 单例模式
class FastDeployLogger:
_instance = None
_initialized = False
_lock = threading.RLock()
def get_logger(self, name, file_name=None, without_formater=False, print_to_console=False):
# 仅传name → 新统一接口 (_get_unified_logger)
# 传file_name等 → 旧接口 (_get_legacy_logger)两种获取方式:
- 统一接口
_get_unified_logger(name): 自动添加fastdeploy.前缀,使用 dictConfig 配置 - Legacy接口
_get_legacy_logger(name, file_name, ...): 手动创建 handler,与旧代码兼容
dictConfig 配置 (setup_logging.py)
default_config = {
"formatters": {
"standard": {"class": "logging.Formatter", "format": _FORMAT},
"colored": {"class": "fastdeploy.logger.formatters.ColoredFormatter", "format": _FORMAT}
},
"handlers": {
"console": {"class": "logging.StreamHandler", "level": LEVEL, "formatter": "colored"},
"error_file": {"class": "TimedRotatingFileHandler", "level": "ERROR", ...},
"default_file": {"class": "TimedRotatingFileHandler", "level": LEVEL, ...},
"error_archive": {"class": "IntervalRotatingFileHandler", "level": "ERROR", ...},
"default_archive": {"class": "IntervalRotatingFileHandler", "level": LEVEL, ...}
},
"loggers": {
"fastdeploy": {
"level": "DEBUG",
"handlers": ["error_file", "default_file", "error_archive", "default_archive"],
"propagate": False
}
}
}3.2 环境变量接口 (Environment Variables)
| 环境变量 | 默认值 | 功能 |
|---|---|---|
FD_LOG_DIR |
"log" |
日志文件存储目录 |
FD_DEBUG |
0 |
二元开关:0=INFO, 1=DEBUG |
FD_LOG_BACKUP_COUNT |
7 |
日志文件备份数量 |
FD_LOG_LEVEL |
"INFO" (或 FD_DEBUG=1 时 "DEBUG") |
新增 — 支持全部标准级别 |
3.3 预配置Legacy Logger (utils.py 第1155-1165行)
llm_logger = get_logger("fastdeploy", "fastdeploy.log")
data_processor_logger = get_logger("data_processor", "data_processor.log")
scheduler_logger = get_logger("scheduler", "scheduler.log")
api_server_logger = get_logger("api_server", "api_server.log")
console_logger = get_logger("console", "console.log", print_to_console=True)
spec_logger = get_logger("speculate", "speculate.log")
zmq_client_logger = get_logger("zmq_client", "zmq_client.log")
trace_logger = FastDeployLogger().get_trace_logger("trace", "trace.log")
router_logger = get_logger("router", "router.log")
fmq_logger = get_logger("fmq", "fmq.log")
obj_logger = get_logger("obj", "obj.log")4. 定量分析 (Quantitative Analysis)
4.1 print() vs logger 使用统计
| 统计项 | 数量 |
|---|---|
print() 调用总数 |
279 |
logger.*() 调用总数 |
1718 |
| Logger 使用比例 | 86% (1718 / 1997) |
4.2 Logger 级别分布
| 级别 | 调用次数 | 占比 |
|---|---|---|
logger.info() |
1009 | 58.7% |
logger.error() |
301 | 17.5% |
logger.debug() |
251 | 14.6% |
logger.warning() |
156 | 9.1% |
logger.critical() |
1 | 0.06% |
问题: INFO 级别过度使用(58.7%),很多应该是 DEBUG 的信息被标记为 INFO,导致生产环境日志过于冗长。
4.3 各模块 print() 调用分布
| 模块 | print() | logger.*() | print占比 | 严重性 |
|---|---|---|---|---|
entrypoints/ |
62 | 224 | 21.7% | |
cache_manager/ |
54 | 310 | 14.8% | |
benchmarks/ |
51 | 2 | 96.2% | 🔶 中 — 工具代码 |
model_executor/ |
23 | 148 | 13.5% | |
demo/ |
22 | 1 | 95.7% | ⬜ 低 — 示例代码 |
engine/ |
19 | 236 | 7.4% | 🔶 中 |
config.py |
9 | 2 | 81.8% | 🔶 中 — 启动阶段 |
worker/ |
5 | 187 | 2.6% | ⬜ 低 |
scheduler/ |
5 | 79 | 5.9% | ⬜ 低 |
router/ |
5 | 23 | 17.9% | 🔶 中 |
eplb/ |
4 | 46 | 8.0% | ⬜ 低 |
output/ |
4 | 40 | 9.1% | ⬜ 低 |
input/ |
2 | 175 | 1.1% | ⬜ 低 |
trace/ |
1 | 1 | 50.0% | ⬜ 低 |
4.4 print()密度最高的文件 (Top 20)
| 文件 | print()数 | 类型 |
|---|---|---|
cache_manager/transfer_factory/kvcache_transfer/benchmark.py |
39 | 基准测试输出 |
benchmarks/serve.py |
35 | 基准测试输出 |
entrypoints/cli/tokenizer.py |
17 | CLI用户交互 |
engine/common_engine.py |
15 | 引擎状态/配置 |
cache_manager/transfer_factory/kvcache_transfer/test.py |
15 | 测试输出 |
config.py |
9 | 配置验证 |
entrypoints/cli/openai.py |
9 | CLI帮助输出 |
entrypoints/openai/test_openai.py |
8 | 测试输出 |
demo/openai_demo.py |
8 | 示例输出 |
benchmarks/lib/endpoint_request_func.py |
8 | 基准测试 |
demo/openai_vl_demo.py |
7 | 示例输出 |
utils.py |
6 | 工具函数 |
entrypoints/openai/run_batch.py |
5 | 批处理进度 |
entrypoints/cli/benchmark/eval.py |
5 | 评估输出 |
scheduler/config.py |
4 | 调度配置 |
router/utils.py |
4 | 路由状态 |
output/token_processor.py |
4 | 输出处理 |
model_executor/ops/triton_ops/triton_utils_v2.py |
4 | 算子调试 |
model_executor/ops/triton_ops/triton_utils.py |
4 | 算子调试 |
model_executor/models/model_base.py |
4 | 模型加载 |
4.5 Legacy Logger 使用情况
| Logger名称 | 导入文件数 | 实际使用? | 覆盖模块 |
|---|---|---|---|
llm_logger |
16 (+2别名) | ✅ 广泛 | worker, model_executor, engine, scheduler, output, router, cache_manager等 |
data_processor_logger |
39 | ✅ 使用 | input, output, 数据处理 |
get_logger (函数) |
37 | ✅ 使用 | 各模块自建logger |
api_server_logger |
13 (+1别名) | ✅ 使用 | entrypoints/openai |
console_logger |
4 (+4别名) | ✅ 使用 | utils.py (版本检查, 弃用警告) |
scheduler_logger |
3 (+1别名) | ✅ 使用 | scheduler/ |
spec_logger |
3 | ✅ 使用 | spec_decode/ |
router_logger |
2 (+2别名) | ✅ 使用 | router/ |
trace_logger |
1 | ✅ 使用 | trace/ |
fmq_logger |
1 | — | |
obj_logger |
0 | ❌ 未使用 | — |
zmq_client_logger |
0 | ❌ 未使用 | — |
发现: 11个logger中,3个未被实际使用 (obj_logger, zmq_client_logger, fmq_logger几乎不用)。
5. 推理流水线各阶段日志分析 (Pipeline Stage Logging Analysis)
5.1 启动阶段 (Startup)
| 组件 | 日志方式 | 记录内容 |
|---|---|---|
config.py |
print() × 9 |
配置参数验证、版本信息 |
envs.py |
无直接日志 | 环境变量定义 |
engine/common_engine.py |
print() × 15 + logger |
引擎启动参数、GPU信息 |
engine/async_llm.py |
logger |
AsyncLLM初始化 |
entrypoints/llm.py |
logger + root_logger |
LLM入口初始化 |
问题: 启动阶段大量使用 print(),关键配置信息无法通过日志级别过滤。
5.2 模型加载阶段 (Model Loading)
| 组件 | 日志方式 | 记录内容 |
|---|---|---|
model_executor/models/model_base.py |
logger (已迁移) |
模型架构、加载状态 |
model_executor/forward_meta.py |
logging.getLogger(__name__) |
Forward元数据 |
model_executor/layers/ |
logger |
层初始化、量化参数 |
问题: forward_meta.py 绕过统一logger系统,直接使用 logging.getLogger(__name__)。
5.3 请求处理阶段 (Request Processing)
| 组件 | 日志方式 | 记录内容 |
|---|---|---|
entrypoints/openai/api_server.py |
api_server_logger + uvicorn.access |
HTTP请求处理 |
input/ |
data_processor_logger |
Tokenization, 输入验证 |
entrypoints/cli/ |
print() × 17+ |
CLI用户交互 |
5.4 调度与执行阶段 (Scheduling & Execution)
| 组件 | 日志方式 | 记录内容 |
|---|---|---|
scheduler/ |
scheduler_logger + llm_logger |
调度决策、批处理 |
cache_manager/ |
llm_logger + print() × 54 |
Cache分配、Cache传输基准 |
worker/ |
llm_logger |
Worker执行、GPU状态 |
model_executor/ |
llm_logger + print() × 23 |
前向推理、算子调用 |
问题: cache_manager/ 是 print() 密度第二高的核心模块(54次),且 benchmark/test 相关代码使用了大量 print()。
5.5 输出阶段 (Output)
| 组件 | 日志方式 | 记录内容 |
|---|---|---|
output/ |
data_processor_logger + llm_logger |
Token解码、流式输出 |
output/token_processor.py |
print() × 4 |
处理状态 |
6. 问题总结 (Issues Summary)
6.1 核心问题
| 编号 | 问题 | 严重性 | 影响 |
|---|---|---|---|
| P1 | print() 与 logger 混用 — 279个print()调用 |
🔴 高 | 无法按级别过滤,无法写入日志文件 |
| P2 | FD_DEBUG 仅支持二元开关(0/1) |
🔴 高 | 无法设置中间级别(WARNING等) |
| P3 | llm_logger 过度使用("万能logger") |
🟡 中 | 日志来源不清晰,难以按模块过滤 |
| P4 | Legacy logger 与 unified logger 分裂 ("split brain") | 🟡 中 | 两套日志格式/配置共存 |
| P5 | dictConfig 缺少 console handler | 🟡 中 | 交互环境无终端输出 |
| P6 | INFO级别过度使用 (58.7%) | 🟡 中 | 生产环境日志冗长 |
| P7 | 部分模块绕过统一系统 | 🟠 低 | forward_meta.py, api_server.py 直接使用 logging.getLogger() |
| P8 | 3个legacy logger从未使用 | 🟠 低 | 代码冗余 |
6.2 绕过统一日志系统的文件
以下文件直接使用 logging.getLogger() 而非通过 FastDeployLogger:
fastdeploy/benchmarks/datasets.py → logging.getLogger(__name__)
fastdeploy/model_executor/forward_meta.py → logging.getLogger(__name__)
fastdeploy/engine/sched/scheduler_metrics_logger.py → logging.getLogger("fastdeploy.scheduler_metrics")
fastdeploy/entrypoints/openai/api_server.py → logging.getLogger("uvicorn.access")
fastdeploy/entrypoints/llm.py → logging.getLogger() [root logger]
fastdeploy/__init__.py → monkey-patches logging.getLogger
6.3 get_trace_logger() 与 _get_legacy_logger() 代码重复
logger.py 中 get_trace_logger() 和 _get_legacy_logger() 功能几乎相同,约120行重复代码,仅在 handler 类型上有微小差异 (DailyRotatingFileHandler vs LazyFileHandler)。
7. 现有系统优势 (Existing Strengths)
| 优势 | 说明 |
|---|---|
| 单例模式 | FastDeployLogger 确保全局唯一,线程安全 |
| dictConfig | 结构化配置,支持JSON自定义配置文件 |
| 丰富的Handler | DailyRotating, Interval归档, Lazy延迟创建 |
| 彩色终端 | ColoredFormatter 提供可读的终端输出 |
| 错误日志隔离 | 自动创建 *_error.log 文件 |
| 日志归档 | 按天/小时自动归档,自动清理 |
| Paddle拦截 | intercept_paddle_loggers() 统一Paddle框架日志 |
| 确定性日志 | DeterministicLogger 支持Tensor哈希对比 |
8. 结论与建议 (Conclusions and Recommendations)
当前状态评估
FastDeploy 的日志系统已具备良好的基础设施(单例、dictConfig、自定义Handler),但存在两套并行的日志获取方式 (unified vs legacy),且仍有 279个 print() 调用未纳入统一管理。核心推理模块 (cache_manager, model_executor, engine) 的 print() 使用尤为突出。
重构方向建议
- 统一环境变量接口: 用
FD_LOG_LEVEL替代二元FD_DEBUG,支持标准5级日志 ✅ 已实现 - 补充 console handler: 让 dictConfig 的
fastdeploylogger 具备终端输出能力 ✅ 已实现 - 公开 get_logger() API: 通过
fastdeploy.logger.__init__.py暴露简洁接口 ✅ 已实现 - 逐步迁移 print() → logger: 从核心推理模块开始,分批迁移
- 合并 legacy logger: 逐步将
llm_logger,scheduler_logger等迁移到统一命名空间 - 去重 get_trace_logger/_get_legacy_logger: 提取公共逻辑,减少代码重复
- 审查日志级别: 将过度使用的
INFO降级为DEBUG - 清理未使用logger: 移除
obj_logger,zmq_client_logger
本文档为 Task 88 调研文档 (Deliverable 1),配合设计文档 (Deliverable 2) 和代码PR (Deliverable 3) 共同提交。
8cb3b32 to
ebf9815
Compare
概述
本PR提交 Hackathon 9th No.88「为 FastDeploy 重构 log 日志打印范式」任务的 设计文档(RFC)。
任务交付物总览 (Task Deliverables Overview)
文件
rfcs/FastDeploy/20260306_refactor_log_paradigm_for_fastdeploy.md(244 行)RFC 结构 (8 mandatory sections)
设计要点
关联链接