= Vert.x Micrometer Metrics

This project is an implementation of the Vert.x Metrics Service Provider Interface (SPI).
It uses link:http://micrometer.io/[Micrometer] for managing metrics and reporting to several backends.

== Features

* Vert.x core tools monitoring: TCP/HTTP client and servers, `link:../../apidocs/io/vertx/core/datagram/DatagramSocket.html[DatagramSocket]`
, `link:../../apidocs/io/vertx/core/eventbus/EventBus.html[EventBus]` and pools
* User defined metrics through Micrometer
* Reporting to any backend supported by Micrometer
* Built-in options for https://www.influxdata.com/[InfluxDB], https://prometheus.io/[Prometheus] and JMX reporting.

== InfluxDB

=== Prerequisites

Follow the https://docs.influxdata.com/influxdb/latest/introduction/getting_started/[instructions to get InfluxDb up and running].

=== Getting started

The modules _vertx-micrometer-metrics_ and _micrometer-registry-influx_ must be present in the classpath.

Maven users should add this to their project POM file:

[source,xml,subs="+attributes"]
----
<dependency>
  <groupId>io.vertx</groupId>
  <artifactId>vertx-micrometer-metrics</artifactId>
  <version>5.0.0.CR1</version>
</dependency>
<dependency>
  <groupId>io.micrometer</groupId>
  <artifactId>micrometer-registry-influx</artifactId>
  <version>${micrometer.version}</version>
</dependency>
----

And Gradle users, to their build file:

[source,groovy,subs="+attributes"]
----
compile 'io.vertx:vertx-micrometer-metrics:5.0.0.CR1'
compile 'io.micrometer:micrometer-registry-influx:${micrometer.version}'
----

=== Configuration examples

Vert.x does not enable SPI implementations by default.
You must enable metric collection in the Vert.x options.

[source,java]
----
Vertx vertx = Vertx.vertx(new VertxOptions().setMetricsOptions(
  new MicrometerMetricsOptions()
    .setInfluxDbOptions(new VertxInfluxDbOptions().setEnabled(true))
    .setEnabled(true)));
----

==== Using a specific URI

[source,java]
----
Vertx vertx = Vertx.vertx(new VertxOptions().setMetricsOptions(
  new MicrometerMetricsOptions()
    .setInfluxDbOptions(new VertxInfluxDbOptions().setEnabled(true)
      .setUri("http://influxdb.example.com:8888"))
    .setEnabled(true)));
----

==== Connecting to InfluxDB V2

Connecting to InfluxDB V2 requires that at least the `link:../../apidocs/io/vertx/micrometer/VertxInfluxDbOptions.html#setOrg-java.lang.String-[org]` property is set.

[source,java]
----
Vertx vertx = Vertx.vertx(new VertxOptions().setMetricsOptions(
  new MicrometerMetricsOptions()
    .setInfluxDbOptions(new VertxInfluxDbOptions().setEnabled(true)
      .setOrg("my-org"))
    .setEnabled(true)));
----

==== Using a specific database name or bucket

To configure a specific database name:

[source,java]
----
Vertx vertx = Vertx.vertx(new VertxOptions().setMetricsOptions(
  new MicrometerMetricsOptions()
    .setInfluxDbOptions(new VertxInfluxDbOptions().setEnabled(true)
      .setDb("sales-department"))
    .setEnabled(true)));
----

For InfluxDB V2, you can use `link:../../apidocs/io/vertx/micrometer/VertxInfluxDbOptions.html#setBucket-java.lang.String-[setBucket]` as well.

==== With authentication

Authentication can be configured with a username and a password:

[source,java]
----
Vertx vertx = Vertx.vertx(new VertxOptions().setMetricsOptions(
  new MicrometerMetricsOptions()
    .setInfluxDbOptions(new VertxInfluxDbOptions().setEnabled(true)
      .setUserName("username")
      .setPassword("password"))
    .setEnabled(true)));
----

Or it can be configured with a token:

[source,java]
----
Vertx vertx = Vertx.vertx(new VertxOptions().setMetricsOptions(
  new MicrometerMetricsOptions()
    .setInfluxDbOptions(new VertxInfluxDbOptions().setEnabled(true)
      .setToken(authToken))
    .setEnabled(true)));
----

== Prometheus

=== Prerequisites

Follow the https://prometheus.io/docs/prometheus/latest/getting_started/[instructions to get Prometheus up and running].

=== Getting started

The modules _vertx-micrometer-metrics_ and _micrometer-registry-prometheus_ must be present in the classpath.
You may also probably need _vertx-web_, to expose the metrics.

Maven users should add this to their project POM file:

[source,xml,subs="+attributes"]
----
<dependency>
  <groupId>io.vertx</groupId>
  <artifactId>vertx-micrometer-metrics</artifactId>
  <version>5.0.0.CR1</version>
</dependency>
<dependency>
  <groupId>io.micrometer</groupId>
  <artifactId>micrometer-registry-prometheus</artifactId>
  <version>${micrometer.version}</version>
</dependency>
----

And Gradle users, to their build file:

[source,groovy,subs="+attributes"]
----
compile 'io.vertx:vertx-micrometer-metrics:5.0.0.CR1'
compile 'io.micrometer:micrometer-registry-prometheus:${micrometer.version}'
----

=== Configuration examples

Vert.x does not enable SPI implementations by default. You must enable metric collection in the Vert.x options

[source,java]
----
Vertx vertx = Vertx.vertx(new VertxOptions().setMetricsOptions(
  new MicrometerMetricsOptions()
    .setPrometheusOptions(new VertxPrometheusOptions().setEnabled(true))
    .setEnabled(true)));
----

==== Using an embedded HTTP server with custom endpoint

[source,java]
----
Vertx vertx = Vertx.vertx(new VertxOptions().setMetricsOptions(
  new MicrometerMetricsOptions()
    .setPrometheusOptions(new VertxPrometheusOptions().setEnabled(true)
      .setStartEmbeddedServer(true)
      .setEmbeddedServerOptions(new HttpServerOptions().setPort(8080))
      .setEmbeddedServerEndpoint("/metrics/vertx"))
    .setEnabled(true)));
----

If the embedded server endpoint is not specified, it defaults to _/metrics_.

==== Using a custom HTTP server

The `link:../../apidocs/io/vertx/micrometer/PrometheusRequestHandler.html[PrometheusRequestHandler]` provides flexibility in scraping and serving Prometheus metrics.

[source,java]
----
vertx.createHttpServer()
  .requestHandler(PrometheusRequestHandler.create(prometheusMeterRegistry, "/metrics/prometheus"))
  .listen(8888);
----

==== Binding metrics to an existing Vert.x Web router

[source,java]
----
Vertx vertx = Vertx.vertx(new VertxOptions().setMetricsOptions(
  new MicrometerMetricsOptions()
    .setPrometheusOptions(new VertxPrometheusOptions().setEnabled(true))
    .setEnabled(true)));

// Later on, creating a router
Router router = Router.router(vertx);
router.route("/metrics").handler(PrometheusScrapingHandler.create());
vertx.createHttpServer().requestHandler(router).listen(8080);
----

== JMX

=== Getting started

The modules _vertx-micrometer-metrics_ and _micrometer-registry-jmx_ must be present in the classpath.

Maven users should add this to their project POM file:

[source,xml,subs="+attributes"]
----
<dependency>
  <groupId>io.vertx</groupId>
  <artifactId>vertx-micrometer-metrics</artifactId>
  <version>5.0.0.CR1</version>
</dependency>
<dependency>
  <groupId>io.micrometer</groupId>
  <artifactId>micrometer-registry-jmx</artifactId>
  <version>${micrometer.version}</version>
</dependency>
----

And Gradle users, to their build file:

[source,groovy,subs="+attributes"]
----
compile 'io.vertx:vertx-micrometer-metrics:5.0.0.CR1'
compile 'io.micrometer:micrometer-registry-jmx:${micrometer.version}'
----

=== Configuration examples

Vert.x does not enable SPI implementations by default. You must enable metric collection in the Vert.x options

[source,java]
----
Vertx vertx = Vertx.vertx(new VertxOptions().setMetricsOptions(
  new MicrometerMetricsOptions()
    .setJmxMetricsOptions(new VertxJmxMetricsOptions().setEnabled(true))
    .setEnabled(true)));
----

==== With step and domain

In Micrometer, `step` refers to the reporting period, in seconds. `domain` is the JMX domain under which
MBeans are registered.

[source,java]
----
Vertx vertx = Vertx.vertx(new VertxOptions().setMetricsOptions(
  new MicrometerMetricsOptions()
    .setJmxMetricsOptions(new VertxJmxMetricsOptions().setEnabled(true)
      .setStep(5)
      .setDomain("my.metrics.domain"))
    .setEnabled(true)));
----

== Other backends or combinations

Even if not all backends supported by Micrometer are implemented in Vert.x options, it is still possible
to create any Micrometer registry and pass it to Vert.x.

The list of available backends includes Graphite, Ganglia, Atlas, link:http://micrometer.io/docs[etc].
It also enables the link:http://micrometer.io/docs/concepts#_composite_registries[Micrometer Composite Registry]
in order to report the same metrics to multiple backends.

In this example, metrics are reported both for JMX and Graphite:

[source,java]
----
CompositeMeterRegistry myRegistry = new CompositeMeterRegistry();
myRegistry.add(new JmxMeterRegistry(s -> null, Clock.SYSTEM));
myRegistry.add(new GraphiteMeterRegistry(s -> null, Clock.SYSTEM));

Vertx vertx = Vertx.builder()
  .with(new VertxOptions()
    .setMetricsOptions(new MicrometerMetricsOptions()
      .setEnabled(true)))
  .withMetrics(new MicrometerMetricsFactory(myRegistry))
  .build();
----

== Advanced usage

Please refer to `link:../../apidocs/io/vertx/micrometer/MicrometerMetricsOptions.html[MicrometerMetricsOptions]` for an exhaustive list of options.

=== Averages and quantiles in Prometheus

By default, when using the Prometheus registry, histogram-kind metrics will not contain averages or quantile stats.

Averages don't come out of the box, but they are typically link:https://prometheus.io/docs/practices/histograms/#count-and-sum-of-observations[computed at query time],
with `promql`. Example, for HTTP client response time average during the last 5 minutes:

[source]
----
  rate(vertx_http_client_response_time_seconds_sum[5m])
/
  rate(vertx_http_client_response_time_seconds_count[5m])
----

To compute quantiles, there are two options available. The first is to activate quantile stats globally
and make them usable for Prometheus function `histogram_quantile`:

[source,java]
----
Vertx vertx = Vertx.vertx(new VertxOptions().setMetricsOptions(
  new MicrometerMetricsOptions()
    .setPrometheusOptions(new VertxPrometheusOptions().setEnabled(true)
      .setPublishQuantiles(true))
    .setEnabled(true)));
----

And then, for example the `promql` query for the HTTP client response time, 99th percentile over the last 5 minutes:
[source]
----
  histogram_quantile(0.99, sum(rate(vertx_http_client_response_time_seconds_bucket[5m])) by (le))
----

The advantage of this option is that it can be leveraged in `promql`, aggregable across dimensions.
The downside is that it creates a lot of time-series for stats under the hood.

The second option is to create limited stats, non-aggregable across dimensions.
It requires to access directly the Micrometer / Prometheus registry:

[source,java]
----
PrometheusMeterRegistry registry = (PrometheusMeterRegistry) BackendRegistries.getDefaultNow();
registry.config().meterFilter(
  new MeterFilter() {
    @Override
    public DistributionStatisticConfig configure(Meter.Id id, DistributionStatisticConfig config) {
      return DistributionStatisticConfig.builder()
        .percentiles(0.95, 0.99)
        .build()
        .merge(config);
    }
  });
----

See also, more on histograms and percentiles:

* from link:https://micrometer.io/docs/concepts#_histograms_and_percentiles[Micrometer doc]
* from link:https://prometheus.io/docs/prometheus/latest/querying/functions/#histogram_quantile[Prometheus doc]

Furthermore, you can check some link:https://github.com/vert-x3/vertx-examples/tree/master/micrometer-metrics-examples[full working examples].
They come along with few instructions to set up with Prometheus and view dashboards in Grafana.

=== Disable some metric domains

Restricting the Vert.x modules being monitored can be done using
`link:../../apidocs/io/vertx/micrometer/MicrometerMetricsOptions.html#disabledMetricsCategories[disabledMetricsCategories]`.

For a full list of domains, see `link:../../apidocs/io/vertx/micrometer/MetricsDomain.html[MetricsDomain]`

=== User-defined metrics

The Micrometer registries are accessible, in order to create new metrics or fetch the existing ones.
By default, a unique registry is used and will be shared across the Vert.x instances of the JVM:

[source,java]
----
MeterRegistry registry = BackendRegistries.getDefaultNow();
----

It is also possible to have separate registries per Vertx instance, by giving a registry name in metrics options.
Then it can be retrieved specifically:

[source,java]
----
Vertx vertx = Vertx.vertx(new VertxOptions().setMetricsOptions(
  new MicrometerMetricsOptions()
    .setInfluxDbOptions(new VertxInfluxDbOptions().setEnabled(true)) // or VertxPrometheusOptions
    .setRegistryName("my registry")
    .setEnabled(true)));

// Later on:
MeterRegistry registry = BackendRegistries.getNow("my registry");
----

As an example, here is a custom timer that will track the execution time of a piece of code that is regularly called:

[source,java]
----
MeterRegistry registry = BackendRegistries.getDefaultNow();
Timer timer = Timer
  .builder("my.timer")
  .description("a description of what this timer does")
  .register(registry);

vertx.setPeriodic(1000, l -> {
  timer.record(() -> {
    // Running here some operation to monitor
  });
});
----

For more examples, documentation about the Micrometer registry and how to create metrics, check
link:http://micrometer.io/docs/concepts#_registry[Micrometer doc].

=== Reusing an existing registry

It is possible to reuse an existing Micrometer registry (or `CollectorRegistry` from the Prometheus Java client),
and inject it into the Vert.x instance using a `link:../../apidocs/io/vertx/core/VertxBuilder.html[VertxBuilder]`:

[source,java]
----
PrometheusMeterRegistry registry = new PrometheusMeterRegistry(PrometheusConfig.DEFAULT);

// You could also reuse an existing registry from the Prometheus Java client:
PrometheusRegistry prometheusClientRegistry = new PrometheusRegistry();
registry = new PrometheusMeterRegistry(PrometheusConfig.DEFAULT, prometheusClientRegistry, Clock.SYSTEM);

// It's reused in MicrometerMetricsOptions.
// Prometheus options configured here, such as "setPublishQuantiles(true)", will affect the whole registry.
Vertx.builder()
  .with(new VertxOptions().setMetricsOptions(
    new MicrometerMetricsOptions()
      .setPrometheusOptions(new VertxPrometheusOptions().setEnabled(true)
        .setPublishQuantiles(true))
      .setEnabled(true)))
  .withMetrics(new MicrometerMetricsFactory(registry))
  .build();
----

[IMPORTANT]
====
Vert.x Micrometer Metrics registers meter filters for <<_using_matchers,label matching>>.
Since Micrometer 1.13, a https://github.com/micrometer-metrics/micrometer/pull/4917[warning is logged] when a `MeterFilter` is configured after a meter is registered.

To avoid this warning, make sure to register your own meters only after Vert.x Micrometer Metrics has been initialized.
====

=== JVM and system metrics

Vert.x Micrometer Metrics can be configured to collect JVM and system metrics:

[source,java]
----
metricsOptions.setJvmMetricsEnabled(true);
----

=== Netty metrics

Vert.x relies on https://netty.io[Netty] for the networking layer.

Vert.x Micrometer Metrics can be configured to collect Netty metrics:

[source,java]
----
metricsOptions.setNettyMetricsEnabled(true);
----

The metric data collected is related to Vert.x specific byte buffer allocators and event loop groups.

=== Other instrumentations

Since plain access to Micrometer registries is provided, it is possible to leverage the Micrometer API:

[source,java]
----
MeterRegistry registry = BackendRegistries.getDefaultNow();
DiskSpaceMetrics metrics = new DiskSpaceMetrics(new File("/opt/myapp/data"));
metrics.bindTo(registry);
----

=== Metric names

Each metric that Vert.x provides can be renamed through the metrics options, using
`link:../../apidocs/io/vertx/micrometer/MetricsNaming.html[MetricsNaming]` and `link:../../apidocs/io/vertx/micrometer/MicrometerMetricsOptions.html#setMetricsNaming-io.vertx.micrometer.MetricsNaming-[setMetricsNaming]`.
The default metric names were changed in Vert.x 4 to better align with backend conventions, but it is
still possible to retrieve the names used in Vert.x 3.x for compatibility:

[source,java]
----
Vertx vertx = Vertx.vertx(new VertxOptions().setMetricsOptions(
  new MicrometerMetricsOptions()
    .setPrometheusOptions(new VertxPrometheusOptions().setEnabled(true))
    .setMetricsNaming(MetricsNaming.v3Names())
    .setEnabled(true)));
----

=== Labels and matchers

Vert.x Micrometer Metrics defines a set of labels (aka tags or fields) that are used to provide dimensionality
to a metric. For instance, metrics related to event bus messages have an _address_ label, which allows then to query time-series for a specific event bus address, or compare time-series per address, or perform any kind of aggregation
that the query API allows.

While setting up metrics options, you can specify which labels you want to enable or not:

[source,java]
----
Vertx vertx = Vertx.vertx(new VertxOptions().setMetricsOptions(
  new MicrometerMetricsOptions()
    .setPrometheusOptions(new VertxPrometheusOptions().setEnabled(true))
    .setLabels(EnumSet.of(Label.REMOTE, Label.LOCAL, Label.HTTP_CODE, Label.HTTP_PATH))
    .setEnabled(true)));
----

The full list of labels is detailed here: `link:../../apidocs/io/vertx/micrometer/Label.html[Label]`.

WARNING: Enabling labels may result in a high cardinality in values, which can cause troubles on the metrics backend and affect performances.
So it must be used with care.
In general, it is fine to enable labels when the set of possible values is bounded.

For that reason, labels enabled by default are restricted to the ones with known bounded values.

It is possible to interact with labels further than just enabling/disabling. There are two ways for that:

[#_using_matchers]
==== Using Matchers

`link:../../apidocs/io/vertx/micrometer/Match.html[Match]` objects can be used to filter or rename some label value
by matching it with either an exact string or a regular expression (the former being more efficient).

Here is an example to restrict HTTP server metrics to those with label _local=localhost:8080_ only:

[source,java]
----
Vertx vertx = Vertx.vertx(new VertxOptions().setMetricsOptions(
  new MicrometerMetricsOptions()
    .setPrometheusOptions(new VertxPrometheusOptions().setEnabled(true))
    .addLabelMatch(new Match()
      // Restrict HTTP server metrics to those with label "local=localhost:8080" only
      .setDomain(MetricsDomain.HTTP_SERVER)
      .setLabel("local")
      .setValue("localhost:8080"))
    .setEnabled(true)));
----

When an _alias_ is specified in the Match, it will be used to rename value instead of filtering.

Matchers are especially useful to control labelling through configuration as they are set via
`link:../../apidocs/io/vertx/micrometer/MicrometerMetricsOptions.html[MicrometerMetricsOptions]`.

==== Using Micrometer's MeterFilter

Micrometer's link:http://micrometer.io/docs/concepts#_meter_filters[MeterFilter API] can be accessed directly in order to define rules on labels.
Compared to Matchers, it offers more features in manipulating the labels, but cannot be defined from configuration.
So both have their advantages.

Here is an example to replace the actual `path` label of HTTP requests with a generic form using regex:

[source,java]
----
MeterRegistry registry = BackendRegistries.getDefaultNow();
Pattern pattern = Pattern.compile("/foo/bar/.*");

registry.config().meterFilter(
  MeterFilter.replaceTagValues(Label.HTTP_PATH.toString(), actualPath -> {
    Matcher m = pattern.matcher(actualPath);
    if (m.matches()) {
      return "/foo/bar/:id";
    }
    return actualPath;
  }, ""));
----

NOTE: Matchers use MeterFilters under the hood.

=== Custom tags provider

You can define a function that generates additional tags (or labels) for HTTP server or client metrics.
Such function takes an `link:../../apidocs/io/vertx/core/spi/observability/HttpRequest.html[HttpRequest]` object as a parameter, and returns
an Iterable of `link:../../apidocs/io/micrometer/core/instrument/Tag.html[Tag]`.

As an example, here is how to map the _x-user_ header to a custom label _user_ in both server and client metrics:

[source,java]
----
Vertx vertx = Vertx.vertx(new VertxOptions().setMetricsOptions(
  new MicrometerMetricsOptions()
    .setPrometheusOptions(new VertxPrometheusOptions().setEnabled(true))
    .setServerRequestTagsProvider(req -> {
      String user = req.headers().get("x-user");
      return Collections.singletonList(Tag.of("user", user));
    })
    .setClientRequestTagsProvider(req -> {
      String user = req.headers().get("x-user");
      return Collections.singletonList(Tag.of("user", user));
    })
    .setEnabled(true)));
----

=== Snapshots

A `link:../../apidocs/io/vertx/micrometer/MetricsService.html[MetricsService]` can be created out of a `link:../../apidocs/io/vertx/core/metrics/Measured.html[Measured]` object
in order to take a snapshot of its related metrics and measurements.
The snapshot is returned as a `link:../../apidocs/io/vertx/core/json/JsonObject.html[JsonObject]`.

A well known _Measured_ object is simply `link:../../apidocs/io/vertx/core/Vertx.html[Vertx]`:

[source,java]
----
MetricsService metricsService = MetricsService.create(vertx);
JsonObject metrics = metricsService.getMetricsSnapshot();
System.out.println(metrics);
----

Other components, such as an `link:../../apidocs/io/vertx/core/eventbus/EventBus.html[EventBus]` or a `link:../../apidocs/io/vertx/core/http/HttpServer.html[HttpServer]` are
measurable:

[source,java]
----
HttpServer server = vertx.createHttpServer();
MetricsService metricsService = MetricsService.create(server);
JsonObject metrics = metricsService.getMetricsSnapshot();
System.out.println(metrics);
----

Finally, it is possible to filter the returned metrics from their base names:

[source,java]
----
MetricsService metricsService = MetricsService.create(vertx);
// Client + server
JsonObject metrics = metricsService.getMetricsSnapshot("vertx.http");
System.out.println(metrics);
----

== Vert.x core metrics

This section lists all the metrics generated by monitoring the Vert.x core tools.

NOTE: The metric backends may have different conventions or rules for naming metrics.
The names described below are the default ones used in Vert.x 4, using underscore separators.
The actual names may vary depending on the metrics backend.

=== TCP Client

[cols="35,20,10,35", options="header"]
|===
|Metric name
|Labels
|Type
|Description

|`vertx_net_client_bytes_read`
|`local`, `remote`
|Counter
|Number of bytes received from the remote host.

|`vertx_net_client_bytes_written`
|`local`, `remote`
|Counter
|Number of bytes sent to the remote host.

|`vertx_net_client_active_connections`
|`local`, `remote`
|Gauge
|Number of connections to the remote host currently opened.

|`vertx_net_client_errors`
|`local`, `remote`, `class`
|Counter
|Number of errors.

|===

=== HTTP Client

[cols="35,20,10,35", options="header"]
|===
|Metric name
|Labels
|Type
|Description

|`vertx_http_client_bytes_read`
|`local`, `remote`
|Counter
|Number of bytes received from the remote host.

|`vertx_http_client_bytes_written`
|`local`, `remote`
|Counter
|Number of bytes sent to the remote host.

|`vertx_http_client_active_connections`
|`local`, `remote`
|Gauge
|Number of connections to the remote host currently opened.

|`vertx_http_client_errors`
|`local`, `remote`, `class`
|Counter
|Number of errors.

|`vertx_http_client_active_requests`
|`local`, `remote`, `path`, `method`
|Gauge
|Number of requests being processed, waiting for a response.

|`vertx_http_client_requests_total`
|`local`, `remote`, `path`, `method`
|Counter
|Number of requests sent.

|`vertx_http_client_request_bytes`
|`local`, `remote`, `path`, `method`
|Summary
|Size in bytes of the requests.

|`vertx_http_client_response_time_seconds`
|`local`, `remote`, `path`, `method`, `code`
|Timer
|Response time in seconds.

|`vertx_http_client_responses_total`
|`local`, `remote`, `path`, `method`, `code`
|Counter
|Number of received responses.

|`vertx_http_client_response_bytes`
|`local`, `remote`, `path`, `method`, `code`
|Summary
|Size in bytes of the responses.

|`vertx_http_client_active_ws_connections`
|`local`, `remote`
|Gauge
|Number of websockets currently opened.

|===

=== TCP Server

[cols="35,20,10,35", options="header"]
|===
|Metric name
|Labels
|Type
|Description

|`vertx_net_server_bytes_read`
|`local`, `remote`
|Counter
|Number of bytes received by the Net Server.

|`vertx_net_server_bytes_written`
|`local`, `remote`
|Counter
|Number of bytes sent by the Net Server.

|`vertx_net_server_active_connections`
|`local`, `remote`
|Gauge
|Number of opened connections to the Net Server.

|`vertx_net_server_errors`
|`local`, `remote`, `class`
|Counter
|Number of errors.

|===

=== HTTP Server

[cols="35,20,10,35", options="header"]
|===
|Metric name
|Labels
|Type
|Description

|`vertx_http_server_bytes_read`
|`local`, `remote`
|Counter
|Number of bytes received by the HTTP Server.

|`vertx_http_server_bytes_written`
|`local`, `remote`
|Counter
|Number of bytes sent by the HTTP Server.

|`vertx_http_server_active_connections`
|`local`, `remote`
|Gauge
|Number of opened connections to the HTTP Server.

|`vertx_http_server_errors`
|`local`, `remote`, `class`
|Counter
|Number of errors.

|`vertx_http_server_active_requests`
|`local`, `remote`, `path`, `method`
|Gauge
|Number of requests being processed.

|`vertx_http_server_requests_total`
|`local`, `remote`, `path`, `method`, `code`, `route`
|Counter
|Number of processed requests.

|`vertx_http_server_request_resets_total`
|`local`, `remote`, `path`, `method`
|Counter
|Number of request resets.

|`vertx_http_server_request_bytes`
|`local`, `remote`, `path`, `method`
|Summary
|Size in bytes of the requests.

|`vertx_http_server_response_time_seconds`
|`local`, `remote`, `path`, `method`, `code`, `route`
|Timer
|Request processing time in seconds.

|`vertx_http_server_response_bytes`
|`local`, `remote`, `path`, `method`, `code`, `route`
|Summary
|Size in bytes of the responses.

|`vertx_http_server_active_ws_connections`
|`local`, `remote`
|Gauge
|Number of websockets currently opened.

|===

=== Datagram sockets

[cols="35,20,10,35", options="header"]
|===
|Metric name
|Labels
|Type
|Description

|`vertx_datagram_bytes_read`
|`local`
|Summary
|Total number of bytes received on the `<host>:<port>` listening address.

|`vertx_datagram_bytes_written`
|(none)
|Summary
|Total number of bytes sent to the remote host.

|`vertx_datagram_errors`
|`class`
|Counter
|Total number of errors.

|===

=== Event Bus

[cols="35,20,10,35", options="header"]
|===
|Metric name
|Labels
|Type
|Description

|`vertx_eventbus_bytes_read`
|`address`
|Summary
|Total number of bytes received while reading messages from event bus cluster peers.

|`vertx_eventbus_bytes_written`
|`address`
|Summary
|Total number of bytes sent while sending messages to event bus cluster peers.

|`vertx_eventbus_handlers`
|`address`
|Gauge
|Number of event bus handlers in use.

|`vertx_eventbus_pending`
|`address`,`side` (local/remote)
|Gauge
|Number of messages not processed yet. One message published will count for `N` pending if `N` handlers
are registered to the corresponding address.

|`vertx_eventbus_processed`
|`address`,`side` (local/remote)
|Counter
|Number of processed messages.

|`vertx_eventbus_published`
|`address`,`side` (local/remote)
|Counter
|Number of messages published (publish / subscribe).

|`vertx_eventbus_discarded`
|`address`,`side` (local/remote)
|Counter
|Number of discarded messages (e.g. still pending messages while handler is unregistered, or overflowing messages).

|`vertx_eventbus_sent`
|`address`,`side` (local/remote)
|Counter
|Number of messages sent (point-to-point).

|`vertx_eventbus_received`
|`address`,`side` (local/remote)
|Counter
|Number of messages received.

|`vertx_eventbus_delivered`
|`address`,`side` (local/remote)
|Counter
|Number of messages delivered to handlers.

|`vertx_eventbus_reply_failures`
|`address`,`failure`
|Counter
|Number of message reply failures.

|===

=== Worker pool metrics

The Vert.x worker pool expose metrics as defined by the <<pool-metrics,pool metrics>>.

The type of pool (`pool_type`) is _worker_.

Vert.x creates two worker pools upfront, _worker-thread_ and _internal-blocking_.

== Generic metrics

[[pool-metrics]]
=== Pool metrics

Vert.x clients, other than the core HTTP clients, may expose pool metrics.

[cols="35,20,10,35", options="header"]
|===
|Metric name
|Labels
|Type
|Description

|`vertx_pool_queue_time_seconds`
|`pool_type`,`pool_name`
|Timer
|Time spent in queue before being processed, in seconds.

|`vertx_pool_queue_pending`
|`pool_type`,`pool_name`
|Gauge
|Number of pending elements in queue.

|`vertx_pool_usage`
|`pool_type`,`pool_name`
|Timer
|Time using a resource (i.e. processing time for worker pools).

|`vertx_pool_in_use`
|`pool_type`,`pool_name`
|Gauge
|Number of resources used.

|`vertx_pool_completed`
|`pool_type`,`pool_name`
|Counter
|Number of elements done with the resource (i.e. total number of tasks executed for worker pools).

|`vertx_pool_ratio`
|`pool_type`,`pool_name`
|Gauge
|Pool usage ratio, only present if maximum pool size could be determined.

|===

[[clients-metrics]]
=== Client metrics

Vert.x clients, other than the core HTTP / Net clients, may implement a standard set of client metrics.

Such client metrics are named after a "client type" identifier, displayed as `$TYPE` in the table below.

The meaning of the `namespace` label is left to the discretion of the client implementation.

[cols="35,20,10,35", options="header"]
|===
|Metric name
|Labels
|Type
|Description

|`vertx_$TYPE_queue_pending`
|`remote`, `namespace`
|Gauge
|Number of pending elements in queue.

|`vertx_$TYPE_queue_time_seconds`
|`remote`, `namespace`
|Timer
|Time spent in queue before being processed, in seconds.

|`vertx_$TYPE_processing_pending`
|`remote`, `namespace`
|Gauge
|Number of elements being processed.

|`vertx_$TYPE_processing_time_seconds`
|`remote`, `namespace`
|Timer
|Processing time, from request start to response end, in seconds.

|`vertx_$TYPE_resets_total`
|`remote`, `namespace`
|Counter
|Total number of resets.

|===

== Database clients metrics

The following clients expose <<clients-metrics,client metrics>> as well as optionally <<pool-metrics,pool metrics>>.

- Vert.x SQL client
- Vert.x Redis client
- ...

The pool metrics carry a `pool_type`, e.g. the SQL client uses the `*sql*` type

- `vertx.pool.queue.pending` with `pool_type`=*sql*
- `vertx.pool.queue.time` with `pool_type`=*sql*
- `vertx.pool.usage` with `pool_type`=*sql*
- `vertx.pool.ratio` `pool_type`=*sql*
- `vertx.pool.completed` `pool_type`=*sql*
- `vertx.pool.in.use` `pool_type`=*sql*

The client metrics type appears in the metrics name

- `vertx.*sql*.processing.pending`
- `vertx.*sql*.processing.time`

In order to distinguish pools, you can set a pool name on the `PoolOptions`, exposed as a label

- `vertx.pool.queue.pending` with `pool_type`=*sql* and `pool_name`=*the-pool-name*
- `vertx.pool.queue.time` with `pool_type`=*sql* and `pool_name`=*the-pool-name*
- `vertx.pool.usage` with `pool_type`=*sql* and `pool_name`=*the-pool-name*
- `vertx.pool.ratio` `pool_type`=*sql* and `pool_name`=*the-pool-name*
- `vertx.pool.completed` `pool_type`=*sql* and `pool_name`=*the-pool-name*
- `vertx.pool.in.use` `pool_type`=*sql* and `pool_name`=*the-pool-name*

Likewise, client metrics use a namespace with distinguish between them

- `vertx.*sql*.processing.pending` with `client_namespace`=`*the-client-name*`
- `vertx.*sql*.processing.time` with `client_namespace`=`*the-client-name*`

Micrometer must be configured to expose these labels

[source,java]
----
micrometerMetricsOptions.addLabels(Label.POOL_NAME);
micrometerMetricsOptions.addLabels(Label.NAMESPACE);
----

=== Vert.x SQL client

Vert.x SQL client uses the `sql` type.

Use `PoolOptions#setName(String)` to name the pool

[source,java]
----
poolOptions.setName("the-pool-name");
----

Likewise, use `SqlConnectOptions#setMetricsName(String)` to scope the client metrics

[source,java]
----
connectOptions.setMetricsName("the-client-name");
----

=== Vert.x Redis client

Vert.x SQL client uses the `redis` type.

Use `RedisOptions#setPoolName(String)` to name the pool

[source,java]
----
redisOptions.setPoolName("the-pool-name");
----

Likewise, use `RedisOptions#setMetricsName(String)` to scope the client metrics

[source,java]
----
redisOptions.setMetricsName("the-client-name");
----