用途:该技能规范 Rust 代码如何报告自身运行情况,适用于库与二进制项目的日志、追踪和错误上报设计,帮助团队获得可查询、可过滤、可关联请求上下文的事件流。
主要能力:
- 结构化事件:日志行是带命名字段的事件而非句子,error!(user_id, %path, "config load failed") 中的 user_id 与 path 可被查询,而插值成字符串的形式只能靠正则事后解析。
- 三层选择:println! 无级别、无过滤、无结构,只适合 CLI 输出用户请求的结果,绝不用于库;log 是较老的 facade,依赖预算紧张时可用;tracing 是默认选择,因为 span 能跨 .await 点携带上下文,正是异步代码需要的能力。
- 事件命名:采用 component.operation.state 的统一方案,例如 config.load.failed、pool.connection.acquired;已使用消息模板的项目也可接受,模板只是字段思想的一种实现。
- Span:#[tracing::instrument] 让函数内所有事件继承请求上下文,skip 用于排除大参数或敏感参数;span 是有起止的工作单元,event 是时间点。
- 级别与过滤:error! 表示应有人查看,被处理且预期内的失败最多用 warn! 或 debug!;info! 用于读者关心的生命周期事件;debug!/trace! 为开发者细节,生产环境关闭。EnvFilter 支持按模块控制;库只发出事件,绝不安装 subscriber,安装属于应用的全局状态,二进制只安装一次,库若也安装会争抢全局,tracing 下表现为启动 panic,log 下表现为事件流被重新格式化。
- 错误只记录一次并带完整链:在真正处理错误的边界记录,而非每层都记;记录整个 source 链,而不是只有最不具体的顶层 Display。
- 绝不记录秘密:令牌、密码、密钥、个人数据;结构性做法是定义 newtype,让 Debug 与 Display 输出脱敏形式,使未来疏忽的调用点也无法泄露。示例中 ApiToken 的 Debug 输出 "ApiToken(<redacted>)",Display 输出 "<redacted>";? 形式经由 Debug 打印,% 形式经由 Display 打印,裸形式对自定义类型根本无法编译。
- 开销:宏对字段值惰性求值,不要为可能被过滤的 debug! 提前 format! 或分配;先 let summary = summarize(); 再 debug!(?summary); 会在每次调用时执行,而 debug!(summary = ?summarize()); 只在事件启用时执行。
使用方式与验证:运行 cargo clippy --all-targets,按目标仓库配置的 lint 级别执行,仅当仓库未配置任何 lint 时用 cargo clippy -- -D warnings 作为兜底;用 rg 'println!|eprintln!' src/ 检索,库中应为零;用 rg 'info!("|warn!("|error!("' src/ 查找只有插值消息而无字段的可疑写法;再运行 cargo test。这些检索只是起点而非判决,CLI 打印实际输出时使用 println! 是合理的。
适用场景:Rust 库与服务的日志与追踪设计、异步代码上下文传递、错误上报边界设计、敏感数据脱敏、日志性能优化与代码审查。
限制与暂未提供:资料未涉及具体依赖版本、subscriber 与导出器的具体选型、与具体后端平台的集成方式、性能基准数据或收费标准。错误类型内容与链式设计属于 rust-errors,脱敏 newtype 的建模属于 type-driven-design,取消场景下 span 行为属于 async-rust,均超出本技能范围。