大数跨境
0
0

Spring Boot 日志处理的两大核心技术:请求跟踪与日志过滤

Spring Boot 日志处理的两大核心技术:请求跟踪与日志过滤 Spring全家桶实战案例
2025-12-06
0
导读:Spring Boot 日志处理的两大核心技术:请求跟踪与日志过滤
Spring Boot 3实战案例锦集PDF电子书已更新至130篇!

🎉🎉《Spring Boot实战案例合集》目前已更新195个案例,我们将持续不断的更新。文末有电子书目录。

💪💪永久更新承诺

我们郑重承诺,所有订阅合集的粉丝都将享受永久免费的后续更新服务

💌💌如何获取
订阅我们的合集点我订阅,并通过私信联系我们,我们将第一时间将电子书发送给您。

→ 现在就订阅合集

环境:SpringBoot3.4.2



1. 简介

在分布式系统及复杂业务场景下,日志作为系统运行的关键记录,其有效管理与分析至关重要。请求跟踪能监控流转路径、定位故障,而MDC作为线程绑定的诊断工具,可关联链路数据辅助排查。但日志量庞大时,精准过滤与高效处理成为难题。Logback的TurboFilter能在日志处理早期进行精细控制,满足基于动态条件过滤等需求,为日志管理提供了有力手段。

本篇文章我们将深入探讨日志处理领域中请求跟踪与日志过滤两大关键技术。

2.实战案例
2.1 请求跟踪

请求跟踪可全程监控请求流转路径,精准定位性能瓶颈与故障点。结合MDC,能在日志里高效关联链路数据。

什么是MDC?

MDC(Mapped Diagnostic Context)是线程绑定的诊断上下文工具,可存储键值对信息。在请求跟踪中,它能在日志里自动关联请求链路数据,助力快速定位问题,提升系统可观测性与故障排查效率。

接下来,我们借助MDC在日志中植入唯一ID,以此构建完整的请求链路标识,实现精准高效的请求跟踪。

首先,定义Filter通过过滤器将唯一标识加入到线程上下文中
@Componentpublic class TraceXFilter implements Filter {  private static final Logger logger = LoggerFactory.getLogger(TraceXFilter.class) ;  public static final String TRACE_KEY = "traceXId" ;
  @Override  public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)      throws IOException, ServletException {    HttpServletRequest req = (HttpServletRequest) request ;    // 通过请求header获取自定义的traceId,没有则系统生成    String traceId = req.getHeader("x-trace") ;
    if (!StringUtils.hasLength(traceId)) {      traceId = UUID.randomUUID().toString().replace("-""").toUpperCase() ;    }    // 将当前请求的traceId存入到MDC中    MDC.put(TRACE_KEY, traceId) ;
    logger.info("请求: {}", req.getServletPath()) ;    try {      chain.doFilter(request, response) ;    } finally {      MDC.remove(TRACE_KEY) ;    }  }}
接下来,我们只需要在日志配置文件中进行如下配置
<configuration scan="true">  <contextName>trace-mdc</contextName>  <!-- 注意这里的traceXId就是我们往MDC中存入的key了,通过%X{traceXId}获取唯一标识 -->  <property name="TRACEX_PATTERN"    value="%green(%d{HH:mm:ss}) traceId:【%red(%X{traceXId})】 %highlight(%-5level) [%yellow(%thread)] %logger Line:%-3L - %msg%n" />
  <appender name="TRACEX" class="ch.qos.logback.core.ConsoleAppender">    <encoder>      <pattern>${TRACEX_PATTERN}</pattern>      <charset>UTF-8</charset>    </encoder>  </appender>
  <springProfile name="dev | default">    <root level="INFO">      <appender-ref ref="TRACEX" />    </root>  </springProfile></configuration>
最后,我们定义Controller接口进行测试
private final static Logger logger = LoggerFactory.getLogger(ApiController.class) ; @GetMapping("/query")public ResponseEntity<?> query() {  logger.info("query start...") ;  return ResponseEntity.ok("api query...") ;}
访问该接口,控制台日志输出如下:

在当前请求的链路里,日志具备唯一标识后,我们能够更加便捷、高效地排查问题。

2.2 日志过滤
Logback内部提供了 TurboFilter 过滤器(注意这可不是Servlet中的过滤器,不是一个东西),通过该过滤器,我们可以在不牺牲性能的前提下,对日志消息的处理方式和时机进行精细控制。
什么是TurboFilter?

TurboFilter在日志处理流程的非常早期阶段就被调用——甚至在对日志级别进行检查之前。这意味着,一旦日志框架看到日志语句,你就可以立即决定是否让该日志语句继续处理。

通常在以下情况下,我们是非常需要TurboFilter:

  • 你想基于动态条件(如会话中的用户ID)来过滤日志

  • 在高性能应用中,你需要超快速地决定是否记录某些内容

  • 你想避免日志污染,在日志消息甚至还未输出到控制台或日志文件之前就将其丢弃

  • 你需要在日志生命周期的早期阶段使用映射诊断上下文(Mapped Diagnostic Context,MDC)或标记(Markers)

接下来,我们通过TurboFilter实现日志过滤功能。

我们只需要在logback-spring.xml中加入如下配置:

<configuration>  <turboFilter class="ch.qos.logback.classic.turbo.MDCFilter">    <MDCKey>userId</MDCKey>      <Value>admin</Value>      <OnMatch>ACCEPT</OnMatch>      <OnMismatch>DENY</OnMismatch>  </turboFilter></configuration>    

有了该配置它会检查MDC键userId是否等于“admin”。如果匹配,则接受并处理日志消息。如果不匹配,则丢弃日志消息——避免日志文件杂乱!

修改TraceXFilter过滤器如下:

public class TraceXFilter implements Filter {  public void doFilter(...) {    MDC.put("userId", request.getParameter("name")) ;  }}

接下来,我们继续访问上面的/api/query?name=admin接口,控制台输出:

而当name是其它取值,控制台将不输出任何内容。

在该日志输出情况看到,这时候不管什么级别的日志都输出了,这是由于我们配置的OnMatch=ACCEPT的原因,这将完全绕过 <root level="INFO"> 的级别控制。我们将其修改为NEUTRAL,这样就继续后续过滤器或root级别判断。输出如下:

2.3 自定义日志过滤器
如果你希望更多细粒度的控制日志,那么我们完全可以自定义TurboFilter,如下示例:
public class PackTurboFilter extends TurboFilter {  private static final String SENSITIVE_LOG = "com.pack.sensitive" ;
  @Override  public FilterReply decide(Marker marker, ch.qos.logback.classic.Logger logger, Level level, String format,      Object[] params, Throwable t) {    if (level.isGreaterOrEqual(Level.WARN)) {      return FilterReply.ACCEPT;    }    if (SENSITIVE_LOG.equals(logger.getName())) {      return FilterReply.DENY;    }    String userId = getContext().getCopyOfPropertyMap().get("userId") ;    if ("admin".equals(userId)) {        return FilterReply.ACCEPT ;    }    return FilterReply.NEUTRAL;  }}
说明:
  1. 基于日志级别的过滤

  2. 基于Logger名称的过滤

  3. 基于MDC值的过滤

修改logback-spring.xml
<configuration>  <turboFilter class="com.pack.mdc.filter.PackTurboFilter"/></configuration>

总结:TurboFilter 的优势在于其早期过滤能力,但不当使用可能会:

  • 引入不必要的同步开销

  • 增加内存使用(如果存储状态)

  • 意外过滤掉重要日志

所以,我们还是慎重考虑使用,用也应该进行必要的性能测试。

以上是本篇文章的全部内容,如对你有帮助帮忙点赞+转发+收藏
字段权限!Spring Boot 最简单的控制方式

强大!Spring非常实用的内置类专门处理Rest API异常

性能优化!Spring Boot 优化JPA插入操作,性能提升N倍,尤其批量操作

Spring Boot 基于注解实现字段级完整性校验,支持JPA、Mybatis

别再错过!Spring Boot 12个高级开发技巧,助你成为大神

告别下载风险!Spring Boot 打造安全的文件下载功能

全栈开发!Spring Boot 文件下载的N种神级姿势

告别内存溢出!Spring StreamingResponseBody 三大实战案例,性能提升100%

API接口优化!基于Spring Boot 实现Deflate压缩技术

强大!SQL解析神器JSQLParser

强大!Spring Boot敏感数据动态配置,这样做更安全

图片
图片
图片
图片
图片
图片
图片
图片
图片

【声明】内容源于网络
0
0
Spring全家桶实战案例
Java全栈开发,前端Vue2/3全家桶;Spring, SpringBoot 2/3, Spring Cloud各种实战案例及源码解读
内容 832
粉丝 0
Spring全家桶实战案例 Java全栈开发,前端Vue2/3全家桶;Spring, SpringBoot 2/3, Spring Cloud各种实战案例及源码解读
总阅读7
粉丝0
内容832