agent-skill-backend/LOG_ANNOTATION_GUIDE.md

340 lines
9.3 KiB
Markdown
Raw Permalink 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.

# @Log 注解使用指南
## 一、概述
`@Log` 注解是 skills 项目中用于记录操作日志的核心功能。它基于 **AOP面向切面编程****拦截器** 机制实现,能够自动捕获 Controller 层方法的请求和响应信息,并异步保存到数据库的 `sys_log` 表中。
## 二、核心特性
**无侵入性**: 只需添加 `@Log` 注解,无需修改业务代码
**自动化**: 请求/响应信息自动捕获,无需手动记录
**高性能**: 异步保存,不影响接口响应速度
**智能化**: 自动识别浏览器、操作系统、IP等信息
**可扩展**: 支持类级别和方法级别的注解配置
## 三、快速开始
### 3.1 数据库初始化
执行 SQL 脚本创建或更新日志表:
```bash
# 在项目根目录执行
mysql -u root -p skills < backend/db/alter_sys_log_table.sql
```
### 3.2 在控制器上添加注解
#### 方式一:类级别注解(推荐)
在 Controller 类上添加 `@Log` 注解,该类下所有方法都会记录日志:
```java
@Log(module = "用户管理")
@RestController
@RequestMapping("/api/user")
public class UserController {
@PostMapping("/add")
public CommonResult addUser(@RequestBody UserReq req) {
// 自动记录日志
}
}
```
#### 方式二:方法级别注解
在特定方法上添加 `@Log` 注解,只记录该方法的日志:
```java
@RestController
@RequestMapping("/api/order")
public class OrderController {
@Log(module = "订单管理", description = "创建订单")
@PostMapping("/create")
public CommonResult createOrder(@RequestBody OrderReq req) {
// 自动记录日志
}
}
```
#### 方式三:忽略特定接口
对于高频调用的接口,可以设置 `ignore = true` 不记录日志:
```java
@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 数据库查询
```sql
-- 查询最近的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 提供的接口查询日志:
```bash
# 分页查询
POST /api/sysLog/getPageList
{
"pageNum": 1,
"pageSize": 10,
"module": "登录认证",
"status": 1
}
```
## 八、性能优化
### 8.1 异步保存
日志保存采用异步方式,不会阻塞主业务流程:
```java
@Async
public void saveLogAsync(LogRecord logRecord) {
// 异步保存逻辑
}
```
### 8.2 数据库索引
日志表已添加以下索引以优化查询性能:
- `idx_module`: 模块查询优化
- `idx_ip`: IP查询优化
- `idx_create_time`: 时间范围查询优化
- `idx_status`: 状态查询优化
### 8.3 定期清理
建议定期清理历史日志,避免数据量过大:
```sql
-- 保留最近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` 方法中添加:
```java
// 从 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` 方法中添加自定义过滤逻辑:
```java
// 排除敏感接口
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