博客/工程

如何用OpenTelemetry Java Instrumentation代理捕获Spring引导指标

2022年5月4日7分钟

在之前的一篇博客文章中,Adam Quan提出了一个伟大的介绍了如何为Spring Boot应用程序设置可观察性.对于度量,Adam使用Prometheus Java客户端库并展示了如何使用链接度量和跟踪范本

然而,Prometheus Java Client库并不是从数据库中获取度量的唯一方法春天的引导一种替代方法是使用OpenTelemetry Java检测代理直接以OpenTelemetry格式公开Spring的度量。

这篇博文展示了如何用OpenTelemetry Java检测代理捕获Spring引导指标。

设置一个示例应用程序

在这篇文章中,我们将使用一个简单的Hello World REST服务作为示例应用程序。源代码来自/完成/。目录示例代码春天的构建基于rest的Web服务指南。

git克隆https://github.com/spring-guides/gs-rest-service.git cd gs-rest-service/complete/ ./mvnw清洁包java -jar target/rest-service-complete-0.0.1-SNAPSHOT.jar

应用程序在端口8080上公开了一个REST服务,您可以在其中欢迎不同的名称,例如http://localhost:8080/greeting?name=Grafana.它还没有公开任何指标。

暴露一个普罗米修斯度量端点

作为第一步,我们在示例应用程序中启用度量,并直接以Prometheus格式公开这些度量。我们还没有使用OpenTelemetry Java检测代理。

我们需要两个额外的依赖项pom.xml

<依赖> < groupId > org.springframework。启动< / groupId > < artifactId > spring-boot-starter-actuator < / artifactId > < /依赖> <依赖> < groupId > io。micrometer micrometer-registry-prometheus runtime 

spring-boot-starter-actuator提供指标API和一些开箱即用的指标。在底层,它使用Micrometer度量库。的micrometer-registry-prometheus用于以Prometheus格式公开千分尺度量。

接下来,我们需要启用Prometheus端点。创建文件。/ src / main /资源/ application.properties用下面这行:

management.endpoints.web.exposure.include =普罗米修斯

重新编译并重新启动应用程序后,您将看到指标http://localhost:8080/actuator/prometheus.开箱即用的指标包括一些JVM指标,例如jvm_gc_pause_seconds,一些来自日志框架的度量logback_events_total,以及来自REST端点的一些指标,例如http_server_requests

最后,我们想要使用一个自定义度量。自定义指标必须注册到MeterRegistry由Spring Boot提供。第一步是注入MeterRegistryGreetingController,例如通过构造函数注入:

/ /……进口io.micrometer.core.instrument.MeterRegistry;@RestController公共类GreetingController{//…私有最终MeterRegistry注册表;//使用构造函数注入来获得MeterRegistry公共GreetingController(MeterRegistry注册表){this. GreetingController(this. GreetingController)注册表;} //…}

现在,我们可以添加我们的自定义度量。我们将创建一个计数器按名字跟踪问候语。类的现有实现中添加计数器问候()REST端点:

@GetMapping("/greeting") public问候语问候语(@RequestParam(value = "name", defaultValue = "World") String name){//添加一个计数器,按名称跟踪问候语呼叫registry.counter("greeting . name")Total ", "name", name).increment();/ /……}

让我们尝试一下:重新编译并重新启动应用程序,并使用不同的名称调用问候语端点,例如http://localhost:8080/greeting?name=Grafana.在http://localhost:8080/actuator/prometheus你会看到度规greetings_total计算每个名字的调用次数:

# HELP greetings_total··# TYPE greetings_total counter greetings_total{name="Grafana",} 2.0 greetings_total{name="Prometheus",} 1.0

注意,使用用户输入作为标签值通常不是一个好主意,因为这很容易导致错误基数爆炸(即,为每个名称创建一个新指标)。但是,在我们的示例中,它很方便,因为它为我们提供了一种简单的方法来尝试不同的标签值。

将OpenTelemetry收集器放在中间

OpenTelemetry收集器是接收、处理和导出遥测数据的组件。它通常位于要监视的应用程序和监视后端之间的中间位置。

下一步,我们将配置一个OpenTelemetry收集器,从Prometheus端点获取度量标准,并以Prometheus格式公开它们。

到目前为止,除了将OpenTelemetry收集器作为一个新的基础设施组件之外,这不会添加任何功能。收集器在端口8889上公开的度量应该与应用程序在端口8080上公开的度量相同。

下载最新资料otelcol_ * gz释放https://github.com/open-telemetry/opentelemetry-collector-releases/releases,然后打开包装。它应该包含一个名为otelcol.在撰写本文时,最新的版本是otelcol_0.47.0_linux_amd64.tar.gz

创建一个名为config.yaml内容如下:

接收者:prometheus: config: scrape_configs:—job_name: "example" scrape_interval: 5s metrics_path: " /actuator/prometheus " static_configs:—targets: ["localhost:8080"] processors: batch: exporters: prometheus: endpoint: "localhost:8889" service: pipelines: metrics: Receivers: [prometheus] processors: [batch] exporters: [prometheus]

现在运行收集器

/ otelcol - config = config.yaml

你可以访问度量http://localhost:8889/metrics

附加OpenTelemetry Java检测代理

我们现在准备将我们的应用程序从公开Prometheus度量转换为直接提供OpenTelemetry度量。我们将在应用程序中去掉Prometheus端点,并使用OpenTelemetry Java检测代理来公开度量。

首先,我们必须重新配置OpenTelemetry收集器的接收端,以使用OpenTelemetry Line Protocol (otlp),而不是从Prometheus端点抓取指标:

receiver: otlp: protocols: grpc: http: processors: batch: exporters: prometheus: endpoint: "localhost:8889" service: pipelines: metrics: Receivers: [otlp] processors: [batch] exporters: [prometheus]

现在,下载OpenTelemetry Java检测代理的最新版本https://github.com/open-telemetry/opentelemetry-java-instrumentation/releases.默认情况下,代理中禁用度量,因此您需要通过设置环境变量来启用它们OTEL_METRICS_EXPORTER = otlp.然后,重新启动附加代理的示例应用程序:

export otel_metrics_export =otlp java -javaagent:./ opentmetric -javaagent.jar -jar ./target/rest-service-complete-0.0.1-SNAPSHOT.jar

大约一分钟后,您将看到收集器公开了指标http://localhost:8889/metrics一次。但是,这次使用OpenTelemetry线路协议将它们直接传送到收集器。不再涉及应用程序的Prometheus端点。中删除Prometheus端点配置application.properties然后移除micrometer-registry-prometheus依赖于pom.xml

然而,如果你仔细观察,你会发现这些指标与之前公布的有所不同。

连接OpenTelemetry和千分尺

我们现在在收集器中看到的指标来自OpenTelemetry Java检测代理本身。他们是Spring Boot应用程序维护的原始度量。代理在为我们提供REST端点调用的一些开箱即用的度量方面做得很好,例如http_server_duration.然而,有些指标明显缺失了,比如logback_events_total最初由Spring框架提供的度量。我们的自定义度规greetings_total不再可用。

为了理解原因,我们需要看一看Spring Boot指标在内部是如何工作的。Spring使用测微计作为它的度量库。Micrometer为应用程序开发人员提供了通用API,并为供应商提供了灵活的仪表注册表,以便为其特定的监控后端公开指标。

在上面的第一步中,我们使用了普罗米修斯仪表登记处,它是Micrometer注册表,用于公开Prometheus的度量。

使用OpenTelemetry Java检测代理捕获千分尺度量几乎开箱即用:代理检测千分尺并注册一个OpenTelemetryMeterRegistry在飞行中。

不幸的是,代理注册微米的Metrics.globalRegistry,而Spring通过依赖注入使用自己的注册表实例。如果OpenTelemetryMeterRegistry结果是错的MeterRegistry实例,它没有被Spring使用。

为了解决这个问题,我们需要OpenTelemetry的OpenTelemetryMeterRegistry作为Spring bean可用,以便Spring在设置依赖注入时可以正确地注册它。这可以通过在Spring引导应用程序中添加以下代码来实现:

//从Metrics中注销OpenTelemetryMeterRegistryglobalRegistry,并使其可用//作为Spring bean。@Bean @ConditionalOnClass(name = "io. opentelemetryjavaagent . opentelemetryagent ") public MeterRegistry otelRegistry(){可选 otelRegistry = Metrics.globalRegistry.getRegistries().stream() .filter(r -> r. getclass ().getName().contains("OpenTelemetryMeterRegistry")) .findAny();otelRegistry.ifPresent (Metrics.globalRegistry:删除);返回otelRegistry.orElse(空);} //…}

上面的代码段注销了OpenTelemetryMeterRegistry从测微计Metrics.globalRegistry并将其暴露为Spring bean。方法实现附加代理时,它才会运行@ConditionalOnClass注释。

在重新编译和重新启动应用程序之后,OpenTelemetry收集器将可以使用所有指标,包括所有原始Spring Boot指标和我们的自定义指标greetings_total

有些信息是冗余的,所以你甚至可以比较其中的信息http_server_requests中的信息提供给Spring Boothttp_server_duration由OpenTelemetry的Java检测代理添加。

总结

在这篇博客文章中,我们向您展示了如何使用OpenTelemetry Java检测代理捕获Spring引导指标。我们首先以Prometheus格式公开Spring Boot指标,然后将OpenTelemetry收集器放在中间,然后将示例应用程序从公开Prometheus切换到直接公开OpenTelemetry行协议。

最后,我们强调了需要添加到Java应用程序中的几行代码,以便将Spring Boot的Micrometer度量与OpenTelemetryMeterRegistry由OpenTelemetry Java检测代理提供。

Grafana Cloud是开始使用度量、日志、跟踪和仪表板的最简单方法。我们有一个慷慨的免费永远层和计划为每个bob体育手机二维码用例。现在免费注册