Skip to content

Commit

Permalink
Implement custom tags provider for HTTP metrics
Browse files Browse the repository at this point in the history
- Allows to implement a custom tags provider (Function: request -> Tags) to provide tags out
of HttpRequest objects.
- Add tests

Fixes vert-x3#89

Signed-off-by: Joel Takvorian <[email protected]>
  • Loading branch information
jotak committed Jul 12, 2021
1 parent 9263339 commit 9e842ac
Show file tree
Hide file tree
Showing 13 changed files with 277 additions and 18 deletions.
25 changes: 25 additions & 0 deletions src/main/java/io/vertx/micrometer/MicrometerMetricsOptions.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,17 @@
package io.vertx.micrometer;

import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.Tag;
import io.vertx.codegen.annotations.DataObject;
import io.vertx.codegen.annotations.GenIgnore;
import io.vertx.core.json.JsonArray;
import io.vertx.core.json.JsonObject;
import io.vertx.core.metrics.MetricsOptions;
import io.vertx.core.spi.VertxMetricsFactory;
import io.vertx.core.spi.observability.HttpRequest;

import java.util.*;
import java.util.function.Function;

/**
* Vert.x micrometer configuration.
Expand Down Expand Up @@ -66,6 +69,8 @@ public class MicrometerMetricsOptions extends MetricsOptions {
private VertxJmxMetricsOptions jmxMetricsOptions;
private boolean jvmMetricsEnabled;
private MetricsNaming metricsNaming;
@GenIgnore
private Function<HttpRequest, Iterable<Tag>> requestsTagsProvider;

/**
* Creates default options for Micrometer metrics.
Expand All @@ -77,6 +82,7 @@ public MicrometerMetricsOptions() {
labelMatches = new ArrayList<>();
jvmMetricsEnabled = DEFAULT_JVM_METRICS_ENABLED;
metricsNaming = DEFAULT_METRICS_NAMING;
requestsTagsProvider = null;
}

/**
Expand All @@ -100,6 +106,7 @@ public MicrometerMetricsOptions(MicrometerMetricsOptions other) {
}
jvmMetricsEnabled = other.jvmMetricsEnabled;
metricsNaming = other.metricsNaming;
requestsTagsProvider = other.requestsTagsProvider;
}

/**
Expand Down Expand Up @@ -415,4 +422,22 @@ public MicrometerMetricsOptions setMetricsNaming(MetricsNaming metricsNaming) {
this.metricsNaming = metricsNaming;
return this;
}

/**
* @return an optional custom tags provider for HTTP requests
*/
public Function<HttpRequest, Iterable<Tag>> getRequestsTagsProvider() {
return requestsTagsProvider;
}

/**
* Sets a custom tags provider for HTTP requests. Allows to generate custom tags for every {@code HttpRequest} object processed through the metrics SPI.
*
* @param requestsTagsProvider an object implementing the {@code CustomTagsProvider} interface for {@code HttpRequest}.
* @return a reference to this, so that the API can be used fluently
*/
public MicrometerMetricsOptions setRequestsTagsProvider(Function<HttpRequest, Iterable<Tag>> requestsTagsProvider) {
this.requestsTagsProvider = requestsTagsProvider;
return this;
}
}
28 changes: 18 additions & 10 deletions src/main/java/io/vertx/micrometer/impl/VertxHttpServerMetrics.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
package io.vertx.micrometer.impl;

import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.Tag;
import io.vertx.core.http.HttpMethod;
import io.vertx.core.http.ServerWebSocket;
import io.vertx.core.net.SocketAddress;
Expand All @@ -34,6 +35,7 @@
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.atomic.LongAdder;
import java.util.function.Function;

/**
* @author Joel Takvorian
Expand All @@ -46,9 +48,11 @@ class VertxHttpServerMetrics extends VertxNetServerMetrics {
private final Timers processingTime;
private final Summaries responseBytes;
private final Gauges<LongAdder> wsConnections;
private final Function<HttpRequest, Iterable<Tag>> customTagsProvider;

VertxHttpServerMetrics(MeterRegistry registry, MetricsNaming names) {
VertxHttpServerMetrics(MeterRegistry registry, MetricsNaming names, Function<HttpRequest, Iterable<Tag>> customTagsProvider) {
super(registry, MetricsDomain.HTTP_SERVER, names);
this.customTagsProvider = customTagsProvider;
requests = longGauges(names.getHttpActiveRequests(), "Number of requests being processed", Label.LOCAL, Label.REMOTE, Label.HTTP_PATH, Label.HTTP_METHOD);
requestCount = counters(names.getHttpRequestsCount(), "Number of processed requests", Label.LOCAL, Label.REMOTE, Label.HTTP_ROUTE, Label.HTTP_PATH, Label.HTTP_METHOD, Label.HTTP_CODE);
requestResetCount = counters(names.getHttpRequestResetsCount(), "Number of request resets", Label.LOCAL, Label.REMOTE, Label.HTTP_PATH, Label.HTTP_METHOD);
Expand All @@ -71,26 +75,29 @@ class Instance extends VertxNetServerMetrics.Instance implements HttpServerMetri
@Override
public Handler requestBegin(String remote, HttpRequest request) {
Handler handler = new Handler(remote, request.uri(), request.method().name());
requests.get(local, remote, handler.path, handler.method).increment();
if (customTagsProvider != null) {
handler.customTags = customTagsProvider.apply(request);
}
requests.get(handler.customTags, local, remote, handler.path, handler.method).increment();
handler.timer = processingTime.start();
return handler;
}

@Override
public void requestReset(Handler handler) {
requestResetCount.get(local, handler.address, handler.path, handler.method).increment();
requests.get(local, handler.address, handler.path, handler.method).decrement();
requestResetCount.get(handler.customTags, local, handler.address, handler.path, handler.method).increment();
requests.get(handler.customTags, local, handler.address, handler.path, handler.method).decrement();
}

@Override
public void requestEnd(Handler handler, HttpRequest request, long bytesRead) {
requestBytes.get(local, handler.address, handler.path, handler.method).record(bytesRead);
requestBytes.get(handler.customTags, local, handler.address, handler.path, handler.method).record(bytesRead);
}

@Override
public Handler responsePushed(String remote, HttpMethod method, String uri, HttpResponse response) {
Handler handler = new Handler(remote, uri, method.name());
requests.get(local, remote, handler.path, handler.method).increment();
requests.get(handler.customTags, local, remote, handler.path, handler.method).increment();
return handler;
}

Expand All @@ -102,10 +109,10 @@ public void responseBegin(Handler handler, HttpResponse response) {
public void responseEnd(Handler handler, HttpResponse response, long bytesWritten) {
String code = String.valueOf(response.statusCode());
String handlerRoute = handler.getRoute();
handler.timer.end(local, handler.address, handlerRoute, handler.path, handler.method, code);
requestCount.get(local, handler.address, handlerRoute, handler.path, handler.method, code).increment();
requests.get(local, handler.address, handler.path, handler.method).decrement();
responseBytes.get(local, handler.address, handlerRoute, handler.path, handler.method, code).record(bytesWritten);
handler.timer.end(handler.customTags, local, handler.address, handlerRoute, handler.path, handler.method, code);
requestCount.get(handler.customTags, local, handler.address, handlerRoute, handler.path, handler.method, code).increment();
requests.get(handler.customTags, local, handler.address, handler.path, handler.method).decrement();
responseBytes.get(handler.customTags, local, handler.address, handlerRoute, handler.path, handler.method, code).record(bytesWritten);
}

@Override
Expand Down Expand Up @@ -138,6 +145,7 @@ public static class Handler {
// tracks length of resulting routes string
private int routesLength;
private Timers.EventTiming timer;
private Iterable<Tag> customTags;

Handler(String address, String path, String method) {
this.address = address;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ public VertxMetricsImpl(MicrometerMetricsOptions options, BackendRegistry backen
httpClientMetrics = options.isMetricsCategoryDisabled(HTTP_CLIENT) ? null
: new VertxHttpClientMetrics(registry, names);
httpServerMetrics = options.isMetricsCategoryDisabled(HTTP_SERVER) ? null
: new VertxHttpServerMetrics(registry, names);
: new VertxHttpServerMetrics(registry, names, options.getRequestsTagsProvider());
poolMetrics = options.isMetricsCategoryDisabled(NAMED_POOLS) ? null
: new VertxPoolMetrics(registry, names);
}
Expand Down
15 changes: 14 additions & 1 deletion src/main/java/io/vertx/micrometer/impl/meters/Counters.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,15 @@

import io.micrometer.core.instrument.Counter;
import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.Tag;
import io.vertx.micrometer.Label;
import io.vertx.micrometer.impl.Labels;

import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;

/**
* @author Joel Takvorian
*/
Expand All @@ -41,10 +47,17 @@ public Counters(String name,
}

public Counter get(String... values) {
return get(null, values);
}

public Counter get(Iterable<Tag> customTags, String... values) {
List<Tag> tags = customTags != null
? Stream.concat(Labels.toTags(keys, values).stream(), StreamSupport.stream(customTags.spliterator(), false)).collect(Collectors.toList())
: Labels.toTags(keys, values);
// Get or create the Counter
return Counter.builder(name)
.description(description)
.tags(Labels.toTags(keys, values))
.tags(tags)
.register(registry);
}
}
16 changes: 14 additions & 2 deletions src/main/java/io/vertx/micrometer/impl/meters/Gauges.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,18 @@
import io.micrometer.core.instrument.Gauge;
import io.micrometer.core.instrument.Meter;
import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.Tag;
import io.vertx.micrometer.Label;
import io.vertx.micrometer.impl.Labels;

import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Supplier;
import java.util.function.ToDoubleFunction;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;

/**
* @author Joel Takvorian
Expand Down Expand Up @@ -53,7 +58,14 @@ public Gauges(String name,
this.keys = keys;
}

public synchronized T get(String... values) {
public T get(String... values) {
return get(null, values);
}

public synchronized T get(Iterable<Tag> customTags, String... values) {
List<Tag> tags = customTags != null
? Stream.concat(Labels.toTags(keys, values).stream(), StreamSupport.stream(customTags.spliterator(), false)).collect(Collectors.toList())
: Labels.toTags(keys, values);
// This method is synchronized to make sure the "T" built via supplier will match the one passed to Gauge
// since it is stored as WeakReference in Micrometer DefaultGauge, it must not be lost.
T t = tSupplier.get();
Expand All @@ -63,7 +75,7 @@ public synchronized T get(String... values) {
// Micrometer will not register the gauge twice if it was already created.
Gauge g = Gauge.builder(name, t, dGetter)
.description(description)
.tags(Labels.toTags(keys, values))
.tags(tags)
.register(registry);
return gauges.computeIfAbsent(g.getId(), v -> t);
}
Expand Down
15 changes: 14 additions & 1 deletion src/main/java/io/vertx/micrometer/impl/meters/Summaries.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,15 @@

import io.micrometer.core.instrument.DistributionSummary;
import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.Tag;
import io.vertx.micrometer.Label;
import io.vertx.micrometer.impl.Labels;

import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;

/**
* @author Joel Takvorian
*/
Expand All @@ -41,10 +47,17 @@ public Summaries(String name,
}

public DistributionSummary get(String... values) {
return get(null, values);
}

public DistributionSummary get(Iterable<Tag> customTags, String... values) {
List<Tag> tags = customTags != null
? Stream.concat(Labels.toTags(keys, values).stream(), StreamSupport.stream(customTags.spliterator(), false)).collect(Collectors.toList())
: Labels.toTags(keys, values);
// Get or create the Summary
return DistributionSummary.builder(name)
.description(description)
.tags(Labels.toTags(keys, values))
.tags(tags)
.register(registry);
}
}
20 changes: 18 additions & 2 deletions src/main/java/io/vertx/micrometer/impl/meters/Timers.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,16 @@
package io.vertx.micrometer.impl.meters;

import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.Tag;
import io.micrometer.core.instrument.Timer;
import io.vertx.micrometer.Label;
import io.vertx.micrometer.impl.Labels;

import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;

/**
* @author Joel Takvorian
Expand All @@ -43,10 +48,17 @@ public Timers(String name,
}

public Timer get(String... values) {
return get(null, values);
}

public Timer get(Iterable<Tag> customTags, String... values) {
List<Tag> tags = customTags != null
? Stream.concat(Labels.toTags(keys, values).stream(), StreamSupport.stream(customTags.spliterator(), false)).collect(Collectors.toList())
: Labels.toTags(keys, values);
// Get or create the Timer
return Timer.builder(name)
.description(description)
.tags(Labels.toTags(keys, values))
.tags(tags)
.register(registry);
}

Expand All @@ -64,7 +76,11 @@ private EventTiming(Timers ref) {
}

public void end(String... values) {
Timer t = ref.get(values);
end(null, values);
}

public void end(Iterable<Tag> customTags, String... values) {
Timer t = ref.get(customTags, values);
t.record(System.nanoTime() - nanoStart, TimeUnit.NANOSECONDS);
}
}
Expand Down
Loading

0 comments on commit 9e842ac

Please sign in to comment.