From 176741713b172d7bf08343e8837d1cb129961c2b Mon Sep 17 00:00:00 2001 From: "Marvin B. Lillehaug" Date: Wed, 8 Nov 2023 13:35:40 +0100 Subject: [PATCH] Support Micrometer @MeterTag --- .../main/asciidoc/telemetry-micrometer.adoc | 55 ++++++++- .../deployment/MicrometerProcessor.java | 3 + .../MicrometerCounterInterceptorTest.java | 6 + .../micrometer/test/CountedResource.java | 5 +- .../micrometer/test/TestValueResolver.java | 13 +++ .../micrometer/runtime/MeterTagsSupport.java | 105 ++++++++++++++++++ .../runtime/MicrometerCountedInterceptor.java | 22 ++-- .../runtime/MicrometerTimedInterceptor.java | 12 +- .../prometheus/AnnotatedResource.java | 9 +- .../AnswerToEverythingExpressionResolver.java | 14 +++ .../prometheus/PrefixingValueResolver.java | 13 +++ .../PrometheusMetricsRegistryTest.java | 32 +++--- 12 files changed, 247 insertions(+), 42 deletions(-) create mode 100644 extensions/micrometer/deployment/src/test/java/io/quarkus/micrometer/test/TestValueResolver.java create mode 100644 extensions/micrometer/runtime/src/main/java/io/quarkus/micrometer/runtime/MeterTagsSupport.java create mode 100644 integration-tests/micrometer-prometheus/src/main/java/io/quarkus/it/micrometer/prometheus/AnswerToEverythingExpressionResolver.java create mode 100644 integration-tests/micrometer-prometheus/src/main/java/io/quarkus/it/micrometer/prometheus/PrefixingValueResolver.java diff --git a/docs/src/main/asciidoc/telemetry-micrometer.adoc b/docs/src/main/asciidoc/telemetry-micrometer.adoc index 2c753d8013993..146df14de7d24 100644 --- a/docs/src/main/asciidoc/telemetry-micrometer.adoc +++ b/docs/src/main/asciidoc/telemetry-micrometer.adoc @@ -603,8 +603,59 @@ The `@Timed` annotation will wrap the execution of a method and will emit the fo 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). -Using annotations is limited, as you can't dynamically assign meaningful tag values. -Also note that many methods, e.g. REST endpoint methods or Vert.x Routes, are counted and timed by the micrometer extension out of the box. +Parameters to `@Counted` and `@Timed` can be annotated with `@MeterTag` to dynamically assign meaningful tag values. + +`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` 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. + +[source,java] +---- +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) { ... } +---- + +IMPORTANT: 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. + +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 diff --git a/extensions/micrometer/deployment/src/main/java/io/quarkus/micrometer/deployment/MicrometerProcessor.java b/extensions/micrometer/deployment/src/main/java/io/quarkus/micrometer/deployment/MicrometerProcessor.java index 256f6fbd6a624..d1f95bd0bd34d 100644 --- a/extensions/micrometer/deployment/src/main/java/io/quarkus/micrometer/deployment/MicrometerProcessor.java +++ b/extensions/micrometer/deployment/src/main/java/io/quarkus/micrometer/deployment/MicrometerProcessor.java @@ -51,6 +51,7 @@ import io.quarkus.micrometer.runtime.MeterRegistryCustomizer; import io.quarkus.micrometer.runtime.MeterRegistryCustomizerConstraint; import io.quarkus.micrometer.runtime.MeterRegistryCustomizerConstraints; +import io.quarkus.micrometer.runtime.MeterTagsSupport; import io.quarkus.micrometer.runtime.MicrometerCounted; import io.quarkus.micrometer.runtime.MicrometerCountedInterceptor; import io.quarkus.micrometer.runtime.MicrometerRecorder; @@ -73,6 +74,7 @@ public class MicrometerProcessor { private static final DotName COUNTED_INTERCEPTOR = DotName.createSimple(MicrometerCountedInterceptor.class.getName()); private static final DotName TIMED_ANNOTATION = DotName.createSimple(Timed.class.getName()); private static final DotName TIMED_INTERCEPTOR = DotName.createSimple(MicrometerTimedInterceptor.class.getName()); + private static final DotName METER_TAG_SUPPORT = DotName.createSimple(MeterTagsSupport.class.getName()); public static class MicrometerEnabled implements BooleanSupplier { MicrometerConfig mConfig; @@ -123,6 +125,7 @@ UnremovableBeanBuildItem registerAdditionalBeans(CombinedIndexBuildItem indexBui .addBeanClass(COUNTED_ANNOTATION.toString()) .addBeanClass(COUNTED_BINDING.toString()) .addBeanClass(COUNTED_INTERCEPTOR.toString()) + .addBeanClass(METER_TAG_SUPPORT.toString()) .build()); // @Timed is registered as an additional interceptor binding diff --git a/extensions/micrometer/deployment/src/test/java/io/quarkus/micrometer/runtime/MicrometerCounterInterceptorTest.java b/extensions/micrometer/deployment/src/test/java/io/quarkus/micrometer/runtime/MicrometerCounterInterceptorTest.java index 7364893851673..1e2cb176cc451 100644 --- a/extensions/micrometer/deployment/src/test/java/io/quarkus/micrometer/runtime/MicrometerCounterInterceptorTest.java +++ b/extensions/micrometer/deployment/src/test/java/io/quarkus/micrometer/runtime/MicrometerCounterInterceptorTest.java @@ -16,6 +16,7 @@ import io.micrometer.core.instrument.simple.SimpleMeterRegistry; import io.quarkus.micrometer.test.CountedResource; import io.quarkus.micrometer.test.GuardedResult; +import io.quarkus.micrometer.test.TestValueResolver; import io.quarkus.micrometer.test.TimedResource; import io.quarkus.test.QuarkusUnitTest; import io.smallrye.mutiny.Uni; @@ -30,6 +31,7 @@ public class MicrometerCounterInterceptorTest { .overrideConfigKey("quarkus.micrometer.registry-enabled-default", "false") .overrideConfigKey("quarkus.redis.devservices.enabled", "false") .withApplicationRoot((jar) -> jar + .addClass(TestValueResolver.class) .addClass(CountedResource.class) .addClass(TimedResource.class) .addClass(GuardedResult.class)); @@ -58,6 +60,7 @@ void testCountAllMetrics_MetricsOnSuccess() { .tag("method", "countAllInvocations") .tag("class", "io.quarkus.micrometer.test.CountedResource") .tag("extra", "tag") + .tag("do_fail", "prefix_false") .tag("exception", "none") .tag("result", "success").counter(); Assertions.assertNotNull(counter); @@ -71,6 +74,7 @@ void testCountAllMetrics_MetricsOnFailure() { .tag("method", "countAllInvocations") .tag("class", "io.quarkus.micrometer.test.CountedResource") .tag("extra", "tag") + .tag("do_fail", "prefix_true") .tag("exception", "NullPointerException") .tag("result", "failure").counter(); Assertions.assertNotNull(counter); @@ -85,6 +89,7 @@ void testCountEmptyMetricName_Success() { .tag("method", "emptyMetricName") .tag("class", "io.quarkus.micrometer.test.CountedResource") .tag("exception", "none") + .tag("fail", "false") .tag("result", "success").counter(); Assertions.assertNotNull(counter); Assertions.assertEquals(1, counter.count()); @@ -98,6 +103,7 @@ void testCountEmptyMetricName_Failure() { .tag("method", "emptyMetricName") .tag("class", "io.quarkus.micrometer.test.CountedResource") .tag("exception", "NullPointerException") + .tag("fail", "true") .tag("result", "failure").counter(); Assertions.assertNotNull(counter); Assertions.assertEquals(1, counter.count()); diff --git a/extensions/micrometer/deployment/src/test/java/io/quarkus/micrometer/test/CountedResource.java b/extensions/micrometer/deployment/src/test/java/io/quarkus/micrometer/test/CountedResource.java index add85789e2b3b..ddc7a1078aaf1 100644 --- a/extensions/micrometer/deployment/src/test/java/io/quarkus/micrometer/test/CountedResource.java +++ b/extensions/micrometer/deployment/src/test/java/io/quarkus/micrometer/test/CountedResource.java @@ -7,6 +7,7 @@ import jakarta.enterprise.context.ApplicationScoped; import io.micrometer.core.annotation.Counted; +import io.micrometer.core.aop.MeterTag; import io.smallrye.mutiny.Uni; @ApplicationScoped @@ -16,14 +17,14 @@ public void onlyCountFailures() { } @Counted(value = "metric.all", extraTags = { "extra", "tag" }) - public void countAllInvocations(boolean fail) { + public void countAllInvocations(@MeterTag(key = "do_fail", resolver = TestValueResolver.class) boolean fail) { if (fail) { throw new NullPointerException("Failed on purpose"); } } @Counted(description = "nice description") - public void emptyMetricName(boolean fail) { + public void emptyMetricName(@MeterTag boolean fail) { if (fail) { throw new NullPointerException("Failed on purpose"); } diff --git a/extensions/micrometer/deployment/src/test/java/io/quarkus/micrometer/test/TestValueResolver.java b/extensions/micrometer/deployment/src/test/java/io/quarkus/micrometer/test/TestValueResolver.java new file mode 100644 index 0000000000000..aace9841984a7 --- /dev/null +++ b/extensions/micrometer/deployment/src/test/java/io/quarkus/micrometer/test/TestValueResolver.java @@ -0,0 +1,13 @@ +package io.quarkus.micrometer.test; + +import jakarta.inject.Singleton; + +import io.micrometer.common.annotation.ValueResolver; + +@Singleton +public class TestValueResolver implements ValueResolver { + @Override + public String resolve(Object parameter) { + return "prefix_" + parameter; + } +} diff --git a/extensions/micrometer/runtime/src/main/java/io/quarkus/micrometer/runtime/MeterTagsSupport.java b/extensions/micrometer/runtime/src/main/java/io/quarkus/micrometer/runtime/MeterTagsSupport.java new file mode 100644 index 0000000000000..14399c6f536e2 --- /dev/null +++ b/extensions/micrometer/runtime/src/main/java/io/quarkus/micrometer/runtime/MeterTagsSupport.java @@ -0,0 +1,105 @@ +package io.quarkus.micrometer.runtime; + +import java.lang.reflect.Method; +import java.lang.reflect.Parameter; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import jakarta.enterprise.inject.Instance; +import jakarta.inject.Singleton; + +import io.micrometer.common.annotation.NoOpValueResolver; +import io.micrometer.common.annotation.ValueExpressionResolver; +import io.micrometer.common.annotation.ValueResolver; +import io.micrometer.common.util.StringUtils; +import io.micrometer.core.aop.MeterTag; +import io.micrometer.core.instrument.Tag; +import io.micrometer.core.instrument.Tags; +import io.quarkus.arc.All; +import io.quarkus.arc.ArcInvocationContext; +import io.quarkus.arc.ClientProxy; + +@Singleton +public class MeterTagsSupport { + private final Map, ValueResolver> valueResolvers; + private final ValueExpressionResolver valueExpressionResolver; + + public MeterTagsSupport(@All List valueResolvers, + Instance valueExpressionResolver) { + this.valueResolvers = createValueResolverMap(valueResolvers); + this.valueExpressionResolver = valueExpressionResolver.isUnsatisfied() ? null : valueExpressionResolver.get(); + } + + Tags getTags(ArcInvocationContext context) { + return getCommonTags(context) + .and(getMeterTags(context)); + } + + private Tags getMeterTags(ArcInvocationContext context) { + List tags = new ArrayList<>(); + Method method = context.getMethod(); + Parameter[] parameters = method.getParameters(); + for (int i = 0; i < parameters.length; i++) { + Parameter methodParameter = parameters[i]; + MeterTag annotation = methodParameter.getAnnotation(MeterTag.class); + if (annotation != null) { + Object parameterValue = context.getParameters()[i]; + + tags.add(Tag.of( + resolveTagKey(annotation, methodParameter.getName()), + resolveTagValue(annotation, parameterValue))); + } + } + return Tags.of(tags); + } + + private static Tags getCommonTags(ArcInvocationContext context) { + Method method = context.getMethod(); + String className = method.getDeclaringClass().getName(); + String methodName = method.getName(); + return Tags.of("class", className, "method", methodName); + } + + /* + * Precedence copied from MeterTagAnnotationHandler + */ + private String resolveTagValue(MeterTag annotation, Object parameterValue) { + if (annotation.resolver() != NoOpValueResolver.class) { + ValueResolver valueResolver = valueResolvers.get(annotation.resolver()); + return valueResolver.resolve(parameterValue); + } else if (StringUtils.isNotBlank(annotation.expression())) { + if (valueExpressionResolver == null) { + throw new IllegalArgumentException("No valueExpressionResolver is defined"); + } + return valueExpressionResolver.resolve(annotation.expression(), parameterValue); + } else if (parameterValue != null) { + return parameterValue.toString(); + } else { + return ""; + } + } + + /* + * Precedence copied from MeterTagAnnotationHandler + */ + private static String resolveTagKey(MeterTag annotation, String parameterName) { + if (StringUtils.isNotBlank(annotation.value())) { + return annotation.value(); + } else if (StringUtils.isNotBlank(annotation.key())) { + return annotation.key(); + } else { + return parameterName; + } + } + + private static Map, ValueResolver> createValueResolverMap(List valueResolvers) { + Map, ValueResolver> valueResolverMap = new HashMap<>(); + for (ValueResolver valueResolver : valueResolvers) { + ValueResolver instance = ClientProxy.unwrap(valueResolver); + valueResolverMap.put(instance.getClass(), valueResolver); + } + return valueResolverMap; + } +} diff --git a/extensions/micrometer/runtime/src/main/java/io/quarkus/micrometer/runtime/MicrometerCountedInterceptor.java b/extensions/micrometer/runtime/src/main/java/io/quarkus/micrometer/runtime/MicrometerCountedInterceptor.java index 152a36486b456..4b2230d53cf0b 100644 --- a/extensions/micrometer/runtime/src/main/java/io/quarkus/micrometer/runtime/MicrometerCountedInterceptor.java +++ b/extensions/micrometer/runtime/src/main/java/io/quarkus/micrometer/runtime/MicrometerCountedInterceptor.java @@ -32,9 +32,11 @@ public class MicrometerCountedInterceptor { public final String RESULT_TAG_SUCCESS_VALUE = "success"; private final MeterRegistry meterRegistry; + private final MeterTagsSupport meterTagsSupport; - public MicrometerCountedInterceptor(MeterRegistry meterRegistry) { + public MicrometerCountedInterceptor(MeterRegistry meterRegistry, MeterTagsSupport meterTagsSupport) { this.meterRegistry = meterRegistry; + this.meterTagsSupport = meterTagsSupport; } /** @@ -61,7 +63,7 @@ Object countedMethod(ArcInvocationContext context) throws Exception { return context.proceed(); } Method method = context.getMethod(); - Tags commonTags = getCommonTags(method.getDeclaringClass().getName(), method.getName()); + Tags tags = meterTagsSupport.getTags(context); Class returnType = method.getReturnType(); if (TypesUtil.isCompletionStage(returnType)) { @@ -69,11 +71,11 @@ Object countedMethod(ArcInvocationContext context) throws Exception { return ((CompletionStage) context.proceed()).whenComplete(new BiConsumer() { @Override public void accept(Object o, Throwable throwable) { - recordCompletionResult(counted, commonTags, throwable); + recordCompletionResult(counted, tags, throwable); } }); } catch (Throwable e) { - record(counted, commonTags, e); + record(counted, tags, e); } } else if (TypesUtil.isUni(returnType)) { try { @@ -81,22 +83,22 @@ public void accept(Object o, Throwable throwable) { new Functions.TriConsumer<>() { @Override public void accept(Object o, Throwable throwable, Boolean cancelled) { - recordCompletionResult(counted, commonTags, throwable); + recordCompletionResult(counted, tags, throwable); } }); } catch (Throwable e) { - record(counted, commonTags, e); + record(counted, tags, e); } } try { Object result = context.proceed(); if (!counted.recordFailuresOnly()) { - record(counted, commonTags, null); + record(counted, tags, null); } return result; } catch (Throwable e) { - record(counted, commonTags, e); + record(counted, tags, e); throw e; } } @@ -122,8 +124,4 @@ private void record(MicrometerCounted counted, Tags commonTags, Throwable throwa builder.register(meterRegistry).increment(); } - private Tags getCommonTags(String className, String methodName) { - return Tags.of("class", className, "method", methodName); - } - } diff --git a/extensions/micrometer/runtime/src/main/java/io/quarkus/micrometer/runtime/MicrometerTimedInterceptor.java b/extensions/micrometer/runtime/src/main/java/io/quarkus/micrometer/runtime/MicrometerTimedInterceptor.java index 7d6ff73b77260..76415a669883e 100644 --- a/extensions/micrometer/runtime/src/main/java/io/quarkus/micrometer/runtime/MicrometerTimedInterceptor.java +++ b/extensions/micrometer/runtime/src/main/java/io/quarkus/micrometer/runtime/MicrometerTimedInterceptor.java @@ -1,6 +1,5 @@ package io.quarkus.micrometer.runtime; -import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -33,9 +32,11 @@ public class MicrometerTimedInterceptor { public static final String DEFAULT_METRIC_NAME = "method.timed"; private final MeterRegistry meterRegistry; + private final MeterTagsSupport meterTagsSupport; - public MicrometerTimedInterceptor(MeterRegistry meterRegistry) { + public MicrometerTimedInterceptor(MeterRegistry meterRegistry, MeterTagsSupport meterTagsSupport) { this.meterRegistry = meterRegistry; + this.meterTagsSupport = meterTagsSupport; } @AroundInvoke @@ -85,18 +86,17 @@ public void accept(Object o, Throwable throwable, Boolean cancelled) { } private List getSamples(ArcInvocationContext context) { - Method method = context.getMethod(); - Tags commonTags = getCommonTags(method.getDeclaringClass().getName(), method.getName()); List timed = context.findIterceptorBindings(Timed.class); if (timed.isEmpty()) { return Collections.emptyList(); } + Tags tags = meterTagsSupport.getTags(context); List samples = new ArrayList<>(timed.size()); for (Timed t : timed) { if (t.longTask()) { - samples.add(new LongTimerSample(t, commonTags)); + samples.add(new LongTimerSample(t, tags)); } else { - samples.add(new TimerSample(t, commonTags)); + samples.add(new TimerSample(t, tags)); } } return samples; diff --git a/integration-tests/micrometer-prometheus/src/main/java/io/quarkus/it/micrometer/prometheus/AnnotatedResource.java b/integration-tests/micrometer-prometheus/src/main/java/io/quarkus/it/micrometer/prometheus/AnnotatedResource.java index 5d9d67c2eaef8..35badea2479c5 100644 --- a/integration-tests/micrometer-prometheus/src/main/java/io/quarkus/it/micrometer/prometheus/AnnotatedResource.java +++ b/integration-tests/micrometer-prometheus/src/main/java/io/quarkus/it/micrometer/prometheus/AnnotatedResource.java @@ -12,6 +12,7 @@ import io.micrometer.core.annotation.Counted; import io.micrometer.core.annotation.Timed; +import io.micrometer.core.aop.MeterTag; @Path("/all-the-things") public class AnnotatedResource { @@ -74,12 +75,12 @@ public Object onlyCountFailures() { } @Counted(value = "metric.all", extraTags = { "extra", "tag" }) - public Object countAllInvocations(boolean fail) { + public Object countAllInvocations(@MeterTag boolean fail) { return new Response(fail).get(); } @Counted(description = "nice description") - public Object emptyMetricName(boolean fail) { + public Object emptyMetricName(@MeterTag(resolver = PrefixingValueResolver.class) boolean fail) { return new Response(fail).get(); } @@ -89,12 +90,12 @@ public CompletableFuture onlyCountAsyncFailures() { } @Counted(value = "async.all", extraTags = { "extra", "tag" }) - public CompletableFuture countAllAsyncInvocations(boolean fail) { + public CompletableFuture countAllAsyncInvocations(@MeterTag(key = "do_fail_call") boolean fail) { return CompletableFuture.supplyAsync(new Response(fail)); } @Counted - public CompletableFuture emptyAsyncMetricName(boolean fail) { + public CompletableFuture emptyAsyncMetricName(@MeterTag(expression = "expression") boolean fail) { return CompletableFuture.supplyAsync(new Response(fail)); } diff --git a/integration-tests/micrometer-prometheus/src/main/java/io/quarkus/it/micrometer/prometheus/AnswerToEverythingExpressionResolver.java b/integration-tests/micrometer-prometheus/src/main/java/io/quarkus/it/micrometer/prometheus/AnswerToEverythingExpressionResolver.java new file mode 100644 index 0000000000000..18643d7bd22a2 --- /dev/null +++ b/integration-tests/micrometer-prometheus/src/main/java/io/quarkus/it/micrometer/prometheus/AnswerToEverythingExpressionResolver.java @@ -0,0 +1,14 @@ +package io.quarkus.it.micrometer.prometheus; + +import jakarta.inject.Singleton; + +import io.micrometer.common.annotation.ValueExpressionResolver; + +@Singleton +public class AnswerToEverythingExpressionResolver implements ValueExpressionResolver { + @Override + public String resolve(String expression, Object parameter) { + // Answer to the Ultimate Question of Life, the Universe, and Everything. + return "42"; + } +} diff --git a/integration-tests/micrometer-prometheus/src/main/java/io/quarkus/it/micrometer/prometheus/PrefixingValueResolver.java b/integration-tests/micrometer-prometheus/src/main/java/io/quarkus/it/micrometer/prometheus/PrefixingValueResolver.java new file mode 100644 index 0000000000000..5f257408909c5 --- /dev/null +++ b/integration-tests/micrometer-prometheus/src/main/java/io/quarkus/it/micrometer/prometheus/PrefixingValueResolver.java @@ -0,0 +1,13 @@ +package io.quarkus.it.micrometer.prometheus; + +import jakarta.inject.Singleton; + +import io.micrometer.common.annotation.ValueResolver; + +@Singleton +public class PrefixingValueResolver implements ValueResolver { + @Override + public String resolve(Object parameter) { + return "prefix " + parameter; + } +} diff --git a/integration-tests/micrometer-prometheus/src/test/java/io/quarkus/it/micrometer/prometheus/PrometheusMetricsRegistryTest.java b/integration-tests/micrometer-prometheus/src/test/java/io/quarkus/it/micrometer/prometheus/PrometheusMetricsRegistryTest.java index 67c1c7cf63d31..186cb2268a90b 100644 --- a/integration-tests/micrometer-prometheus/src/test/java/io/quarkus/it/micrometer/prometheus/PrometheusMetricsRegistryTest.java +++ b/integration-tests/micrometer-prometheus/src/test/java/io/quarkus/it/micrometer/prometheus/PrometheusMetricsRegistryTest.java @@ -148,22 +148,22 @@ void testPrometheusScrapeEndpointTextPlain() { // Annotated counters .body(not(containsString("metric_none"))) .body(containsString( - "metric_all_total{class=\"io.quarkus.it.micrometer.prometheus.AnnotatedResource\",env=\"test\",env2=\"test\",exception=\"none\",extra=\"tag\",method=\"countAllInvocations\",registry=\"prometheus\",result=\"success\",} 1.0")) + "metric_all_total{class=\"io.quarkus.it.micrometer.prometheus.AnnotatedResource\",env=\"test\",env2=\"test\",exception=\"none\",extra=\"tag\",fail=\"false\",method=\"countAllInvocations\",registry=\"prometheus\",result=\"success\",} 1.0")) .body(containsString( - "metric_all_total{class=\"io.quarkus.it.micrometer.prometheus.AnnotatedResource\",env=\"test\",env2=\"test\",exception=\"NullPointerException\",extra=\"tag\",method=\"countAllInvocations\",registry=\"prometheus\",result=\"failure\",} 1.0")) + "metric_all_total{class=\"io.quarkus.it.micrometer.prometheus.AnnotatedResource\",env=\"test\",env2=\"test\",exception=\"NullPointerException\",extra=\"tag\",fail=\"true\",method=\"countAllInvocations\",registry=\"prometheus\",result=\"failure\",} 1.0")) .body(containsString( - "method_counted_total{class=\"io.quarkus.it.micrometer.prometheus.AnnotatedResource\",env=\"test\",env2=\"test\",exception=\"NullPointerException\",method=\"emptyMetricName\",registry=\"prometheus\",result=\"failure\",} 1.0")) + "method_counted_total{class=\"io.quarkus.it.micrometer.prometheus.AnnotatedResource\",env=\"test\",env2=\"test\",exception=\"NullPointerException\",fail=\"prefix true\",method=\"emptyMetricName\",registry=\"prometheus\",result=\"failure\",} 1.0")) .body(containsString( - "method_counted_total{class=\"io.quarkus.it.micrometer.prometheus.AnnotatedResource\",env=\"test\",env2=\"test\",exception=\"none\",method=\"emptyMetricName\",registry=\"prometheus\",result=\"success\",} 1.0")) + "method_counted_total{class=\"io.quarkus.it.micrometer.prometheus.AnnotatedResource\",env=\"test\",env2=\"test\",exception=\"none\",fail=\"prefix false\",method=\"emptyMetricName\",registry=\"prometheus\",result=\"success\",} 1.0")) .body(not(containsString("async_none"))) .body(containsString( - "async_all_total{class=\"io.quarkus.it.micrometer.prometheus.AnnotatedResource\",env=\"test\",env2=\"test\",exception=\"NullPointerException\",extra=\"tag\",method=\"countAllAsyncInvocations\",registry=\"prometheus\",result=\"failure\",} 1.0")) + "async_all_total{class=\"io.quarkus.it.micrometer.prometheus.AnnotatedResource\",do_fail_call=\"true\",env=\"test\",env2=\"test\",exception=\"NullPointerException\",extra=\"tag\",method=\"countAllAsyncInvocations\",registry=\"prometheus\",result=\"failure\",} 1.0")) .body(containsString( - "async_all_total{class=\"io.quarkus.it.micrometer.prometheus.AnnotatedResource\",env=\"test\",env2=\"test\",exception=\"none\",extra=\"tag\",method=\"countAllAsyncInvocations\",registry=\"prometheus\",result=\"success\",} 1.0")) + "async_all_total{class=\"io.quarkus.it.micrometer.prometheus.AnnotatedResource\",do_fail_call=\"false\",env=\"test\",env2=\"test\",exception=\"none\",extra=\"tag\",method=\"countAllAsyncInvocations\",registry=\"prometheus\",result=\"success\",} 1.0")) .body(containsString( - "method_counted_total{class=\"io.quarkus.it.micrometer.prometheus.AnnotatedResource\",env=\"test\",env2=\"test\",exception=\"NullPointerException\",method=\"emptyAsyncMetricName\",registry=\"prometheus\",result=\"failure\",} 1.0")) + "method_counted_total{class=\"io.quarkus.it.micrometer.prometheus.AnnotatedResource\",env=\"test\",env2=\"test\",exception=\"NullPointerException\",fail=\"42\",method=\"emptyAsyncMetricName\",registry=\"prometheus\",result=\"failure\",} 1.0")) .body(containsString( - "method_counted_total{class=\"io.quarkus.it.micrometer.prometheus.AnnotatedResource\",env=\"test\",env2=\"test\",exception=\"none\",method=\"emptyAsyncMetricName\",registry=\"prometheus\",result=\"success\",} 1.0")) + "method_counted_total{class=\"io.quarkus.it.micrometer.prometheus.AnnotatedResource\",env=\"test\",env2=\"test\",exception=\"none\",fail=\"42\",method=\"emptyAsyncMetricName\",registry=\"prometheus\",result=\"success\",} 1.0")) // Annotated Timers .body(containsString( @@ -240,22 +240,22 @@ void testPrometheusScrapeEndpointOpenMetrics() { // Annotated counters .body(not(containsString("metric_none"))) .body(containsString( - "metric_all_total{class=\"io.quarkus.it.micrometer.prometheus.AnnotatedResource\",env=\"test\",env2=\"test\",exception=\"none\",extra=\"tag\",method=\"countAllInvocations\",registry=\"prometheus\",result=\"success\"} 1.0 # {span_id=")) + "metric_all_total{class=\"io.quarkus.it.micrometer.prometheus.AnnotatedResource\",env=\"test\",env2=\"test\",exception=\"none\",extra=\"tag\",fail=\"false\",method=\"countAllInvocations\",registry=\"prometheus\",result=\"success\"} 1.0 # {span_id=")) .body(containsString( - "metric_all_total{class=\"io.quarkus.it.micrometer.prometheus.AnnotatedResource\",env=\"test\",env2=\"test\",exception=\"NullPointerException\",extra=\"tag\",method=\"countAllInvocations\",registry=\"prometheus\",result=\"failure\"} 1.0")) + "metric_all_total{class=\"io.quarkus.it.micrometer.prometheus.AnnotatedResource\",env=\"test\",env2=\"test\",exception=\"NullPointerException\",extra=\"tag\",fail=\"true\",method=\"countAllInvocations\",registry=\"prometheus\",result=\"failure\"} 1.0")) .body(containsString( - "method_counted_total{class=\"io.quarkus.it.micrometer.prometheus.AnnotatedResource\",env=\"test\",env2=\"test\",exception=\"NullPointerException\",method=\"emptyMetricName\",registry=\"prometheus\",result=\"failure\"} 1.0 # {span_id=")) + "method_counted_total{class=\"io.quarkus.it.micrometer.prometheus.AnnotatedResource\",env=\"test\",env2=\"test\",exception=\"NullPointerException\",fail=\"prefix true\",method=\"emptyMetricName\",registry=\"prometheus\",result=\"failure\"} 1.0 # {span_id=")) .body(containsString( - "method_counted_total{class=\"io.quarkus.it.micrometer.prometheus.AnnotatedResource\",env=\"test\",env2=\"test\",exception=\"none\",method=\"emptyMetricName\",registry=\"prometheus\",result=\"success\"} 1.0")) + "method_counted_total{class=\"io.quarkus.it.micrometer.prometheus.AnnotatedResource\",env=\"test\",env2=\"test\",exception=\"none\",fail=\"prefix false\",method=\"emptyMetricName\",registry=\"prometheus\",result=\"success\"} 1.0")) .body(not(containsString("async_none"))) .body(containsString( - "async_all_total{class=\"io.quarkus.it.micrometer.prometheus.AnnotatedResource\",env=\"test\",env2=\"test\",exception=\"NullPointerException\",extra=\"tag\",method=\"countAllAsyncInvocations\",registry=\"prometheus\",result=\"failure\"} 1.0")) + "async_all_total{class=\"io.quarkus.it.micrometer.prometheus.AnnotatedResource\",do_fail_call=\"true\",env=\"test\",env2=\"test\",exception=\"NullPointerException\",extra=\"tag\",method=\"countAllAsyncInvocations\",registry=\"prometheus\",result=\"failure\"} 1.0")) .body(containsString( - "async_all_total{class=\"io.quarkus.it.micrometer.prometheus.AnnotatedResource\",env=\"test\",env2=\"test\",exception=\"none\",extra=\"tag\",method=\"countAllAsyncInvocations\",registry=\"prometheus\",result=\"success\"} 1.0")) + "async_all_total{class=\"io.quarkus.it.micrometer.prometheus.AnnotatedResource\",do_fail_call=\"false\",env=\"test\",env2=\"test\",exception=\"none\",extra=\"tag\",method=\"countAllAsyncInvocations\",registry=\"prometheus\",result=\"success\"} 1.0")) .body(containsString( - "method_counted_total{class=\"io.quarkus.it.micrometer.prometheus.AnnotatedResource\",env=\"test\",env2=\"test\",exception=\"NullPointerException\",method=\"emptyAsyncMetricName\",registry=\"prometheus\",result=\"failure\"} 1.0")) + "method_counted_total{class=\"io.quarkus.it.micrometer.prometheus.AnnotatedResource\",env=\"test\",env2=\"test\",exception=\"NullPointerException\",fail=\"42\",method=\"emptyAsyncMetricName\",registry=\"prometheus\",result=\"failure\"} 1.0")) .body(containsString( - "method_counted_total{class=\"io.quarkus.it.micrometer.prometheus.AnnotatedResource\",env=\"test\",env2=\"test\",exception=\"none\",method=\"emptyAsyncMetricName\",registry=\"prometheus\",result=\"success\"} 1.0")) + "method_counted_total{class=\"io.quarkus.it.micrometer.prometheus.AnnotatedResource\",env=\"test\",env2=\"test\",exception=\"none\",fail=\"42\",method=\"emptyAsyncMetricName\",registry=\"prometheus\",result=\"success\"} 1.0")) // Annotated Timers .body(containsString(