【问题标题】:How to trace requests in normal Spring micro service app (non Spring boot)?如何在普通 Spring 微服务应用程序(非 Spring 启动)中跟踪请求?
【发布时间】:2020-05-29 21:45:10
【问题描述】:

如何在普通的 Spring 微服务应用程序(非 Spring 启动)中跟踪请求? 我知道 Spring Boot 给了 Sleuth,但我想对非 Spring Boot 应用程序做类似的事情,它是一个普通的 Spring 应用程序。当请求通过不同的微服务时,我们要跟踪它们。

【问题讨论】:

  • 您要追踪哪些内容?执行时间也一样?
  • 说请求从模块 A -> 模块 B -> 模块 C 传递,这些模块/应用程序中的每一个都会有自己的处理,所以我有兴趣通过每个应用程序找到请求,如果它失败或者在任何应用程序中运行缓慢,我们可以通过唯一 id 对其进行跟踪

标签: java spring http spring-mvc optimization


【解决方案1】:
  1. 您需要将 Spring 应用程序配置为使用 logback.xml 文件进行日志记录。
  2. 创建一个拦截器,可以像 Sleuth 一样设置额外的 MDC 上下文
  3. 您需要将相同的附加 MDC 上下文传递给 HTTP 标头中的其他服务。

登录配置

<configuration>
      <appender class="ch.qos.logback.core.ConsoleAppender" name="STDOUT">
        <encoder>
          <pattern>[%date{dd-MM-yyyy HH:mm:ss.SSS}]  [%thread] %-5level %X{traceId:-} %X{spanId:-} ${PID:-} %logger{36} - %msg%n</pattern>
        </encoder>
      </appender>
      <appender class="ch.qos.logback.core.rolling.RollingFileAppender" name="FILE">
        <encoder>
          <pattern>[%date{dd-MM-yyyy HH:mm:ss.SSS}]  [%thread] %-5level %X{traceId:-} %X{spanId:-} ${PID:-} %logger{36} - %msg%n</pattern>
        </encoder>
        <file>log/app.log</file>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
          <fileNamePattern>log/app.%d{yyyy-MM-dd-HH}.log</fileNamePattern>
          <maxHistory>30</maxHistory>
          <totalSizeCap>200MB</totalSizeCap>
        </rollingPolicy>
      </appender>

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

为跟踪设置 MDC 上下文的拦截器。

@Slf4j
public class LoggerInterceptor implements HandlerInterceptor {
  @Override
  public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
      throws Exception {
    String traceId = request.getHeader("TRACE_ID");
    String spanId = request.getHeader("SPAN_ID");
    if (traceId == null) {
      traceId = UUID.randomUUID().toString();
    }
    // You can generate new spanId or use the same one
    if (spanId == null) {
      spanId = UUID.randomUUID().toString();
    }
    MDC.put("TRACE_ID", traceId);
    MDC.put("traceId", traceId);
    MDC.put("SPAN_ID", spanId);
    MDC.put("spanId", spanId);
    log.info("[preHandle] HTTP: {}, URL: {} ", request.getMethod(), request.getRequestURI());
    return true;
  }

  @Override
  public void postHandle(
      HttpServletRequest request,
      HttpServletResponse response,
      Object handler,
      ModelAndView modelAndView)
      throws Exception {
    log.info("[postHandle] HTTP: {}, URL: {} ", request.getMethod(), request.getRequestURI());
    MDC.clear();
  }
}

如果您想测量执行时间,请添加一个分析器。在Profiling Spring Boot 的示例中了解更多信息,它具体说明了 Spring boot,但您也可以在 Spring 应用程序中使用相同的方法。

如果您使用的是 RestTemplate,那么您可以设置这些标头。

  HttpHeaders headers = new HttpHeaders();
  headers.set("TRACE_ID", MDC.get("TRACE_ID"));
  headers.set("SPAN_ID", MDC.get("SPAN_ID"));

  HttpEntity entity = new HttpEntity(headers);
  RestTemplate restTemplate = new RestTemplate();
  SimpleClientHttpRequestFactory rf =
      (SimpleClientHttpRequestFactory) restTemplate.getRequestFactory();
  rf.setReadTimeout(2 * Constants.ONE_MILLI_INT);
  rf.setConnectTimeout(2 * Constants.ONE_MILLI_INT);
  ResponseEntity<String> response =
      restTemplate.exchange(url, HttpMethod.GET, entity, String.class);

在这个简单的示例中,TRACE_IDSPAN_ID 标头已设置。

【讨论】:

  • 谢谢,如果有任何现有的图书馆这样做,请告诉我
  • 就我个人而言,我还没有见过这样的库,也许有一些。你可以把这段代码放在一些常用的模块中,跨服务使用。
  • 好的,它不会与 log4j 一起工作,对 logback 有任何特定依赖吗?
  • 它将与log4j一起使用,您需要添加一些与log back相关的依赖项。我相信您可能已经有了这些依赖项。
猜你喜欢
  • 1970-01-01
  • 2015-10-05
  • 2016-02-02
  • 2021-08-25
  • 2020-01-13
  • 2022-07-08
  • 2018-10-27
  • 2018-11-08
  • 1970-01-01
相关资源
最近更新 更多