Agrife-LogTest/documents/日志规范完善版.md

335 lines
8.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 日志规范完善版 (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 / 跨服务调用记录前后摘要、耗时和状态**
如果所有日志都遵守“谁负责谁记录、下游异常不重复记、日志只保留关键上下文”这三个原则,后续排障和审计都会轻松很多。