06-日志和错误处理规范.md 7.1 KB

06-日志和错误处理规范

概述

本规范基于项目现有代码实践,规定了日志记录和错误处理的统一标准。所有日志和错误处理必须遵循现有代码的实现方式,确保一致性和可维护性。

日志规范

日志框架

  • 项目统一使用 SLF4J (Simple Logging Facade for Java) 作为日志门面。
  • 底层实现使用 Logback。
  • 在类中声明 Logger 实例:

    private static final Logger logger = LoggerFactory.getLogger(ClassName.class);
    

日志级别

  • DEBUG: 用于调试信息,如方法调用参数、API 请求响应等。
  • INFO: 用于重要业务逻辑信息,如令牌过期等。
  • WARN: 用于警告信息,如 API 未返回预期数据。
  • ERROR: 用于错误信息,如异常发生时。

日志配置

  • 日志配置文件位于 src/main/resources/logback-spring.xml
  • 输出到控制台和文件。
  • 文件日志路径:${LOG_PATH}/app.log,默认 ./logs/app.log
  • 日志轮转:按日期轮转,保留 30 天历史日志。
  • 日志格式:%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n

  • application.yml 中配置日志级别:

    logging:
    level:
      root: info
      work.baiyun.chronicdiseaseapp: debug
    

日志使用原则

  • 在服务实现类中使用 Logger 记录关键操作和异常。
  • 使用占位符记录变量值,如 logger.debug("validateToken: token={}, userToken={}", token, ut)
  • 异常记录时包含异常对象,如 logger.error("Error while calling Weixin API", e)

错误处理规范

全局异常处理器

  • 使用 @RestControllerAdvice 注解的 CustomExceptionHandler 类统一处理异常。
  • 返回统一响应格式 R<T>,包含错误码和消息。

异常类型处理

  • BindException: 参数绑定异常,提取所有错误消息返回。
  • ConstraintViolationException: 参数校验异常,提取约束违反消息返回。
  • CustomException: 自定义异常,返回异常消息。
  • Exception: 未知异常,记录错误日志,返回通用错误信息。

自定义异常

  • 自定义业务异常 CustomException 在代码中继承自 RuntimeException(运行时异常),全局异常处理器会捕获并转换为统一 R.fail() 响应。
  • 构造函数接受消息字符串:

    public class CustomException extends RuntimeException {
    public CustomException(String message) {
      super(message);
    }
    }
    

错误码体系

错误码设计原则

  1. 统一性: 所有错误码在项目中保持统一格式和规范
  2. 可读性: 错误码具有明确的含义和业务指向
  3. 可扩展性: 错误码体系支持模块化扩展
  4. 兼容性: 与现有系统和API保持兼容

错误码结构

错误码采用数字编码方式,每个错误码由5位数字组成:

  • 第1位:错误级别(1-通用错误,2-用户相关,3-微信相关,4-数据相关,5-地理位置相关)
  • 第2-5位:具体错误编号

错误码分类

通用错误码 (1000-1999)
错误码 错误信息 说明
1000 系统内部错误 未预期的系统错误
1001 参数错误 请求参数不合法或缺失
1002 未授权访问 缺少有效的身份认证信息
1003 权限不足 当前用户无权执行该操作
1004 资源不存在 请求的资源未找到
1005 请求方法不被允许 使用了不支持的HTTP方法
用户相关错误码 (2000-2999)
错误码 错误信息 说明
2000 用户不存在 指定的用户ID找不到对应用户
2001 用户密码错误 提供的用户密码不正确
2002 用户未登录 用户会话已过期或未登录
2003 用户已存在 尝试创建已存在的用户
2004 用户账户被锁定 用户账户因安全原因被锁定
微信相关错误码 (3000-3999)
错误码 错误信息 说明
3000 微信授权码无效 提供的微信code参数无效或已过期
3001 获取微信openid失败 调用微信接口获取openid时失败
3002 用户角色不能为空 创建用户时未指定角色类型
3003 用户角色无效 提供的用户角色代码不合法
数据相关错误码 (4000-4999)
错误码 错误信息 说明
4000 数据不存在 指定的数据记录未找到
4001 无权访问该数据 当前用户无权访问指定的数据
4002 数据删除失败 执行数据删除操作时发生错误
4003 数据保存失败 执行数据保存操作时发生错误
地理位置相关错误码 (5000-5999)
错误码 错误信息 说明
5000 地理位置请求失败 调用地理位置服务时发生错误
5001 地理位置服务不可用 地理位置服务暂时不可用

错误码使用规范

错误码枚举类

项目中使用ErrorCode枚举类来定义和管理所有错误码,位于work.baiyun.chronicdiseaseapp.enums.ErrorCode

控制器中使用错误码

所有控制器在返回错误响应时,应使用统一的R.fail()方法,并传入相应的错误码和错误信息:

// 正确用法
return R.fail(ErrorCode.PARAMETER_ERROR.getCode(), 
              ErrorCode.PARAMETER_ERROR.getMessage() + ": Missing code parameter");

// 错误用法(不推荐)
return R.fail(400, "Missing code parameter");
异常处理中使用错误码

在全局异常处理器或控制器的try-catch块中,应根据具体的异常类型返回相应的错误码:

try {
    // 业务逻辑
} catch (IllegalArgumentException e) {
    return R.fail(ErrorCode.PARAMETER_ERROR.getCode(), 
                  ErrorCode.PARAMETER_ERROR.getMessage() + ": " + e.getMessage());
} catch (Exception e) {
    return R.fail(ErrorCode.SYSTEM_ERROR.getCode(), 
                  ErrorCode.SYSTEM_ERROR.getMessage() + ": " + e.getMessage());
}

异常处理原则

  • 业务逻辑中的异常应抛出 CustomException 或记录日志后处理。
  • 全局异常处理器确保所有未捕获异常被统一处理。
  • 异常信息不应暴露敏感数据给客户端。
  • 所有控制器应统一使用R类返回错误响应,避免直接抛出异常,确保API响应格式的一致性。

ID 在日志与错误信息中的格式(补充)

建议:

  • 在记录日志或返回错误信息时,建议以字符串形式记录业务 ID,确保与对外 API 返回格式一致,便于排查与跨端比对。
  • 避免在日志格式化中对大整数进行科学计数或截断(例如使用占位符 {} 直接记录字符串值)。
  • 示例:

    logger.info("处理记录完成,recordId={}", String.valueOf(record.getId()));
    

注意:日志中以字符串记录 ID 并不改变数据库或实体类型,仅是记录/展示层的一致性约定。