Files
qiming/qiming-rcoder/.qoder/repowiki/zh/content/可观测性/日志系统.md
2026-06-01 13:54:52 +08:00

12 KiB
Raw Blame History

日志系统

**本文引用的文件** - [Cargo.toml](file://Cargo.toml) - [rcoder 主程序](file://crates/rcoder/src/main.rs) - [agent_runner 主程序](file://crates/agent_runner/src/main.rs) - [rcoder 追踪中间件](file://crates/rcoder/src/middleware/tracing_middleware.rs) - [agent_runner 追踪中间件](file://crates/agent_runner/src/middleware/tracing_middleware.rs) - [诊断脚本](file://docker/scripts/diagnose-blocking.sh)

目录

  1. 简介
  2. 项目结构
  3. 核心组件
  4. 架构总览
  5. 详细组件分析
  6. 依赖分析
  7. 性能考量
  8. 故障排查指南
  9. 结论

简介

本文件系统性阐述基于 tracing 和 tracing-appender 的日志实现,覆盖以下要点:

  • 控制台与文件双输出配置
  • JSON 格式化输出
  • 按天滚动策略与日志保留
  • 日志级别与过滤
  • 线程信息包含
  • 与链路追踪的集成trace_id 注入)
  • 常见问题(路径不存在、权限不足)及解决方案
  • 性能优化建议(异步写入、滚动开销)

该说明面向初学者与资深开发者,既提供清晰的背景知识,也给出深入的技术细节与可视化图示。

项目结构

日志系统在两个二进制服务中分别初始化:

  • rcoder 服务:负责主业务逻辑与容器管理
  • agent_runner 服务:负责代理与子进程交互

两者均通过统一的遥测初始化流程,创建 logs 目录、配置文件 appender、控制台层并注册 EnvFilter 作为日志级别来源。

graph TB
subgraph "rcoder 服务"
RMain["crates/rcoder/src/main.rs<br/>init_telemetry()"]
RMid["crates/rcoder/src/middleware/tracing_middleware.rs<br/>HTTP 追踪中间件"]
end
subgraph "agent_runner 服务"
AMain["crates/agent_runner/src/main.rs<br/>init_telemetry()"]
AMid["crates/agent_runner/src/middleware/tracing_middleware.rs<br/>HTTP 追踪中间件"]
end
RMain --> |"注册 EnvFilter + 文件层 + 控制台层"| RMain
AMain --> |"注册 EnvFilter + 文件层 + 控制台层"| AMain
RMid --> |"生成/提取 trace_id 并注入 span"| RMain
AMid --> |"生成/提取 trace_id 并注入 span"| AMain

图表来源

章节来源

核心组件

  • 日志订阅者与层级
    • EnvFilter从环境变量读取日志级别若未设置则回退到默认级别
    • 文件层JSON按天滚动保留最近 N 份日志文件
    • 控制台层:简洁输出,便于本地调试
  • 链路追踪集成
    • 设置全局 TextMapPropagator支持 trace context 传播
    • HTTP 中间件为每个请求生成/提取 trace_id并注入到日志 span
  • 目录与文件管理
    • 启动时自动创建 logs 目录
    • 文件名前缀区分不同服务rcoder、agent-runner

章节来源

架构总览

日志系统由“订阅者注册 + 层级配置 + 过滤 + 追踪中间件”构成,形成“双输出 + 结构化 + 可追踪”的日志体系。

sequenceDiagram
participant Svc as "服务进程"
participant Sub as "tracing_subscriber : : registry"
participant Env as "EnvFilter"
participant F as "文件层(JSON)"
participant C as "控制台层"
participant Mid as "HTTP 追踪中间件"
participant Log as "日志输出"
Svc->>Sub : 初始化订阅者
Sub->>Env : 注册 EnvFilter
Sub->>F : 注册文件层(JSON)
Sub->>C : 注册控制台层
Svc->>Mid : 注入 HTTP 中间件
Mid->>Mid : 提取/生成 trace_id
Mid->>Log : 写入带 trace_id 的结构化日志
F-->>Log : 写入 JSON 日志
C-->>Log : 写入控制台日志

图表来源

详细组件分析

1) 日志订阅者与层级配置

  • EnvFilter
    • 从环境变量读取日志级别;若未设置,则 rcoder 回退到 infoagent_runner 回退到更细粒度的调试级别
  • 文件层JSON
    • 使用 tracing-appender 的按天滚动策略
    • 通过 filename_prefix 区分服务
    • max_log_files 限制保留的旧日志数量
    • 输出 JSON便于后续结构化分析
  • 控制台层
    • 简洁输出,便于本地快速查看
    • 关闭 ANSI避免非终端环境污染

章节来源

2) 日志目录创建与文件滚动策略

  • 目录创建
    • 启动时检查 logs 目录是否存在,不存在则创建
  • 滚动策略
    • Rotation::DAILY按自然日滚动
    • filename_prefixrcoder 或 agent-runner 前缀
    • max_log_files保留最近 N 个日志文件,超出自动清理

章节来源

3) 日志级别与输出格式

  • 日志级别
    • EnvFilter 优先级:环境变量 > 默认值
    • rcoder 默认 info
    • agent_runner 默认更细粒度,便于调试
  • 输出格式
    • 文件层JSON包含目标、线程 ID、线程名等字段
    • 控制台层:简洁,便于人类阅读

章节来源

4) 线程信息包含

  • 文件层开启线程 ID 与线程名,便于定位并发场景下的日志来源
  • 控制台层关闭线程信息,避免冗余

章节来源

5) 链路追踪与 trace_id 注入

  • 全局传播器
    • 设置 TraceContextPropagator支持 trace context 传播
  • HTTP 中间件
    • 从请求头提取 trace_id若无则生成新的 UUID
    • 为每次请求创建 info_span携带 trace_id、方法、URI、UA、Content-Type 等
    • 将 trace_id 注入请求扩展,便于后续处理器使用
    • 在 span 中记录请求开始与结束,形成完整的调用链日志
sequenceDiagram
participant Client as "客户端"
participant Router as "Axum 路由"
participant Mid as "Tracing 中间件"
participant Handler as "业务处理器"
participant Log as "日志系统(JSON/控制台)"
Client->>Router : HTTP 请求
Router->>Mid : 进入中间件
Mid->>Mid : 提取/生成 trace_id
Mid->>Log : 写入请求开始日志(含 trace_id)
Mid->>Handler : 调用业务处理器
Handler-->>Mid : 返回响应
Mid->>Log : 写入请求结束日志(含 trace_id)
Mid-->>Router : 返回响应

图表来源

章节来源

6) 类图:日志与追踪相关组件

classDiagram
class InitTelemetry {
+init_telemetry() Result
}
class EnvFilter {
+try_from_default_env() Filter
}
class FileLayer {
+json()
+with_writer(writer)
+with_target(flag)
+with_thread_ids(flag)
+with_thread_names(flag)
}
class ConsoleLayer {
+with_target(flag)
+with_ansi(flag)
}
class TracingMiddleware {
+tracing_middleware_handler(req,next) Response
+add_tracing_layer(router) Router
}
InitTelemetry --> EnvFilter : "注册"
InitTelemetry --> FileLayer : "注册"
InitTelemetry --> ConsoleLayer : "注册"
TracingMiddleware --> InitTelemetry : "配合使用"

图表来源

依赖分析

  • 核心依赖
    • tracing、tracing-subscriber日志框架与订阅者
    • tracing-appender文件滚动与 writer
    • opentelemetry、opentelemetry_sdk、tracing-opentelemetry、axum-tracing-opentelemetry链路追踪与传播
    • uuid生成 trace_id
  • 服务差异
    • rcoderEnvFilter 默认 info
    • agent_runnerEnvFilter 默认更细粒度,便于调试

章节来源

性能考量

  • 异步日志写入
    • tracing-appender 默认异步写入,减少阻塞
    • 建议保持默认异步配置,避免同步 I/O 导致延迟放大
  • 滚动开销
    • 按天滚动在高吞吐下会产生少量文件系统操作
    • max_log_files 控制保留数量,避免无限增长
  • JSON 输出
    • JSON 格式便于结构化分析,但序列化成本略高于文本
    • 若对性能极度敏感,可在生产环境切换为文本格式或减少字段
  • 级别过滤
    • EnvFilter 仅在必要时进行解析,建议通过环境变量集中管理
  • 并发与线程信息
    • 启用线程 ID/名称会增加少量开销,建议仅在调试阶段开启

[本节为通用性能建议,无需特定文件来源]

故障排查指南

  • 日志文件路径不存在
    • 现象:启动时报错或无日志文件
    • 处理:确认 logs 目录存在;若不存在,服务会自动创建
    • 参考:日志初始化中包含目录创建逻辑
  • 权限不足
    • 现象:无法写入日志文件
    • 处理:确保运行用户对 logs 目录具有写权限
  • 日志过多占用磁盘
    • 现象:磁盘空间被占满
    • 处理:调整 max_log_files或定期清理旧日志
  • 无法看到 trace_id
    • 现象:日志中缺少 trace_id
    • 处理:确认中间件已注入;检查请求头是否携带 trace_id或允许自动生成
  • 诊断脚本辅助
    • 使用诊断脚本检查今日日志中的 ERROR/WARN
    • 参考:诊断脚本中对日志文件的读取与错误定位

章节来源

结论

该日志系统以 tracing 为核心,结合 tracing-appender 实现了“双输出 + JSON + 按天滚动 + trace_id 注入”的完整方案。通过 EnvFilter 精准控制日志级别,借助 HTTP 中间件将 trace_id 无缝注入到每条日志中,既满足日常运维需求,又为分布式追踪提供了坚实基础。建议在生产环境中保持异步写入与合理的滚动策略,并根据需要调整日志级别与输出格式,以平衡可观测性与性能。