一、需求分析
1. 日志记录目标:
- 记录用户在系统中的关键操作行为
- 辅助问题排查和系统审计
- 支持用户行为分析和安全监控
2. 需记录的操作类型:
- 用户登录/登出
- 订单操作(创建、修改、取消)
- 商品管理(添加、修改、删除)
- 库存调整
- 权限变更
- 敏感数据访问
二、系统设计
1. 日志数据结构
```json
{
"log_id": "唯一标识符",
"user_id": "操作用户ID",
"username": "用户名",
"operation_type": "操作类型",
"operation_content": "操作内容详情",
"operation_time": "操作时间(ISO8601)",
"ip_address": "用户IP",
"device_info": "设备信息",
"result": "操作结果(成功/失败)",
"module": "所属模块",
"related_id": "关联业务ID(如订单ID)"
}
```
2. 技术架构选择
- 存储方案:Elasticsearch + MySQL
- Elasticsearch:支持快速检索和分析
- MySQL:持久化存储,关键日志备份
- 采集方式:
- AOP切面编程(Spring框架)
- 拦截器模式
- 手动记录(敏感操作)
3. 日志级别划分
| 级别 | 描述 | 示例 |
|------|------|------|
| INFO | 常规操作记录 | 用户登录、订单查询 |
| WARN | 可疑操作或边界情况 | 频繁登录失败 |
| ERROR | 操作失败记录 | 订单创建失败 |
| AUDIT | 敏感操作审计 | 权限变更、数据删除 |
三、开发实现
1. 核心代码实现(Spring Boot示例)
```java
@Aspect
@Component
public class OperationLogAspect {
@Autowired
private OperationLogService logService;
@Autowired
private HttpServletRequest request;
// 环绕通知 - 记录方法调用
@Around("@annotation(operationLog)")
public Object around(ProceedingJoinPoint joinPoint, OperationLog operationLog) throws Throwable {
// 获取方法参数
Object[] args = joinPoint.getArgs();
// 获取用户信息(从Token或Session)
String userId = getUserIdFromRequest();
String username = getUsernameFromRequest();
// 记录开始时间
long startTime = System.currentTimeMillis();
try {
// 执行原方法
Object result = joinPoint.proceed();
// 记录成功日志
logOperation(userId, username, operationLog,
args, result, "SUCCESS", startTime);
return result;
} catch (Exception e) {
// 记录失败日志
logOperation(userId, username, operationLog,
args, null, "FAIL: " + e.getMessage(), startTime);
throw e;
}
}
private void logOperation(String userId, String username,
OperationLog annotation, Object[] args,
Object result, String status, long startTime) {
// 构建日志对象
OperationLogEntity log = new OperationLogEntity();
log.setUserId(userId);
log.setUsername(username);
log.setOperationType(annotation.value());
log.setModule(annotation.module());
log.setOperationContent(buildOperationContent(annotation, args));
log.setResult(status);
log.setIpAddress(getIpAddress());
log.setOperationTime(new Date());
log.setCostTime(System.currentTimeMillis() - startTime);
// 保存日志
logService.save(log);
}
// 其他辅助方法...
}
```
2. 日志服务实现
```java
@Service
public class OperationLogServiceImpl implements OperationLogService {
@Autowired
private OperationLogMapper logMapper;
@Autowired
private ElasticsearchOperations elasticsearchOperations;
@Override
@Transactional
public void save(OperationLogEntity log) {
// 1. 保存到MySQL
logMapper.insert(log);
// 2. 异步保存到Elasticsearch
CompletableFuture.runAsync(() -> {
// 转换日志格式
Map
esLog = convertToEsLog(log);
IndexQuery indexQuery = new IndexQueryBuilder()
.withId(log.getLogId().toString())
.withObject(esLog)
.build();
elasticsearchOperations.index(indexQuery,
IndexCoordinates.of("operation_logs"));
});
}
// 其他方法...
}
```
3. 自定义注解
```java
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface OperationLog {
String value() default ""; // 操作类型
String module() default ""; // 所属模块
boolean logParams() default true; // 是否记录参数
boolean logResult() default false; // 是否记录结果
}
```
四、高级功能实现
1. 日志脱敏处理
```java
public class SensitiveDataUtils {
private static final Pattern PHONE_PATTERN = Pattern.compile("(\\d{3})\\d{4}(\\d{4})");
private static final Pattern ID_CARD_PATTERN = Pattern.compile("(\\d{4})\\d{10}(\\w|X)");
public static String desensitize(String content, String type) {
if (content == null) return null;
switch (type.toLowerCase()) {
case "phone":
return PHONE_PATTERN.matcher(content)
.replaceAll("$1$2");
case "idcard":
return ID_CARD_PATTERN.matcher(content)
.replaceAll("$1$2");
// 其他脱敏规则...
default:
return content;
}
}
}
```
2. 异步日志写入
```java
@Configuration
public class LogAsyncConfig {
@Bean(name = "logTaskExecutor")
public Executor logTaskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(5);
executor.setMaxPoolSize(10);
executor.setQueueCapacity(100);
executor.setThreadNamePrefix("log-thread-");
executor.initialize();
return executor;
}
}
// 在Service中使用
@Async("logTaskExecutor")
public void asyncSaveLog(OperationLogEntity log) {
// 保存日志逻辑
}
```
五、日志查询与分析
1. 查询接口实现
```java
@RestController
@RequestMapping("/api/logs")
public class LogController {
@Autowired
private OperationLogService logService;
@GetMapping
public ResponseEntity> queryLogs(
@RequestParam(required = false) String userId,
@RequestParam(required = false) String operationType,
@RequestParam(required = false) Date startTime,
@RequestParam(required = false) Date endTime,
@RequestParam(defaultValue = "0") int page,
@RequestParam(defaultValue = "10") int size) {
Pageable pageable = PageRequest.of(page, size);
Page result = logService.queryLogs(
userId, operationType, startTime, endTime, pageable);
return ResponseEntity.ok(result);
}
}
```
2. Elasticsearch查询示例
```java
public List searchLogs(String keyword, Date startTime, Date endTime) {
NativeSearchQuery searchQuery = new NativeSearchQueryBuilder()
.withQuery(QueryBuilders.boolQuery()
.must(QueryBuilders.rangeQuery("operationTime")
.gte(startTime.toInstant().toEpochMilli())
.lte(endTime.toInstant().toEpochMilli()))
.should(QueryBuilders.matchQuery("username", keyword))
.should(QueryBuilders.matchQuery("operationContent", keyword))
.minimumShouldMatch(1))
.withSort(SortBuilders.fieldSort("operationTime").order(SortOrder.DESC))
.build();
SearchHits searchHits = elasticsearchOperations
.search(searchQuery, OperationLogEsDTO.class);
return searchHits.stream()
.map(hit -> hit.getContent())
.collect(Collectors.toList());
}
```
六、部署与优化
1. 日志存储策略:
- 近期日志(30天)存储在Elasticsearch
- 历史日志归档到对象存储(如S3)
2. 性能优化:
- 批量写入日志
- 异步非阻塞处理
- 日志分级存储
3. 监控告警:
- 日志写入失败监控
- 异常操作频率告警
- 敏感操作实时通知
七、安全考虑
1. 日志访问权限控制
2. 敏感信息脱敏存储
3. 日志传输加密
4. 定期日志清理策略
八、测试用例示例
1. 正常操作日志记录:
- 用户登录成功应记录日志
- 订单创建应记录关键参数
2. 异常操作日志记录:
- 权限不足的操作应记录失败原因
- 系统异常应记录堆栈信息
3. 边界条件测试:
- 超长参数截断处理
- 特殊字符转义处理
4. 性能测试:
- 高并发下的日志写入性能
- 日志查询响应时间
九、后续改进方向
1. 引入日志分析AI模型,自动识别异常行为
2. 实现实时日志流处理,支持实时监控
3. 增加日志可视化分析界面
4. 支持多维度日志下钻分析
以上是快驴生鲜系统用户操作日志模块的完整开发记录,涵盖了从需求分析到实现落地的全过程。实际开发中可根据具体业务需求和技术栈进行调整。