agent-skill-backend/LOG_ANNOTATION_GUIDE.md

9.3 KiB
Raw Permalink Blame History

@Log 注解使用指南

一、概述

@Log 注解是 skills 项目中用于记录操作日志的核心功能。它基于 AOP面向切面编程拦截器 机制实现,能够自动捕获 Controller 层方法的请求和响应信息,并异步保存到数据库的 sys_log 表中。

二、核心特性

无侵入性: 只需添加 @Log 注解,无需修改业务代码
自动化: 请求/响应信息自动捕获,无需手动记录
高性能: 异步保存,不影响接口响应速度
智能化: 自动识别浏览器、操作系统、IP等信息
可扩展: 支持类级别和方法级别的注解配置

三、快速开始

3.1 数据库初始化

执行 SQL 脚本创建或更新日志表:

# 在项目根目录执行
mysql -u root -p skills < backend/db/alter_sys_log_table.sql

3.2 在控制器上添加注解

方式一:类级别注解(推荐)

在 Controller 类上添加 @Log 注解,该类下所有方法都会记录日志:

@Log(module = "用户管理")
@RestController
@RequestMapping("/api/user")
public class UserController {
    
    @PostMapping("/add")
    public CommonResult addUser(@RequestBody UserReq req) {
        // 自动记录日志
    }
}

方式二:方法级别注解

在特定方法上添加 @Log 注解,只记录该方法的日志:

@RestController
@RequestMapping("/api/order")
public class OrderController {
    
    @Log(module = "订单管理", description = "创建订单")
    @PostMapping("/create")
    public CommonResult createOrder(@RequestBody OrderReq req) {
        // 自动记录日志
    }
}

方式三:忽略特定接口

对于高频调用的接口,可以设置 ignore = true 不记录日志:

@Log(module = "认证")
@RestController
@RequestMapping("/api/auth")
public class AuthController {
    
    @PostMapping("/login")
    public CommonResult login(@RequestBody LoginReq req) {
        // 会记录日志
    }
    
    @Log(ignore = true)
    @GetMapping("/check/token")
    public CommonResult checkToken(@RequestParam String token) {
        // 不会记录日志(高频调用接口)
    }
}

四、注解属性说明

属性 类型 说明 默认值 示例
module String 模块名称 空字符串 "用户管理"
description String 日志描述 空字符串 "创建用户"
ignore boolean 是否忽略记录 false true/false

五、已添加注解的控制器

以下控制器已经添加了 @Log 注解:

  1. LoginController - 登录认证模块

    • 路径: /api/login/**
    • 模块名: "登录认证"
  2. CmsContentController - 内容管理模块

    • 路径: /api/cmsContent/**
    • 模块名: "内容管理"
  3. AccountController - 账户管理模块

    • 路径: /api/account/**
    • 模块名: "账户管理"
  4. AccountFrozenController - 账户冻结模块

    • 路径: /api/accountFrozen/**
    • 模块名: "账户冻结"

六、日志记录内容

系统会自动记录以下信息:

6.1 请求信息

  • 请求方法GET、POST等
  • 请求URL
  • 请求头
  • 请求体
  • 客户端IP
  • IP归属地
  • 浏览器信息
  • 操作系统

6.2 响应信息

  • 响应状态码
  • 响应头
  • 响应体(如果可用)
  • 执行耗时(毫秒)

6.3 其他信息

  • 模块名称
  • 日志描述
  • 成功/失败状态
  • 错误信息(如果失败)
  • 创建时间

七、日志查询

7.1 数据库查询

-- 查询最近的10条日志
SELECT * FROM sys_log ORDER BY create_time DESC LIMIT 10;

-- 按模块查询
SELECT * FROM sys_log WHERE module = '登录认证' ORDER BY create_time DESC;

-- 查询失败的日志
SELECT * FROM sys_log WHERE status = 2 ORDER BY create_time DESC;

-- 按IP查询
SELECT * FROM sys_log WHERE ip = '192.168.1.100' ORDER BY create_time DESC;

-- 按时间范围查询
SELECT * FROM sys_log 
WHERE create_time BETWEEN '2026-04-14 00:00:00' AND '2026-04-14 23:59:59'
ORDER BY create_time DESC;

7.2 通过 API 查询

可以使用现有的 SysLogController 提供的接口查询日志:

# 分页查询
POST /api/sysLog/getPageList
{
  "pageNum": 1,
  "pageSize": 10,
  "module": "登录认证",
  "status": 1
}

八、性能优化

8.1 异步保存

日志保存采用异步方式,不会阻塞主业务流程:

@Async
public void saveLogAsync(LogRecord logRecord) {
    // 异步保存逻辑
}

8.2 数据库索引

日志表已添加以下索引以优化查询性能:

  • idx_module: 模块查询优化
  • idx_ip: IP查询优化
  • idx_create_time: 时间范围查询优化
  • idx_status: 状态查询优化

8.3 定期清理

建议定期清理历史日志,避免数据量过大:

-- 保留最近6个月的日志
DELETE FROM sys_log WHERE create_time < DATE_SUB(NOW(), INTERVAL 6 MONTH);

九、常见问题

9.1 日志未记录

可能原因:

  1. 方法标注了 @Log(ignore = true)
  2. 异步线程池配置问题

排查步骤:

  • 检查控制器是否添加了 @Log 注解
  • 查看应用日志是否有错误信息
  • 确认 @EnableAsync 已启用

9.2 响应体为空

原因: 拦截器无法直接读取响应体

解决方案:

  • 当前版本暂时不记录响应体
  • 如需记录,需要使用 ContentCachingResponseWrapper

9.3 用户ID为空

原因: 尚未实现从 Token 解析用户ID的逻辑

解决方案:

  • 在 LogInterceptor 的 saveLogAsync 方法中添加用户ID解析逻辑
  • 根据实际使用的认证框架(如 Sa-Token实现

十、扩展开发

10.1 添加用户ID解析

LogInterceptor.saveLogAsync 方法中添加:

// 从 Token 中解析用户ID
try {
    String token = request.getHeaders().get("Authorization");
    if (token != null && token.startsWith("Bearer ")) {
        token = token.substring(7);
        // 使用 Sa-Token 解析用户ID
        Object loginId = StpUtil.getLoginIdByToken(token);
        if (loginId != null) {
            sysLog.setCreateUser(Long.parseLong(loginId.toString()));
        }
    }
} catch (Exception e) {
    logger.warn("解析用户ID失败: {}", e.getMessage());
}

10.2 自定义日志过滤

可以在 LogInterceptor.preHandle 方法中添加自定义过滤逻辑:

// 排除敏感接口
String requestUri = request.getRequestURI();
if (requestUri.contains("/sensitive/")) {
    return true;  // 不记录日志
}

十一、技术架构

11.1 核心组件

┌─────────────────────────────────────┐
│      Controller (@Log 注解)          │
└──────────────┬──────────────────────┘
               │
               ▼
┌─────────────────────────────────────┐
│    LogInterceptor (拦截器)           │
│  - preHandle: 捕获请求信息           │
│  - afterCompletion: 捕获响应信息     │
└──────────────┬──────────────────────┘
               │
               ▼
┌─────────────────────────────────────┐
│  LogInterceptor.saveLogAsync         │
│  (@Async 异步保存)                   │
└──────────────┬──────────────────────┘
               │
               ▼
┌─────────────────────────────────────┐
│    SysLogMapper (持久层)             │
└──────────────┬──────────────────────┘
               │
               ▼
┌─────────────────────────────────────┐
│    sys_log (MySQL 数据库表)          │
└─────────────────────────────────────┘

11.2 相关文件

文件路径 说明
annotation/Log.java @Log 注解定义
entity/LogRecord.java 日志记录对象
entity/SysLog.java 日志实体类
interceptor/LogInterceptor.java 日志拦截器
config/LogConfiguration.java 日志配置类
mapper/SysLogMapper.java 日志 Mapper 接口
resources/mapper/SysLogMapper.xml 日志 SQL 映射
db/alter_sys_log_table.sql 数据库建表脚本

十二、总结

@Log 注解为 skills 项目提供了强大的操作日志记录功能,具有以下优势:

  • 简单易用: 只需添加注解即可启用
  • 性能优异: 异步保存,不影响业务性能
  • 信息完整: 自动捕获请求/响应的详细信息
  • 灵活配置: 支持类级别和方法级别的配置
  • 易于扩展: 可以根据需求自定义日志记录逻辑

通过合理使用 @Log 注解,可以实现:

  • 操作审计追溯
  • 安全事件监控
  • 接口调用统计
  • 问题排查分析

文档版本: v1.0
最后更新: 2026-04-14
作者: Lingma AI Assistant