[spring-projects/spring-boot]提供配置属性来指定 ServerHttpObservationFilter 的顺序

2024-05-08 317 views
2

你好,

从 Spring Cloud Sleuth 迁移到 Spring Boot 3 时,曾经有一个属性可以覆盖 TraceFilter:

spring:
  sleuth:
    web:
      filter-order: -111

这对我们来说非常重要,因为我们需要在任何观察之前运行一些过滤器。我注意到 Spring Boot 3 中的顺序是硬编码的:

public class WebFluxObservationAutoConfiguration {

...

    @Bean
    @ConditionalOnMissingBean
    @Order(Ordered.HIGHEST_PRECEDENCE + 1)
    public ServerHttpObservationFilter webfluxObservationFilter(ObservationRegistry registry,

}

是否可以覆盖ServerHttpObservationFilter顺序(特别是反应版本)?

谢谢

回答

0

我们有一些过滤器,需要在任何观察之前运行

任何具有最高优先级的过滤器都应该在 之前运行ServerHttpObservationFilter

是否可以覆盖 ServerHttpObservationFilter 顺序

目前还没有基于财产的支持。如果没有这种支持,您就必须在方法上ServerHttpObservationFilter使用适当的注释来定义自己的 bean 。@Order@Bean

5

我遇到的问题是 ServerHttpObservationFilter 按 Ordered.HIGHEST_PRECEDENCE + 1 排序,并且我还有其他三个过滤器。这给了我使用 Ordered.HIGHEST_PRECEDENCE 的唯一选项,它将随机排序。 :-(

我可以定义自己的 ServerHttpObservationFilter 没问题,但属性会更干净。

谢谢

7

该属性名为management.observations.http.server.filter.order.

6

我们还需要考虑 servlet 方面的问题。该属性应该应用于自动配置webMvcObservationFilter,或者其名称应表明它特定于反应式。可能是前者。

9

谢谢安迪,我错过了。

8

我们需要设置ObservationRegistryWebHttpHandlerBuilder如此所述。我们可以删除ServerHttpObservationFilter.对于 servlet 应用程序来说,没有任何变化。

5

我们需要在 WebHttpHandlerBuilder 上设置 ObservationRegistry,如此处所述

对于“我们有一些过滤器需要在任何观察之前运行”的原始要求,这将如何工作?

1

抱歉反馈较晚。

Servlet Filter 抽象通常适用于 Spring MVC,尽管有些人发现其局限性并更喜欢使用自定义 Tomcat Valve 进行观察,以便观察整个链,包括 servlet 容器错误处理。为了准确,观察过滤器应该尽可能早,以便测量大部分处理时间。我认为 Spring Boot 中的其他过滤器没有类似的属性,到目前为止的一般反馈是配置您自己的过滤器实例。我并不反对这种改变,但我想这意味着我们对其他过滤器实现同样的事情。

在 WebFlux 方面,WebFilter根据我们的社区的说法,该方法过于有限。在 WebFlux 中,我们不依赖 Servlet 合约,并且有专用的 SPI。处理DispatcherHandlerHTTP 交换并委托给WebFilterWebExceptionHandler。这意味着错误处理WebExceptionHandler发生在 WebFilter 观察范围之外,并且错误日志未按预期包含跟踪上下文。我们通过更改基础设施在https://github.com/spring-projects/spring-framework/issues/30013中修复了该问题。鉴于 WebFlux 管理 HTTP 合约,这是向我们的用户提供该功能的唯一方法。

使用新的基础设施,观察在涉及任何网络过滤器之前就开始了。 @davidmelia 你能分享更多关于用例的信息吗?也许我们可以做一些事情来帮助解决这个问题,而无需依赖额外的过滤器?

考虑到这一点,如果我们想为 servlet 过滤器提供配置属性,我们可能需要servletreactive命名空间来区分它们是否 100% 对齐的问题。

7

对于“我们有一些过滤器需要在任何观察之前运行”的原始要求,这将如何工作?

恐怕不会,就像布莱恩说的那样。它只是摆脱了弃用。

消除弃用的更改位于此分支中。然而,有3个测试WebFluxObservationAutoConfigurationTests失败。我认为这是因为 WebClient 做了一些奇怪的事情,或者我们在测试中错过了设置 WebFlux 基础设施的重要部分,因为它在独立的应用程序中工作。

6

我认为我们应该恢复迄今为止针对此问题所做的更改。 Servlet 应用程序尚未提出这一要求,并且在我们收到 @davidmelia 的消息之前,我们不知道我们可能需要对反应式应用程序做什么(如果有的话)。

4

@bclozel @wilkinsona 您好 - 就我的用例而言,我们有一些自定义过滤器需要设置观察上下文 - 这包括从自定义标头中提取 IP 地址并提取其他数据源。所有这些数据都是我们的日志记录上下文信息的组成部分(注意我有一个自定义的logging.pattern.level)

ServerHttpObservationFilter因此,虽然我理解应该首先进行的假设(好吧Ordered.HIGHEST_PRECEDENCE + 1),但我有一些预过滤器需要运行来设置观察过滤器。

谢谢

注意我唯一的用例是反应式的。

5

我认为我们应该恢复迄今为止针对此问题所做的更改。尚未针对 servlet 应用程序提出要求

同时我恢复了提交。

6

@davidmelia 我不太确定我是否理解这里的用例。

如果您尝试让其他指标/跟踪标签对观察做出贡献,则无需在观察开始之前进行设置。编写自己的ObservationConvention实现足以增强观察结果。您可以在观察上下文中查找请求标头。

如果您的目标是自定义上下文传播,我需要更多信息。

也许您正试图抢在 Web 观察之前,用自定义值预先填充 MDC?在这种情况下,我相信您可以通过贡献一个HttpHandlerDecoratorFactory可以做到这一点的 bean 来实现这一目标。这些也是有序的,并且在观察开始之前全部处理。

0

@bclozel 我已经尝试过 HttpHandlerDecoratorFactory 并且效果很好:-)。这实际上消除了我重写此过滤器顺序的需要。

0

这是个好消息。感谢您告诉我们,@davidmelia。

我将关闭这个,因为我们不再需要为任一 Web 堆栈配置过滤器顺序。

9

@bclozel 我已经尝试过 HttpHandlerDecoratorFactory 并且效果很好:-)。这实际上消除了我重写此过滤器顺序的需要。

@davidmelia,如果您可以分享涉及 HttpHandlerDecoratorFactory 的解决方案来为其他人提供一些启发,那就太好了。

我有一个类似的用例:从请求中提取特殊的标头值(每个请求过滤器使用一次非常高的顺序 - 如果值无效,则必须拒绝请求),其中该值对于生命周期的其余部分至关重要。我一直在 MDC 中设置该值,以使其在日志中可用,并且还希望使其对所有指标全局可用。

我阅读了该线程并了解到这里有意设置非常高的优先级。

对于这个用例,您会推荐什么? HttpHandlerDecoratorFactory 如何提供帮助?

1

@edigu 你的用例实际上可能有点不同。

  1. 应用程序是响应式的还是基于 Servlet 的?
  2. 您使用的是哪个 Spring Boot 版本?
  3. 如果请求因无效值而被拒绝,是否仍应为此记录观察(指标/跟踪)?

也许您可以在 StackOverflow 问题中分享这些详细信息并向我们指出?已解决的问题不适合就其他问题寻求帮助。

8

@bclozel

  1. 它是基于Servlet的
  2. 使用启动 3.1.x
  3. 不,我以不同的方式跟踪无效值。观察并不是必须的。

是的,你是对的,在最坏的情况下会尝试这样做。由于用例非常相似,因此希望获得反馈。

7

@edigu 我的用例是设置日志上下文,我以前使用 Web 过滤器执行此操作,但没有意识到我可以简单地使用 HttpHandlerDecoratorFactory。下面是一个例子。我可以有多个工厂来处理不同的日志上下文问题

public class MyHttpHandlerDecoratorFactory implements HttpHandlerDecoratorFactory {

  @Override
  public HttpHandler apply(HttpHandler httpHandler) {
    return (request, response) -> {
      log.debug("enter filter()");
      // extract stuff and decide how you want to add this to the log context
      log.debug("end filter()");
      return httpHandler.handle(mutatedRequest, response);
    };
  }

}

@AutoConfiguration
public class HttpHandlerDecorationAuthConfiguration {

  @Bean
  MyHttpHandlerDecoratorFactory myHttpHandlerDecoratorFactory() {
    MyHttpHandlerDecoratorFactory httpHandlerDecorator = new MyHttpHandlerDecoratorFactory();
    return httpHandlerDecorator;
  }
}