淘宝返利软件的日志审计系统:Java Logback+ELK Stack实现操作日志的可追溯与可视化分析

淘宝返利软件的日志审计系统:Java Logback+ELK Stack实现操作日志的可追溯与可视化分析

大家好,我是 微赚淘客系统3.0 的研发者省赚客!

在淘宝返利类软件中,用户提现、订单绑定、佣金结算等关键操作必须具备完整、不可篡改的日志记录,以满足安全审计与问题回溯需求。我们基于 Java 技术栈,采用 Logback 作为日志框架,结合 ELK(Elasticsearch + Logstash + Kibana)构建集中式日志审计系统,实现结构化日志采集、存储与可视化分析。

日志结构化设计

首先定义统一的操作日志模型,确保字段语义清晰:

java 复制代码
package juwatech.cn.log.model;

import com.fasterxml.jackson.annotation.JsonFormat;
import java.time.LocalDateTime;

public class AuditLog {
    private String traceId;           // 全链路追踪ID
    private String userId;            // 操作用户ID
    private String action;            // 操作类型,如 "WITHDRAW_SUBMIT"
    private String resourceId;        // 关联资源ID,如订单号
    private String clientIp;          // 客户端IP
    private String userAgent;         // 客户端标识
    private String status;            // SUCCESS/FAIL
    private String errorMessage;      // 错误详情(可选)
    
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime timestamp;

    // 省略 getter/setter
}

Logback 配置输出 JSON 格式日志

logback-spring.xml 中配置 net.logstash.logback.encoder.LoggingEventCompositeJsonEncoder,将日志直接输出为 JSON:

xml 复制代码
<configuration>
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder class="net.logstash.logback.encoder.LoggingEventCompositeJsonEncoder">
            <providers>
                <timestamp/>
                <logLevel/>
                <loggerName/>
                <message/>
                <arguments/>
                <mdc/> <!-- 支持 MDC 注入 traceId、userId 等 -->
                <stackTrace/>
            </providers>
        </encoder>
    </appender>

    <root level="INFO">
        <appender-ref ref="STDOUT"/>
    </root>
</configuration>

MDC 上下文注入关键字段

在请求入口处通过拦截器注入用户ID、TraceID等信息到 MDC:

java 复制代码
package juwatech.cn.log.interceptor;

import org.slf4j.MDC;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.UUID;

@Component
public class AuditLogInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        String traceId = UUID.randomUUID().toString().replace("-", "");
        String userId = request.getHeader("X-User-ID"); // 由网关注入
        String clientIp = getClientIp(request);

        MDC.put("traceId", traceId);
        MDC.put("userId", userId != null ? userId : "anonymous");
        MDC.put("clientIp", clientIp);
        MDC.put("userAgent", request.getHeader("User-Agent"));

        return true;
    }

    private String getClientIp(HttpServletRequest request) {
        String ip = request.getHeader("X-Forwarded-For");
        if (ip == null || ip.isEmpty()) {
            ip = request.getRemoteAddr();
        }
        return ip;
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
        MDC.clear();
    }
}

注册拦截器:

java 复制代码
package juwatech.cn.config;

import juwatech.cn.log.interceptor.AuditLogInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new AuditLogInterceptor())
                .addPathPatterns("/api/**");
    }
}

业务层记录审计日志

在关键服务方法中记录结构化日志:

java 复制代码
package juwatech.cn.service;

import juwatech.cn.log.model.AuditLog;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

@Service
public class WithdrawService {

    private static final Logger auditLogger = LoggerFactory.getLogger("AUDIT_LOG");
    private final ObjectMapper objectMapper = new ObjectMapper();

    public void submitWithdraw(String userId, String orderId, double amount) {
        try {
            // 执行提现逻辑
            processWithdraw(userId, orderId, amount);

            AuditLog log = new AuditLog();
            log.setAction("WITHDRAW_SUBMIT");
            log.setUserId(userId);
            log.setResourceId(orderId);
            log.setStatus("SUCCESS");
            log.setTimestamp(java.time.LocalDateTime.now());

            auditLogger.info(objectMapper.writeValueAsString(log));
        } catch (Exception e) {
            AuditLog log = new AuditLog();
            log.setAction("WITHDRAW_SUBMIT");
            log.setUserId(userId);
            log.setResourceId(orderId);
            log.setStatus("FAIL");
            log.setErrorMessage(e.getMessage());
            log.setTimestamp(java.time.LocalDateTime.now());

            auditLogger.warn(objectMapper.writeValueAsString(log));
            throw e;
        }
    }

    private void processWithdraw(String userId, String orderId, double amount) {
        // 实际业务逻辑
    }
}

Logstash 配置解析与转发

Logstash 配置文件 logstash.conf 如下,从 Filebeat 或直接从 Docker 日志读取并写入 Elasticsearch:

conf 复制代码
input {
  beats {
    port => 5044
  }
}

filter {
  json {
    source => "message"
    target => "log"
  }
  date {
    match => ["[log][timestamp]", "yyyy-MM-dd HH:mm:ss"]
    target => "@timestamp"
  }
}

output {
  elasticsearch {
    hosts => ["http://elasticsearch.juwatech.cn:9200"]
    index => "juwatech-audit-%{+YYYY.MM.dd}"
  }
}

Kibana 可视化看板

在 Kibana 中创建索引模式 juwatech-audit-*,并基于以下字段构建看板:

  • log.action 统计操作分布
  • log.status 监控失败率
  • 通过 log.traceId 追踪全链路
  • 设置告警规则:当 WITHDRAW_SUBMIT 失败率 > 1% 时触发通知

日志安全与合规

所有审计日志禁止删除,Elasticsearch 索引设置生命周期策略(ILM)保留180天,并开启 HTTPS 与 Basic Auth 访问控制。同时,敏感字段(如手机号)在业务层脱敏后再记录。

本文著作权归 微赚淘客系统3.0 研发团队,转载请注明出处!

相关推荐
云烟成雨TD14 小时前
Spring AI Alibaba 1.x 系列【6】ReactAgent 同步执行 & 流式执行
java·人工智能·spring
于慨14 小时前
Lambda 表达式、方法引用(Method Reference)语法
java·前端·servlet
swg32132114 小时前
Spring Boot 3.X Oauth2 认证服务与资源服务
java·spring boot·后端
gelald15 小时前
SpringBoot - 自动配置原理
java·spring boot·后端
殷紫川15 小时前
深入理解 AQS:从架构到实现,解锁 Java 并发编程的核心密钥
java
一轮弯弯的明月15 小时前
贝尔数求集合划分方案总数
java·笔记·蓝桥杯·学习心得
chenjingming66615 小时前
jmeter线程组设置以及串行和并行设置
java·开发语言·jmeter
殷紫川15 小时前
深入拆解 Java volatile:从内存屏障到无锁编程的实战指南
java
eddieHoo15 小时前
查看 Tomcat 的堆内存参数
java·tomcat
那个失眠的夜15 小时前
Mybatis延迟加载策略
xml·java·数据库·maven·mybatis