淘宝返利软件的日志审计系统: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 研发团队,转载请注明出处!

相关推荐
Remember_9938 分钟前
SpringCloud:Nacos注册中心
java·开发语言·后端·算法·spring·spring cloud·list
QEasyCloud202210 分钟前
WooCommerce 独立站系统集成技术方案
java·前端·数据库
小宋102120 分钟前
从 Kafka 告警到前端实时可见:SSE 在故障诊断平台中的一次完整落地实践
java·前端·kafka
塔尖尖儿21 分钟前
DDD架构
java·架构
牢七1 小时前
反序列化重点模块 private Object readOrdinaryObject(boolean unshared)废案与反思
java·服务器·前端
量子物理学1 小时前
三、C#高级进阶语法——特性(Attribute)
java·算法·c#
刘恒1234567891 小时前
Windows 电脑文件夹手动分类指南
java·windows·python·电脑·php
爱学习的小可爱卢1 小时前
JavaSE基础-Java异常处理全解析:从ClassNotFound到IndexOutOfBounds
java·javase
小王不爱笑1322 小时前
LangChain4j 项目实战--1:硅谷小智(医疗智能客服)笔记
java