# 日志规范完善版 (By ChatGPT) > 基于现有 `日志规范说明.md` 整理,目标是把“什么时候记、谁来记、记什么、记到什么程度”说清楚,便于后续统一埋点和排查问题。 ## 1. 文档目标 日志的核心目标不是“尽可能多地打印”,而是为了后续能够: - 快速定位问题发生在哪一层 - 还原一次请求的完整链路 - 区分业务异常、参数异常和系统异常 - 追踪核心业务动作是否执行成功 - 在网络调用、数据库调用、SDK 调用等场景下,快速确认耗时和返回状态 ## 2. 总体原则 ### 2.1 谁负责记录谁的日志 - **Controller**:负责接口入口层的访问日志和兜底异常日志 - **Service**:负责业务里程碑日志 - **Utils / RPC / HTTP / Redis / DB / SDK**:负责外部依赖调用的前后日志 - **下游异常**:由下游自己记录,不在上游重复记录 ### 2.2 日志要满足的最小信息 一条可用日志,至少应能回答以下问题: - 谁发起的:`uid`、`traceId` - 调了什么:类名、方法名、接口 URI、目标服务名 - 做了多久:`durationMs`、耗时统计 - 结果如何:成功、失败、HTTP 状态码、业务状态码 - 为什么失败:异常类型、必要的错误摘要 ### 2.3 避免重复记录 当异常已经在下游被明确处理并记录时,上游不要再重复打 ERROR: - 下游负责记录:具体依赖失败、远程超时、数据库异常等 - 上游负责感知:把异常继续抛出,或转换为统一业务异常 - 上游只保留必要的上下文日志,不重复打印同一条堆栈 ## 3. Controller 层日志规范 Controller 是接口入口层,重点关注“请求进来了、请求结果是什么、是否发生兜底异常”。 ### 3.1 必须记录的内容 由 `@DefaultControllerLog` 统一记录: - 接口描述 `desc` - 类名 `className` - 方法名 `methodName` - 请求 URI `uri` - 用户标识 `uid` - 耗时 `durationMs` - 响应状态 `status` - 异常类型 `exception` ### 3.2 记录方式 Controller 推荐只保留一层统一切面: - 请求进入时开始计时 - 方法正常返回后记录成功日志 - 方法抛出异常后记录失败日志 - 在 `finally` 中完成统一输出,保证无论成功失败都能落日志 ### 3.3 Controller 的异常处理原则 - Controller 内部应有 **try-catch 兜底** 的意识,但不要吞掉异常 - 如果异常来自下游服务、数据库、SDK 等,应该继续向上抛出,由对应下游层自己先记录 - 如果是 Controller 自身拼装、参数转换、分支判断等导致的异常,可以记录兜底日志 - 参数解析失败、JSON 反序列化失败等客户端问题,优先作为 **400 类问题** 处理,不应误报成系统故障 ### 3.4 建议记录示例 - 成功请求:记录 `INFO` - 业务异常:记录 `WARN` 或 `INFO`,视业务重要程度决定 - 未预期异常:记录 `ERROR` ### 3.5 当前项目中的对应实现 项目里已有: - `DefaultControllerLogAspect` - `ControllerLogBO` - `BusinessControllerExceptionHandler` - `TraceContextUtil` 这套实现已经具备 Controller 统一记录的基础,后续建议补齐: - `uid` 的获取逻辑 - `traceId` / `spanId` 在日志中的统一输出 - 对不同异常类型的日志级别区分 ## 4. Service 层日志规范 Service 层是业务核心,不负责“每一步都打日志”,而是负责记录对业务有里程碑意义的节点。 ### 4.1 应记录的场景 建议在以下场景记录业务日志: - 核心对象创建 - 核心对象删除 - 业务状态变化 - 数据同步完成 - 流程节点切换 - 核心任务开始与结束 - 影响用户结果的关键决策点 ### 4.2 不建议记录的场景 以下情况一般不应在 Service 层重复记录: - 下游抛出的异常已经在下游记录过 - 单纯的参数透传 - 没有业务意义的中间变量变化 - 每次循环都打印相同信息 ### 4.3 Service 层建议关注的日志内容 一条好的业务日志通常包含: - 业务对象 ID - 业务动作 - 状态前后变化 - 处理结果 - 关键条件分支 示例字段: - `orderId` - `userId` - `beforeStatus` - `afterStatus` - `action` - `result` ### 4.4 异常处理原则 - Service 层可对业务异常做转换,但不要重复打印同一个下游异常堆栈 - 如果 Service 自己发现业务不成立,应抛出明确的业务异常 - 如果是资源、网络、数据库等问题,交给下游或统一异常处理层记录 ## 5. Utils 与跨服务调用日志规范 Utils、RPC、HTTP Client、Redis、DB、SDK 等调用是最容易出现网络波动和性能问题的区域,因此必须前后成对记录。 ### 5.1 调用前必须记录 调用发起前,应记录以下信息: - 目标名称:服务名、库名、SDK 名称、URL、Redis Key 前缀等 - 请求摘要:请求参数的关键字段,避免打印敏感数据 - 调用目的:本次调用是为了什么业务动作 - 关联链路:`traceId`、`spanId` ### 5.2 调用后必须记录 调用返回后,应记录: - 耗时 `durationMs` - 返回结果摘要 - 对方状态码或业务状态码 - 是否超时 - 是否重试 ### 5.3 建议关注的日志内容 对于外部依赖,重点不是“全量打印响应”,而是以下信息: - 请求目标 - 请求关键参数 - 返回耗时 - 返回状态 - 失败原因 ### 5.4 不应记录的内容 - 密码、令牌、密钥、身份证号等敏感信息 - 过大的请求/响应全文 - 无法脱敏的用户隐私数据 - 已知会产生大量噪音的调试级细节 ### 5.5 异常处理原则 - 下游调用失败,由下游先记录 - 上游只做必要的异常转换或透传 - 若需要重试,应记录每次重试的次数和最终结果 ## 6. 日志字段建议 建议统一使用以下基础字段: - `traceId`:一次请求链路的全局标识 - `spanId`:当前调用点标识 - `uid`:用户标识 - `className`:类名 - `methodName`:方法名 - `uri`:请求路径或目标路径 - `durationMs`:耗时 - `status`:HTTP 状态或调用状态 - `exception`:异常类型或摘要 - `desc`:业务描述 ### 6.1 字段使用建议 - `traceId`:用于串联一次请求的完整链路 - `spanId`:用于区分同一请求内的不同调用点 - `uid`:用于追踪用户行为 - `durationMs`:用于性能分析 - `status`:用于快速判断结果是否成功 - `exception`:用于快速定位失败类型 ## 7. 日志级别建议 ### 7.1 INFO 适用于: - 请求正常完成 - 核心业务动作成功 - 外部调用成功且有分析价值 ### 7.2 WARN 适用于: - 客户端参数错误 - 可预期的业务失败 - 可恢复的下游失败 - 需要关注但不一定影响主流程的异常 ### 7.3 ERROR 适用于: - 未预期系统异常 - 无法恢复的故障 - 需要立即排查的严重错误 ## 8. 推荐的统一输出格式 建议日志内容尽量结构化,方便后续检索和分析。 示例结构: ```text {"traceId":"...","spanId":"...","uid":"...","className":"...","methodName":"...","uri":"...","durationMs":123,"status":"OK","exception":null,"desc":"..."} ``` 对于外部调用,可再补充: - `target` - `requestSummary` - `responseSummary` - `retryCount` - `remoteCode` ## 9. 常见误区 ### 9.1 过度记录 问题表现: - 一个方法内打印很多行 - 同一异常被多层重复打印 - 每个中间步骤都记日志 后果: - 日志噪音过大 - 关键问题被淹没 - 排障效率下降 ### 9.2 只记异常,不记上下文 问题表现: - 只有 `NullPointerException` - 没有用户、接口、调用目标、耗时 后果: - 无法快速定位具体链路 ### 9.3 打印敏感信息 问题表现: - 直接打印完整请求体 - 直接打印密码或 token 后果: - 安全风险 - 合规风险 ## 10. 新增接口或调用点时的检查清单 新增代码前,建议逐项确认: - [ ] 这段代码属于 Controller、Service 还是 Utils/外部调用 - [ ] 是否已经有统一切面或统一处理器 - [ ] 是否只记录了应该记录的那一层 - [ ] 是否避免了重复打印下游异常 - [ ] 是否包含 `traceId` / `spanId` - [ ] 是否包含业务关键字段 - [ ] 是否脱敏了敏感数据 - [ ] 是否记录了耗时和结果状态 - [ ] 是否对异常级别做了合理区分 ## 11. 建议落地顺序 如果要逐步完善当前项目,建议按下面顺序推进: 1. 统一 `traceId` / `spanId` 输出 2. 补齐 `uid` 获取逻辑 3. 完善 Controller 统一访问日志 4. 补充 Service 业务里程碑日志 5. 为外部调用增加前后日志模板 6. 统一异常分类与日志级别 ## 12. 总结 这份规范的核心只有三句话: - **Controller 记录入口和兜底异常** - **Service 记录业务里程碑** - **Utils / 跨服务调用记录前后摘要、耗时和状态** 如果所有日志都遵守“谁负责谁记录、下游异常不重复记、日志只保留关键上下文”这三个原则,后续排障和审计都会轻松很多。