010-53388338

快驴生鲜系统日志方案:从需求分析到部署监控,实现全面日志管理

分类:IT频道 时间:2026-02-13 00:15 浏览:23
概述
    一、需求分析    1.日志记录目的:  -审计追踪:记录用户所有关键操作,便于问题排查和合规性检查  -数据分析:通过操作日志分析用户行为模式  -安全监控:检测异常操作行为    2.需记录内容:  -操作时间  -操作用户  -操作类型(增删改查等)  -操作对象(如商品ID、订单号等
内容
  
   一、需求分析
  
  1. 日志记录目的:
   - 审计追踪:记录用户所有关键操作,便于问题排查和合规性检查
   - 数据分析:通过操作日志分析用户行为模式
   - 安全监控:检测异常操作行为
  
  2. 需记录内容:
   - 操作时间
   - 操作用户
   - 操作类型(增删改查等)
   - 操作对象(如商品ID、订单号等)
   - 操作结果(成功/失败)
   - 客户端信息(IP、设备类型等)
   - 操作详情(可选,如修改前后的值)
  
   二、技术方案设计
  
   1. 日志存储方案
  
  方案一:数据库存储
  - 优点:结构化查询方便,可与业务数据关联
  - 缺点:高并发写入可能影响性能
  
  方案二:文件存储+ELK
  - 优点:高性能写入,适合大规模日志
  - 缺点:需要额外维护ELK栈
  
  最终选择:混合方案
  - 核心业务操作日志存入MySQL(便于审计)
  - 非关键操作日志写入文件,由Filebeat收集到ELK
  
   2. 日志级别设计
  
  | 级别 | 描述 | 示例 |
  |------|------|------|
  | INFO | 常规操作记录 | 用户登录、商品查询 |
  | WARN | 可疑但未失败的操作 | 频繁错误密码尝试 |
  | ERROR | 操作失败记录 | 创建订单失败 |
  | CRITICAL | 严重系统问题 | 数据库连接中断 |
  
   3. 关键表设计(MySQL)
  
  ```sql
  CREATE TABLE `operation_log` (
   `id` bigint(20) NOT NULL AUTO_INCREMENT,
   `user_id` bigint(20) DEFAULT NULL COMMENT 操作用户ID,
   `username` varchar(50) DEFAULT NULL COMMENT 用户名,
   `operation_type` varchar(20) NOT NULL COMMENT 操作类型(CREATE/UPDATE/DELETE/VIEW),
   `module` varchar(50) NOT NULL COMMENT 操作模块(商品/订单/库存等),
   `resource_id` varchar(64) DEFAULT NULL COMMENT 操作资源ID,
   `resource_type` varchar(50) DEFAULT NULL COMMENT 资源类型,
   `ip_address` varchar(50) DEFAULT NULL COMMENT 操作IP,
   `user_agent` varchar(500) DEFAULT NULL COMMENT 用户代理,
   `status` tinyint(1) DEFAULT 1 COMMENT 状态(1成功 0失败),
   `result_data` text COMMENT 操作结果数据(JSON),
   `request_params` text COMMENT 请求参数(JSON),
   `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 创建时间,
   `cost_time` int(11) DEFAULT NULL COMMENT 耗时(毫秒),
   PRIMARY KEY (`id`),
   KEY `idx_user` (`user_id`),
   KEY `idx_time` (`create_time`),
   KEY `idx_module` (`module`)
  ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT=用户操作日志表;
  ```
  
   三、开发实现
  
   1. Spring AOP实现日志记录
  
  ```java
  @Aspect
  @Component
  public class OperationLogAspect {
  
   @Autowired
   private OperationLogService logService;
  
   @Autowired
   private HttpServletRequest request;
  
   // 定义切点:标注了@OperationLog的方法
   @Pointcut("@annotation(com.kuailv.annotation.OperationLog)")
   public void logPointCut() {}
  
   @Around("logPointCut()")
   public Object around(ProceedingJoinPoint point) throws Throwable {
   long beginTime = System.currentTimeMillis();
  
   // 执行方法
   Object result = point.proceed();
  
   // 执行时长(毫秒)
   long time = System.currentTimeMillis() - beginTime;
  
   // 保存日志
   saveLog(point, time, null);
  
   return result;
   }
  
   @AfterThrowing(pointcut = "logPointCut()", throwing = "e")
   public void afterThrowing(JoinPoint point, Exception e) {
   long time = System.currentTimeMillis() - System.currentTimeMillis(); // 实际应记录开始时间
   saveLog((ProceedingJoinPoint)point, time, e);
   }
  
   private void saveLog(ProceedingJoinPoint joinPoint, long time, Exception e) {
   MethodSignature signature = (MethodSignature) joinPoint.getSignature();
   Method method = signature.getMethod();
  
   OperationLog operationLog = new OperationLog();
   OperationLog annotation = method.getAnnotation(OperationLog.class);
  
   // 设置注解上的信息
   if(annotation != null){
   operationLog.setModule(annotation.module());
   operationLog.setOperationType(annotation.operationType().name());
   // 其他注解属性...
   }
  
   // 从切面上下文中获取方法参数
   Object[] args = joinPoint.getArgs();
   try {
   // 处理参数,记录关键信息(避免记录敏感信息)
   String params = JsonUtils.toJson(args);
   operationLog.setRequestParams(params);
   } catch (Exception ex) {
   // 参数序列化失败处理
   }
  
   // 获取请求信息
   String ip = IpUtils.getIpAddr(request);
   operationLog.setIpAddress(ip);
   operationLog.setUserAgent(request.getHeader("User-Agent"));
  
   // 获取用户信息
   Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
   if(authentication != null && authentication.getPrincipal() instanceof UserDetails){
   UserDetails userDetails = (UserDetails) authentication.getPrincipal();
   operationLog.setUserId(((User)userDetails).getId());
   operationLog.setUsername(userDetails.getUsername());
   }
  
   // 异常信息
   if(e != null){
   operationLog.setStatus(0); // 失败
   operationLog.setResultData(e.getMessage());
   } else {
   operationLog.setStatus(1); // 成功
   // 可记录返回结果的关键信息
   }
  
   operationLog.setCostTime((int)time);
   operationLog.setCreateTime(new Date());
  
   // 异步保存日志
   logService.saveAsync(operationLog);
   }
  }
  ```
  
   2. 日志注解定义
  
  ```java
  @Target(ElementType.METHOD)
  @Retention(RetentionPolicy.RUNTIME)
  public @interface OperationLog {
   /
   * 操作模块
   */
   String module() default "";
  
   /
   * 操作类型
   */
   OperationType operationType() default OperationType.VIEW;
  
   /
   * 是否保存请求参数
   */
   boolean saveParams() default true;
  
   /
   * 是否保存结果数据
   */
   boolean saveResult() default false;
  
   /
   * 操作描述
   */
   String desc() default "";
  }
  
  public enum OperationType {
   CREATE, UPDATE, DELETE, VIEW, OTHER
  }
  ```
  
   3. 异步日志服务
  
  ```java
  @Service
  public class OperationLogServiceImpl implements OperationLogService {
  
   @Autowired
   private OperationLogMapper logMapper;
  
   @Async
   @Override
   public void saveAsync(OperationLog log) {
   try {
   logMapper.insert(log);
   } catch (Exception e) {
   // 失败处理,可写入文件或发送到消息队列重试
   log.error("保存操作日志失败", e);
   }
   }
  }
  ```
  
   四、高级功能实现
  
   1. 日志脱敏处理
  
  ```java
  public class LogDesensitizationUtil {
  
   public static String desensitize(String content) {
   if(StringUtils.isBlank(content)){
   return content;
   }
  
   // 手机号脱敏
   content = content.replaceAll("(\\d{3})\\d{4}(\\d{4})", "$1$2");
   // 身份证号脱敏
   content = content.replaceAll("(\\d{4})\\d{10}(\\w{4})", "$1$2");
   // 邮箱脱敏
   content = content.replaceAll("(\\w?)(\\w+)(\\w)(@\\w+\\.[a-z]+(\\.[a-z]+)?)", "$1$3$4");
  
   return content;
   }
  }
  ```
  
   2. 日志查询接口
  
  ```java
  @RestController
  @RequestMapping("/api/logs")
  public class LogController {
  
   @Autowired
   private OperationLogService logService;
  
   @GetMapping
   public Result> queryLogs(
   @RequestParam(required = false) String username,
   @RequestParam(required = false) String module,
   @RequestParam(required = false) Date startTime,
   @RequestParam(required = false) Date endTime,
   @RequestParam(defaultValue = "1") Integer pageNum,
   @RequestParam(defaultValue = "20") Integer pageSize) {
  
   PageHelper.startPage(pageNum, pageSize);
   List logs = logService.queryLogs(username, module, startTime, endTime);
  
   PageInfo pageInfo = new PageInfo<>(logs);
   PageData pageData = new PageData<>();
   pageData.setTotal(pageInfo.getTotal());
   pageData.setList(BeanCopyUtils.copyList(logs, OperationLogVO.class));
  
   return Result.success(pageData);
   }
  }
  ```
  
   五、部署与监控
  
  1. 日志轮转配置:
   - 对于文件日志,配置logrotate每日轮转
   - 设置保留周期(如30天)
  
  2. 监控告警:
   - 监控日志写入失败率
   - 对ERROR级别日志设置告警阈值
   - 监控异常操作模式(如短时间内大量失败登录)
  
  3. 性能优化:
   - 批量插入日志(每100条或每5秒)
   - 对高频操作采用采样记录(如商品浏览日志)
  
   六、测试用例
  
  1. 正常操作测试:
   - 创建商品并验证日志记录
   - 修改订单状态并验证日志
  
  2. 异常操作测试:
   - 无权限操作验证日志
   - 系统异常时日志记录
  
  3. 性能测试:
   - 高并发下日志写入性能
   - 日志查询响应时间
  
   七、后续优化方向
  
  1. 引入日志压缩减少存储空间
  2. 实现日志自动归档和清理策略
  3. 增加日志行为分析功能,识别潜在安全威胁
  4. 对关键操作实现双因素认证并记录
  
  通过以上方案,快驴生鲜系统实现了全面的用户操作日志记录功能,既满足了审计合规要求,也为系统运维和安全分析提供了有力支持。
评论
  • 下一篇

  • Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 16384 bytes) in /www/wwwroot/www.sjwxsc.com/config/function.php on line 274