# 异步日志监听系统

## 功能说明

本系统实现了对 Logger 输出的监听，将ERROR级别及以上的日志异步写入数据库，用于日志审计和问题追踪。

## 核心组件

### 1. DatabaseAppender
**路径**: `system/src/main/java/org/xyzh/system/log/DatabaseAppender.java`

自定义 Log4j2 Appender，负责：
- 监听所有日志输出
- 过滤 ERROR 级别及以上的日志
- 将日志事件放入异步队列（非阻塞，防止影响业务性能）
- 队列容量：10000条

### 2. LogEventHandler
**路径**: `system/src/main/java/org/xyzh/system/log/LogEventHandler.java`

日志事件处理器，负责：
- 从异步队列获取日志事件
- 转换为 `TbSysOperationLog` 对象
- 异步批量写入数据库
- 自动提取：用户信息、请求信息、IP、浏览器、OS等

### 3. SpringContextUtil
**路径**: `system/src/main/java/org/xyzh/system/log/SpringContextUtil.java`

Spring上下文工具类，用于在非Spring管理的类（如Log4j2 Appender）中获取Spring Bean。

### 4. AsyncLogConfig
**路径**: `system/src/main/java/org/xyzh/system/config/AsyncLogConfig.java`

异步执行器配置：
- 核心线程数：2
- 最大线程数：5
- 队列容量：1000
- 拒绝策略：CallerRunsPolicy（防止日志丢失）

## 配置方法

### 1. 在 log4j2-spring.xml 中添加 Database Appender

```xml
<appenders>
    <!-- ... 其他 appenders ... -->
    
    <!-- 数据库日志Appender -->
    <DatabaseAppender name="DatabaseAppender" ignoreExceptions="false">
        <ThresholdFilter level="error" onMatch="ACCEPT" onMismatch="DENY"/>
    </DatabaseAppender>
</appenders>

<loggers>
    <root level="info">
        <!-- ... 其他 appenders ... -->
        <!-- 数据库日志Appender -->
        <appender-ref ref="DatabaseAppender"/>
    </root>
</loggers>
```

### 2. 确保数据库表存在

表名：`tb_sys_operation_log`

主要字段：
- `id` - 主键
- `user_id` - 用户ID
- `username` - 用户名
- `module` - 模块名（Logger名称）
- `operation` - 操作类型（日志级别）
- `method` - 方法名
- `request_url` - 请求URL
- `request_method` - 请求方法
- `request_params` - 请求参数
- `response_data` - 日志消息
- `ip_address` - IP地址
- `ip_source` - IP来源
- `browser` - 浏览器
- `os` - 操作系统
- `status` - 状态（0-失败，1-成功）
- `error_message` - 异常堆栈
- `execute_time` - 执行时间
- `create_time` - 创建时间

## 使用示例

### 记录错误日志

```java
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class UserService {
    private static final Logger logger = LoggerFactory.getLogger(UserService.class);
    
    public void someMethod() {
        try {
            // 业务逻辑
        } catch (Exception e) {
            // 这条ERROR日志会自动写入数据库
            logger.error("用户操作失败", e);
        }
    }
}
```

### 记录警告日志（不会写入数据库）

```java
// WARN级别日志不会写入数据库，只写入文件
logger.warn("这是一个警告信息");
```

## 性能优化

1. **异步队列**：日志事件先放入内存队列，不阻塞业务线程
2. **批量处理**：后台线程批量从队列取出并处理
3. **线程池**：使用专用线程池处理日志写入
4. **非阻塞**：队列满时丢弃日志而不阻塞
5. **级别过滤**：只处理ERROR及以上级别，减少数据库压力

## 注意事项

1. **日志级别**：默认只记录ERROR级别及以上的日志到数据库
2. **队列容量**：队列容量10000，超出会丢弃（打印警告到stderr）
3. **关闭等待**：应用关闭时会等待60秒完成日志写入
4. **循环依赖**：LogEventHandler中不要使用logger.error()，会造成循环
5. **性能影响**：每次ERROR日志会触发数据库写入，避免频繁ERROR日志

## 监控建议

1. 定期检查 `tb_sys_operation_log` 表大小
2. 定期归档或删除旧日志（如30天前的）
3. 监控队列满的告警（stderr输出）
4. 监控数据库写入性能

## 扩展功能

### 自定义日志级别过滤

修改 `LogEventHandler.handleLogEvent()` 方法：

```java
// 改为记录WARN及以上级别
if (event.getLevel().isMoreSpecificThan(org.apache.logging.log4j.Level.WARN)) {
    // ...
}
```

### 添加自定义字段

在 `buildOperationLog()` 方法中添加自定义字段提取逻辑。

### 批量写入优化

可以修改为收集多条日志后批量写入数据库，进一步提升性能。

