Logbook 4在 Spring Boot 4中未记录异步响应的trace-id

后端开发 2026-07-10

在从Spring Boot 3.5/Logbook 3.12迁移到Spring Boot 4/Logbook 4.0.4之后,我发现Logbook生成的日志在Spring Web MVC控制器的异步HTTP响应中缺少trace-id。

在我的情况下,异步响应是使用Reactor的 Mono 返回类型实现的控制器方法,这是被允许的——参见: https://docs.spring.io/spring-framework/reference/web/webmvc/mvc-ann-async.html#mvc-ann-async-reactive-types

我猜这是Spring Boot、Micrometer Tracing与 Logbook集成方面的一个问题。理论上Logbook对 Micrometer一无所知,Spring Boot也可以在没有Micrometer的情况下工作。因此我猜新版本中的Micrometer Tracing在异步HTTP响应领域缺少了某些东西。

添加下面的Spring bean也不起作用:

  @Bean
  ContextPropagatingTaskDecorator contextPropagatingTaskDecorator() {
    return new ContextPropagatingTaskDecorator();
  }

在单元测试前面添加下面这行代码也同样不起作用:

Hooks.enableAutomaticContextPropagation();

我使用以下依赖:

  • org.springframework.boot:spring-boot-starter-actuator
  • org.springframework.boot:spring-boot-micrometer-tracing-opentelemetry
  • io.micrometer:micrometer-tracing-bridge-otel

如果我把控制器方法的返回类型从 Mono<T> 改为 CompletableFuture<T>,从而消除Reactor,问题仍然存在。因此这与Reactor无关。


我认为这里的根本原因在于方法 javax.servlet.AsyncListener::onComplete 没有在重新创建的上下文快照(Micrometer术语)中被调用。在这种情况下 LogbookFilter 注册了一个 LogbookAsyncListener 类的实例,该实例实现了 javax.servlet.AsyncListener 接口。所以这是Logbook与 Servlet容器集成的一个领域。我的猜测是,当存在Micrometer Tracing时,Spring Boot应该正确对Servlet堆栈进行打点,这样 javax.servlet.AsyncListener 应该在重新创建的上下文快照中被调用。

有什么办法可以修复吗?

解决方案

我来回答我自己的问题:在这种情况下的一个变通方案是准备一个自定义bean类来替换LogbookFilter。自定义过滤器类必须:

if (request.isAsyncStarted()) {
  var wrapped = contextSnapshotFactory.captureAll().wrap(() -> {
        try {
          write(response, writing);
        } catch (IOException e) {
          throw new UncheckedIOException(e);
        }
      });
  request.getAsyncContext().addListener(
    new LogbookAsyncListener(event -> wrapped.run()));
}

如果 LobookFilter 类能提供可注入工厂,用于生成 LogbookAsyncListener 实例或 AsyncOnCompleteListener 实例,那么就可以提供自定义实现,但现在Logbook不支持它。此外Logbook类是final,因此需要如上完整地替换。

站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章