Micrometer Metrics

Micrometer fournit une couche d’abstraction pour la collecte des métriques. Il définit une API pour les types de compteurs de base, tels que les compteurs, les jauges, les minuteries et les résumés de distribution, ainsi qu’une API MeterRegistry qui généralise la collecte et la propagation des métriques pour différents systèmes de surveillance principaux.

Micrometer provides an abstraction layer for metrics collection. It defines an API for basic meter types, like counters, gauges, timers, and distribution summaries, along with a MeterRegistry API that generalizes metrics collection and propagation for different backend monitoring systems.

Micrometer est l’approche recommandée pour les métriques pour Quarkus.

Micrometer is the recommended approach to metrics for Quarkus.

Par défaut, les métriques sont exposées sur le serveur HTTP principal. Si vous souhaitez afficher les métriques à partir d’un port de gestion distinct, consultez la section Managed interface .

By default, the metrics are exposed on the main HTTP server. If you would like to surface metrics from a separate management port, see the management-interface section.

Micrometer and monitoring system extensions

Les extensions Micrometer de Quarkus sont structurées de la même manière que le projet Micrometer. L’extension quarkus-micrometer fournit le support Micrometer de base et l’intégration du runtime. D’autres extensions Quarkus et Quarkiverse utilisent l’extension Quarkus Micrometer pour fournir une prise en charge d’autres systèmes de surveillance.

Quarkus Micrometer extensions are structured in the same way as the Micrometer project. The quarkus-micrometer extension provides core Micrometer support and runtime integration. Other Quarkus and Quarkiverse extensions use the Quarkus Micrometer extension to provide support for other monitoring systems.

Extensions Quarkus :

Quarkus extensions:

  • micrometer

  • micrometer-registry-prometheus

Quarkiverse extensions (peut être incomplet) :

Quarkiverse extensions (may be incomplete):

  • micrometer-registry-azure-monitor

  • micrometer-registry-datadog

  • micrometer-registry-graphite

  • micrometer-registry-influx

  • micrometer-registry-jmx

  • micrometer-registry-newrelic-telemetry

  • micrometer-registry-otlp

  • micrometer-registry-signalfx

  • micrometer-registry-stackdriver

  • micrometer-registry-statsd

Pour ajouter la prise en charge des métriques Prometheus à votre application, par exemple, utilisez l’extension micrometer-registry-prometheus . Il intègrera l’extension Quarkus Micrometer et les librairies de base Micrometer en tant que dépendances.

To add support for Prometheus metrics to your application, for example, use the micrometer-registry-prometheus extension. It will bring in the Quarkus Micrometer extension and Micrometer core libraries as dependencies.

Ajoutez l’extension à votre projet à l’aide de la commande suivante (à partir du répertoire de votre projet) :

Add the extension to your project using following command (from your project directory):

Unresolved directive in telemetry-micrometer.adoc - include::{includes}/devtools/extension-add.adoc[]

这会将以下内容添加到构建文件中:

This will add the following to your build file:

pom.xml
<dependency>
    <groupId>io.quarkus</groupId>
    <artifactId>quarkus-micrometer-registry-prometheus</artifactId>
</dependency>
build.gradle
implementation("io.quarkus:quarkus-micrometer-registry-prometheus")

Et vous êtes prêts !

And you’re all set!

Un processus similaire s’applique aux autres extensions de registre de compteur. Pour utiliser Micrometer StackDriver MeterRegistry, par exemple, vous utiliseriez l’extension quarkus-micrometer-registry-stackdriver de Quarkiverse :

A similar process applies for other meter registry extensions. To use the Micrometer StackDriver MeterRegistry, for example, you would use the quarkus-micrometer-registry-stackdriver extension from the Quarkiverse:

Unresolved directive in telemetry-micrometer.adoc - include::{includes}/devtools/extension-add.adoc[]

pom.xml
<dependency>
    <groupId>io.quarkiverse.micrometer.registry</groupId>
    <artifactId>quarkus-micrometer-registry-stackdriver</artifactId>
</dependency>
build.gradle
implementation("io.quarkiverse.micrometer.registry:quarkus-micrometer-registry-stackdriver")

Other registry implementations

Si le registre Micrometer que vous souhaitez utiliser n’a pas encore d’extension associée, utilisez l’extension quarkus-micrometer et ajoutez directement la dépendance du registre de compteur Micrometer :

If the Micrometer registry you would like to use does not yet have an associated extension, use the quarkus-micrometer extension and bring in the Micrometer meter registry dependency directly:

pom.xml
<dependency>
    <groupId>io.quarkus</groupId>
    <artifactId>quarkus-micrometer</artifactId>
</dependency>
<dependency>
    <groupId>com.acme</groupId>
    <artifactId>custom-micrometer-registry</artifactId>
    <version>...</version>
</dependency>
build.gradle
implementation("io.quarkus:quarkus-micrometer")
implementation("com.acme:custom-micrometer-registry")

Vous devrez ensuite spécifier votre propre fournisseur pour configurer et initialiser MeterRegistry, comme indiqué dans la section suivante.

You will then need to specify your own provider to configure and initialize the MeterRegistry, as discussed in the next section.

Create a customized MeterRegistry

如果您需要,可以使用自定义的 @Produces 方法来创建和配置自己的 MeterRegistry

Use a custom @Produces method to create and configure a your own MeterRegistry if you need to.

以下示例自定义了 StatsD 所用的行格式:

The following example customizes the line format used for StatsD:

@Produces
@Singleton (1)
public StatsdMeterRegistry createStatsdMeterRegistry(StatsdConfig statsdConfig, Clock clock) { (2)
    // define what to do with lines
    Consumer<String> lineLogger = line -> logger.info(line);

    // inject a configuration object, and then customize the line builder
    return StatsdMeterRegistry.builder(statsdConfig)
          .clock(clock)
          .lineSink(lineLogger)
          .build();
}
1 The method returns a @Singleton.
2 The method returns the specific type of MeterRegistry

此示例对应于 Micrometer 文档中的以下说明: Micrometer StatsD: Customizing the Metrics Sink

This example corresponds to the following instructions in the Micrometer documentation: Micrometer StatsD: Customizing the Metrics Sink

使用 MicroProfile Config 注入配置注册表所需的任何配置属性。大多数 Micrometer 注册表扩展(如 quarkus-micrometer-registry-statsd),提供与 Quarkus 配置模型集成的注册表特定配置对象。 Quarkiverse GitHub Repository 可以作为有用的实现参考。

Use MicroProfile Config to inject any configuration attributes you need to configure the registry. Most Micrometer registry extensions, like quarkus-micrometer-registry-statsd, provide registry-specific configuration objects that are integrated with the Quarkus configuration model. The Quarkiverse GitHub Repository can be a useful implementation reference.

Create your own metrics

指标数据被用于聚合中,以观察数据在一段时间内的变化情况。此数据用于趋势分析、异常检测和告警。数据由后端监控系统存储在时序数据库中,新值追加到序列的末尾。

Metrics data is used in the aggregate to observe how data changes over time. This data is used for trend analysis, anomaly detection, and alerting. Data is stored by backend monitoring systems in time series databases, with new values appended to the end of the series.

指标是惰性构建的。在执行用于创建指标的动作(例如,访问端点)之前,您可能看不到要查找的指标的任何数据。

Metrics are constructed lazily. You may not see any data for the metric you’re looking for until you’ve performed an action that will create it, like visiting an endpoint.

Naming conventions

指标名称应使用点分隔段,a.name.like.this。Micrometer 应用命名约定将已注册的指标名称转换成与后端监控系统期望相符的形式。

Meter names should use dots to separate segments, a.name.like.this. Micrometer applies naming conventions to convert registered meter names to match the expectations of backend monitoring systems.

给定计时器的以下声明: registry.timer("http.server.requests"),应用的命名约定将针对不同的监控系统发出以下指标:

Given the following declaration of a timer: registry.timer("http.server.requests"), applied naming conventions will emit the following metrics for different monitoring systems:

  • Prometheus: http_server_requests_duration_seconds

  • Atlas: httpServerRequests

  • Graphite: http.server.requests

  • InfluxDB: http_server_requests

Define dimensions for aggregation

指标(单个数字测量值)通常还有其他与之捕获的数据。这些辅助数据用于对指标进行分组或聚合以供分析。Micrometer API 将这些维度数据称为标签,但您可能会在其他文档来源中看到它们被称为“标签”或“属性”。

Metrics, single numerical measurements, often have additional data captured with them. This ancillary data is used to group or aggregate metrics for analysis. The Micrometer API refers to this dimensional data as tags, but you may see it referred to as "labels" or "attributes" in other documentation sources.

Micrometer 主要构建用于支持维度数据(使用键/值对丰富指标名称)的后端监控系统。针对仅支持平面指标名称的分层系统,Micrometer 将将键/值对集(按键排序)展平,并将其添加到该名称中。

Micrometer is built primariliy for backend monitoring systems that support dimensional data (metric names that are enchriched with key/value pairs). For heirarchical systems that only support a flat metric name, Micrometer will flatten the set of key/value pairs (sorted by key) and add them to the name.

当使用 MeterRegistry 注册指标或使用 Meter Filter 注册指标时,可以指定标记。

Tags can be specified when a meter is registered with a MeterRegistry or using a meter-filter.

请参阅 Micrometer 文档以获取有关 tag naming 的其他建议。

See the Micrometer documentation for additional advice on tag naming.

指标名称和维度的每个唯一组合都会生成唯一的时间序列。使用无界维度数据集会导致“基数爆炸”,即新时序的创建呈指数级增加。

Each unique combination of metric name and dimension produces a unique time series. Using an unbounded set of dimensional data can lead to a "cardinality explosion", an exponential increase in the creation of new time series.

Obtain a reference to a MeterRegistry

要注册指标,您需要一个对 MeterRegistry 的引用,它是由 Micrometer 扩展配置和维护的。

To register meters, you need a reference to a MeterRegistry, which is configured and maintained by the Micrometer extension.

使用以下方法之一获取对 MeterRegistry 的引用:

Use one of the following methods to obtain a reference to a MeterRegistry:

  1. Use CDI Constructor injection:[source, java]

package org.acme.micrometer;

import io.micrometer.core.instrument.MeterRegistry;

import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;

@Path("/example")
@Produces("text/plain")
public class ExampleResource {

    private final MeterRegistry registry;

    ExampleResource(MeterRegistry registry) {
        this.registry = registry;
    }
}
  1. Use a MeterRegistry member variable and use @Inject:[source, java]

    @Inject
    MeterRegistry registry;
  1. Use the global MeterRegistry:[source, java]

    MeterRegistry registry = Metrics.globalRegistry;

Gauges

计量器测量一个可以随时间增大或减小的值,就像汽车上的速度计。监控缓存或集合的统计信息时,计量器非常有用。

Gauges measure a value that can increase or decrease over time, like the speedometer on a car. Gauges can be useful when monitoring the statistics for a cache or collection.

仪表值是采样而非设置的;没有记录与测量值之间仪表相关值如何变化的记录。

Gauge values are sampled rather than set; there is no record of how the value associated with a gauge may have changed between measurements.

微计提供几种机制用于创建仪表:

Micrometer provides a few mechanisms for creating gauges:

  1. Wrap construction of a collection to monitor its size:[source, java]

List<String> list = registry.gaugeCollectionSize("fantastic.list", (1)
        Tags.of("key", "value") // optional 2
        new ArrayList<>());  (3)
1 Create a new gauge, list.size, using the dot-separated convention.
2 Associate define-tags with the gauge. Gauge tag values are constant, and must be assigned at construction time.
3 Construct the array list whose size should be observed.
  1. Use a builder to create a Gauge that will call a function:[source, java]

Gauge.builder("jvm.threads.peak", threadBean, ThreadMXBean::getPeakThreadCount) (1)
    .baseUnit(BaseUnits.THREADS) // optional 2
    .description("The peak live thread count...") // optional 3
    .tags("key", "value") // optional 4
    .register(registry); (5)
1 Create a new gauge called jvm.threads.peak that will call getPeakThreadCount on threadBean, an instance of ThreadMXBean
2 Define the base unit, see BaseUnits.java for predefined values.
3 Provide a description of the Gauge
4 Associate define-tags with the gauge
5 Register the Gauge with the MeterRegistry

更多信息和示例,请见微计档中的 Gauges。需要注意的是两个特殊情况:TimeGauge,用于测量时间,和 MultiGauge,用于共同汇报多个标准。

See Gauges in the Micrometer documentation for more information and examples. Of note are two special cases: TimeGauge for measuring time, and a MultiGauge for reporting several criteria together.

微计默认不建立强烈引用的待观察对象。根据注册表,微计要么完全忽略观察垃圾收集对象的仪表,要么使用 NaN(不是数字)作为观察值。

Micrometer does not create strong references to the objects it observes by default. Depending on the registry, Micrometer either omits gauges that observe objects that have been garbage-collected entirely or uses NaN (not a number) as the observed value.

何时应使用仪表?只有在没有其他办法使用时才使用仪表。仪表可能不如其他仪表易于使用。如果要测量内容是可计数的(因为值始终递增),则使用计数器。

When should you use a gauge? Only use a gauge when you can’t use something else. Gauges can be less straight-forward to use than other meters. If what you are measuring can be counted (because the value always increments), use a counter instead.

Counters

计数器测量仅增加的值。使用以下方法之一创建计数器。

Counters measure values that only increase. Use one of the methods below to create a counter.

  1. Use a convenience method on the MeterRegistry:[source, java]

registry.counter("example.prime.number", "type", "prime"); // <1> 2
1 example.prime.number is the counter name.
2 type is a dimensional tag with value prime.
  1. Use Counter.builder to provide a description and units:[source, java]

Counter.builder("count.me") (1)
    .baseUnit("beans")            // optional 2
    .description("a description") // optional 3
    .tags("region", "test")       // optional 4
    .register(registry);
1 Create a new counter called count.me
2 Define a custom base unit. See BaseUnits.java for predefined values.
3 Provide a description for the counter
4 Associate define-tags with the counter
  1. annotations a method[source, java]

@Counted(value = "counted.method", extraTags = { "extra", "annotated" }) // <1> 2
void countThisMethod(){
    ...
}
1 A CDI interceptor will create and register a counter called counted.method
2 The interceptor-created counter will have the "extra" dimension tag with value "annotated"

请参阅 Micrometer 文档中的 Counters 了解更多信息和示例,包括不太常见的 FunctionCounter,可用于测量总是增加函数返回的结果

See Counters in the Micrometer documentation for more information and examples, including the less common FunctionCounter that can be used to measure the result returned by an always increasing function.

您何时应使用计数器?如果您正在执行无法计时或总结的操作,请使用计数器。如果您想更多地了解一个值是怎样发生改变的,计时器(当基本测量单位是时间时)或分布摘要可能更加合适

When should you use a counter? Use a counter if you are doing something that can not be either timed or summarized. If you want to understand more about how a value is changing, a timer (when the base unit of measurement is time) or a distribution summary might be more appropriate.

Summaries and Timers

Micrometer 中的计时器和分布摘要非常相似。这两个度量记录数据,并且可以捕捉额外的直方图或百分位数数据。虽然分布摘要可用于任意类型的数据,但计时器经过优化用于测量时间和持续时间

Timers and distribution summaries in Micrometer are very similar. Both meters record data, and can capture additional histogram or percentile data. While distribution summaries can be use for arbitrary types of data, timers are optimized for measuring time and durations.

计时器和分布摘要在内部至少存储三个值:

Timers and distribution summaries store at least three values internally:

  • the aggregation of all recorded values as a sum

  • the number of values that have been recorded (a counter)

  • the highest value seen within a decaying time window (a gauge).

Create a distribution summary

使用分布摘要记录值,而非时间。使用以下方法之一创建分布摘要

Use a distribution summary to record a value, not time. Use one of the following methods to create a distribution summary.

  1. Use a convenience method on the MeterRegistry:[source, java]

registry.summary("bytes.written", "protocol", "http"); // <1> 2
1 bytes.written is the summary name
2 protocol is a dimensional tag with value http.
  1. Use DistributionSummary.builder to provide a description and units:[source, java]

DistributionSummary.builder("response.size") (1)
    .baseUnit("bytes")            // optional 2
    .description("a description") // optional 3
    .tags("protocol", "http")     // optional 4
    .register(registry);
1 Create a new distribution summary called response.size
2 Use bytes as a base unit. See BaseUnits.java for predefined values.
3 Provide a description for the distribution summary
4 Associate define-tags with the distribution summary

Create a timer

计时器测量短时延和它们发生的频率。不支持负值,并且较长的持续时间可能导致总时间溢出(Long.MAX_VALUE 纳秒(292.3 年))。

Timers measure short-duration latencies and how often they occur. Negative values are not supported, and longer durations could cause an overflow of the total time (Long.MAX_VALUE nanoseconds (292.3 years)).

使用以下方法之一构造计时器。

Use one of the following methods to construct a timer.

  1. Use a convenience method on the MeterRegistry:[source, java]

registry.timer("fabric.selection", "primary", "blue"); // <1> 2
1 fabric.selection is the summary name
2 primary is a dimensional tag with value blue.
  1. Use Timer.builder to provide a description and units:[source, java]

Timer.builder("my.timer")        // <1> 2
    .description("description ") // optional 3
    .tags("region", "test")      // optional 4
    .register(registry);
1 Create a new timer called my.timer
2 Timers measure time, and will convert it into the units required by the monitoring backend
3 Provide a description for the distribution summary
4 Associate define-tags with the timer
  1. annotations a method[source, java]

@Timed(value = "call", extraTags = {"region", "test"}) // <1> 2
1 A CDI interceptor will create and register a timer called call
2 The interceptor-created timer will have the "region" dimension tag with value "test"

Measure durations with Timers

Micrometer 提供以下便利机制用于记录持续时间:

Micrometer provides the following convenience mechanisms for recording durations.

  1. Wrap the invocation of a Runnable:[source, java]

timer.record(() -> noReturnValue());
  1. Wrap the invocation of a Callable:[source, java]

timer.recordCallable(() -> returnValue());
  1. Create a wrapped Runnable for repeated invocation:[source, java]

Runnable r = timer.wrap(() -> noReturnValue());
  1. Create a wrapped Callable for repeated invocation:[source, java]

Callable c = timer.wrap(() -> returnValue());
  1. Use a Sample for more complex code paths:[source, java]

Sample sample = Timer.start(registry); (1)

doStuff; (2)

sample.stop(registry.timer("my.timer", "response", response.status())); (3)
1 We create a sample, which records the start of the timer.
2 The sample can be passed along as context
3 We can choose the timer when the sample is stopped. This example uses a response status as a tag identifying the timer, which won’t be known until processing is complete.

Histograms and percentiles

计时器和分布摘要都可以配置为发出附加统计信息,如直方图数据、预计算百分比或服务水平目标 (SLO) 边界。有关更多信息和示例,请参阅 Micrometer 文档中的 TimersDistribution Summaries,包括对这两种类型进行内存占用估计。

Both timers and distribution summaries can be configured to emit additional statistics, like histogram data, precomputed percentiles, or service level objective (SLO) boundaries. See Timers and Distribution Summaries in the Micrometer documentation for more information and examples, including memory footprint estimation for both types.

计时器和分布摘要关联的计数、总和和直方图数据可以跨维度(或跨一系列实例)重新聚合。

The count, sum, and histogram data associated with timers and distribution summaries can be re-aggregated across dimensions (or across a series of instances).

预计算百分比值不可行。百分比对于每个数据集都是唯一的(此测量集合的 90th 百分位)。

Precomputed percentile values can not. Percentiles are unique to each dataset (the 90th percentile of this collection of measurements).

Automatically generated metrics

Micrometer 扩展程序自动计时 HTTP 服务器请求。遵循 Prometheus 计时器的命名惯例,查找 http_server_requests_seconds_counthttp_server_requests_seconds_sum`和 `http_server_requests_seconds_max。已为请求的 uri、HTTP 方法(GET、POST 等)、状态代码(200、302、404 等)和更通用的结果字段添加了维度标记。

The Micrometer extension automatically times HTTP server requests. Following Prometheus naming conventions for timers, look for http_server_requests_seconds_count, http_server_requests_seconds_sum, and http_server_requests_seconds_max. Dimensional labels have been added for the requested uri, the HTTP method (GET, POST, etc.), the status code (200, 302, 404, etc.), and a more general outcome field.

Ignoring endpoints

你可以使用 quarkus.micrometer.binder.http-server.ignore-patterns`属性禁用 HTTP 端点的测量。此属性接受一个逗号分隔的简单正则表达式匹配模式列表,用于识别应该忽略的 URI 路径。例如,设置 `quarkus.micrometer.binder.http-server.ignore-patterns=/example/prime/[0-9]+ 将忽略对 http://localhost:8080/example/prime/7919 的请求。对 http://localhost:8080/example/gauge/7919 的请求仍会被测量。

Ignoring endpoints

You can disable measurement of HTTP endpoints using the quarkus.micrometer.binder.http-server.ignore-patterns property. This property accepts a comma-separated list of simple regex match patterns identifying URI paths that should be ignored. For example, setting quarkus.micrometer.binder.http-server.ignore-patterns=/example/prime/[0-9]+ will ignore a request to http://localhost:8080/example/prime/7919. A request to http://localhost:8080/example/gauge/7919 would still be measured.

URI templates

micrometer 扩展程序将在模板形式中尽力表示包含路径参数的 URI。使用以上示例,对 http://localhost:8080/example/prime/7919 的请求应显示为 http_server_requests_seconds_* 度量中的一个属性,其值为 uri=/example/prime/{number}

URI templates

The micrometer extension will make a best effort at representing URIs containing path parameters in templated form. Using examples from above, a request to http://localhost:8080/example/prime/7919 should appear as an attribute of http_server_requests_seconds_* metrics with a value of uri=/example/prime/{number}.

如果无法确定正确的 URL,请使用 quarkus.micrometer.binder.http-server.match-patterns 属性。此属性接受一个逗号分隔的列表,定义简单的正则表达式匹配模式和替换字符串之间的关联。例如,设置 quarkus.micrometer.binder.http-server.match-patterns=/example/prime/[role="0-9"][.0-9]=/example/{jellybeans} 将对任何时候匹配 /example/prime/[0-9] 的请求 uri 使用 /example/{jellybeans} 值作为 uri 属性。

Use the quarkus.micrometer.binder.http-server.match-patterns property if the correct URL can not be determined. This property accepts a comma-separated list defining an association between a simple regex match pattern and a replacement string. For example, setting quarkus.micrometer.binder.http-server.match-patterns=/example/prime/[role="0-9"][.0-9]=/example/{jellybeans} would use the value /example/{jellybeans} for the uri attribute any time the requested uri matches /example/prime/[0-9].

Exported metrics format

默认情况下,度量使用 Prometheus 格式 application/openmetrics-text`导出,你可以通过将 `Accept 请求头指定为 text/plain (curl -H "Accept: text/plain" localhost:8080/q/metrics/) 来恢复为以前的形式。

Exported metrics format

By default, the metrics are exported using the Prometheus format application/openmetrics-text, you can revert to the former format by specifying the Accept request header to text/plain (curl -H "Accept: text/plain" localhost:8080/q/metrics/).

Customizing Micrometer

Quarkus 提供了多种自定义 Micrometer 的方式。

Quarkus provides a variety of way to customize Micrometer.

Use MeterFilter to customize emitted tags and metrics

Micrometer 使用 MeterFilter 实例来自定义由 MeterRegistry 实例发出的度量。Micrometer 扩展程序将检测 MeterFilter CDI Bean,并在初始化 `MeterRegistry`实例时使用它们。

Micrometer uses MeterFilter instances to customize the metrics emitted by MeterRegistry instances. The Micrometer extension will detect MeterFilter CDI beans and use them when initializing MeterRegistry instances.

@Singleton
public class CustomConfiguration {

    @ConfigProperty(name = "deployment.env")
    String deploymentEnv;

    /** Define common tags that apply only to a Prometheus Registry */
    @Produces
    @Singleton
    @MeterFilterConstraint(applyTo = PrometheusMeterRegistry.class)
    public MeterFilter configurePrometheusRegistries() {
        return MeterFilter.commonTags(Arrays.asList(
                Tag.of("registry", "prometheus")));
    }

    /** Define common tags that apply globally */
    @Produces
    @Singleton
    public MeterFilter configureAllRegistries() {
        return MeterFilter.commonTags(Arrays.asList(
                Tag.of("env", deploymentEnv)));
    }

    /** Enable histogram buckets for a specific timer */
    @Produces
    @Singleton
    public MeterFilter enableHistogram() {
        return new MeterFilter() {
            @Override
            public DistributionStatisticConfig configure(Meter.Id id, DistributionStatisticConfig config) {
                if(id.getName().startsWith("myservice")) {
                    return DistributionStatisticConfig.builder()
                        .percentiles(0.5, 0.95)     // median and 95th percentile, not aggregable
                        .percentilesHistogram(true) // histogram buckets (e.g. prometheus histogram_quantile)
                        .build()
                        .merge(config);
                }
                return config;
            }
        };
    }
}

在此示例中,一个单例 CDI Bean 将产生两个不同的 MeterFilter Bean。一个仅应用于 Prometheus MeterRegistry 实例(使用 @MeterFilterConstraint 限定符),另一个将应用于所有 MeterRegistry 实例。一个应用程序配置属性也会被注入并用作标签值。可以在 official documentation 中找到 MeterFilters 的其他示例。

In this example, a singleton CDI bean will produce two different MeterFilter beans. One will be applied only to Prometheus MeterRegistry instances (using the @MeterFilterConstraint qualifier), and another will be applied to all MeterRegistry instances. An application configuration property is also injected and used as a tag value. Additional examples of MeterFilters can be found in the official documentation.

Use HttpServerMetricsTagsContributor for server HTTP requests

通过提供实现 io.quarkus.micrometer.runtime.HttpServerMetricsTagsContributor 的 CDI Bean,用户代码可以根据 HTTP 请求的详细信息提供任意标签。

By providing CDI beans that implement io.quarkus.micrometer.runtime.HttpServerMetricsTagsContributor, user code can contribute arbitrary tags based on the details of HTTP request

Use MeterRegistryCustomizer for arbitrary customizations to meter registries

通过提供实现 io.quarkus.micrometer.runtime.MeterRegistryCustomizer 的 CDI Bean,用户代码可以有机会更改任何已激活的 MeterRegistry 的配置。除非一个实现带 @io.quarkus.micrometer.runtime.MeterRegistryCustomizerConstraint 注释,否则自定义将适用于所有 MeterRegistry 实例。

By providing CDI beans that implement io.quarkus.micrometer.runtime.MeterRegistryCustomizer user code has the change to change the configuration of any MeterRegistry that has been activated. Unless an implementation is annotated with @io.quarkus.micrometer.runtime.MeterRegistryCustomizerConstraint, the customization applies to all MeterRegistry instances.

Does Micrometer support annotations?

Micrometer 确实定义了两个注释,@Counted@Timed,它们可以添加到方法中。@Timed 注释将包装方法的执行,并将发出以下标签作为补充除了注释本身定义的任何标签:类、方法和异常(“none” 或检测到的异常的简单类名)。

Micrometer does define two annotations, @Counted and @Timed, that can be added to methods. The @Timed annotation will wrap the execution of a method and will emit the following tags in addition to any tags defined on the annotation itself: class, method, and exception (either "none" or the simple class name of a detected exception).

@Counted@Timed 的参数可以使用 @MeterTag 注释动态分配有意义的标签值。

Parameters to @Counted and @Timed can be annotated with @MeterTag to dynamically assign meaningful tag values.

可使用 MeterTag.resolver 从方法参数提取标记,方法是创建一个实现 io.micrometer.common.annotation.ValueResolver 的 bean,并引用此类: @MeterTag(resolver=CustomResolver.class)

MeterTag.resolver can be used to extract a tag from a method parameter, by creating a bean implementing io.micrometer.common.annotation.ValueResolver and referring to this class: @MeterTag(resolver=CustomResolver.class)

还支持 MeterTag.expression,但您必须实现表达式的计算,方法是创建一个实现 io.micrometer.common.annotation.ValueExpressionResolver 的 bean,它可以计算表达式。

MeterTag.expression is also supported, but you have to implement the evaluation of the expression by creating a bean implementing io.micrometer.common.annotation.ValueExpressionResolver that can evaluate expressions.

enum Currency { USD, EUR }

@Singleton
class EnumOrdinalResolver implements ValueResolver {
    @Override
    public String resolve(Object parameter) {
        if(parameter instanceof Enum) {
            return String.valueOf(((Enum<?>) parameter).ordinal());
        }
        return null;
    }
}

@Singleton
public class MyExpressionResolver implements ValueExpressionResolver {
    @Override
    public String resolve(String expression, Object parameter) {
        return someParser.parse(expression).evaluate(parameter);
    }
}

// tags = type=with_enum, currency=${currency.toString()}
@Timed(value="time_something", extraTags = {"type", "with_enum"})
public Something calculateSomething(@MeterTag Currency currency) { ... }

// tags = type=with_enum, the_currency=${currency.toString()}
@Timed(value="time_something", extraTags = {"type", "with_enum"})
public Something calculateSomething(@MeterTag(key="the_currency") Currency currency) { ... }

// tags = type=with_enum, currency=${currency.ordinal()}
@Timed(value="time_something", extraTags = {"type", "with_enum"})
public Something calculateSomething(@MeterTag(resolver=EnumOrdinalResolver.class) Currency currency) { ... }

// tags = type=with_enum, currency=${currency.ordinal()}
@Timed(value="time_something", extraTags = {"type", "with_enum"})
public Something calculateSomething(@MeterTag(expression="currency.ordinal()") Currency currency) { ... }

提供的标记值必须是低基数的。高基数值可能导致指标后端的性能和存储问题(“基数爆炸”)。标记值不应使用最终用户数据,因为这些数据可能是高基数的。

Provided tag values MUST BE of LOW-CARDINALITY. High-cardinality values can lead to performance and storage issues in your metrics backend (a "cardinality explosion"). Tag values should not use end-user data, since those could be high-cardinality.

微计扩展开箱即用地对许多方法(例如 REST 端点方法或 Vert.x 路由)进行计数和计时。

Many methods, like REST endpoint methods or Vert.x Routes, are counted and timed by the micrometer extension out of the box.

Support for the MicroProfile Metrics API

如果您在应用程序中使用 MicroProfile 指标 API, 微计扩展将创建一个自适应层,以将这些指标映射到微计注册表中。请注意,两个系统之间的命名约定不同,因此在使用 MP 指标和微计时发出的指标将会发生变化。

If you use the MicroProfile Metrics API in your application, the Micrometer extension will create an adaptive layer to map those metrics into the Micrometer registry. Note that naming conventions between the two systems is different, so the metrics that are emitted when using MP Metrics with Micrometer will change.

使用 MeterFilter 根据您的约定重新映射名称或标记。

Use a MeterFilter to remap names or tags according to your conventions.

@Produces
@Singleton
public MeterFilter renameApplicationMeters() {
    final String targetMetric = MPResourceClass.class.getName() + ".mpAnnotatedMethodName";

    return MeterFilter() {
        @Override
        public Meter.Id map(Meter.Id id) {
            if (id.getName().equals(targetMetric)) {
                // Drop the scope tag (MP Registry type: application, vendor, base)
                List<Tag> tags = id.getTags().stream().filter(x -> !"scope".equals(x.getKey()))
                        .collect(Collectors.toList());
                // rename the metric
                return id.withName("my.metric.name").replaceTags(tags);
            }
            return id;
        }
    };
}

如果您需要 MicroProfile 指标 API,请确保存在以下依赖关系:

Ensure the following dependency is present if you require the MicroProfile Metrics API:

pom.xml
<dependency>
    <groupId>org.eclipse.microprofile.metrics</groupId>
    <artifactId>microprofile-metrics-api</artifactId>
</dependency>
build.gradle
implementation("org.eclipse.microprofile.metrics:microprofile-metrics-api")

将来,MP 指标 API 兼容层可能会移至其他扩展。

The MP Metrics API compatibility layer may be moved to a different extension in the future.

Management interface

默认情况下,指标在主 HTTP 服务器上公开。

By default, the metrics are exposed on the main HTTP server.

您可以通过在应用程序配置中设置 quarkus.management.enabled=true 来在单独的网络接口和端口上公开它们。注意,此属性是构建时间属性。此值在运行时不可重写。

You can expose them on a separate network interface and port by setting quarkus.management.enabled=true in your application configuration. Note that this property is a build-time property. The value cannot be overridden at runtime.

如果您在未自定义管理网络接口和端口的情况下启用管理界面,则指标在以下位置公开: http://0.0.0.0:9000/q/metrics

If you enable the management interface without customizing the management network interface and port, the metrics are exposed under: http://0.0.0.0:9000/q/metrics.

您可以使用以下配置路径配置每个公开格式的路径:

You can configure the path of each exposed format using:

quarkus.micrometer.export.json.enabled=true # Enable json metrics
quarkus.micrometer.export.json.path=metrics/json
quarkus.micrometer.export.prometheus.path=metrics/prometheus

通过此类配置,可以从 http://0.0.0.0:9000/q/metrics/json 获得 json 指标。可以从 http://0.0.0.0:9000/q/metrics/prometheus 获得 prometheus 指标。

With such a configuration, the json metrics will be available from http://0.0.0.0:9000/q/metrics/json. The prometheus metrics will be available from http://0.0.0.0:9000/q/metrics/prometheus.

请参阅 management interface reference 了解更多信息。

Refer to the management interface reference for more information.

Configuration Reference

Unresolved directive in telemetry-micrometer.adoc - include::{generated-dir}/config/quarkus-micrometer.adoc[]