淘宝返利软件的日志审计系统:Java Logback+ELK Stack实现操作日志的可追溯与可视化分析
大家好,我是 微赚淘客系统3.0 的研发者省赚客!
在淘宝返利类软件中,用户提现、订单绑定、佣金结算等关键操作必须具备完整、不可篡改的日志记录,以满足安全审计与问题回溯需求。我们基于 Java 技术栈,采用 Logback 作为日志框架,结合 ELK(Elasticsearch + Logstash + Kibana)构建集中式日志审计系统,实现结构化日志采集、存储与可视化分析。
日志结构化设计
首先定义统一的操作日志模型,确保字段语义清晰:
packagejuwatech.cn.log.model;importcom.fasterxml.jackson.annotation.JsonFormat;importjava.time.LocalDateTime;publicclassAuditLog{privateStringtraceId;// 全链路追踪IDprivateStringuserId;// 操作用户IDprivateStringaction;// 操作类型,如 "WITHDRAW_SUBMIT"privateStringresourceId;// 关联资源ID,如订单号privateStringclientIp;// 客户端IPprivateStringuserAgent;// 客户端标识privateStringstatus;// SUCCESS/FAILprivateStringerrorMessage;// 错误详情(可选)@JsonFormat(pattern="yyyy-MM-dd HH:mm:ss")privateLocalDateTimetimestamp;// 省略 getter/setter}Logback 配置输出 JSON 格式日志
在logback-spring.xml中配置net.logstash.logback.encoder.LoggingEventCompositeJsonEncoder,将日志直接输出为 JSON:
<configuration><appendername="STDOUT"class="ch.qos.logback.core.ConsoleAppender"><encoderclass="net.logstash.logback.encoder.LoggingEventCompositeJsonEncoder"><providers><timestamp/><logLevel/><loggerName/><message/><arguments/><mdc/><!-- 支持 MDC 注入 traceId、userId 等 --><stackTrace/></providers></encoder></appender><rootlevel="INFO"><appender-refref="STDOUT"/></root></configuration>MDC 上下文注入关键字段
在请求入口处通过拦截器注入用户ID、TraceID等信息到 MDC:
packagejuwatech.cn.log.interceptor;importorg.slf4j.MDC;importorg.springframework.stereotype.Component;importorg.springframework.web.servlet.HandlerInterceptor;importjavax.servlet.http.HttpServletRequest;importjavax.servlet.http.HttpServletResponse;importjava.util.UUID;@ComponentpublicclassAuditLogInterceptorimplementsHandlerInterceptor{@OverridepublicbooleanpreHandle(HttpServletRequestrequest,HttpServletResponseresponse,Objecthandler){StringtraceId=UUID.randomUUID().toString().replace("-","");StringuserId=request.getHeader("X-User-ID");// 由网关注入StringclientIp=getClientIp(request);MDC.put("traceId",traceId);MDC.put("userId",userId!=null?userId:"anonymous");MDC.put("clientIp",clientIp);MDC.put("userAgent",request.getHeader("User-Agent"));returntrue;}privateStringgetClientIp(HttpServletRequestrequest){Stringip=request.getHeader("X-Forwarded-For");if(ip==null||ip.isEmpty()){ip=request.getRemoteAddr();}returnip;}@OverridepublicvoidafterCompletion(HttpServletRequestrequest,HttpServletResponseresponse,Objecthandler,Exceptionex){MDC.clear();}}注册拦截器:
packagejuwatech.cn.config;importjuwatech.cn.log.interceptor.AuditLogInterceptor;importorg.springframework.context.annotation.Configuration;importorg.springframework.web.servlet.config.annotation.InterceptorRegistry;importorg.springframework.web.servlet.config.annotation.WebMvcConfigurer;@ConfigurationpublicclassWebConfigimplementsWebMvcConfigurer{@OverridepublicvoidaddInterceptors(InterceptorRegistryregistry){registry.addInterceptor(newAuditLogInterceptor()).addPathPatterns("/api/**");}}业务层记录审计日志
在关键服务方法中记录结构化日志:
packagejuwatech.cn.service;importjuwatech.cn.log.model.AuditLog;importcom.fasterxml.jackson.databind.ObjectMapper;importorg.slf4j.Logger;importorg.slf4j.LoggerFactory;importorg.springframework.stereotype.Service;@ServicepublicclassWithdrawService{privatestaticfinalLoggerauditLogger=LoggerFactory.getLogger("AUDIT_LOG");privatefinalObjectMapperobjectMapper=newObjectMapper();publicvoidsubmitWithdraw(StringuserId,StringorderId,doubleamount){try{// 执行提现逻辑processWithdraw(userId,orderId,amount);AuditLoglog=newAuditLog();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(Exceptione){AuditLoglog=newAuditLog();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));throwe;}}privatevoidprocessWithdraw(StringuserId,StringorderId,doubleamount){// 实际业务逻辑}}Logstash 配置解析与转发
Logstash 配置文件logstash.conf如下,从 Filebeat 或直接从 Docker 日志读取并写入 Elasticsearch:
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 研发团队,转载请注明出处!