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

8.9 KiB
Raw Permalink Blame History

日志规范完善版 (By ChatGPT)

基于现有 日志规范说明.md 整理,目标是把“什么时候记、谁来记、记什么、记到什么程度”说清楚,便于后续统一埋点和排查问题。

1. 文档目标

日志的核心目标不是“尽可能多地打印”,而是为了后续能够:

  • 快速定位问题发生在哪一层
  • 还原一次请求的完整链路
  • 区分业务异常、参数异常和系统异常
  • 追踪核心业务动作是否执行成功
  • 在网络调用、数据库调用、SDK 调用等场景下,快速确认耗时和返回状态

2. 总体原则

2.1 谁负责记录谁的日志

  • Controller:负责接口入口层的访问日志和兜底异常日志
  • Service:负责业务里程碑日志
  • Utils / RPC / HTTP / Redis / DB / SDK:负责外部依赖调用的前后日志
  • 下游异常:由下游自己记录,不在上游重复记录

2.2 日志要满足的最小信息

一条可用日志,至少应能回答以下问题:

  • 谁发起的:uidtraceId
  • 调了什么:类名、方法名、接口 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
  • 业务异常:记录 WARNINFO,视业务重要程度决定
  • 未预期异常:记录 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 前缀等
  • 请求摘要:请求参数的关键字段,避免打印敏感数据
  • 调用目的:本次调用是为了什么业务动作
  • 关联链路:traceIdspanId

5.2 调用后必须记录

调用返回后,应记录:

  • 耗时 durationMs
  • 返回结果摘要
  • 对方状态码或业务状态码
  • 是否超时
  • 是否重试

5.3 建议关注的日志内容

对于外部依赖,重点不是“全量打印响应”,而是以下信息:

  • 请求目标
  • 请求关键参数
  • 返回耗时
  • 返回状态
  • 失败原因

5.4 不应记录的内容

  • 密码、令牌、密钥、身份证号等敏感信息
  • 过大的请求/响应全文
  • 无法脱敏的用户隐私数据
  • 已知会产生大量噪音的调试级细节

5.5 异常处理原则

  • 下游调用失败,由下游先记录
  • 上游只做必要的异常转换或透传
  • 若需要重试,应记录每次重试的次数和最终结果

6. 日志字段建议

建议统一使用以下基础字段:

  • traceId:一次请求链路的全局标识
  • spanId:当前调用点标识
  • uid:用户标识
  • className:类名
  • methodName:方法名
  • uri:请求路径或目标路径
  • durationMs:耗时
  • statusHTTP 状态或调用状态
  • exception:异常类型或摘要
  • desc:业务描述

6.1 字段使用建议

  • traceId:用于串联一次请求的完整链路
  • spanId:用于区分同一请求内的不同调用点
  • uid:用于追踪用户行为
  • durationMs:用于性能分析
  • status:用于快速判断结果是否成功
  • exception:用于快速定位失败类型

7. 日志级别建议

7.1 INFO

适用于:

  • 请求正常完成
  • 核心业务动作成功
  • 外部调用成功且有分析价值

7.2 WARN

适用于:

  • 客户端参数错误
  • 可预期的业务失败
  • 可恢复的下游失败
  • 需要关注但不一定影响主流程的异常

7.3 ERROR

适用于:

  • 未预期系统异常
  • 无法恢复的故障
  • 需要立即排查的严重错误

8. 推荐的统一输出格式

建议日志内容尽量结构化,方便后续检索和分析。

示例结构:

{"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 / 跨服务调用记录前后摘要、耗时和状态

如果所有日志都遵守“谁负责谁记录、下游异常不重复记、日志只保留关键上下文”这三个原则,后续排障和审计都会轻松很多。