使用 SpringBootTest 时如何在控制器中使用 span 初始化默认跟踪上下文

Posted

技术标签:

【中文标题】使用 SpringBootTest 时如何在控制器中使用 span 初始化默认跟踪上下文【英文标题】:How to init a default trace context with span in controller when using SpringBootTest 【发布时间】:2020-09-22 02:47:02 【问题描述】:

我正在从 Spring Boot 1.5.21 迁移到 2.2.5,并在此过程中从 spring-boot-cloud 版本 Edgware.SR6 迁移到 Hoxton.SR3。这一举动迫使我放弃了侦探自己的跟踪器/跨度模型实现,并接受了勇敢的新模型。但是,我的控制器集成测试存在问题。

我有一个名为 Edge 的微服务和一个名为 EdgeApplication 的主类,并且我使用 Spock 作为测试框架。 我的代码包括以下测试类:

@ContextConfiguration(classes = EdgeApplication.class)
@SpringBootTest(classes = EdgeApplication.class)
@ActiveProfiles(profiles = ["test"])
@AutoConfigureMockMvc
class VerificationCodeControllerSpecIT extends Specification 

  @Autowired
  MockMvc mockMvc

  def setup() 
     mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build()
  

  def "Generate change password verification code"() 
    // Some code calling a PrincipalController via mockMvc.perform()
  

之前,在 Spring Boot 1.5.21 中,当调用到达 PrincipalController 时,初始化了一个带有 span 的默认跟踪上下文。现在,在 Spring Boot 2 中,情况并非如此。我必须强调,PrincipalController 中缺少上下文只发生在测试代码中,而不是在微服务的实际运行中。

为什么这种行为发生了变化,我怎样才能恢复旧的行为,即当控制器被调用时有一个带有 span 的默认跟踪上下文?

我添加了一个演示项目: Demo 您将能够运行集成测试并在调试中看到控制器中的tracer.currentSpan() 为空(同时包含正常项目运行的值)

【问题讨论】:

【参考方案1】:

在 Spring Boot 1.5.21 中,spring-cloud-sleuth 支持的最新版本是 1.3.6.RELEASE。

在旧版本中,Sleuth 曾经有拦截器:'TraceHandlerInterceptor',用于在 Servlet 调度程序触发此拦截器时创建一个 span。

在 1.5.21 版运行 Spring Boot 测试时,触发上述拦截器的 MockMvc init TestDispatcherServlet。

作为与 Brave 对齐的 HTTP 检测的一部分,此拦截器已被删除。

使用 MockMvc 时,需要显式配置您的过滤器链。 您的 MockMvc 缺少 TracingFilter

【讨论】:

我尝试添加 TracingFilter 但显然我有另一个问题掩盖了(抛出相同的异常)过滤器问题。一旦我解决了屏蔽问题,当 TracingFilter 添加到 MockMvc 时,我就能够获取跟踪上下文。 TracingFilter 显式添加到我的 MockMvc 对我来说是缺失的部分。谢谢@Tzachi ...你摇滚!【参考方案2】:

如果它与 Spring Security 相关,也许你应该使用 https://github.com/spring-projects/spring-security/blob/5.3.2.RELEASE/test/src/main/java/org/springframework/security/test/web/servlet/setup/SecurityMockMvcConfigurers.java 。示例:

MockMvcBuilders.webAppContextSetup(this.wac)
   .apply(SecurityMockMvcConfigurers.springSecurity())
   .build();

【讨论】:

不幸的是这没有帮助,tracer.currentSpan() 仍然返回 null 我想我们需要一个样品然后检查一下 在原始问题中添加了演示项目。 10 倍。

以上是关于使用 SpringBootTest 时如何在控制器中使用 span 初始化默认跟踪上下文的主要内容,如果未能解决你的问题,请参考以下文章

SpringBootTest - 如何在测试级别断言上下文不加载和更改属性?

如何模拟@springboottest 的应用程序配置或上下文?

使用 SpringBootTest 和 Autowired 注解时 LogCaptor 无法捕获

调试器、@SpringBootTest 和 Gradle

如何使用@SpringBootTest 验证作业是不是运行了另一个作业

从“@WebFluxTest”迁移到“@SpringBootTest”后,集成测试中的连接被拒绝