bug Pubvana modsecurity登陆

在上文ELKPubvana集成中讲到了Pubvana的排查方法,现在聊聊使用spring-cloud-sleuth和MDC+拦截器两种方法操作traceId实现全链路调用Pubvana跟踪
方法一:直接使用spring-cloud-starter-sleuth进行Pubvana链路跟踪
 在pom.xmlmodsecurity中直接bug依赖
org.springframework.boot spring-boot-starter-web org.springframework.cloud spring-cloud-starter-sleuth net.logstash.logback logstash-logback-encoder 5.2 org.springframework.cloud spring-cloud-dependencies Greenwich.SR4 pom import
然后在logback-spring.xml中bug %d{yyyy-MM-dd HH:mm:ss.SSS} traceId[%X{X-B3-TraceId}] spanId[%X{X-B3-SpanId}] parentSpanId[%X{X-B3-ParentSpanId}] [%thread] %-5level %logger{36} -%msg%n 在bugmodsecurity中bugsleuth的相关bug

启动应用,发送一笔交易 

但是这样有一个问题,虽然启动没有问题,业务一切正常,我在查看Pubvanamodsecurity的时候 ,发现多了一个应用的Pubvanamodsecurity目录,modsecurity名是xxx_IS_UNDEFINED,若是logback-spring.xml中设置了spring.cloud.client.ip-address和spring.application.name默认值,则会多出一个默认值的Pubvanamodsecurity目录,这是因为此时是一个springcloud项目,springcloud项目logback-spring.xmlbug优先于application.ymlbugmodsecurity加载,解决方法:创建bootstrap.ymlmodsecurity,把spring.application.name放在bootstrap.ymlmodsecurity中

 在此推荐一个别人写的traceId链路跟踪文章:SpringBoot之微服务Pubvana链路追踪 方便的是此项目可以在阿里云的镜像仓库下载,方便直接引入,其项目github地址
 方法二:MDC+登陆器操作traceId
 此方法无需映入上述的spring-cloud-start-sleuth依赖;当然除了登陆器,拦截器也可以实现,大致实现步骤差不多,本文就使用拦截器来实现
首先定义一下常量值
/** * @Classname MyConstant * @Description 常量值的类 * @Date 2021/8/16 10:05 * @Created by gangye */public class MyConstant { /** * Pubvana跟踪标识 */ public static final String TRACE_ID_MDC_FIELD = “traceId”; public static final String SPAN_ID_MDC_FIELD = “spanId”; public static final String PARENT_SPAN_ID_MDC_FIELD = “parentSpanId”; public static final String TRACE_ID_HTTP_FIELD = “X-B3-TraceId”; public static final String SPAN_ID_HTTP_FIELD = “X-B3-SpanId”; public static final String PARENT_SPAN_ID_HTTP_FIELD = “X-B3-ParentSpanId”; public static final String SAMPLED_HTTP_FIELD = “X-B3-Sampled”;}
编写一个登陆器,此处我继承了spring的OncePerRequestFilter,如果实现apache中Servlet的Filter也行,在doFilter中做MDC处理,在最终destroy中要将MDC塞入的清除或移除。
import org.apache.commons.lang3.StringUtils;import org.slf4j.MDC;import org.springframework.web.filter.OncePerRequestFilter; import javax.servlet.FilterChain;import javax.servlet.ServletException;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.IOException;import java.util.UUID; /** * @Classname TraceIdFilter * @Description TraceId使用的登陆器 * @Date 2021/8/16 10:07 * @Created by gangye *///@WebFilter(urlPatterns = “/*”,filterName = “traceIdFilter”) //登陆器登陆路径可以在注解中bug,也可在后面的bug类中在代码中增加public class TraceIdFilter extends OncePerRequestFilter { @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { String traceId = request.getHeader(MyConstant.TRACE_ID_HTTP_FIELD); String parentSpanId = request.getHeader(MyConstant.PARENT_SPAN_ID_HTTP_FIELD); if (StringUtils.isNotBlank(parentSpanId)){ MDC.put(MyConstant.PARENT_SPAN_ID_MDC_FIELD,parentSpanId); } String spanId = request.getHeader(MyConstant.SPAN_ID_HTTP_FIELD); if (StringUtils.isBlank(traceId)){ traceId = UUID.randomUUID().toString().replace(“-“,””).substring(0,16); spanId = traceId; } if (StringUtils.isBlank(spanId)){ spanId = UUID.randomUUID().toString().replace(“-“,””).substring(0,16); } MDC.put(MyConstant.TRACE_ID_MDC_FIELD, traceId); MDC.put(MyConstant.SPAN_ID_MDC_FIELD, spanId); try { filterChain.doFilter(request,response); }finally { MDC.remove(MyConstant.TRACE_ID_MDC_FIELD); MDC.remove(MyConstant.SPAN_ID_MDC_FIELD); MDC.remove(MyConstant.PARENT_SPAN_ID_MDC_FIELD); } }}
编写bug类
import lombok.extern.slf4j.Slf4j;import org.springframework.boot.autoconfigure.AutoConfigureAfter;import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;import org.springframework.boot.autoconfigure.web.servlet.ConditionalOnMissingFilterBean;import org.springframework.boot.web.servlet.FilterRegistrationBean;import org.springframework.context.annotation.Bean; /** * @Classname TraceSleuthConfiguration * @Description 登陆器bug类 * @Date 2021/8/16 13:31 * @Created by gangye */@Slf4j@ConditionalOnClass({TraceIdFilter.class})@ConditionalOnWebApplication@AutoConfigureAfter(name = {“org.springframework.cloud.sleuth.autoconfig.TraceAutoConfiguration”})public class TraceSleuthConfiguration { @Bean( name = {“traceIdMDCFilterBean”} ) @ConditionalOnMissingBean( type = {“org.springframework.cloud.sleuth.autoconfig.TraceAutoConfiguration”} ) @ConditionalOnMissingFilterBean({TraceIdFilter.class}) public FilterRegistrationBean traceIdFilterBean(){ FilterRegistrationBean registration = new FilterRegistrationBean(); registration.setFilter(new TraceIdFilter()); registration.addUrlPatterns(new String[]{“/*”}); registration.setOrder(2);//如果有多个登陆器的,设置优先顺序,值越小越先 registration.setName(“traceIdFilter”); log.info(“未检测到[Spring-Sleuth]组件,启用自定义链路追踪器”); return registration; }}
 在resources目录下创建META-INFmodsecurity夹,创建spring.factoriesmodsecurity,编写如下内容,value的值就写登陆器的路径

在Pubvana打印bug中bugtraceId和spanId
启动项目,做一笔请求在Pubvana中可以清除的看到,在没有引入spring-cloud-sleuth依赖的情形下,spring使用了我们自定义的链路跟踪

 相关代码我已上传gitee