keyfil/文档/基础组件/20250428-后端服务日志规范.md
liuxiaohua 9dde371db9
All checks were successful
Publish to Confluence / confluence (push) Successful in 56s
[2025-04-28] 添加错误日志规范
2025-04-28 20:20:24 +08:00

242 lines
8.3 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.

<!-- Space: qifu -->
<!-- Parent: 后端技术&知识&规范 -->
<!-- Parent: 技术方案 -->
<!-- Parent: 基建 -->
<!-- Parent: 00-基础组件 -->
<!-- Title: 20250428-后端服务日志规范 -->
<!-- Macro: :anchor\((.*)\):
Template: ac:anchor
Anchor: ${1} -->
<!-- Macro: \!\[.*\]\((.+)\)\<\!\-\- width=(.*) \-\-\>
Template: ac:image
Url: ${1}
Width: ${2} -->
<!-- Macro: \<\!\-\- :toc: \-\-\>
Template: ac:toc
Printable: 'false'
MinLevel: 2
MaxLevel: 4 -->
<!-- Include: 杂项/声明文件.md -->
<!-- :toc: -->
# 后端服务日志规范
## 一、日志级别定义与使用场景
| 日志级别 | 使用场景 | 典型输出示例 |
|-----------|---------------------------------|---------------------------------------------------------------------------|
| **TRACE** | 最细粒度的调试信息,用于跟踪代码执行路径:(生产环境默认关闭) | `TRACE [http-nio-8080-exec-1] c.a.Service - Entering calculate() method` |
| **DEBUG** | 开发/测试环境使用的调试信息,记录关键变量值、流程分支等 | `DEBUG [http-nio-8080-exec-1] c.a.Service - UserID=123, balance=500.00` |
| **INFO** | 重要业务流程节点信息,用于跟踪系统运行状态 | `INFO [http-nio-8080-exec-1] c.a.Service - Order 20230815001 created` |
| **WARN** | 非预期但可恢复的异常情况,需要人工关注但不需要立即干预 | `WARN [http-nio-8080-exec-1] c.a.Service - Cache miss for key: user_123` |
| **ERROR** | 系统级错误,导致当前操作失败且无法自动恢复的异常(需触发告警) | `ERROR [http-nio-8080-exec-1] c.a.Service - DB connection failed` |
---
## 二、错误日志控制原则(重点)
### 1. 禁止使用ERROR级别的场景
#### 1.1. 可控异常使用示例
```java
public void test() {
// ❌ 错误示例 - 业务流程控制异常
try {
controllableExceptionMethod(params);
} catch (Exception e) {
// 可控的业务异常不应使用ERROR
log.error("参数校验失败", e);
throw new YmException(BaseCode.CODE, "可控异常", e)
}
}
```
```java
public void test() {
// ✅ 正确处理 - 使用WARN级别
try {
controllableExceptionMethod(params);
} catch (BusinessException e) {
log.warn("参数校验失败: {}", e.getMessage()); // 补充业务上下文
throw new YmBizException(400, "参数错误");
}
}
```
#### 1.2. 禁用ERROR的情况
- 参数校验不通过
- 业务流程中的预期异常(如余额不足、重复提交)
- 第三方服务返回的已知错误码
- 数据不存在等正常业务分支
### 2. 必须使用ERROR级别的场景
#### 2.1. 不可控异常使用示例
```java
public void test() {
// ✅ 正确示例 - 不可恢复的系统错误
try {
db.executeTransaction();
} catch (SQLException e) {
log.error("数据库事务执行失败 [TXID:{}]", transactionId, e); // 附加关键上下文
throw new YmException("系统繁忙");
}
}
```
#### 2.2. 必须使用ERROR的情况
- 数据库连接失败
- 文件IO异常
- 缓存集群不可用
- 消息队列消费失败(超过重试次数)
- 关键资源初始化失败
---
## 三、日志规范增强要求
### 1. 上下文信息规范
```java
public void log() {
// ✅ 良好的日志示例
log.info("订单创建成功 [OrderID:{}, UserID:{}, Amount:{}]", order.getId(), userId, order.getAmount());
// ❌ 不推荐的日志
log.info("Order created"); // 缺少关键业务参数
}
```
### 2. 性能优化建议
- 避免在高频代码路径中使用DEBUG级别日志
- 使用占位符(`{}`)代替字符串拼接
```java
public void log() {
// ✅ 性能友好的写法
log.debug("Processing item {} of {}", index, total);
// ❌ 存在性能损耗的写法
log.debug("Processing item " + index + " of " + total);
}
```
---
## 四、异常体系与日志级别映射
| 异常类型 | 日志级别 | 继承关系 | 使用场景说明 |
|------------------------|-------|------------------------------------------------------|------------------------------------------|
| **YmBizDataException** | INFO | `extends YmBizException` | 业务数据相关预期异常(不影响主流程)。例:查询结果为空、数据状态不满足条件 |
| **YmBizException** | WARN | `extends YmException` | 业务流程中的可控异常(需明确处理流程)。例:参数校验失败、权限不足、业务规则限制 |
| **YmException** | ERROR | `extends RuntimeException` | 系统级不可恢复异常(需立即介入)。例:基础设施故障、关键依赖服务不可用 |
| **自定义业务异常** | 继承父类 | `extends YmException/YmBizException/YmBiz*Exception` | 根据业务需求扩展,自动继承父类日志级别策略 |
---
## 五、监控告警策略
| 异常类型 | 告警策略 |
|--------------------|--------------------------|
| YmBizDataException | 不触发告警,用于业务看板数据统计 |
| YmBizException | 不触发实时告警按小时统计TOP高频异常 |
| YmException | 立即触发P1级告警邮件/短信/webhook |
---
## 六、异常使用规范与代码示例
#### 1. YmBizException 使用规范WARN级别
```java
public void test() {
// 示例:用户权限校验
try {
checkUserPermission(userId);
} catch (YmBizException e) {
log.warn("[权限校验] 操作拒绝 UserID={}, RequiredRole={} | 原因:{}", userId, "ADMIN", e.getMessage());
}
}
```
#### 2. YmBizDataException 使用规范INFO级别
```java
// 示例:查询空数据时的处理
public Order getOrder(String orderId) {
Order order = orderDao.findById(orderId);
if (order == null) {
log.info("[订单查询] 数据不存在 OrderID={}", orderId); // INFO级别记录
throw new YmBizDataException("订单不存在");
}
return order;
}
```
#### 3. YmException 使用规范ERROR级别
```java
public void test() {
// 示例:数据库连接失败
try {
Connection conn = dataSource.getConnection();
} catch (SQLException e) {
log.error("[DB连接] 数据库不可用 [DS={}] | 错误:{}", dataSource.getName(), e.getMessage(), e); // 必须记录完整堆栈
throw new YmException("DB_FATAL_ERROR", e); // 包装为系统异常
}
}
```
## 七、异常分类决策树
```java
public void exception(Exception e) {
if (e instanceof YmBizDataException) {
log.info("biz data exception: code = {}, message = {}, data = {}", e.geCode(), e.getMessage(), e.getData(), e);
} else if (e instanceof YmBizException) {
log.warn("biz exception: code = {}, message = {}", e.geCode(), e.getMessage(), e);
} else if (e instanceof YmException) {
log.error("biz error: code = {}, message = {}", e.getCode().e.getMessage(), e);
} else {
log.error("error: message = {}", e.getMessage(), e)
}
}
```
## 八、总结
1. 业务预期异常 → 使用WARN级别如参数错误、权限校验失败
2. 第三方服务异常 → 根据是否可恢复选择WARN/ERROR
3. 资源不可用 → 必须使用ERROR级别
4. 所有ERROR日志必须包含
- 唯一请求标识TraceIdSkyWalking已支持
- 关键业务参数
- 完整的异常堆栈
5. **禁止在循环体内输出ERROR日志防止日志风暴**
### 1. 通过规范日志级别使用,可有效提升以下能力
1. 减少非关键ERROR日志噪音提升问题排查效率
2. 准确触发生产告警(降低误报率)
3. 通过日志分析业务趋势基于INFO日志
### 2. 通过该规范可实现
1. 精准区分业务异常与系统异常
2. 避免ERROR日志污染降低70%以上无效错误日志)
3. 异常分类监控(业务异常看板 vs 系统健康度仪表盘)
## 九、核心能力支撑
- [ ] 核心包全局拦截支撑
- [ ] 基础异常梳理及扩展
- [ ] 基本校验工具类支撑