= 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 io.vertx.core.datagram.DatagramSocket}
, {@link io.vertx.core.eventbus.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>${maven.version}</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:${maven.version}'
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,$lang]
----
{@link examples.MicrometerMetricsExamples#setupMinimalInfluxDB()}
----

==== Using a specific URI and database name

[source,$lang]
----
{@link examples.MicrometerMetricsExamples#setupInfluxDBWithUriAndDatabase()}
----

==== With authentication

[source,$lang]
----
{@link examples.MicrometerMetricsExamples#setupInfluxDBWithAuthentication()}
----

== 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>${maven.version}</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:${maven.version}'
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,$lang]
----
{@link examples.MicrometerMetricsExamples#setupMinimalPrometheus()}
----

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

[source,$lang]
----
{@link examples.MicrometerMetricsExamples#setupPrometheusEmbeddedServer()}
----

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

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

[source,$lang]
----
{@link examples.MicrometerMetricsExamples#setupPrometheusBoundRouter()}
----

== 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>${maven.version}</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:${maven.version}'
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,$lang]
----
{@link examples.MicrometerMetricsExamples#setupMinimalJMX()}
----

==== 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,$lang]
----
{@link examples.MicrometerMetricsExamples#setupJMXWithStepAndDomain()}
----

== 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,$lang]
----
{@link examples.MicrometerMetricsExamples#setupWithCompositeRegistry()}
----

== Advanced usage

Please refer to {@link io.vertx.micrometer.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_responseTime_seconds_sum[5m])
/
  rate(vertx_http_client_responseTime_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,$lang]
----
{@link examples.MicrometerMetricsExamples#enableQuantiles()}
----

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_responseTime_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 timeseries 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,$lang]
----
{@link examples.MicrometerMetricsExamples#enableLimitedQuantiles()}
----

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 setup with Prometheus and view dashboards in Grafana.

=== Disable some metric domains

Restricting the Vert.x modules being monitored can be done using
{@link io.vertx.micrometer.MicrometerMetricsOptions#disabledMetricsCategories}.

For a full list of domains, see {@link io.vertx.micrometer.MetricsDomain}

=== User-defined metrics

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

[source,$lang]
----
{@link examples.MicrometerMetricsExamples#accessDefaultRegistry()}
----

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,$lang]
----
{@link examples.MicrometerMetricsExamples#setupAndAccessCustomRegistry()}
----

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

[source,$lang]
----
{@link examples.MicrometerMetricsExamples#customTimerExample()}
----

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

=== Other instrumentation

Since plain access to Micrometer registries is provided, it is possible to leverage the Micrometer API.
For instance, to instrument the JVM:

[source,$lang]
----
{@link examples.MicrometerMetricsExamples#instrumentJVM()}
----

_From link:http://micrometer.io/docs/ref/jvm[Micrometer documentation]._

=== 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
timeseries for a specific event bus address, or compare timeseries 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,$lang]
----
{@link examples.MicrometerMetricsExamples#setupWithLabelsEnabled()}
----

The full list of labels is detailed here: {@link io.vertx.micrometer.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

{@link io.vertx.micrometer.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,$lang]
----
{@link examples.MicrometerMetricsExamples#setupWithMatcherForFiltering()}
----

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 io.vertx.micrometer.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,$lang]
----
{@link examples.MicrometerMetricsExamples#useMicrometerFilters()}
----

NOTE: Matchers use MeterFilters under the hood.

=== Snapshots

A {@link io.vertx.micrometer.MetricsService} can be created out of a {@link io.vertx.core.metrics.Measured} object
in order to take a snapshot of its related metrics and measurements.
The snapshot is returned as a {@link io.vertx.core.json.JsonObject}.

A well known _Measured_ object is simply {@link io.vertx.core.Vertx}:

[source,$lang]
----
{@link examples.MicrometerMetricsExamples#createFullSnapshot()}
----

Other components, such as an {@link io.vertx.core.eventbus.EventBus} or a {@link io.vertx.core.http.HttpServer} are
measurable:

[source,$lang]
----
{@link examples.MicrometerMetricsExamples#createPartialSnapshot()}
----

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

[source,$lang]
----
{@link examples.MicrometerMetricsExamples#createSnapshotFromPrefix()}
----

== Vert.x core tools 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 given with underscore separators, but the actual names may vary
depending on the backend used.

=== Net Client

[cols="15,50,35", options="header"]
|===
|Metric type
|Metric name
|Description

|Gauge
|`vertx_net_client_connections{local=<local address>,remote=<remote address>}`
|Number of connections to the remote host currently opened.

|Summary
|`vertx_net_client_bytesReceived{local=<local address>,remote=<remote address>}`
|Number of bytes received from the remote host.

|Summary
|`vertx_net_client_bytesSent{local=<local address>,remote=<remote address>}`
|Number of bytes sent to the remote host.

|Counter
|`vertx_net_client_errors{local=<local address>,remote=<remote address>,class=<class>}`
|Number of errors.

|===

=== HTTP Client

[cols="15,50,35", options="header"]
|===
|Metric type
|Metric name
|Description

|Gauge
|`vertx_http_client_connections{local=<local address>,remote=<remote address>}`
|Number of connections to the remote host currently opened.

|Summary
|`vertx_http_client_bytesReceived{local=<local address>,remote=<remote address>}`
|Number of bytes received from the remote host.

|Summary
|`vertx_http_client_bytesSent{local=<local address>,remote=<remote address>}`
|Number of bytes sent to the remote host.

|Counter
|`vertx_http_client_errors{local=<local address>,remote=<remote address>,class=<class>}`
|Number of errors.

|Gauge
|`vertx_http_client_requests{local=<local address>,remote=<remote address>}`
|Number of requests waiting for a response.

|Counter
|`vertx_http_client_requestCount{local=<local address>,remote=<remote address>,method=<http method>}`
|Number of requests sent.

|Timer
|`vertx_http_client_responseTime{local=<local address>,remote=<remote address>}`
|Response time.

|Counter
|`vertx_http_client_responseCount{local=<local address>,remote=<remote address>,code=<response code>}`
|Number of received responses.

|Gauge
|`vertx_http_client_wsConnections{local=<local address>,remote=<remote address>}`
|Number of websockets currently opened.

|===

=== Datagram socket

[cols="15,50,35", options="header"]
|===
|Metric type
|Metric name
|Description

|Summary
|`vertx_datagram_bytesReceived{local=<local>,remote=<remote>}`
|Total number of bytes received on the `<host>:<port>` listening address.

|Summary
|`vertx_datagram_bytesSent{remote=<remote>}`
|Total number of bytes sent to the remote host.

|Counter
|`vertx_datagram_errors{class=<class>}`
|Total number of errors.

|===

=== Net Server

[cols="15,50,35", options="header"]
|===
|Metric type
|Metric name
|Description

|Gauge
|`vertx_net_server_connections{local=<local address>}`
|Number of opened connections to the Net Server.

|Summary
|`vertx_net_server_bytesReceived{local=<local address>}`
|Number of bytes received by the Net Server.

|Summary
|`vertx_net_server_bytesSent{local=<local address>}`
|Number of bytes sent by the Net Server.

|Counter
|`vertx_net_server_errors{local=<local address>,class=<class>}`
|Number of errors.

|===

=== HTTP Server

[cols="15,50,35", options="header"]
|===
|Metric type
|Metric name
|Description

|Gauge
|`vertx_http_server_connections{local=<local address>}`
|Number of opened connections to the HTTP Server.

|Summary
|`vertx_http_server_bytesReceived{local=<local address>}`
|Number of bytes received by the HTTP Server.

|Summary
|`vertx_http_server_bytesSent{local=<local address>}`
|Number of bytes sent by the HTTP Server.

|Counter
|`vertx_http_server_errors{local=<local address>,class=<class>}`
|Number of errors.

|Gauge
|`vertx_http_server_requests{local=<local address>}`
|Number of requests being processed.

|Counter
|`vertx_http_server_requestCount{local=<local address>,method=<http method>,code=<response code>}`
|Number of processed requests.

|Counter
|`vertx_http_server_requestResetCount{local=<local address>}`
|Number of requests reset.

|Timer
|`vertx_http_server_processingTime{local=<local address>}`
|Request processing time.

|Gauge
|`vertx_http_client_wsConnections{local=<local address>}`
|Number of websockets currently opened.

|===

=== Event Bus

[cols="15,50,35", options="header"]
|===
|Metric type
|Metric name
|Description

|Gauge
|`vertx_eventbus_handlers{address=<address>}`
|Number of event bus handlers in use.

|Counter
|`vertx_eventbus_errors{address=<address>,class=<class>}`
|Number of errors.

|Summary
|`vertx_eventbus_bytesWritten{address=<address>}`
|Total number of bytes sent while sending messages to event bus cluster peers.

|Summary
|`vertx_eventbus_bytesRead{address=<address>}`
|Total number of bytes received while reading messages from event bus cluster peers.

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

|Counter
|`vertx_eventbus_published{address=<address>,side=<local/remote>}`
|Number of messages published (publish / subscribe).

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

|Counter
|`vertx_eventbus_received{address=<address>,side=<local/remote>}`
|Number of messages received.

|Counter
|`vertx_eventbus_delivered{address=<address>,side=<local/remote>}`
|Number of messages delivered to handlers.

|Counter
|`vertx_eventbus_replyFailures{address=<address>,failure=<failure name>}`
|Number of message reply failures.

|Timer
|`vertx_eventbus_processingTime{address=<address>}`
|Processing time for handlers listening to the `address`.

|===

== Vert.x pool metrics

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

There are two types currently supported:

* _worker_ (see {@link io.vertx.core.WorkerExecutor})
* _datasource_ (created with Vert.x JDBC client)

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

[cols="15,50,35", options="header"]
|===
|Metric type
|Metric name
|Description

|Timer
|`vertx_pool_queue_delay{pool_type=<type>,pool_name=<name>}`
|Time waiting for a resource (queue time).

|Gauge
|`vertx_pool_queue_size{pool_type=<type>,pool_name=<name>}`
|Number of elements waiting for a resource.

|Timer
|`vertx_pool_usage{pool_type=<type>,pool_name=<name>}`
|Time using a resource (i.e. processing time for worker pools).

|Gauge
|`vertx_pool_inUse{pool_type=<type>,pool_name=<name>}`
|Number of resources used.

|Counter
|`vertx_pool_completed{pool_type=<type>,pool_name=<name>}`
|Number of elements done with the resource (i.e. total number of tasks executed for worker pools).

|Gauge
|`vertx_pool_ratio{pool_type=<type>,pool_name=<name>}`
|Pool usage ratio, only present if maximum pool size could be determined.

|===

== Verticle metrics

[cols="15,50,35", options="header"]
|===
|Metric type
|Metric name
|Description

|Gauge
|`vertx_verticle_deployed{name=<name>}`
|Number of verticle instances deployed.

|===
