[spring-projects/spring-boot]优化 OpenTelemetry Metric 和 Tracing 自动配置

2024-06-26 437 views
1

嗨!我想提出一种改进 OpenTelemetry 指标和跟踪自动配置方式的建议。这与问题相关:https://github.com/spring-projects/spring-boot/issues/30156以及我在最后的评论。

作为起点,跟踪OpenTelemetryAutoConfiguration会设置 OpenTelemetry 的一个实例并获取跟踪提供程序列表。这是指定不受支持的导出器(例如,OtlpGrpcSpanExporter代替 brave/zipkin/wavefront)的好方法。

但是OtlpMetricsExportAutoConfiguration根本不使用 OpenTelemetry 实例,而是OtlpMeterRegistry根据配置注册。目前我无法指定OtlpGrpcMetricExporter它想要使用的。

我的建议是拥有单独的基本 OpenTelemetry 自动配置、OpenTelemetry 跟踪自动配置以及最终的 OpenTelemetry 指标自动配置。

OpenTeleletry 的主要自动配置如下:

    @Bean
    @ConditionalOnMissingBean
    // puts the sevice name based on the spring.application.name, additionally reads in additional attributes like OtlpMetricsExportAutoConfiguration does
    fun otelResource(environment: Environment): Resource {
        val applicationName = environment.getProperty("spring.application.name", "application")
        return Resource.create(Attributes.of(ResourceAttributes.SERVICE_NAME, applicationName))
    }

    @Bean
    @ConditionalOnMissingBean
    fun openTelemetry(
        sdkTracerProvider: ObjectProvider<SdkTracerProvider>,
        sdkMeterProvider: ObjectProvider<SdkMeterProvider>,  // This is the new bit - custom SdkMeterProvider that is set up like SdkTracerProvider allowing me to create a OtlpGrpcMetricExporter bean
        contextPropagators: ObjectProvider<ContextPropagators>
    ): OpenTelemetry {
        val builder = OpenTelemetrySdk.builder()
        contextPropagators.ifUnique {
            builder.setPropagators(it)
        }
        sdkMeterProvider.ifUnique {
            builder.setMeterProvider(it)
        }
        sdkTracerProvider.ifUnique {
            // set by org.springframework.boot.actuate.autoconfigure.tracing.OpenTelemetryAutoConfiguration.otelSdkTracerProvider
            builder.setTracerProvider(it)
        }
        return builder.build()
    }

otelResource是为指标和跟踪指定服务名称和其他参数的一致方法。OpenTelemetry 接受附加信息sdkMeterProvider并允许设置自定义信息MetricExporter

OtlpMetricsExportAutoConfiguration将创建SdkMeterProvider出口商和注册中心:

    @Bean
    fun sdkMeterProvider(
        metricExportersProvider: ObjectProvider<List<MetricExporter>>,
        otelResource: Resource
    ): SdkMeterProvider {
        // from https://github.com/open-telemetry/opentelemetry-java-instrumentation/blob/main/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/OpenTelemetryAutoConfiguration.java
        val meterProviderBuilder = SdkMeterProvider.builder()
        val interval = properties.metrics.interval
        metricExportersProvider.getIfAvailable { emptyList() }
            .map { metricExporter ->
                val metricReaderBuilder = PeriodicMetricReader.builder(metricExporter)
                if (interval != null) {
                    metricReaderBuilder.setInterval(interval)
                }
                metricReaderBuilder.build()
            }
            .forEach { reader ->
                meterProviderBuilder.registerMetricReader(reader)
            }
        return meterProviderBuilder.setResource(otelResource).build()
    }

    @Bean
    fun otelMeterRegistry(openTelemetry: OpenTelemetry): MeterRegistry {
        return OpenTelemetryMeterRegistry.create(openTelemetry)
    }

    @Bean
    @ConditionalOnMissingBean(MetricExporter::class)
    fun metricExporter(...) : OtlpHttpMetricExporter {  
       // ...
    }

因此,现在跟踪和指标都使用同一个 OpenTelemetry 实例,该实例通过单个 OpenTelemetry 资源实例设置。默认指标导出器是OtlpHttpMetricExporter,可以使用 GRPC 版本覆盖。

回答

6

感谢您的建议,@FranPregernik。不幸的是,我很难理解您的确切意思。例如,您似乎建议对 进行更改,OtlpMetricsExportAutoConfiguration使其不再定义 a OtlpMeterRegistry,而是定义 an OpenTelemetryMeterRegistry。据我所知,这似乎是https://github.com/open-telemetry/opentelemetry-java-instrumentation的一部分,而 Spring Boot 并未使用。

我认为,如果我们退一步并专注于您希望能够做的事情,而不是描述您认为可以实现的代码更改,可能会更容易。或者,查看包含导入的 Java 代码(而不是 Kotlin)可能有助于我们更好地了解您的目标。

7

如果我正确理解了@FranPregernik 并且通过检查代码:

  1. OtlpMeterRegistry自行进行直接发布并仅支持 HTTP。如果它桥接到 OpenTelemetry 并允许我们提供或OtlpGrpcMetricExporterOtlpHttpMetricExporter或支持标准OTEL_...环境(https://opentelemetry.io/docs/concepts/sdk-configuration/otlp-exporter-configuration/)以供选择),那就更好了。
  2. Resource配置不一致。 OtlpConfig为指标提供了必要的设置,但没有为跟踪提供此类设置。跟踪从中获取属性,除了完全替换该 bean 之外,没有其他添加属性的方法。一个通用的可覆盖资源 bean 会很有用,默认情况下也会为跟踪OpenTelemetryAutoConfiguration.otelSdkTracerProvider重用该 bean 。OtlpConfig
  3. (添加我自己的一个新实例)OpenTelemetryAutoConfiguration构建一个OpenTelemetry实例。其他 OpenTelemetry 库看不到此实例,例如opentelemetry-jdbc用于获取其实例。需要有一种共享方式。我目前正在按照https://stackoverflow.com/questions/75293292/spGlobalOpenTelemetry.get ​​ring-micrometer-opentelemetry-exporter-otlp 中讨论的方式进行操作
9

也对 #2 特别感兴趣。目前没有办法识别被跟踪的应用程序,environment这使得它很难在具有开发、暂存、生产等的工作场所中使用。

理想情况下,您可以提供像指标这样的配置属性,但目前需要替换整个 SdkTracerProvider。

2

我认为这是可行的:

我们只需要将所有otel.带前缀的 spring 属性设置为系统属性,然后传递给 SDK 自动配置即可。WDYT?

5

我们只需要将所有otel.带前缀的 spring 属性设置为系统属性,然后传递给 SDK 自动配置即可。WDYT?

我们正在使用此策略,以便我们可以通过 spring boot 属性支持所有 otel 配置标志 - 并提供额外的配置方式。我本来打算为 Spring 提出这个建议,但目前我看到的一个缺点是 otel-sdk-autoconfigure 版本有-alpha后缀:请参阅他们的版本https://mvnrepository.com/artifact/io.opentelemetry/opentelemetry-sdk-extension-autoconfigure。不确定他们什么时候会将其升级到稳定版本。

ps:您可以提供属性供应商并提供从 spring boot 属性生成的映射,而不是使用系统属性。例如:

Map<String, String> otelProperties = readPropertiesStartingWith("otel", env);
final AutoConfiguredOpenTelemetrySdkBuilder sdkBuilder = AutoConfiguredOpenTelemetrySdk.builder();
sdkBuilder.addPropertiesSupplier(() -> otelProperties);
2

我现在已经创建了一个PR草稿:

  • 使用 SDK 自动配置和使用 opentelemetry-micrometer-1.5 桥似乎有效
  • 此更改不完全向后兼容,可以通过添加新的自动配置类来改进 - 应该进行讨论
  • 所有 spring 配置选项仍然受尊重,包括提供 bean(例如跨度过滤)和应用程序属性
  • 如果用户没有在应用程序属性中明确配置设置,则使用 SDK 自动配置,例如,您可以使用management.tracing.propagationotel.propagators- 不确定这是否会令人惊讶
  • sdk autoconfig 和 opentelemetry-micrometer-1.5 都alpha在 otel 中,但最近几个月没有发生任何不兼容的变化 - 我会在 Java SIG 中询问它
8

@wilkinsona 对于我们这些现在试图做“alpha”事情(比如日志和指标)的人来说,在 OpenTelemetryAutoConfiguration 类中创建类似这样的内容可能会有所帮助:

  @Bean
  @ConditionalOnMissingBean
  public Resource resource(Environment environment) {
    String applicationName = environment.getProperty("spring.application.name", DEFAULT_APPLICATION_NAME);
    return Resource.getDefault()
        .merge(Resource.create(Attributes.of(ResourceAttributes.SERVICE_NAME, applicationName)));
  }

然后在自动配置的 SdkTracerProvider bean 中使用该 bean。这样,那些希望自己创建类似资源的人就可以轻松获得/重用该资源:

  @Bean
  public SdkLoggerProvider sdkLoggerProvider(Resource resource) {

    SdkLoggerProvider sdkLoggerProvider = SdkLoggerProvider.builder().setResource(resource)
        .addLogRecordProcessor(
            SimpleLogRecordProcessor.create(
                OtlpGrpcLogRecordExporter.builder()
                    .setEndpoint(otelCollectorEndpoint)
                    .build()))
        .build();

    GlobalLoggerProvider.set(sdkLoggerProvider);
    return sdkLoggerProvider;
  }

否则,我们可能需要覆盖其他类,例如 SdkTracerProvider,我宁愿让 spring 自动配置。

3

看到这个问题已经被标记了for: team-meeting将近 4 个月,团队能否分享一下社区何时可以看到一些更新?谢谢。

8

可能与此问题相关,OpenTelemetry Java 刚刚发布,1.28.0它将 OpenTelemetry SDK 自动配置模块提升为稳定版。

8

这个问题涉及很多内容,我认为应该分成多个问题。

让我们进一步分析一下:

OtlpMeterRegistry自行进行直接发布并仅支持 HTTP。如果它桥接到 OpenTelemetry 并允许我们提供或OtlpGrpcMetricExporterOtlpHttpMetricExporter或支持标准OTEL_...环境(https://opentelemetry.io/docs/concepts/sdk-configuration/otlp-exporter-configuration/)以供选择),那就更好了。

OtlpMeterRegistry来自 Micrometer,Spring Boot 仅具有自动配置功能。我认为不能将 Micrometer 更改为委托给 OpenTelemetry。是这样的吗,@jonatan-ivanov?

将指标发送到 OpenTelemetry 的另一种选择是什么?如果我理解正确的话,我们通过 OTel 为跨度提供 OTLP 支持,OtlpHttpSpanExporter并通过 Micrometer 提供 OTLP 指标支持OtlpMeterRegistry(它不是在 OTel 之上实现的,它只使用来自 OTel 的一些协议类)。

你们都希望直接通过 OTel 支持 OTLP 指标,以便所有其他抽象(资源OtlpGrpcMetricExporterOtlpHttpMetricExporter)都可用于指标。对吗?

3

Resource配置不一致。 OtlpConfig为指标提供了必要的设置,但没有为跟踪提供此类设置。跟踪从中获取OpenTelemetryAutoConfiguration.otelSdkTracerProvider属性,除了完全替换该 bean 之外,没有其他添加属性的方法。一个常见的可覆盖资源 bean 会很有用...

@Bean可以通过在自动配置中创建一个方法来解决此问题,如https://github.com/spring-projects/spring-boot/issues/34023#issuecomment-1590215356Resource中所建议的那样。

并且默认情况下也会重复使用OtlpConfigfor 跟踪。

这意味着将配置属性从 移动management.otlp.metrics.export.resource-attributes到更通用的 OTel 属性,因为它现在适用于指标和跟踪。但我不认为management.otlp这是正确的命名空间,因为Resource它不是 OTLP 特定的,不是吗?类似的东西management.opentelemetry会更合适。

0

OtlpMeterRegistry 自行进行直接发布,并且仅支持 HTTP。如果它能够桥接到 OpenTelemetry,并允许我们提供 OtlpGrpcMetricExporter 或 OtlpHttpMetricExporter(或支持标准 OTEL_... envs(https://opentelemetry.io/docs/concepts/sdk-configuration/otlp-exporter-configuration/)以供选择),那就更好了。

OtlpMeterRegistry 来自 Micrometer,Spring Boot 仅对它进行了自动配置。我认为不能将 Micrometer 更改为委托给 OpenTelemetry。是这样的吗,@jonatan-ivanov?

是的,OtlpMeterRegistry只依赖于opentelemetry-protoSDK,而不依赖于 SDK。我很好奇你 (@jimbogithub) 为什么认为依赖于 SDK 更好。OtlpMeterRegistry使用 HTTP 发布数据,所有收集器都必须支持该数据,并且它也支持相关的 OTel 环境变量。请注意,注册表的目标是支持 OTLP,根据 OTel 规范,这应该是完全没问题的(任何人都可以发出 OTLP)。

8

我已将此问题拆分为多个小问题,并将关闭此问题。请订阅您感兴趣的问题:

  • 36544
  • 36545
  • 36546
  • 36248