Skip to content

Commit

Permalink
Merge pull request #200 from tsegismont/metrics-perf-improvements
Browse files Browse the repository at this point in the history
Performance improvements
  • Loading branch information
tsegismont authored Oct 17, 2023
2 parents 99ab177 + 3cf5fad commit 28f3fe5
Show file tree
Hide file tree
Showing 45 changed files with 1,499 additions and 1,832 deletions.
13 changes: 6 additions & 7 deletions src/main/asciidoc/index.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,7 @@ Please refer to {@link io.vertx.micrometer.MicrometerMetricsOptions} for an exha

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],
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]
Expand All @@ -256,7 +256,7 @@ And then, for example the `promql` query for the HTTP client response time, 99th
----

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 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:
Expand All @@ -272,7 +272,7 @@ See also, more on histograms and percentiles:
* 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.
They come along with few instructions to set up with Prometheus and view dashboards in Grafana.

=== Disable some metric domains

Expand All @@ -284,7 +284,7 @@ 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:
By default, a unique registry is used and will be shared across the Vert.x instances of the JVM:

[source,$lang]
----
Expand Down Expand Up @@ -346,8 +346,7 @@ still possible to retrieve the names used in Vert.x 3.x for compatibility:
=== 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
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:
Expand Down Expand Up @@ -433,7 +432,7 @@ measurable:
{@link examples.MicrometerMetricsExamples#createPartialSnapshot()}
----

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

[source,$lang]
----
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,11 @@ public static void fromJson(Iterable<java.util.Map.Entry<String, Object>> json,
obj.setMetricsNaming(new io.vertx.micrometer.MetricsNaming((io.vertx.core.json.JsonObject)member.getValue()));
}
break;
case "meterCacheEnabled":
if (member.getValue() instanceof Boolean) {
obj.setMeterCacheEnabled((Boolean)member.getValue());
}
break;
}
}
}
Expand Down Expand Up @@ -129,5 +134,6 @@ public static void toJson(MicrometerMetricsOptions obj, java.util.Map<String, Ob
if (obj.getMetricsNaming() != null) {
json.put("metricsNaming", obj.getMetricsNaming().toJson());
}
json.put("meterCacheEnabled", obj.isMeterCacheEnabled());
}
}
17 changes: 2 additions & 15 deletions src/main/java/examples/MicrometerMetricsExamples.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,7 @@
*/
package examples;

import io.micrometer.core.instrument.Clock;
import io.micrometer.core.instrument.Meter;
import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.Tag;
import io.micrometer.core.instrument.Timer;
import io.micrometer.core.instrument.*;
import io.micrometer.core.instrument.binder.jvm.ClassLoaderMetrics;
import io.micrometer.core.instrument.binder.jvm.JvmGcMetrics;
import io.micrometer.core.instrument.binder.jvm.JvmMemoryMetrics;
Expand All @@ -40,16 +36,7 @@
import io.vertx.core.json.JsonObject;
import io.vertx.docgen.Source;
import io.vertx.ext.web.Router;
import io.vertx.micrometer.Label;
import io.vertx.micrometer.Match;
import io.vertx.micrometer.MetricsDomain;
import io.vertx.micrometer.MetricsNaming;
import io.vertx.micrometer.MetricsService;
import io.vertx.micrometer.MicrometerMetricsOptions;
import io.vertx.micrometer.PrometheusScrapingHandler;
import io.vertx.micrometer.VertxInfluxDbOptions;
import io.vertx.micrometer.VertxJmxMetricsOptions;
import io.vertx.micrometer.VertxPrometheusOptions;
import io.vertx.micrometer.*;
import io.vertx.micrometer.backends.BackendRegistries;

import java.util.Collections;
Expand Down
49 changes: 48 additions & 1 deletion src/main/java/io/vertx/micrometer/MetricsNaming.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2018 Red Hat, Inc. and/or its affiliates
* Copyright 2023 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
Expand Down Expand Up @@ -576,4 +576,51 @@ public MetricsNaming setPoolQueuePending(String poolQueuePending) {
this.poolQueuePending = poolQueuePending;
return this;
}

public MetricsNaming withBaseName(String baseName) {
if (baseName == null || baseName.isEmpty()) {
return new MetricsNaming(this);
}
MetricsNaming copy = new MetricsNaming();
copy.clientQueueTime = baseName + this.clientQueueTime;
copy.clientQueuePending = baseName + this.clientQueuePending;
copy.clientProcessingTime = baseName + this.clientProcessingTime;
copy.clientProcessingPending = baseName + this.clientProcessingPending;
copy.clientResetsCount = baseName + this.clientResetsCount;
copy.datagramBytesRead = baseName + this.datagramBytesRead;
copy.datagramBytesWritten = baseName + this.datagramBytesWritten;
copy.datagramErrorCount = baseName + this.datagramErrorCount;
copy.ebHandlers = baseName + this.ebHandlers;
copy.ebPending = baseName + this.ebPending;
copy.ebProcessed = baseName + this.ebProcessed;
copy.ebPublished = baseName + this.ebPublished;
copy.ebSent = baseName + this.ebSent;
copy.ebReceived = baseName + this.ebReceived;
copy.ebDelivered = baseName + this.ebDelivered;
copy.ebDiscarded = baseName + this.ebDiscarded;
copy.ebReplyFailures = baseName + this.ebReplyFailures;
copy.ebBytesRead = baseName + this.ebBytesRead;
copy.ebBytesWritten = baseName + this.ebBytesWritten;
copy.httpQueueTime = baseName + this.httpQueueTime;
copy.httpQueuePending = baseName + this.httpQueuePending;
copy.httpActiveRequests = baseName + this.httpActiveRequests;
copy.httpRequestsCount = baseName + this.httpRequestsCount;
copy.httpRequestBytes = baseName + this.httpRequestBytes;
copy.httpResponseTime = baseName + this.httpResponseTime;
copy.httpResponsesCount = baseName + this.httpResponsesCount;
copy.httpResponseBytes = baseName + this.httpResponseBytes;
copy.httpActiveWsConnections = baseName + this.httpActiveWsConnections;
copy.httpRequestResetsCount = baseName + this.httpRequestResetsCount;
copy.netActiveConnections = baseName + this.netActiveConnections;
copy.netBytesRead = baseName + this.netBytesRead;
copy.netBytesWritten = baseName + this.netBytesWritten;
copy.netErrorCount = baseName + this.netErrorCount;
copy.poolQueueTime = baseName + this.poolQueueTime;
copy.poolQueuePending = baseName + this.poolQueuePending;
copy.poolUsage = baseName + this.poolUsage;
copy.poolInUse = baseName + this.poolInUse;
copy.poolUsageRatio = baseName + this.poolUsageRatio;
copy.poolCompleted = baseName + this.poolCompleted;
return copy;
}
}
38 changes: 32 additions & 6 deletions src/main/java/io/vertx/micrometer/MicrometerMetricsOptions.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2011-2017 The original author or authors
* Copyright (c) 2011-2023 The original author or authors
* ------------------------------------------------------
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
Expand Down Expand Up @@ -47,7 +47,7 @@ public class MicrometerMetricsOptions extends MetricsOptions {
/**
* Default label match for public http server: exclude remote label
*/
public static final List<Label> DEFAULT_LABELS = Arrays.asList(Label.HTTP_ROUTE, Label.HTTP_METHOD, Label.HTTP_CODE, Label.POOL_TYPE, Label.EB_SIDE);
public static final List<Label> DEFAULT_LABELS = Arrays.asList(Label.HTTP_METHOD, Label.HTTP_CODE, Label.POOL_TYPE, Label.EB_SIDE);

/**
* Whether JVM metrics should be collected by default = false.
Expand All @@ -59,6 +59,11 @@ public class MicrometerMetricsOptions extends MetricsOptions {
*/
public static final MetricsNaming DEFAULT_METRICS_NAMING = MetricsNaming.v4Names();

/**
* Whether a meter cache should be enabled by default = true.
*/
public static final boolean DEFAULT_METER_CACHED_ENABLED = true;

private Set<String> disabledMetricsCategories;
private String registryName;
private Set<Label> labels;
Expand All @@ -71,6 +76,7 @@ public class MicrometerMetricsOptions extends MetricsOptions {
private MetricsNaming metricsNaming;
private Function<HttpRequest, Iterable<Tag>> serverRequestTagsProvider;
private Function<HttpRequest, Iterable<Tag>> clientRequestTagsProvider;
private boolean meterCacheEnabled;

/**
* Creates default options for Micrometer metrics.
Expand All @@ -84,6 +90,7 @@ public MicrometerMetricsOptions() {
metricsNaming = DEFAULT_METRICS_NAMING;
serverRequestTagsProvider = null;
clientRequestTagsProvider = null;
meterCacheEnabled = DEFAULT_METER_CACHED_ENABLED;
}

/**
Expand All @@ -109,6 +116,7 @@ public MicrometerMetricsOptions(MicrometerMetricsOptions other) {
metricsNaming = other.metricsNaming;
serverRequestTagsProvider = other.serverRequestTagsProvider;
clientRequestTagsProvider = other.clientRequestTagsProvider;
meterCacheEnabled = other.meterCacheEnabled;
}

/**
Expand Down Expand Up @@ -208,7 +216,7 @@ public MicrometerMetricsOptions addDisabledMetricsCategory(String category) {

/**
* Is the given metrics category disabled?
* @return true if it is disabled
* @return {@code true} if it is disabled
*/
@GenIgnore
public boolean isMetricsCategoryDisabled(MetricsDomain metricsDomain) {
Expand All @@ -217,7 +225,7 @@ public boolean isMetricsCategoryDisabled(MetricsDomain metricsDomain) {

/**
* Is the given metrics category disabled?
* @return true if it is disabled
* @return {@code true} if it is disabled
*/
@GenIgnore
public boolean isMetricsCategoryDisabled(String category) {
Expand Down Expand Up @@ -388,7 +396,7 @@ public MicrometerMetricsOptions setJmxMetricsOptions(VertxJmxMetricsOptions jmxM
}

/**
* @return true if JVM metrics should be collected, false otherwise
* @return {@code true} if JVM metrics should be collected, {@code false} otherwise
*/
public boolean isJvmMetricsEnabled() {
return jvmMetricsEnabled;
Expand All @@ -397,7 +405,7 @@ public boolean isJvmMetricsEnabled() {
/**
* Whether JVM metrics should be collected. Defaults to {@code false}.
*
* @param jvmMetricsEnabled true to collect JVM metrics, false otherwise. Defaults to {@code false}.
* @param jvmMetricsEnabled {@code true} to collect JVM metrics, {@code false} otherwise. Defaults to {@code false}.
* @return a reference to this, so the API can be used fluently
*/
public MicrometerMetricsOptions setJvmMetricsEnabled(boolean jvmMetricsEnabled) {
Expand Down Expand Up @@ -487,4 +495,22 @@ public MicrometerMetricsOptions setClientRequestTagsProvider(Function<HttpReques
this.clientRequestTagsProvider = clientRequestTagsProvider;
return this;
}

/**
* @return {@code true} if a meter cache should be enabled, {@code false} otherwise
*/
public boolean isMeterCacheEnabled() {
return meterCacheEnabled;
}

/**
* Whether a meter cache should be enabled. Defaults to {@code true}.
*
* @param meterCacheEnabled {@code true} to enable a meter cache, {@code false} otherwise. Defaults to {@code true}.
* @return a reference to this, so the API can be used fluently
*/
public MicrometerMetricsOptions setMeterCacheEnabled(boolean meterCacheEnabled) {
this.meterCacheEnabled = meterCacheEnabled;
return this;
}
}
42 changes: 4 additions & 38 deletions src/main/java/io/vertx/micrometer/backends/BackendRegistries.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2018 Red Hat, Inc. and/or its affiliates
* Copyright 2023 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
Expand All @@ -18,27 +18,16 @@

import io.micrometer.core.instrument.Meter;
import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.Tag;
import io.micrometer.core.instrument.config.MeterFilter;
import io.micrometer.prometheus.PrometheusMeterRegistry;
import io.vertx.micrometer.Label;
import io.vertx.micrometer.Match;
import io.vertx.micrometer.MetricsDomain;
import io.vertx.micrometer.MicrometerMetricsOptions;
import io.vertx.micrometer.VertxInfluxDbOptions;
import io.vertx.micrometer.VertxPrometheusOptions;
import io.vertx.micrometer.*;

import java.util.ArrayList;
import java.util.EnumSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.regex.Pattern;

import static java.util.stream.Collectors.*;

/**
* {@link BackendRegistries} is responsible for managing registries related to particular micrometer backends (influxdb, prometheus...)
* It contains a store of {@link BackendRegistry} objects, each of whose encapsulating a micrometer's {@link MeterRegistry}
Expand Down Expand Up @@ -79,7 +68,7 @@ public static BackendRegistry setupBackend(MicrometerMetricsOptions options) {
// No backend setup, use global registry
reg = NoopBackendRegistry.INSTANCE;
}
registerMatchers(reg.getMeterRegistry(), options.getLabels(), options.getLabelMatches());
registerMatchers(reg.getMeterRegistry(), options.getLabelMatches());
return reg;
});
}
Expand Down Expand Up @@ -119,13 +108,7 @@ public static void stop(String registryName) {
}
}

public static void registerMatchers(MeterRegistry registry, Set<Label> enabledLabels, List<Match> matches) {
Set<String> ignored = EnumSet.complementOf(EnumSet.copyOf(enabledLabels)).stream()
.map(Label::toString)
.collect(toSet());
if (!ignored.isEmpty()) {
registry.config().meterFilter(ignoreTags(ignored));
}
public static void registerMatchers(MeterRegistry registry, List<Match> matches) {
matches.forEach(m -> {
switch (m.getType()) {
case EQUALS:
Expand Down Expand Up @@ -186,23 +169,6 @@ public static void registerMatchers(MeterRegistry registry, Set<Label> enabledLa
});
}

private static MeterFilter ignoreTags(Set<String> ignored) {
return new MeterFilter() {
@Override
public Meter.Id map(Meter.Id id) {
List<Tag> tags = new ArrayList<>();
int count = 0;
for (Tag tag : id.getTagsAsIterable()) {
if (!ignored.contains(tag.getKey())) {
tags.add(tag);
}
count++;
}
return tags.size() == count ? id : id.replaceTags(tags);
}
};
}

private static MeterFilter replaceTagValues(MetricsDomain domain, String tagKey, Function<String, String> replacement) {
return new MeterFilter() {
@Override
Expand Down
Loading

0 comments on commit 28f3fe5

Please sign in to comment.