From 718c4c207ca923a3ccdf44a9bba0bed2af9add45 Mon Sep 17 00:00:00 2001 From: "tim.quinn@oracle.com" Date: Thu, 7 Jul 2022 17:24:32 -0500 Subject: [PATCH 1/9] Save WIP --- .../quickstarts/helidon-quickstart-mp/pom.xml | 4 + microprofile/grpc/metrics/pom.xml | 4 + .../grpc/metrics/GrpcMetricsCdiExtension.java | 97 ++--- ...MetricAnnotationDiscoveryObserverImpl.java | 86 +++++ ...nnotationDiscoveryObserverImplFactory.java | 34 ++ .../MetricRegistrationObserverImpl.java | 55 +++ ...MetricRegistrationObserverImplFactory.java | 34 ++ .../grpc/metrics/MetricsConfigurer.java | 232 +++++------- .../metrics/src/main/java/module-info.java | 9 +- .../GrpcMetricsCoverageTestCdiExtension.java | 13 +- .../grpc/metrics/TestMetricsCoverage.java | 42 ++- microprofile/metrics/pom.xml | 4 + .../metrics/InterceptorConcurrentGauge.java | 36 +- .../metrics/InterceptorCounted.java | 36 +- .../metrics/InterceptorMetered.java | 35 +- .../metrics/InterceptorSimplyTimed.java | 35 +- .../metrics/InterceptorTimed.java | 33 +- .../MetricAnnotationDiscoveryImpl.java | 125 +++++++ .../MetricAnnotationDiscoveryObserver.java | 103 ++++++ .../metrics/MetricAnnotationInfo.java | 6 +- .../metrics/MetricRegistrationObserver.java | 46 +++ .../microprofile/metrics/MetricUtil.java | 262 +------------- .../metrics/MetricsCdiExtension.java | 331 +++++++++--------- ...icAnnotationDiscoveryObserverProvider.java | 34 ++ .../MetricRegistrationObserverProvider.java | 34 ++ .../metrics/api/package-info.java | 20 ++ .../metrics/src/main/java/module-info.java | 7 +- .../metrics/TestDiscoveryObserverImpl.java | 49 +++ .../microprofile/metrics/TestObservers.java | 40 +++ .../metrics/TestRegistrationObserverImpl.java | 54 +++ ....MetricAnnotationDiscoveryObserverProvider | 17 + ...ics.api.MetricRegistrationObserverProvider | 17 + tests/integration/mp-grpc/pom.xml | 13 +- .../grpc/metrics/MetricsConfigurerTest.java | 31 +- .../grpc/server/GrpcServerTestProducer.java | 33 ++ .../grpc/server/InterceptorsTest.java | 27 +- .../META-INF/microprofile-config.properties | 17 + 37 files changed, 1347 insertions(+), 708 deletions(-) create mode 100644 microprofile/grpc/metrics/src/main/java/io/helidon/microprofile/grpc/metrics/MetricAnnotationDiscoveryObserverImpl.java create mode 100644 microprofile/grpc/metrics/src/main/java/io/helidon/microprofile/grpc/metrics/MetricAnnotationDiscoveryObserverImplFactory.java create mode 100644 microprofile/grpc/metrics/src/main/java/io/helidon/microprofile/grpc/metrics/MetricRegistrationObserverImpl.java create mode 100644 microprofile/grpc/metrics/src/main/java/io/helidon/microprofile/grpc/metrics/MetricRegistrationObserverImplFactory.java create mode 100644 microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/MetricAnnotationDiscoveryImpl.java create mode 100644 microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/MetricAnnotationDiscoveryObserver.java create mode 100644 microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/MetricRegistrationObserver.java create mode 100644 microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/api/MetricAnnotationDiscoveryObserverProvider.java create mode 100644 microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/api/MetricRegistrationObserverProvider.java create mode 100644 microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/api/package-info.java create mode 100644 microprofile/metrics/src/test/java/io/helidon/microprofile/metrics/TestDiscoveryObserverImpl.java create mode 100644 microprofile/metrics/src/test/java/io/helidon/microprofile/metrics/TestObservers.java create mode 100644 microprofile/metrics/src/test/java/io/helidon/microprofile/metrics/TestRegistrationObserverImpl.java create mode 100644 microprofile/metrics/src/test/resources/META-INF/services/io.helidon.microprofile.metrics.api.MetricAnnotationDiscoveryObserverProvider create mode 100644 microprofile/metrics/src/test/resources/META-INF/services/io.helidon.microprofile.metrics.api.MetricRegistrationObserverProvider create mode 100644 tests/integration/mp-grpc/src/test/java/io/helidon/microprofile/grpc/server/GrpcServerTestProducer.java create mode 100644 tests/integration/mp-grpc/src/test/resources/META-INF/microprofile-config.properties diff --git a/examples/quickstarts/helidon-quickstart-mp/pom.xml b/examples/quickstarts/helidon-quickstart-mp/pom.xml index 2b46c17e831..f78e15f787c 100644 --- a/examples/quickstarts/helidon-quickstart-mp/pom.xml +++ b/examples/quickstarts/helidon-quickstart-mp/pom.xml @@ -42,6 +42,10 @@ runtime true + + io.helidon.microprofile.grpc + helidon-microprofile-grpc-metrics + org.junit.jupiter junit-jupiter-api diff --git a/microprofile/grpc/metrics/pom.xml b/microprofile/grpc/metrics/pom.xml index a3d3878525f..dec7b83636d 100644 --- a/microprofile/grpc/metrics/pom.xml +++ b/microprofile/grpc/metrics/pom.xml @@ -42,6 +42,10 @@ io.helidon.microprofile.grpc helidon-microprofile-grpc-server + + io.helidon.common + helidon-common-service-loader + io.helidon.microprofile.metrics helidon-microprofile-metrics diff --git a/microprofile/grpc/metrics/src/main/java/io/helidon/microprofile/grpc/metrics/GrpcMetricsCdiExtension.java b/microprofile/grpc/metrics/src/main/java/io/helidon/microprofile/grpc/metrics/GrpcMetricsCdiExtension.java index 86e5bc706a7..099bd1c522a 100644 --- a/microprofile/grpc/metrics/src/main/java/io/helidon/microprofile/grpc/metrics/GrpcMetricsCdiExtension.java +++ b/microprofile/grpc/metrics/src/main/java/io/helidon/microprofile/grpc/metrics/GrpcMetricsCdiExtension.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2021 Oracle and/or its affiliates. + * Copyright (c) 2019, 2022 Oracle and/or its affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,26 +17,25 @@ package io.helidon.microprofile.grpc.metrics; import java.lang.annotation.Annotation; -import java.util.EnumMap; +import java.lang.reflect.Method; +import java.util.List; import java.util.Map; +import java.util.ServiceLoader; +import java.util.stream.Collectors; +import io.helidon.common.serviceloader.HelidonServiceLoader; import io.helidon.microprofile.grpc.core.AnnotatedMethod; -import io.helidon.microprofile.grpc.core.Grpc; import io.helidon.microprofile.grpc.core.GrpcMethod; +import io.helidon.microprofile.metrics.MetricAnnotationDiscoveryObserver; +import io.helidon.microprofile.metrics.MetricAnnotationDiscoveryObserver.MetricAnnotationDiscovery; +import io.helidon.microprofile.metrics.MetricRegistrationObserver; -import jakarta.annotation.Priority; import jakarta.enterprise.event.Observes; +import jakarta.enterprise.inject.spi.BeforeBeanDiscovery; import jakarta.enterprise.inject.spi.Extension; -import jakarta.enterprise.inject.spi.ProcessAnnotatedType; -import jakarta.enterprise.inject.spi.WithAnnotations; import jakarta.enterprise.inject.spi.configurator.AnnotatedMethodConfigurator; import jakarta.interceptor.Interceptor; -import org.eclipse.microprofile.metrics.MetricType; -import org.eclipse.microprofile.metrics.annotation.ConcurrentGauge; -import org.eclipse.microprofile.metrics.annotation.Counted; -import org.eclipse.microprofile.metrics.annotation.Metered; -import org.eclipse.microprofile.metrics.annotation.SimplyTimed; -import org.eclipse.microprofile.metrics.annotation.Timed; +import org.eclipse.microprofile.metrics.Metadata; /** * A CDI extension for gRPC metrics. @@ -49,60 +48,24 @@ * method type annotation they metrics annotation will be effectively removed from the CDI * bean so that normal Helidon metrics interceptors do not also intercept that method. */ -public class GrpcMetricsCdiExtension - implements Extension { +public class GrpcMetricsCdiExtension implements Extension { - static final int OBSERVER_PRIORITY = Interceptor.Priority.APPLICATION; - - static final EnumMap> METRICS_ANNOTATIONS; - - static { - Map> map = Map.of( - MetricType.CONCURRENT_GAUGE, ConcurrentGauge.class, - MetricType.COUNTER, Counted.class, - MetricType.METERED, Metered.class, - MetricType.SIMPLE_TIMER, SimplyTimed.class, - MetricType.TIMER, Timed.class - ); - METRICS_ANNOTATIONS = new EnumMap<>(map); - } - - - /** - * Observer {@link ProcessAnnotatedType} events and process any method - * annotated with a gRPC method annotation and a metric annotation. - * - * @param pat the {@link ProcessAnnotatedType} to observer - */ - private void registerMetrics(@Observes - @WithAnnotations({Counted.class, Timed.class, Metered.class, ConcurrentGauge.class, - SimplyTimed.class, Grpc.class}) - @Priority(OBSERVER_PRIORITY) - ProcessAnnotatedType pat) { - METRICS_ANNOTATIONS.values().forEach(type -> - pat.configureAnnotatedType() - .methods() - .stream() - .filter(method -> isRpcMethod(method, type)) - .forEach(method -> method.remove(ann -> type.isAssignableFrom(ann.getClass())))); - } - - /** - * Determine whether a method is annotated with both a metrics annotation - * and an annotation of type {@link io.helidon.microprofile.grpc.core.GrpcMethod}. - * - * @param configurator the {@link AnnotatedMethodConfigurator} representing - * the annotated method - * - * @return {@code true} if the method is a timed gRPC method - */ - private boolean isRpcMethod(AnnotatedMethodConfigurator configurator, Class type) { - AnnotatedMethod method = AnnotatedMethod.create(configurator.getAnnotated().getJavaMember()); - GrpcMethod rpcMethod = method.firstAnnotationOrMetaAnnotation(GrpcMethod.class); - if (rpcMethod != null) { - Annotation annotation = method.firstAnnotationOrMetaAnnotation(type); - return annotation != null; - } - return false; - } +// /** +// * Determine whether a method is annotated with both a metrics annotation +// * and an annotation of type {@link io.helidon.microprofile.grpc.core.GrpcMethod}. +// * +// * @param configurator the {@link AnnotatedMethodConfigurator} representing +// * the annotated method +// * +// * @return {@code true} if the method is a timed gRPC method +// */ +// static boolean isRpcMethod(AnnotatedMethodConfigurator configurator, Class type) { +// AnnotatedMethod method = AnnotatedMethod.create(configurator.getAnnotated().getJavaMember()); +// GrpcMethod rpcMethod = method.firstAnnotationOrMetaAnnotation(GrpcMethod.class); +// if (rpcMethod != null) { +// Annotation annotation = method.firstAnnotationOrMetaAnnotation(type); +// return annotation != null; +// } +// return false; +// } } diff --git a/microprofile/grpc/metrics/src/main/java/io/helidon/microprofile/grpc/metrics/MetricAnnotationDiscoveryObserverImpl.java b/microprofile/grpc/metrics/src/main/java/io/helidon/microprofile/grpc/metrics/MetricAnnotationDiscoveryObserverImpl.java new file mode 100644 index 00000000000..f577ceb8c49 --- /dev/null +++ b/microprofile/grpc/metrics/src/main/java/io/helidon/microprofile/grpc/metrics/MetricAnnotationDiscoveryObserverImpl.java @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2022 Oracle and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.helidon.microprofile.grpc.metrics; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.Map; + +import io.helidon.microprofile.grpc.core.AnnotatedMethod; +import io.helidon.microprofile.grpc.core.GrpcMethod; +import io.helidon.microprofile.metrics.MetricAnnotationDiscoveryObserver; + +import jakarta.enterprise.inject.spi.configurator.AnnotatedMethodConfigurator; + +/** + * The gRPC implementation of {@link io.helidon.microprofile.metrics.MetricAnnotationDiscoveryObserver} with a static factory + * method. + */ +class MetricAnnotationDiscoveryObserverImpl implements MetricAnnotationDiscoveryObserver { + + static MetricAnnotationDiscoveryObserverImpl instance() { + return MetricAnnotationDiscoveryObserverImplFactory.instance(); + } + + public MetricAnnotationDiscoveryObserverImpl() { + int i = 3; + } + private final Map, + MetricAnnotationDiscovery.OfMethod>> discoveriesByMethod = + new HashMap<>(); + + @Override + public void onDiscovery(MetricAnnotationDiscovery metricAnnotationDiscovery) { + if (metricAnnotationDiscovery instanceof MetricAnnotationDiscovery.OfMethod discovery) { + if (isRpcMethod(discovery.configurator(), discovery.annotation().annotationType())) { + discovery.disableDefaultInterceptor(); + discoveriesByMethod.computeIfAbsent(discovery.configurator().getAnnotated().getJavaMember(), + key -> new HashMap<>()) + .putIfAbsent(discovery.annotation().annotationType(), + discovery); + } + } + } + + Map, MetricAnnotationDiscovery.OfMethod> discovery(Method method) { + return discoveriesByMethod.get(method); + } + + boolean isDiscovered(Method method) { + return discoveriesByMethod.containsKey(method); + } + + /** + * Determine whether a method is annotated with both a metrics annotation + * and an annotation of type {@link io.helidon.microprofile.grpc.core.GrpcMethod}. + * + * @param configurator the {@link jakarta.enterprise.inject.spi.configurator.AnnotatedMethodConfigurator} representing + * the annotated method + * + * @return {@code true} if the method is a timed gRPC method + */ + private static boolean isRpcMethod(AnnotatedMethodConfigurator configurator, Class type) { + AnnotatedMethod method = AnnotatedMethod.create(configurator.getAnnotated().getJavaMember()); + GrpcMethod rpcMethod = method.firstAnnotationOrMetaAnnotation(GrpcMethod.class); + if (rpcMethod != null) { + Annotation annotation = method.firstAnnotationOrMetaAnnotation(type); + return annotation != null; + } + return false; + } +} diff --git a/microprofile/grpc/metrics/src/main/java/io/helidon/microprofile/grpc/metrics/MetricAnnotationDiscoveryObserverImplFactory.java b/microprofile/grpc/metrics/src/main/java/io/helidon/microprofile/grpc/metrics/MetricAnnotationDiscoveryObserverImplFactory.java new file mode 100644 index 00000000000..1291d42202b --- /dev/null +++ b/microprofile/grpc/metrics/src/main/java/io/helidon/microprofile/grpc/metrics/MetricAnnotationDiscoveryObserverImplFactory.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2022 Oracle and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.helidon.microprofile.grpc.metrics; + +import io.helidon.common.LazyValue; +import io.helidon.microprofile.metrics.api.MetricAnnotationDiscoveryObserverProvider; + +public class MetricAnnotationDiscoveryObserverImplFactory + implements MetricAnnotationDiscoveryObserverProvider { + + private static final LazyValue instance = + LazyValue.create(MetricAnnotationDiscoveryObserverImpl::new); + + static MetricAnnotationDiscoveryObserverImpl instance() { + return instance.get(); + } + @Override + public MetricAnnotationDiscoveryObserverImpl get() { + return instance(); + } +} diff --git a/microprofile/grpc/metrics/src/main/java/io/helidon/microprofile/grpc/metrics/MetricRegistrationObserverImpl.java b/microprofile/grpc/metrics/src/main/java/io/helidon/microprofile/grpc/metrics/MetricRegistrationObserverImpl.java new file mode 100644 index 00000000000..b3bb6cb39b4 --- /dev/null +++ b/microprofile/grpc/metrics/src/main/java/io/helidon/microprofile/grpc/metrics/MetricRegistrationObserverImpl.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2022 Oracle and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.helidon.microprofile.grpc.metrics; + +import java.util.HashMap; +import java.util.Map; + +import io.helidon.microprofile.metrics.MetricAnnotationDiscoveryObserver.MetricAnnotationDiscovery; +import io.helidon.microprofile.metrics.MetricRegistrationObserver; + +import org.eclipse.microprofile.metrics.Metadata; +import org.eclipse.microprofile.metrics.Metric; +import org.eclipse.microprofile.metrics.MetricID; + +/** + * The gRPC implementation of {@link io.helidon.microprofile.metrics.MetricRegistrationObserver} with a static factory method. + */ +class MetricRegistrationObserverImpl implements MetricRegistrationObserver { + + + private final Map metadataByDiscovery = new HashMap<>(); + + public MetricRegistrationObserverImpl() { + int i = 4; + } + + @Override + public void onRegistration(MetricAnnotationDiscovery discovery, + Metadata metadata, + MetricID metricId, + Metric metric) { + metadataByDiscovery.put(discovery, metadata); + } + + Metadata metadata(MetricAnnotationDiscovery discovery) { + return metadataByDiscovery.get(discovery); + } + + static MetricRegistrationObserverImpl instance() { + return MetricRegistrationObserverImplFactory.instance(); + } +} diff --git a/microprofile/grpc/metrics/src/main/java/io/helidon/microprofile/grpc/metrics/MetricRegistrationObserverImplFactory.java b/microprofile/grpc/metrics/src/main/java/io/helidon/microprofile/grpc/metrics/MetricRegistrationObserverImplFactory.java new file mode 100644 index 00000000000..e1094734e79 --- /dev/null +++ b/microprofile/grpc/metrics/src/main/java/io/helidon/microprofile/grpc/metrics/MetricRegistrationObserverImplFactory.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2022 Oracle and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.helidon.microprofile.grpc.metrics; + +import io.helidon.common.LazyValue; +import io.helidon.microprofile.metrics.api.MetricRegistrationObserverProvider; + +public class MetricRegistrationObserverImplFactory implements MetricRegistrationObserverProvider { + + private static final LazyValue instance = + LazyValue.create(MetricRegistrationObserverImpl::new); + + static MetricRegistrationObserverImpl instance() { + return instance.get(); + } + + @Override + public MetricRegistrationObserverImpl get() { + return instance(); + } +} diff --git a/microprofile/grpc/metrics/src/main/java/io/helidon/microprofile/grpc/metrics/MetricsConfigurer.java b/microprofile/grpc/metrics/src/main/java/io/helidon/microprofile/grpc/metrics/MetricsConfigurer.java index cb6dfa9410a..9c2bc35a1ef 100644 --- a/microprofile/grpc/metrics/src/main/java/io/helidon/microprofile/grpc/metrics/MetricsConfigurer.java +++ b/microprofile/grpc/metrics/src/main/java/io/helidon/microprofile/grpc/metrics/MetricsConfigurer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2021 Oracle and/or its affiliates. + * Copyright (c) 2019, 2022 Oracle and/or its affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,13 +18,11 @@ import java.lang.annotation.Annotation; import java.lang.reflect.Method; -import java.util.Collections; import java.util.Map; -import java.util.Set; -import java.util.function.Function; import java.util.function.Supplier; import java.util.logging.Level; import java.util.logging.Logger; +import java.util.stream.Collectors; import io.helidon.grpc.metrics.GrpcMetrics; import io.helidon.grpc.server.ServiceDescriptor; @@ -33,18 +31,21 @@ import io.helidon.microprofile.grpc.core.GrpcMethod; import io.helidon.microprofile.grpc.server.AnnotatedServiceConfigurer; import io.helidon.microprofile.grpc.server.GrpcServiceBuilder; -import io.helidon.microprofile.metrics.MetricUtil; -import io.helidon.microprofile.metrics.MetricsCdiExtension; +import io.helidon.microprofile.metrics.MetricAnnotationDiscoveryObserver; +import org.eclipse.microprofile.metrics.Counter; +import org.eclipse.microprofile.metrics.Metadata; +import org.eclipse.microprofile.metrics.Meter; +import org.eclipse.microprofile.metrics.Metric; import org.eclipse.microprofile.metrics.MetricType; +import org.eclipse.microprofile.metrics.SimpleTimer; +import org.eclipse.microprofile.metrics.Timer; import org.eclipse.microprofile.metrics.annotation.ConcurrentGauge; import org.eclipse.microprofile.metrics.annotation.Counted; import org.eclipse.microprofile.metrics.annotation.Metered; import org.eclipse.microprofile.metrics.annotation.SimplyTimed; import org.eclipse.microprofile.metrics.annotation.Timed; -import static io.helidon.microprofile.metrics.MetricUtil.getMetricName; - /** * A {@link AnnotatedServiceConfigurer} that adds a * {@link io.helidon.grpc.metrics.GrpcMetrics gRPC metrics interceptor} @@ -59,129 +60,52 @@ public class MetricsConfigurer private static final Logger LOGGER = Logger.getLogger(MetricsConfigurer.class.getName()); - /** - * Captures information and logic for dealing with the various metrics annotations. This allows the metrics handling to be - * largely data-driven rather than requiring separate code for each type of metric. - * - * @param the type of the specific metrics annotation - */ - private static class MetricAnnotationInfo { - private final Class annotationClass; - private final Supplier gRpcMetricsSupplier; - private final Function annotationNameFunction; - private final Function annotationAbsoluteFunction; - private final Function annotationDescriptorFunction; - private final Function annotationDisplayNameFunction; - private final Function annotationUnitsFunction; - - - MetricAnnotationInfo( - Class annotationClass, - Supplier gRpcMetricsSupplier, - Function annotationNameFunction, - Function annotationAbsoluteFunction, - Function annotationDescriptorFunction, - Function annotationDisplayNameFunction, - Function annotationUnitsFunction) { - this.annotationClass = annotationClass; - this.gRpcMetricsSupplier = gRpcMetricsSupplier; - this.annotationNameFunction = annotationNameFunction; - this.annotationAbsoluteFunction = annotationAbsoluteFunction; - this.annotationDescriptorFunction = annotationDescriptorFunction; - this.annotationDisplayNameFunction = annotationDisplayNameFunction; - this.annotationUnitsFunction = annotationUnitsFunction; - } - - A annotationOnMethod(AnnotatedMethod am) { - return am.getAnnotation(annotationClass); - } - - String name(AnnotatedMethod am) { - return annotationNameFunction.apply(am.getAnnotation(annotationClass)); - } - - boolean absolute(AnnotatedMethod am) { - return annotationAbsoluteFunction.apply(am.getAnnotation(annotationClass)); - } - - String displayName(AnnotatedMethod am) { - return annotationDisplayNameFunction.apply(am.getAnnotation(annotationClass)); - } - - String description(AnnotatedMethod am) { - return annotationDescriptorFunction.apply(am.getAnnotation(annotationClass)); - } + static final Map, MetricInfo> METRIC_ANNOTATION_INFO = Map.of( + Counted.class, MetricInfo.create(GrpcMetrics::counted, Counter.class), + Metered.class, MetricInfo.create(GrpcMetrics::metered, Meter.class), + Timed.class, MetricInfo.create(GrpcMetrics::timed, Timer.class), + ConcurrentGauge.class, MetricInfo.create(GrpcMetrics::concurrentGauge, + org.eclipse.microprofile.metrics.ConcurrentGauge.class), + SimplyTimed.class, MetricInfo.create(GrpcMetrics::simplyTimed, SimpleTimer.class) + ); - String units(AnnotatedMethod am) { - return annotationUnitsFunction.apply(am.getAnnotation(annotationClass)); + // Package-private for testing. + record MetricInfo(Supplier grpcMetricsSupplier, + Class metricClass) { + private static MetricInfo create(Supplier grpcMetricsSupplier, Class metricClass) { + return new MetricInfo(grpcMetricsSupplier, metricClass); } } - private static final Map, MetricAnnotationInfo> METRIC_ANNOTATION_INFO = Map.of( - Counted.class, new MetricAnnotationInfo( - Counted.class, - GrpcMetrics::counted, - Counted::name, - Counted::absolute, - Counted::description, - Counted::displayName, - Counted::unit), - Metered.class, new MetricAnnotationInfo( - Metered.class, - GrpcMetrics::metered, - Metered::name, - Metered::absolute, - Metered::description, - Metered::displayName, - Metered::unit), - Timed.class, new MetricAnnotationInfo( - Timed.class, - GrpcMetrics::timed, - Timed::name, - Timed::absolute, - Timed::description, - Timed::displayName, - Timed::unit), - ConcurrentGauge.class, new MetricAnnotationInfo( - ConcurrentGauge.class, - GrpcMetrics::concurrentGauge, - ConcurrentGauge::name, - ConcurrentGauge::absolute, - ConcurrentGauge::description, - ConcurrentGauge::displayName, - ConcurrentGauge::unit), - SimplyTimed.class, new MetricAnnotationInfo( - SimplyTimed.class, - GrpcMetrics::simplyTimed, - SimplyTimed::name, - SimplyTimed::absolute, - SimplyTimed::description, - SimplyTimed::displayName, - SimplyTimed::unit) - ); - - // for testing - static Set> metricsAnnotationsSupported() { - return Collections.unmodifiableSet(METRIC_ANNOTATION_INFO.keySet()); - } @Override public void accept(Class serviceClass, Class annotatedClass, ServiceDescriptor.Builder builder) { AnnotatedMethodList methodList = AnnotatedMethodList.create(serviceClass); - METRIC_ANNOTATION_INFO.forEach((annotationClass, info) -> methodList.withAnnotation(annotationClass) - .stream() - .filter(am -> isServiceAnnotated(serviceClass, am, annotationClass)) - .forEach(annotatedMethod -> { - Annotation anno = info.annotationOnMethod(annotatedMethod); - addMetric(builder, - annotatedMethod, - info.gRpcMetricsSupplier.get(), - anno, - info.name(annotatedMethod), - info.absolute(annotatedMethod)); - })); + // For each annotated method: + // Retrieve all discoveries of metric annotations on that method, and for each: + // Get the metric registration for it (which has the metric metadata). + // Add the interceptor for the annotation associated with the annotation site that was discovered. + methodList.stream() + .filter(am -> isDiscovered(am.method())) + .forEach(annotatedMethod -> + discoveries(annotatedMethod.method()) + .forEach((annotationClass, discovery) -> + metadata(annotatedMethod.method()) + .forEach(metadata -> + processMetricAnnotationSite( + builder, + annotatedMethod, + METRIC_ANNOTATION_INFO + .get(annotationClass) + .grpcMetricsSupplier + .get(), + discovery.annotation(), + metadata) + ) + ) + ); } private boolean isServiceAnnotated(Class cls, AnnotatedMethod annotatedMethod, Class annotation) { @@ -189,59 +113,39 @@ private boolean isServiceAnnotated(Class cls, AnnotatedMethod annotatedMethod return method.getDeclaringClass().equals(cls) && method.isAnnotationPresent(annotation); } - private void addMetric(ServiceDescriptor.Builder builder, - AnnotatedMethod annotatedMethod, - GrpcMetrics interceptor, - Annotation annotation, - String name, - boolean absolute) { + private void processMetricAnnotationSite(ServiceDescriptor.Builder builder, + AnnotatedMethod annotatedMethod, + GrpcMetrics interceptor, + Annotation annotation, + Metadata metadata) { GrpcMethod rpcMethod = annotatedMethod.firstAnnotationOrMetaAnnotation(GrpcMethod.class); if (rpcMethod != null) { - Method method = findAnnotatedMethod(annotatedMethod, annotation.annotationType()); - Class annotatedClass = method.getDeclaringClass(); String grpcMethodName = GrpcServiceBuilder.determineMethodName(annotatedMethod, rpcMethod); - String metricName = getMetricName(method, - annotatedClass, - MetricUtil.MatchingType.METHOD, - name, - absolute); LOGGER.log(Level.FINE, () -> String.format("Adding gRPC '%s' metric interceptor to service '%s' method '%s'", annotation.annotationType().getSimpleName(), builder.name(), grpcMethodName)); - MetricUtil.LookupResult lookupResult - = MetricUtil.lookupAnnotation(method, annotation.annotationType(), annotatedClass); - - MetricAnnotationInfo mInfo = METRIC_ANNOTATION_INFO.get(annotation.annotationType()); - if (mInfo != null && mInfo.annotationClass.isInstance(annotation)) { - String candidateDescription = mInfo.description(annotatedMethod); + if (METRIC_ANNOTATION_INFO.containsKey(annotation.annotationType()) + && annotation.annotationType().isInstance(annotation)) { + String candidateDescription = metadata.getDescription(); if (candidateDescription != null && !candidateDescription.trim().isEmpty()) { interceptor = interceptor.description(candidateDescription.trim()); } - String candidateDisplayName = mInfo.displayName(annotatedMethod); + String candidateDisplayName = metadata.getDisplayName(); if (candidateDisplayName != null && !candidateDisplayName.trim().isEmpty()) { interceptor = interceptor.displayName(candidateDisplayName.trim()); } interceptor = interceptor - .units(mInfo.units(annotatedMethod)); + .units(metadata.getUnit()); } - MetricsCdiExtension.registerMetric(method, annotatedClass, lookupResult); - builder.intercept(grpcMethodName, interceptor.nameFunction(new ConstantNamingFunction(metricName))); + builder.intercept(grpcMethodName, interceptor.nameFunction(new ConstantNamingFunction(metadata.getName()))); } } - private Method findAnnotatedMethod(AnnotatedMethod annotatedMethod, Class type) { - Method method = annotatedMethod.declaredMethod(); - if (!method.isAnnotationPresent(type)) { - method = annotatedMethod.method(); - } - return method; - } - /** * A {@link GrpcMetrics.NamingFunction} that returns a constant name. */ @@ -258,4 +162,28 @@ public String createName(ServiceDescriptor service, String methodName, MetricTyp return name; } } + + private boolean isDiscovered(Method method) { + return MetricAnnotationDiscoveryObserverImpl.instance().isDiscovered(method); + } + + private Map, MetricAnnotationDiscoveryObserver.MetricAnnotationDiscovery.OfMethod> discovery(Method method) { + return MetricAnnotationDiscoveryObserverImpl.instance().discovery(method); + } + + private Metadata metadata(MetricAnnotationDiscoveryObserver.MetricAnnotationDiscovery discovery) { + return MetricRegistrationObserverImpl.instance().metadata(discovery); + } + + Iterable metadata(Method method){ + return discovery(method) + .values() + .stream() + .map(this::metadata) + .collect(Collectors.toList()); + } + + Map, MetricAnnotationDiscoveryObserver.MetricAnnotationDiscovery.OfMethod> discoveries(Method method) { + return discovery(method); + } } diff --git a/microprofile/grpc/metrics/src/main/java/module-info.java b/microprofile/grpc/metrics/src/main/java/module-info.java index 4de0abf97f4..821d3f8a012 100644 --- a/microprofile/grpc/metrics/src/main/java/module-info.java +++ b/microprofile/grpc/metrics/src/main/java/module-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2021 Oracle and/or its affiliates. + * Copyright (c) 2019, 2022 Oracle and/or its affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -24,6 +24,7 @@ requires transitive io.helidon.microprofile.grpc.server; requires transitive io.helidon.microprofile.metrics; requires transitive io.helidon.microprofile.server; + requires io.helidon.common.serviceloader; requires io.helidon.servicecommon.restcdi; @@ -35,4 +36,10 @@ provides jakarta.enterprise.inject.spi.Extension with io.helidon.microprofile.grpc.metrics.GrpcMetricsCdiExtension; + + provides io.helidon.microprofile.metrics.api.MetricAnnotationDiscoveryObserverProvider + with io.helidon.microprofile.grpc.metrics.MetricAnnotationDiscoveryObserverImplFactory; + + provides io.helidon.microprofile.metrics.api.MetricRegistrationObserverProvider + with io.helidon.microprofile.grpc.metrics.MetricRegistrationObserverImplFactory; } \ No newline at end of file diff --git a/microprofile/grpc/metrics/src/test/java/io/helidon/microprofile/grpc/metrics/GrpcMetricsCoverageTestCdiExtension.java b/microprofile/grpc/metrics/src/test/java/io/helidon/microprofile/grpc/metrics/GrpcMetricsCoverageTestCdiExtension.java index 973801b3c77..91b68ef9224 100644 --- a/microprofile/grpc/metrics/src/test/java/io/helidon/microprofile/grpc/metrics/GrpcMetricsCoverageTestCdiExtension.java +++ b/microprofile/grpc/metrics/src/test/java/io/helidon/microprofile/grpc/metrics/GrpcMetricsCoverageTestCdiExtension.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 Oracle and/or its affiliates. + * Copyright (c) 2021, 2022 Oracle and/or its affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -34,9 +34,12 @@ import jakarta.enterprise.inject.spi.ProcessAnnotatedType; import jakarta.enterprise.inject.spi.ProcessManagedBean; import jakarta.enterprise.inject.spi.WithAnnotations; +import jakarta.interceptor.Interceptor; public class GrpcMetricsCoverageTestCdiExtension implements Extension { + private static final int OBSERVER_PRIORITY = Interceptor.Priority.APPLICATION; + private static final Logger LOGGER = Logger.getLogger(GrpcMetricsCoverageTestCdiExtension.class.getName()); private final Set> metricsAnnotationsUsed = new HashSet<>(); @@ -55,7 +58,7 @@ void before(@Observes BeforeBeanDiscovery bbd) { String testBeanClassBaseName = CoverageTestBeanBase.class.getName(); String testBeanClassNamePrefix = testBeanClassBaseName.substring(0, testBeanClassBaseName.indexOf("Base")); - GrpcMetricsCdiExtension.METRICS_ANNOTATIONS.values().forEach(annotationClass -> { + MetricsConfigurer.METRIC_ANNOTATION_INFO.forEach((annotationClass, metricInfo) -> { String testBeanClassName = testBeanClassNamePrefix + annotationClass.getSimpleName(); try { Class testBeanClass = Class.forName(testBeanClassName); @@ -81,7 +84,7 @@ void before(@Observes BeforeBeanDiscovery bbd) { *

* @param pat */ - void recordMetricsAnnotationsOnTestBean(@Observes @Priority(GrpcMetricsCdiExtension.OBSERVER_PRIORITY - 10) + void recordMetricsAnnotationsOnTestBean(@Observes @Priority(OBSERVER_PRIORITY - 10) @WithAnnotations(GrpcMethod.class) ProcessAnnotatedType pat) { pat.getAnnotatedType() @@ -92,7 +95,7 @@ void recordMetricsAnnotationsOnTestBean(@Observes @Priority(GrpcMetricsCdiExtens .map(Annotation::annotationType) .collect(Collectors.toSet()); - metricsAnnotationClassesForThisMethod.retainAll(GrpcMetricsCdiExtension.METRICS_ANNOTATIONS.values()); + metricsAnnotationClassesForThisMethod.retainAll(MetricsConfigurer.METRIC_ANNOTATION_INFO.keySet()); LOGGER.log(Level.FINE, () -> String.format("Recording annotation(s) %s on %s", metricsAnnotationClassesForThisMethod, m.getJavaMember().toString())); metricsAnnotationsUsed.addAll(metricsAnnotationClassesForThisMethod); @@ -113,7 +116,7 @@ void checkForMetricsAnnotations(@Observes ProcessManagedBean, Set>> leftoverAnnotations = - extension.remainingTestBeanMethodAnnotations(); - - assertThat("Metrics annotations unexpectedly remain on method", leftoverAnnotations.keySet(), is(empty())); - } - @Test public void checkThatAllMetricsAnnotationsWereEncountered() { Set> metricsAnnotationsUnused = - new HashSet<>(GrpcMetricsCdiExtension.METRICS_ANNOTATIONS.values()); + new HashSet<>(MetricsConfigurer.METRIC_ANNOTATION_INFO.keySet()); metricsAnnotationsUnused.removeAll(extension.metricsAnnotationsUsed()); - assertThat("The CoverageTestBeanBase subclasses seem not to cover all known annotations", metricsAnnotationsUnused, + assertThat("Known annotations not covered by CoverageTestBeanBase subclasses", metricsAnnotationsUnused, is(empty())); } @@ -84,12 +77,18 @@ public void checkThatAllMetricsAnnotationsWereEncountered() { */ @Test public void checkForAllMetricsInMetricInfo() { - Set> metricsAnnotations = - new HashSet<>(GrpcMetricsCdiExtension.METRICS_ANNOTATIONS.values()); + var metricTypesSupportedByGrpc = new HashSet<>(List.of(MetricType.values())); + metricTypesSupportedByGrpc.removeAll(Set.of(MetricType.GAUGE, MetricType.HISTOGRAM, MetricType.INVALID)); + + var metricTypesAbsentFromMetricsConfigurer = new HashSet<>(metricTypesSupportedByGrpc); + + // Remove metrics types represented in the MetricsConfigurer's annotation info. + MetricsConfigurer.METRIC_ANNOTATION_INFO.forEach((annotationClass, metricInfo) -> { + metricTypesAbsentFromMetricsConfigurer.remove(MetricType.from(metricInfo.metricClass())); + }); - metricsAnnotations.removeAll(MetricsConfigurer.metricsAnnotationsSupported()); - assertThat("One or more metrics annotations seem not supported in MetricsConfigurer but should be", - metricsAnnotations, is(empty())); + assertThat("Metrics types not supported in MetricsConfigurer but should be", + metricTypesAbsentFromMetricsConfigurer, is(empty())); } /** @@ -106,7 +105,12 @@ public void checkForAllMetricTypesMappedToAnnotationType() { Set incorrectlySkippedMetricTypes = new HashSet<>(Arrays.asList(MetricType.values())); incorrectlySkippedMetricTypes.removeAll(ignoredMetricTypes); - incorrectlySkippedMetricTypes.removeAll(GrpcMetricsCdiExtension.METRICS_ANNOTATIONS.keySet()); + MetricsConfigurer.METRIC_ANNOTATION_INFO.values() + .stream() + .map(MetricsConfigurer.MetricInfo::metricClass) + .map(MetricType::from) + .toList() + .forEach(incorrectlySkippedMetricTypes::remove); assertThat("At least one MicroProfile metric with an annotation exists that is not present in " + "GrpcMetricsCdiExtension.METRICS_ANNOTATIONS", incorrectlySkippedMetricTypes, is(empty())); diff --git a/microprofile/metrics/pom.xml b/microprofile/metrics/pom.xml index e21e8225ba8..797922584ff 100644 --- a/microprofile/metrics/pom.xml +++ b/microprofile/metrics/pom.xml @@ -69,6 +69,10 @@ io.helidon.metrics helidon-metrics-service-api
+ + io.helidon.common + helidon-common-service-loader + io.helidon.metrics helidon-metrics diff --git a/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/InterceptorConcurrentGauge.java b/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/InterceptorConcurrentGauge.java index d905e826dea..856a66fa798 100644 --- a/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/InterceptorConcurrentGauge.java +++ b/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/InterceptorConcurrentGauge.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2021 Oracle and/or its affiliates. + * Copyright (c) 2019, 2022 Oracle and/or its affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,18 +16,30 @@ package io.helidon.microprofile.metrics; +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + import jakarta.annotation.Priority; +import jakarta.enterprise.util.AnnotationLiteral; import jakarta.interceptor.Interceptor; +import jakarta.interceptor.InterceptorBinding; import org.eclipse.microprofile.metrics.ConcurrentGauge; /** * Interceptor for {@link ConcurrentGauge} annotation. */ -@org.eclipse.microprofile.metrics.annotation.ConcurrentGauge +@InterceptorConcurrentGauge.Binding @Interceptor @Priority(Interceptor.Priority.PLATFORM_BEFORE + 11) final class InterceptorConcurrentGauge extends MetricsInterceptorBase.WithPostCompletion { + static Binding.Literal binding() { + return Binding.Literal.getInstance(); + } + InterceptorConcurrentGauge() { super(org.eclipse.microprofile.metrics.annotation.ConcurrentGauge.class, ConcurrentGauge.class); @@ -42,4 +54,24 @@ void preInvoke(ConcurrentGauge metric) { void postComplete(ConcurrentGauge metric) { metric.dec(); } + @Inherited + @InterceptorBinding + @Target({ElementType.TYPE}) + @Retention(RetentionPolicy.RUNTIME) + @org.eclipse.microprofile.metrics.annotation.ConcurrentGauge + @interface Binding { + class Literal extends AnnotationLiteral implements Binding { + + private static final long serialVersionUID = 1L; + + private static final Literal INSTANCE = new Literal(); + + static Literal getInstance() { + return INSTANCE; + } + + private Literal() { + } + } + } } diff --git a/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/InterceptorCounted.java b/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/InterceptorCounted.java index 19beed87f84..c101e2632d6 100644 --- a/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/InterceptorCounted.java +++ b/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/InterceptorCounted.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021 Oracle and/or its affiliates. + * Copyright (c) 2018, 2022 Oracle and/or its affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,19 +16,31 @@ package io.helidon.microprofile.metrics; +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + import jakarta.annotation.Priority; +import jakarta.enterprise.util.AnnotationLiteral; import jakarta.interceptor.Interceptor; +import jakarta.interceptor.InterceptorBinding; import org.eclipse.microprofile.metrics.Counter; import org.eclipse.microprofile.metrics.annotation.Counted; /** * Interceptor for {@link Counted} annotation. */ -@Counted +@InterceptorCounted.Binding @Interceptor @Priority(Interceptor.Priority.PLATFORM_BEFORE + 8) final class InterceptorCounted extends MetricsInterceptorBase { + static Binding.Literal binding() { + return Binding.Literal.getInstance(); + } + InterceptorCounted() { super(Counted.class, Counter.class); } @@ -37,4 +49,24 @@ final class InterceptorCounted extends MetricsInterceptorBase { void preInvoke(Counter metric) { metric.inc(); } + @Inherited + @InterceptorBinding + @Target({ElementType.TYPE}) + @Retention(RetentionPolicy.RUNTIME) + @Counted + @interface Binding { + class Literal extends AnnotationLiteral implements Binding { + + private static final long serialVersionUID = 1L; + + private static final Literal INSTANCE = new Literal(); + + static Literal getInstance() { + return INSTANCE; + } + + private Literal() { + } + } + } } diff --git a/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/InterceptorMetered.java b/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/InterceptorMetered.java index f564ea847ee..05445d01120 100644 --- a/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/InterceptorMetered.java +++ b/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/InterceptorMetered.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021 Oracle and/or its affiliates. + * Copyright (c) 2018, 2022 Oracle and/or its affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,19 +16,30 @@ package io.helidon.microprofile.metrics; +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + import jakarta.annotation.Priority; +import jakarta.enterprise.util.AnnotationLiteral; import jakarta.interceptor.Interceptor; +import jakarta.interceptor.InterceptorBinding; import org.eclipse.microprofile.metrics.Meter; import org.eclipse.microprofile.metrics.annotation.Metered; /** * Interceptor for {@link Metered} annotation. */ -@Metered +@InterceptorMetered.Binding @Interceptor @Priority(Interceptor.Priority.PLATFORM_BEFORE + 9) final class InterceptorMetered extends MetricsInterceptorBase { + static Binding.Literal binding() { + return Binding.Literal.getInstance(); + } InterceptorMetered() { super(Metered.class, Meter.class); } @@ -37,5 +48,25 @@ final class InterceptorMetered extends MetricsInterceptorBase { void preInvoke(Meter metric) { metric.mark(); } + @Inherited + @InterceptorBinding + @Target({ElementType.TYPE}) + @Retention(RetentionPolicy.RUNTIME) + @Metered + @interface Binding { + class Literal extends AnnotationLiteral implements Binding { + + private static final long serialVersionUID = 1L; + + private static final Literal INSTANCE = new Literal(); + + static Literal getInstance() { + return INSTANCE; + } + + private Literal() { + } + } + } } diff --git a/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/InterceptorSimplyTimed.java b/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/InterceptorSimplyTimed.java index 23744da4b3f..35d169e4df8 100644 --- a/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/InterceptorSimplyTimed.java +++ b/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/InterceptorSimplyTimed.java @@ -16,9 +16,18 @@ package io.helidon.microprofile.metrics; +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + import jakarta.annotation.Priority; +import jakarta.enterprise.util.AnnotationLiteral; import jakarta.interceptor.Interceptor; +import jakarta.interceptor.InterceptorBinding; import org.eclipse.microprofile.metrics.SimpleTimer; +import org.eclipse.microprofile.metrics.annotation.Metered; import org.eclipse.microprofile.metrics.annotation.SimplyTimed; /** @@ -29,11 +38,15 @@ * method, and the separate {@link InterceptorSyntheticRestRequest} interceptor deals with those. *

*/ -@SimplyTimed +@InterceptorSimplyTimed.Binding @Interceptor @Priority(Interceptor.Priority.PLATFORM_BEFORE + 10) final class InterceptorSimplyTimed extends InterceptorTimedBase { + static Binding.Literal binding() { + return Binding.Literal.getInstance(); + } + InterceptorSimplyTimed() { super(SimplyTimed.class, SimpleTimer.class); } @@ -43,4 +56,24 @@ void postComplete(SimpleTimer metric) { metric.update(duration()); } + @Inherited + @InterceptorBinding + @Target({ElementType.TYPE}) + @Retention(RetentionPolicy.RUNTIME) + @Metered + @interface Binding { + class Literal extends AnnotationLiteral implements Binding { + + private static final long serialVersionUID = 1L; + + private static final Literal INSTANCE = new Literal(); + + static Literal getInstance() { + return INSTANCE; + } + + private Literal() { + } + } + } } diff --git a/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/InterceptorTimed.java b/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/InterceptorTimed.java index 9906e12a883..f77148a2ec3 100644 --- a/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/InterceptorTimed.java +++ b/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/InterceptorTimed.java @@ -16,21 +16,32 @@ package io.helidon.microprofile.metrics; +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; import java.time.Duration; import jakarta.annotation.Priority; +import jakarta.enterprise.util.AnnotationLiteral; import jakarta.interceptor.Interceptor; +import jakarta.interceptor.InterceptorBinding; import org.eclipse.microprofile.metrics.Timer; import org.eclipse.microprofile.metrics.annotation.Timed; /** * Interceptor for {@link Timed} annotation. */ -@Timed +@InterceptorTimed.Binding @Interceptor @Priority(Interceptor.Priority.PLATFORM_BEFORE + 10) final class InterceptorTimed extends InterceptorTimedBase { + static Binding.Literal binding() { + return Binding.Literal.getInstance(); + } + InterceptorTimed() { super(Timed.class, Timer.class); } @@ -39,4 +50,24 @@ final class InterceptorTimed extends InterceptorTimedBase { void postComplete(Timer metric) { metric.update(Duration.ofNanos(durationNanoseconds())); } + @Inherited + @InterceptorBinding + @Target({ElementType.TYPE}) + @Retention(RetentionPolicy.RUNTIME) + @Timed + @interface Binding { + class Literal extends AnnotationLiteral implements Binding { + + private static final long serialVersionUID = 1L; + + private static final Literal INSTANCE = new Literal(); + + static Literal getInstance() { + return INSTANCE; + } + + private Literal() { + } + } + } } diff --git a/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/MetricAnnotationDiscoveryImpl.java b/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/MetricAnnotationDiscoveryImpl.java new file mode 100644 index 00000000000..db918288086 --- /dev/null +++ b/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/MetricAnnotationDiscoveryImpl.java @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2022 Oracle and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package io.helidon.microprofile.metrics; + +import java.lang.annotation.Annotation; + +import jakarta.enterprise.inject.spi.configurator.AnnotatedConstructorConfigurator; +import jakarta.enterprise.inject.spi.configurator.AnnotatedMethodConfigurator; +import jakarta.enterprise.inject.spi.configurator.AnnotatedTypeConfigurator; + +/** + * Implementation of metrics annotation discovery event. + *

+ * The {@link jakarta.enterprise.inject.spi.configurator.AnnotatedConstructorConfigurator} and + * {@link jakarta.enterprise.inject.spi.configurator.AnnotatedMethodConfigurator} interfaces share no common ancestor, so + * we have two subtypes of discovery, one for each: + * {@link io.helidon.microprofile.metrics.MetricAnnotationDiscoveryImpl.OfConstructor OfConstructor} and + * {@link io.helidon.microprofile.metrics.MetricAnnotationDiscoveryObserver.MetricAnnotationDiscovery.OfMethod ofMethod}. + *

+ * + */ +abstract class MetricAnnotationDiscoveryImpl implements MetricAnnotationDiscoveryObserver.MetricAnnotationDiscovery { + + static MetricAnnotationDiscoveryImpl create( + AnnotatedTypeConfigurator annotatedTypeConfigurator, + C annotatedCallableConfigurator, + Annotation annotation) { + if (annotatedCallableConfigurator instanceof AnnotatedConstructorConfigurator) { + return new OfConstructor(annotatedTypeConfigurator, + (AnnotatedConstructorConfigurator) annotatedCallableConfigurator, + annotation); + } else if (annotatedCallableConfigurator instanceof AnnotatedMethodConfigurator) { + return new OfMethod(annotatedTypeConfigurator, + (AnnotatedMethodConfigurator) annotatedCallableConfigurator, + annotation); + } else { + throw new IllegalArgumentException(String.format("annotatedCallableConfigurator must be of type %s or %s", + AnnotatedConstructorConfigurator.class.getName(), + AnnotatedMethodConfigurator.class.getName())); + } + } + + + private final AnnotatedTypeConfigurator annotatedTypeConfigurator; + private final Annotation annotation; + + private boolean disableDefaultInterceptor = false; + + private MetricAnnotationDiscoveryImpl(AnnotatedTypeConfigurator annotatedTypeConfigurator, + Annotation annotation) { + this.annotatedTypeConfigurator = annotatedTypeConfigurator; + this.annotation = annotation; + } + + @Override + public AnnotatedTypeConfigurator annotatedTypeConfigurator() { + return annotatedTypeConfigurator; + } + + @Override + public Annotation annotation() { + return annotation; + } + + @Override + public void disableDefaultInterceptor() { + disableDefaultInterceptor = true; + } + + boolean isDisableDefaultInterceptor() { + return disableDefaultInterceptor; + } + + private static class OfConstructor extends MetricAnnotationDiscoveryImpl + implements MetricAnnotationDiscoveryObserver.MetricAnnotationDiscovery.OfConstructor { + + private final AnnotatedConstructorConfigurator configurator; + + private OfConstructor( + AnnotatedTypeConfigurator annotatedTypeConfigurator, + AnnotatedConstructorConfigurator annotatedConstructorConfigurator, + Annotation annotation) { + super(annotatedTypeConfigurator, annotation); + configurator = annotatedConstructorConfigurator; + } + + @Override + public AnnotatedConstructorConfigurator configurator() { + return configurator; + } + } + + private static class OfMethod extends MetricAnnotationDiscoveryImpl + implements MetricAnnotationDiscoveryObserver.MetricAnnotationDiscovery.OfMethod { + + private final AnnotatedMethodConfigurator configurator; + + private OfMethod( + AnnotatedTypeConfigurator annotatedTypeConfigurator, + AnnotatedMethodConfigurator annotatedMethodConfigurator, + Annotation annotation) { + super(annotatedTypeConfigurator, annotation); + configurator = annotatedMethodConfigurator; + } + + @Override + public AnnotatedMethodConfigurator configurator() { + return configurator; + } + } +} diff --git a/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/MetricAnnotationDiscoveryObserver.java b/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/MetricAnnotationDiscoveryObserver.java new file mode 100644 index 00000000000..ae4c1511a48 --- /dev/null +++ b/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/MetricAnnotationDiscoveryObserver.java @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2022 Oracle and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package io.helidon.microprofile.metrics; + +import java.lang.annotation.Annotation; + +import jakarta.enterprise.inject.spi.configurator.AnnotatedConstructorConfigurator; +import jakarta.enterprise.inject.spi.configurator.AnnotatedMethodConfigurator; +import jakarta.enterprise.inject.spi.configurator.AnnotatedTypeConfigurator; + +/** + * Observer of the discovery of metric annotations which are applied to constructors and methods. + *

+ * Implementations make themselves known via the Java service loader mechanism. + *

+ *

+ * Once registered, the observer is notified later, during {@code ProcessAnnotatedType}, for each metric annotation that is + * discovered to apply to an executable, via a + * {@link io.helidon.microprofile.metrics.MetricAnnotationDiscoveryObserver.MetricAnnotationDiscovery} event. + *

+ */ +public interface MetricAnnotationDiscoveryObserver { + + /** + * Notifies the observer that a metric annotation has been discovered to apply to a constructor or method. + * + * @param metricAnnotationDiscovery the discovery event + */ + void onDiscovery(MetricAnnotationDiscovery metricAnnotationDiscovery); + + /** + * Conveys information about the discovery of a metric annotation as it applies to an executable. + *

+ * The discovery event describes the executable to which the metric annotation applies. + * This is not necessarily where the annotation appears, because a metric annotation which appears on the + * type applies to all methods and constructors on that type. + * In that case, the discovery event describes the discovery of the metric as applied + * to the method or constructor, not to the type itself. + * Further, a metric annotation declared at the type level triggers a separate discovery event for each constructor + * and method on the type. + *

+ */ + interface MetricAnnotationDiscovery { + + /** + * Returns the configurator for the annotated type containing the site to which the metric annotation applies. + * + * @return the configurator for the annotated type + */ + AnnotatedTypeConfigurator annotatedTypeConfigurator(); + + /** + * Returns the {@link java.lang.annotation.Annotation} object for the metric annotation discovered. + * + * @return the annotation object for the metrics annotation + */ + Annotation annotation(); + + /** + * Requests that the default metrics interceptor not be used for the metric corresponding to the indicated annotation + * which appears on this method. + */ + void disableDefaultInterceptor(); + + /** + * Discovery of an annotation of interest on a constructor. + */ + interface OfConstructor extends MetricAnnotationDiscovery { + + /** + * + * @return the configurator for the constructor on which an annotation of interest appears + */ + AnnotatedConstructorConfigurator configurator(); + } + + /** + * Discovery of an annotation of interest on a method. + */ + interface OfMethod extends MetricAnnotationDiscovery { + + /** + * + * @return the configurotor for the method on which an annotation of interest appears + */ + AnnotatedMethodConfigurator configurator(); + } + } +} diff --git a/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/MetricAnnotationInfo.java b/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/MetricAnnotationInfo.java index 70b5ae433a5..c6edce347e4 100644 --- a/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/MetricAnnotationInfo.java +++ b/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/MetricAnnotationInfo.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 Oracle and/or its affiliates. + * Copyright (c) 2021, 2022 Oracle and/or its affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -123,6 +123,10 @@ Class annotationType() { return annotationType; } + Metadata metadata() { + return metadata; + } + Metric register(MetricRegistry registry) { return registration.register(registry, metadata, tags); } diff --git a/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/MetricRegistrationObserver.java b/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/MetricRegistrationObserver.java new file mode 100644 index 00000000000..16c13b49f24 --- /dev/null +++ b/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/MetricRegistrationObserver.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2022 Oracle and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package io.helidon.microprofile.metrics; + +import io.helidon.microprofile.metrics.MetricAnnotationDiscoveryObserver.MetricAnnotationDiscovery; + +import org.eclipse.microprofile.metrics.Metadata; +import org.eclipse.microprofile.metrics.Metric; +import org.eclipse.microprofile.metrics.MetricID; + +/** + * Observer of the registration of metrics due to metric annotations applied to executables--constructors and methods. + *

+ * Implementations make themselves known via the Java service loader mechanism. + *

+ *

+ * Once registered, the observer is notified each time a metric required by a metric annotation is registered. + *

+ */ +public interface MetricRegistrationObserver { + + /** + * Notifies the observer that a metric has been registered due to a metric annotation that applies to an executable. + * + * @param discovery the {@link MetricAnnotationDiscovery} + * triggering this metric registration + * @param metadata the metrics {@link org.eclipse.microprofile.metrics.Metadata} for the indicated metric + * @param metricId the {@link org.eclipse.microprofile.metrics.MetricID} for the indicated metric + * @param metric the metric associated with the discovery index + */ + void onRegistration(MetricAnnotationDiscovery discovery, Metadata metadata, MetricID metricId, Metric metric); +} diff --git a/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/MetricUtil.java b/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/MetricUtil.java index 126faeb3137..9b46662ace3 100644 --- a/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/MetricUtil.java +++ b/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/MetricUtil.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021 Oracle and/or its affiliates. + * Copyright (c) 2018, 2022 Oracle and/or its affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -32,77 +32,19 @@ import jakarta.enterprise.inject.spi.Annotated; import jakarta.enterprise.inject.spi.AnnotatedMember; -import jakarta.enterprise.inject.spi.AnnotatedMethod; import jakarta.enterprise.inject.spi.AnnotatedType; -import org.eclipse.microprofile.metrics.Metadata; import org.eclipse.microprofile.metrics.MetricRegistry; -import org.eclipse.microprofile.metrics.MetricType; import org.eclipse.microprofile.metrics.Tag; -import org.eclipse.microprofile.metrics.annotation.ConcurrentGauge; -import org.eclipse.microprofile.metrics.annotation.Counted; -import org.eclipse.microprofile.metrics.annotation.Metered; -import org.eclipse.microprofile.metrics.annotation.SimplyTimed; -import org.eclipse.microprofile.metrics.annotation.Timed; /** * Class MetricUtil. */ -public final class MetricUtil { +final class MetricUtil { private static final Logger LOGGER = Logger.getLogger(MetricUtil.class.getName()); private MetricUtil() { } - /** - * DO NOT USE THIS METHOD please, it will be removed. - *

- * Instead, see {@link MatchingType}. - *

- * - * @param element element - * @param annotClass annotation class - * @param clazz class - * @param element type - * @param
annotation type - * @return lookup result - * @deprecated This method is made public to migrate from metrics1 to metrics2 for gRPC, this should be refactored. - * This method will be removed outside of major version of Helidon. - */ - @SuppressWarnings("unchecked") - @Deprecated - public static - LookupResult lookupAnnotation(E element, Class annotClass, Class clazz) { - // First check annotation on element - A annotation = (A) element.getAnnotation(annotClass); - if (annotation != null) { - return new LookupResult<>(MatchingType.METHOD, annotation); - } - // Finally check annotations on class - annotation = (A) element.getDeclaringClass().getAnnotation(annotClass); - if (annotation == null) { - annotation = (A) clazz.getAnnotation(annotClass); - } - return annotation == null ? null : new LookupResult<>(MatchingType.CLASS, annotation); - } - - @Deprecated - static LookupResult lookupAnnotation( - AnnotatedType annotatedType, - AnnotatedMethod annotatedMethod, - Class annotClass) { - A annotation = annotatedMethod.getAnnotation(annotClass); - if (annotation != null) { - return new LookupResult<>(matchingType(annotatedMethod), annotation); - } - - annotation = annotatedType.getAnnotation(annotClass); - if (annotation == null) { - annotation = annotatedType.getJavaClass().getAnnotation(annotClass); - } - return annotation == null ? null : new LookupResult<>(MatchingType.CLASS, annotation); - } - - @Deprecated static List> lookupAnnotations( AnnotatedType annotatedType, AnnotatedMember annotatedMember, @@ -165,8 +107,7 @@ static Stream metricsAnnotationsOnElement(Annotated an * * @return name of the metric */ - @Deprecated - public static + static String getMetricName(Member element, Class clazz, MatchingType matchingType, String explicitName, boolean absolute) { String result; if (matchingType == MatchingType.METHOD) { @@ -204,182 +145,6 @@ String getMetricName(Member element, Class clazz, MatchingType matchingType, return result; } - /** - * Register a metric. - * - * @param registry the metric registry in which to register the metric - * @param element the annotated element - * @param clazz the annotated class - * @param annotation the annotation to register - * @param type the {@link MatchingType} indicating the type of annotated element - * @param the annotated element type - */ - @Deprecated - public static - void registerMetric(MetricRegistry registry, E element, Class clazz, Annotation annotation, MatchingType type) { - - if (annotation instanceof Counted) { - Counted counted = (Counted) annotation; - String metricName = getMetricName(element, clazz, type, counted.name().trim(), counted.absolute()); - String displayName = counted.displayName().trim(); - Metadata meta = Metadata.builder() - .withName(metricName) - .withDisplayName(displayName.isEmpty() ? metricName : displayName) - .withDescription(counted.description().trim()) - .withType(MetricType.COUNTER) - .withUnit(counted.unit().trim()) - .build(); - registry.counter(meta, tags(counted.tags())); - LOGGER.fine(() -> "### Registered counter " + metricName); - } else if (annotation instanceof Metered) { - Metered metered = (Metered) annotation; - String metricName = getMetricName(element, clazz, type, metered.name().trim(), metered.absolute()); - String displayName = metered.displayName().trim(); - Metadata meta = Metadata.builder() - .withName(metricName) - .withDisplayName(displayName.isEmpty() ? metricName : displayName) - .withDescription(metered.description().trim()) - .withType(MetricType.METERED) - .withUnit(metered.unit().trim()) - .build(); - registry.meter(meta, tags(metered.tags())); - LOGGER.fine(() -> "### Registered meter " + metricName); - } else if (annotation instanceof ConcurrentGauge) { - ConcurrentGauge concurrentGauge = (ConcurrentGauge) annotation; - String metricName = getMetricName(element, clazz, type, concurrentGauge.name().trim(), - concurrentGauge.absolute()); - String displayName = concurrentGauge.displayName().trim(); - Metadata meta = Metadata.builder() - .withName(metricName) - .withDisplayName(displayName.isEmpty() ? metricName : displayName) - .withDescription(concurrentGauge.description().trim()) - .withType(MetricType.METERED) - .withUnit(concurrentGauge.unit().trim()).build(); - registry.concurrentGauge(meta, tags(concurrentGauge.tags())); - LOGGER.fine(() -> "### Registered ConcurrentGauge " + metricName); - } else if (annotation instanceof Timed) { - Timed timed = (Timed) annotation; - String metricName = getMetricName(element, clazz, type, timed.name().trim(), timed.absolute()); - String displayName = timed.displayName().trim(); - Metadata meta = Metadata.builder() - .withName(metricName) - .withDisplayName(displayName.isEmpty() ? metricName : displayName) - .withDescription(timed.description().trim()) - .withType(MetricType.TIMER) - .withUnit(timed.unit().trim()) - .build(); - registry.timer(meta, tags(timed.tags())); - LOGGER.fine(() -> "### Registered timer " + metricName); - } else if (annotation instanceof SimplyTimed) { - SimplyTimed simplyTimed = (SimplyTimed) annotation; - String metricName = getMetricName(element, clazz, type, simplyTimed.name().trim(), simplyTimed.absolute()); - String displayName = simplyTimed.displayName().trim(); - Metadata meta = Metadata.builder() - .withName(metricName) - .withDisplayName(displayName.isEmpty() ? metricName : displayName) - .withDescription(simplyTimed.description().trim()) - .withType(MetricType.SIMPLE_TIMER) - .withUnit(simplyTimed.unit().trim()) - .build(); - registry.simpleTimer(meta, tags(simplyTimed.tags())); - LOGGER.fine(() -> "### Registered simple timer " + metricName); - } - } - - /** - * Register a metric. - * - * @param element the annotated element - * @param clazz the annotated class - * @param lookupResult the annotation lookup result - * @param the annotated element type - */ - public static - void registerMetric(E element, Class clazz, LookupResult lookupResult) { - registerMetric(element, clazz, lookupResult.getAnnotation(), lookupResult.getType()); - } - - /** - * Register a metric. - * - * @param element the annotated element - * @param clazz the annotated class - * @param annotation the annotation to register - * @param type the {@link MatchingType} indicating the type of annotated element - * @param the annotated element type - */ - public static - void registerMetric(E element, Class clazz, Annotation annotation, MatchingType type) { - MetricRegistry registry = getMetricRegistry(); - - if (annotation instanceof Counted) { - Counted counted = (Counted) annotation; - String metricName = getMetricName(element, clazz, type, counted.name().trim(), counted.absolute()); - String displayName = counted.displayName().trim(); - Metadata meta = Metadata.builder() - .withName(metricName) - .withDisplayName(displayName.isEmpty() ? metricName : displayName) - .withDescription(counted.description().trim()) - .withType(MetricType.COUNTER) - .withUnit(counted.unit().trim()) - .build(); - registry.counter(meta); - LOGGER.fine(() -> "### Registered counter " + metricName); - } else if (annotation instanceof Metered) { - Metered metered = (Metered) annotation; - String metricName = getMetricName(element, clazz, type, metered.name().trim(), metered.absolute()); - String displayName = metered.displayName().trim(); - Metadata meta = Metadata.builder() - .withName(metricName) - .withDisplayName(displayName.isEmpty() ? metricName : displayName) - .withDescription(metered.description().trim()) - .withType(MetricType.METERED) - .withUnit(metered.unit().trim()) - .build(); - registry.meter(meta); - LOGGER.fine(() -> "### Registered meter " + metricName); - } else if (annotation instanceof ConcurrentGauge) { - ConcurrentGauge concurrentGauge = (ConcurrentGauge) annotation; - String metricName = getMetricName(element, clazz, type, concurrentGauge.name().trim(), - concurrentGauge.absolute()); - String displayName = concurrentGauge.displayName().trim(); - Metadata meta = Metadata.builder() - .withName(metricName) - .withDisplayName(displayName.isEmpty() ? metricName : displayName) - .withDescription(concurrentGauge.description().trim()) - .withType(MetricType.METERED) - .withUnit(concurrentGauge.unit().trim()).build(); - registry.concurrentGauge(meta); - LOGGER.fine(() -> "### Registered ConcurrentGauge " + metricName); - } else if (annotation instanceof Timed) { - Timed timed = (Timed) annotation; - String metricName = getMetricName(element, clazz, type, timed.name().trim(), timed.absolute()); - String displayName = timed.displayName().trim(); - Metadata meta = Metadata.builder() - .withName(metricName) - .withDisplayName(displayName.isEmpty() ? metricName : displayName) - .withDescription(timed.description().trim()) - .withType(MetricType.TIMER) - .withUnit(timed.unit().trim()) - .build(); - registry.timer(meta); - LOGGER.fine(() -> "### Registered timer " + metricName); - } else if (annotation instanceof SimplyTimed) { - SimplyTimed simplyTimed = (SimplyTimed) annotation; - String metricName = getMetricName(element, clazz, type, simplyTimed.name().trim(), simplyTimed.absolute()); - String displayName = simplyTimed.displayName().trim(); - Metadata meta = Metadata.builder() - .withName(metricName) - .withDisplayName(displayName.isEmpty() ? metricName : displayName) - .withDescription(simplyTimed.description().trim()) - .withType(MetricType.SIMPLE_TIMER) - .withUnit(simplyTimed.unit().trim()) - .build(); - registry.timer(meta); - LOGGER.fine(() -> "### Registered simple timer " + metricName); - } - } - private static MetricRegistry getMetricRegistry() { return RegistryProducer.getDefaultRegistry(); } @@ -401,14 +166,7 @@ static Tag[] tags(String[] tagStrings) { return result.toArray(new Tag[result.size()]); } - /** - * DO NOT USE THIS CLASS please. - * - * Types of possible matching. - * @deprecated This class is made public to migrate from metrics1 to metrics2 for gRPC, this should be refactored - */ - @Deprecated - public enum MatchingType { + enum MatchingType { /** * Method. */ @@ -426,13 +184,7 @@ private static MatchingType matchingType(Annotated annotated) { : MatchingType.CLASS; } - /** - * DO NOT USE THIS CLASS please. - * @param type of annotation - * @deprecated This class is made public to migrate from metrics1 to metrics2 for gRPC, this should be refactored - */ - @Deprecated - public static class LookupResult { + static class LookupResult { private final MatchingType type; @@ -454,7 +206,7 @@ public static class LookupResult { * * @return matching type */ - public MatchingType getType() { + MatchingType getType() { return type; } @@ -463,7 +215,7 @@ public MatchingType getType() { * * @return the annotation */ - public A getAnnotation() { + A getAnnotation() { return annotation; } } diff --git a/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/MetricsCdiExtension.java b/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/MetricsCdiExtension.java index e13b5573042..1f4a5a76032 100644 --- a/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/MetricsCdiExtension.java +++ b/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/MetricsCdiExtension.java @@ -18,7 +18,6 @@ import java.lang.annotation.Annotation; import java.lang.reflect.AnnotatedElement; -import java.lang.reflect.Constructor; import java.lang.reflect.Executable; import java.lang.reflect.Member; import java.lang.reflect.Method; @@ -31,9 +30,10 @@ import java.util.HashSet; import java.util.List; import java.util.Map; -import java.util.Optional; +import java.util.ServiceLoader; import java.util.Set; -import java.util.concurrent.atomic.AtomicReference; +import java.util.function.BiFunction; +import java.util.function.Function; import java.util.logging.Level; import java.util.logging.Logger; import java.util.stream.Collectors; @@ -41,6 +41,7 @@ import io.helidon.common.Errors; import io.helidon.common.context.Contexts; +import io.helidon.common.serviceloader.HelidonServiceLoader; import io.helidon.config.Config; import io.helidon.config.ConfigSources; import io.helidon.config.ConfigValue; @@ -50,6 +51,8 @@ import io.helidon.metrics.serviceapi.MetricsSupport; import io.helidon.microprofile.metrics.MetricAnnotationInfo.RegistrationPrep; import io.helidon.microprofile.metrics.MetricUtil.LookupResult; +import io.helidon.microprofile.metrics.api.MetricAnnotationDiscoveryObserverProvider; +import io.helidon.microprofile.metrics.api.MetricRegistrationObserverProvider; import io.helidon.microprofile.server.ServerCdiExtension; import io.helidon.servicecommon.restcdi.HelidonRestCdiExtension; import io.helidon.webserver.Routing; @@ -63,7 +66,6 @@ import jakarta.enterprise.inject.spi.AfterDeploymentValidation; import jakarta.enterprise.inject.spi.Annotated; import jakarta.enterprise.inject.spi.AnnotatedCallable; -import jakarta.enterprise.inject.spi.AnnotatedMember; import jakarta.enterprise.inject.spi.AnnotatedMethod; import jakarta.enterprise.inject.spi.AnnotatedType; import jakarta.enterprise.inject.spi.Bean; @@ -73,7 +75,10 @@ import jakarta.enterprise.inject.spi.ProcessAnnotatedType; import jakarta.enterprise.inject.spi.ProcessManagedBean; import jakarta.enterprise.inject.spi.WithAnnotations; +import jakarta.enterprise.inject.spi.configurator.AnnotatedConstructorConfigurator; +import jakarta.enterprise.inject.spi.configurator.AnnotatedMethodConfigurator; import jakarta.enterprise.inject.spi.configurator.AnnotatedTypeConfigurator; +import jakarta.enterprise.util.AnnotationLiteral; import jakarta.inject.Singleton; import jakarta.interceptor.Interceptor; import jakarta.ws.rs.DELETE; @@ -106,8 +111,9 @@ * *

* Earlier versions of this class detected app-provided producer fields and methods and triggered creation and registration - * of the corresponding metrics upon such detection. As explained in - * https://github.com/eclipse/microprofile-metrics/issues/456 and https://github.com/eclipse/microprofile-metrics/pull/594 + * of the corresponding metrics upon such detection. As explained in this + * MP metrics issue + * and this MP metrics PR, * this probably was never correct and does not work because {@code @Metric} no longer applies to producers per the * MP metrics 3.0 spec. The issue and PR discussion explain how developers who provide their own producers should use * CDI qualifiers on the producers (and, therefore, injection points) to avoid ambiguity between their own producers and @@ -122,12 +128,16 @@ public class MetricsCdiExtension extends HelidonRestCdiExtension private static final Logger LOGGER = Logger.getLogger(MetricsCdiExtension.class.getName()); - static final Class[] ALL_METRIC_ANNOTATIONS_ARRAY = - (Class[]) new Class[] - {Counted.class, Metered.class, Timed.class, ConcurrentGauge.class, SimplyTimed.class, Gauge.class}; + static final Set> ALL_METRIC_ANNOTATIONS = Set.of( + Counted.class, Metered.class, Timed.class, ConcurrentGauge.class, SimplyTimed.class, Gauge.class); - static final Set> ALL_METRIC_ANNOTATIONS = - new HashSet<>(Arrays.asList(ALL_METRIC_ANNOTATIONS_ARRAY)); + private static final Map, AnnotationLiteral> INTERCEPTED_METRIC_ANNOTATIONS = + Map.of( + Counted.class, InterceptorCounted.binding(), + Metered.class, InterceptorMetered.binding(), + Timed.class, InterceptorTimed.binding(), + ConcurrentGauge.class, InterceptorConcurrentGauge.binding(), + SimplyTimed.class, InterceptorSimplyTimed.binding()); private static final List> JAX_RS_ANNOTATIONS = Arrays.asList(GET.class, PUT.class, POST.class, HEAD.class, OPTIONS.class, DELETE.class, PATCH.class); @@ -170,10 +180,6 @@ public class MetricsCdiExtension extends HelidonRestCdiExtension .withUnit(MetricUnits.NONE) .build(); - // only for compatibility with gRPC usage of registerMetric - @Deprecated - private static final List LEGACY_ANNOTATED_SITES = new ArrayList<>(); - private boolean restEndpointsMetricsEnabled = REST_ENDPOINTS_METRIC_ENABLED_DEFAULT_VALUE; private final Map> annotatedGaugeSites = new HashMap<>(); @@ -185,11 +191,15 @@ public class MetricsCdiExtension extends HelidonRestCdiExtension private final Set> restRequestMetricsClassesProcessed = new HashSet<>(); private final Set restRequestMetricsToRegister = new HashSet<>(); - private final AtomicReference config = new AtomicReference<>(); - private final AtomicReference metricsConfig = new AtomicReference<>(); - private final WorkItemsManager workItemsManager = WorkItemsManager.create(); + private final List metricAnnotationDiscoveryObservers = new ArrayList<>(); + private final List metricRegistrationObservers = new ArrayList<>(); + + private final Map metricAnnotationDiscoveriesByExecutable = new HashMap<>(); + + @SuppressWarnings("unchecked") + // records stereotype annotations which have metrics annotations inside them private final Map, StereotypeMetricsInfo> stereotypeMetricsInfo = new HashMap<>(); @@ -205,44 +215,6 @@ public MetricsCdiExtension() { super(LOGGER, MetricsSupport::create, "metrics"); } - /** - * DO NOT USE THIS METHOD please. - * - * @param element element - * @param clazz class - * @param lookupResult lookup result - * @param type of element - * @deprecated This method is made public to migrate from metrics1 to metrics2 for gRPC, this should be refactored - */ - @SuppressWarnings("rawtypes") - @Deprecated - public static - void registerMetric(E element, Class clazz, LookupResult lookupResult) { - Executable executable; - if (element instanceof AnnotatedCallable) { - executable = (Executable) ((AnnotatedCallable) element).getJavaMember(); - } else if (element instanceof Constructor) { - // code checking instanceof Executable and casting to it would not compile on Java17 - executable = (Constructor) element; - } else if (element instanceof Method) { - executable = (Method) element; - } else { - throw new IllegalArgumentException("Element must be an AnnotatedCallable or Executable but was " - + element.getClass().getName()); - } - - registerMetricInternal(LEGACY_ANNOTATED_SITES, element, clazz, lookupResult, executable); - } - - static - void registerMetricInternal(List sites, - E element, - Class clazz, - LookupResult lookupResult, - Executable executable) { - recordAnnotatedSite(sites, element, clazz, lookupResult, executable); - } - private static void recordAnnotatedSite( List sites, E element, @@ -258,32 +230,22 @@ private static void recordAnnotatedSite( private void registerMetricsForAnnotatedSites() { MetricRegistry registry = getMetricRegistry(); - List.of(annotatedSites, LEGACY_ANNOTATED_SITES) - .forEach(sites -> { - for (RegistrationPrep registrationPrep : sites) { - org.eclipse.microprofile.metrics.Metric metric = registrationPrep.register(registry); - workItemsManager.put(registrationPrep.executable(), registrationPrep.annotationType(), - BasicMetricWorkItem - .create(new MetricID(registrationPrep.metricName(), - registrationPrep.tags()), - metric)); - } - sites.clear(); - }); - } - - /** - * For test use only. - * - * This method is used from gRPC integration tests and should not be used elsewhere. - */ - @Deprecated - protected static void registerMetricsForAnnotatedSitesFromGrpcTest() { - MetricRegistry registry = getMetricRegistry(); - for (RegistrationPrep registrationPrep : LEGACY_ANNOTATED_SITES) { - registrationPrep.register(registry); - } - LEGACY_ANNOTATED_SITES.clear(); + for (RegistrationPrep registrationPrep : annotatedSites) { + org.eclipse.microprofile.metrics.Metric metric = registrationPrep.register(registry); + MetricID metricID = new MetricID(registrationPrep.metricName(), registrationPrep.tags()); + MetricAnnotationDiscoveryObserver.MetricAnnotationDiscovery discovery = + metricAnnotationDiscoveriesByExecutable.get(registrationPrep.executable()); + metricRegistrationObservers.forEach(o -> o.onRegistration(discovery, + registrationPrep.metadata(), + metricID, + metric)); + workItemsManager.put(registrationPrep.executable(), registrationPrep.annotationType(), + BasicMetricWorkItem + .create(new MetricID(registrationPrep.metricName(), + registrationPrep.tags()), + metric)); + } + annotatedSites.clear(); } @Override @@ -391,6 +353,11 @@ void before(@Observes BeforeBeanDiscovery discovery) { discovery.addAnnotatedType(SyntheticRestRequest.class, SyntheticRestRequest.class.getName()); restEndpointsMetricsEnabled = restEndpointsMetricsEnabled(); + + HelidonServiceLoader.create(ServiceLoader.load(MetricAnnotationDiscoveryObserverProvider.class)) + .forEach(p -> metricAnnotationDiscoveryObservers.add(p.get())); + HelidonServiceLoader.create(ServiceLoader.load(MetricRegistrationObserverProvider.class)) + .forEach(p -> metricRegistrationObservers.add(p.get())); } @Override @@ -406,27 +373,97 @@ public void clearAnnotationInfo(@Observes AfterDeploymentValidation adv) { * observe managed beans (which CDI invokes for all managed beans) where we also have to examine each method and * constructor, we can quickly eliminate from consideration any classes we have not recorded here. * + * This observer runs after other {@code ProcessAnnotatedType} observers to give other extensions a chance to provide their + * own interceptors for selected constructors and methods by adding {@link MetricAnnotationDiscoveryObserver} + * to the configured type, constructor, or method. + * * @param pat ProcessAnnotatedType event */ - private void recordMetricAnnotatedClass(@Observes - @WithAnnotations({Counted.class, Metered.class, Timed.class, ConcurrentGauge.class, SimplyTimed.class, Gauge.class}) - ProcessAnnotatedType pat) { + private void recordMetricAnnotatedClass(@Observes @Priority(Interceptor.Priority.APPLICATION + 500 + 10) + @WithAnnotations({Counted.class, + Metered.class, + Timed.class, + ConcurrentGauge.class, + SimplyTimed.class}) ProcessAnnotatedType pat) { if (isConcreteNonInterceptor(pat)) { recordAnnotatedType(pat); + recordStereotypes(pat); + + /* + Wherever metrics annotations appear--at the type, at each constructor, and at each method--record those sites + and, if the annotation discovery observers concur, set up the normal metrics interceptors as needed. + + We need to visit all the possible sites now so we can add the private interceptor-bound annotations as + appropriate. + + */ + bindInterceptors(pat); + } + } + + private void bindInterceptors(ProcessAnnotatedType pat) { + + // Sadly, the various AnnotatedXXXConfigurator types do not share a common supertype, so we deal with each individually + // using plenty of method references. + + AnnotatedTypeConfigurator annotatedTypeConfigurator = pat.configureAnnotatedType(); + + bindInterceptorsAndRecordDiscoveries(annotatedTypeConfigurator, + pat.configureAnnotatedType().constructors(), + AnnotatedConstructorConfigurator::getAnnotated, + AnnotatedConstructorConfigurator::add); + + bindInterceptorsAndRecordDiscoveries(annotatedTypeConfigurator, + pat.configureAnnotatedType().methods(), + AnnotatedMethodConfigurator::getAnnotated, + (BiFunction, Annotation, + AnnotatedMethodConfigurator>) AnnotatedMethodConfigurator::add); + } + + private > void bindInterceptorsAndRecordDiscoveries( + AnnotatedTypeConfigurator annotatedTypeConfigurator, + Iterable executableConfigurators, + Function configuratorAnnotatedGetter, + BiFunction annotationAdder) { + executableConfigurators.forEach(executableConfigurator -> { + // Process all metric annotations which apply to this executable, either from the type-level or from this + // executable itself. + A annotatedCallable = configuratorAnnotatedGetter.apply(executableConfigurator); + Executable exec = (annotatedCallable.getJavaMember() instanceof Executable) + ? (Executable) annotatedCallable.getJavaMember() + : null; + metricsLookupResults(annotatedTypeConfigurator.getAnnotated(), + annotatedCallable) + .forEach(lookupResult -> { + MetricAnnotationDiscoveryImpl discoveryEvent = MetricAnnotationDiscoveryImpl.create( + annotatedTypeConfigurator, + executableConfigurator, + lookupResult.getAnnotation()); + if (exec != null) { + metricAnnotationDiscoveriesByExecutable.put(exec, discoveryEvent); + metricAnnotationDiscoveryObservers.forEach(observer -> observer.onDiscovery(discoveryEvent)); + } + if (!discoveryEvent.isDisableDefaultInterceptor()) { + Class metricAnnotationClass = lookupResult.getAnnotation().annotationType(); + annotationAdder.apply(executableConfigurator, + INTERCEPTED_METRIC_ANNOTATIONS.get(metricAnnotationClass)); + } + }); + }); + } - // Find and record stereotypes applied to the type or its members which themselves carry metrics annotations. - AnnotatedType annotatedType = pat.getAnnotatedType(); - - Stream.concat(Stream.of(annotatedType), - Stream.concat(pat.getAnnotatedType().getMethods().stream(), - Stream.concat(pat.getAnnotatedType().getConstructors().stream(), - pat.getAnnotatedType().getFields().stream()))) - .map(Annotated::getAnnotations) - .flatMap(Set::stream) - .distinct() - .filter(MetricsCdiExtension::isStereotype) - .forEach(this::recordIfMetricsRelatedStereotype); - } + private void recordStereotypes(ProcessAnnotatedType pat) { + AnnotatedType annotatedType = pat.getAnnotatedType(); + // Find and record stereotypes applied to the type or its members which themselves carry metrics annotations. + Stream.concat(Stream.of(annotatedType), + Stream.concat(pat.getAnnotatedType().getMethods().stream(), + Stream.concat(pat.getAnnotatedType().getConstructors().stream(), + pat.getAnnotatedType().getFields().stream()))) + .map(Annotated::getAnnotations) + .flatMap(Set::stream) + .distinct() + .filter(MetricsCdiExtension::isStereotype) + .forEach(this::recordIfMetricsRelatedStereotype); } private static boolean isStereotype(Annotation annotation) { @@ -444,6 +481,34 @@ private void recordIfMetricsRelatedStereotype(Annotation stereotypeAnnotation) { } } + /** + * Collects all {@code LookupResult} objects for metrics annotations on a given annotated executable. + * + * @param annotatedType the annotated type containing the constructor or method + * @param annotatedMember the constructor or method + * @return {@code LookupResult} instances that apply to the executable + */ + private Iterable> metricsLookupResults(AnnotatedType annotatedType, + AnnotatedCallable annotatedMember) { + List> result = new ArrayList<>(); + INTERCEPTED_METRIC_ANNOTATIONS.keySet().forEach(metricAnnotationClass -> { + result.addAll(MetricUtil.lookupAnnotations(annotatedType, + annotatedMember, + metricAnnotationClass, + stereotypeMetricsInfo)); + }); + return result; + } + +// private Set> metricsAnnotationClasses(Annotated annotated) { +// return annotated +// .getAnnotations() +// .stream() +// .map(Annotation::annotationType) +// .filter(METRIC_ANNOTATIONS::containsKey) +// .collect(Collectors.toSet()); +// } + /** * Checks to make sure the annotated type is not abstract and is not an interceptor. * @@ -729,23 +794,6 @@ private static boolean chooseRestEndpointsSetting(Config metricsConfig) { return result; } - private static MetricType getMetricType(T metric) { - // Find subtype of Metric, needed for user-defined metrics - Class clazz = metric.getClass(); - do { - Optional> optionalClass = Arrays.stream(clazz.getInterfaces()) - .filter(org.eclipse.microprofile.metrics.Metric.class::isAssignableFrom) - .findFirst(); - if (optionalClass.isPresent()) { - clazz = optionalClass.get(); - break; - } - clazz = clazz.getSuperclass(); - } while (clazz != null); - - return MetricType.from(clazz == null ? metric.getClass() : clazz); - } - private void recordAnnotatedGaugeSite(@Observes ProcessManagedBean pmb) { AnnotatedType type = pmb.getAnnotatedBeanClass(); Class clazz = type.getJavaClass(); @@ -904,61 +952,10 @@ private static Class typeToNumber(Class clazz) { return narrowedReturnType; } - static class AnnotatedElementWrapper implements AnnotatedElement, Member { - - private final AnnotatedMember annotatedMember; - - AnnotatedElementWrapper(AnnotatedMember annotatedMember) { - this.annotatedMember = annotatedMember; - } - - @Override - public boolean isAnnotationPresent(Class annotationClass) { - return annotatedMember.isAnnotationPresent(annotationClass); - } - - @Override - public T getAnnotation(Class annotationClass) { - return annotatedMember.getAnnotation(annotationClass); - } - - @Override - public Annotation[] getAnnotations() { - return annotatedMember.getAnnotations().toArray(new Annotation[] {}); - } - - @Override - public Annotation[] getDeclaredAnnotations() { - return getAnnotations(); - } - - @Override - public Class getDeclaringClass() { - return annotatedMember.getDeclaringType().getJavaClass(); - } - - @Override - public String getName() { - return annotatedMember.getJavaMember().getName(); - } - - @Override - public int getModifiers() { - return annotatedMember.getJavaMember().getModifiers(); - } - - @Override - public boolean isSynthetic() { - return annotatedMember.getJavaMember().isSynthetic(); - } - } - - static record StereotypeMetricsInfo(Set metricsAnnotations) { + record StereotypeMetricsInfo(Set metricsAnnotations) { static StereotypeMetricsInfo create(Set metricsAnnotations) { return new StereotypeMetricsInfo(metricsAnnotations); } } - - } diff --git a/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/api/MetricAnnotationDiscoveryObserverProvider.java b/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/api/MetricAnnotationDiscoveryObserverProvider.java new file mode 100644 index 00000000000..759c2a62300 --- /dev/null +++ b/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/api/MetricAnnotationDiscoveryObserverProvider.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2022 Oracle and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.helidon.microprofile.metrics.api; + +import java.util.function.Supplier; + +import io.helidon.microprofile.metrics.MetricAnnotationDiscoveryObserver; + +/** + * Specifies behavior of a provider for a metric annotation discovery observer. + * + * @param specific type of {@link io.helidon.microprofile.metrics.MetricAnnotationDiscoveryObserver} + */ +public interface MetricAnnotationDiscoveryObserverProvider extends Supplier { + + /** + * + * @return the new or pre-existing instance of the observer + */ + T get(); +} diff --git a/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/api/MetricRegistrationObserverProvider.java b/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/api/MetricRegistrationObserverProvider.java new file mode 100644 index 00000000000..e6453e187cf --- /dev/null +++ b/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/api/MetricRegistrationObserverProvider.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2022 Oracle and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.helidon.microprofile.metrics.api; + +import java.util.function.Supplier; + +import io.helidon.microprofile.metrics.MetricRegistrationObserver; + +/** + * Specifies behavior of a provider for a metric annotation discovery observer. + * + * @param specific type of {@link io.helidon.microprofile.metrics.MetricRegistrationObserver} + */ +public interface MetricRegistrationObserverProvider extends Supplier { + + /** + * + * @return new or pre-existing instance of the observer + */ + T get(); +} diff --git a/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/api/package-info.java b/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/api/package-info.java new file mode 100644 index 00000000000..6fa8117119e --- /dev/null +++ b/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/api/package-info.java @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2022 Oracle and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Interfaces optionally implemented by other components interested in key metrics processing events. + */ +package io.helidon.microprofile.metrics.api; diff --git a/microprofile/metrics/src/main/java/module-info.java b/microprofile/metrics/src/main/java/module-info.java index 36e1f7ca2e4..c61298d8dee 100644 --- a/microprofile/metrics/src/main/java/module-info.java +++ b/microprofile/metrics/src/main/java/module-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021 Oracle and/or its affiliates. + * Copyright (c) 2018, 2022 Oracle and/or its affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -31,6 +31,7 @@ requires io.helidon.servicecommon.restcdi; requires io.helidon.microprofile.server; requires io.helidon.microprofile.config; + requires io.helidon.common.serviceloader; requires transitive io.helidon.metrics.api; requires transitive io.helidon.metrics.serviceapi; @@ -39,9 +40,13 @@ requires io.helidon.config.mp; exports io.helidon.microprofile.metrics; + exports io.helidon.microprofile.metrics.api; // this is needed for CDI extensions that use non-public observer methods opens io.helidon.microprofile.metrics to weld.core.impl, io.helidon.microprofile.cdi; provides jakarta.enterprise.inject.spi.Extension with io.helidon.microprofile.metrics.MetricsCdiExtension; + + uses io.helidon.microprofile.metrics.api.MetricAnnotationDiscoveryObserverProvider; + uses io.helidon.microprofile.metrics.api.MetricRegistrationObserverProvider; } diff --git a/microprofile/metrics/src/test/java/io/helidon/microprofile/metrics/TestDiscoveryObserverImpl.java b/microprofile/metrics/src/test/java/io/helidon/microprofile/metrics/TestDiscoveryObserverImpl.java new file mode 100644 index 00000000000..ad81925a72a --- /dev/null +++ b/microprofile/metrics/src/test/java/io/helidon/microprofile/metrics/TestDiscoveryObserverImpl.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2022 Oracle and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.helidon.microprofile.metrics; + +import java.util.ArrayList; +import java.util.List; + +import io.helidon.common.LazyValue; +import io.helidon.microprofile.metrics.api.MetricAnnotationDiscoveryObserverProvider; + +public class TestDiscoveryObserverImpl implements MetricAnnotationDiscoveryObserver { + + public static class Provider implements MetricAnnotationDiscoveryObserverProvider { + + private static final LazyValue instance = LazyValue.create(TestDiscoveryObserverImpl::new); + + @Override + public TestDiscoveryObserverImpl get() { + return instance(); + } + + static TestDiscoveryObserverImpl instance() { + return instance.get(); + } + } + private List discoveries = new ArrayList<>(); + + @Override + public void onDiscovery(MetricAnnotationDiscoveryObserver.MetricAnnotationDiscovery metricAnnotationDiscovery) { + discoveries.add(metricAnnotationDiscovery); + } + + List discoveries() { + return discoveries; + } +} diff --git a/microprofile/metrics/src/test/java/io/helidon/microprofile/metrics/TestObservers.java b/microprofile/metrics/src/test/java/io/helidon/microprofile/metrics/TestObservers.java new file mode 100644 index 00000000000..784cce19422 --- /dev/null +++ b/microprofile/metrics/src/test/java/io/helidon/microprofile/metrics/TestObservers.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2022 Oracle and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.helidon.microprofile.metrics; + +import io.helidon.microprofile.tests.junit5.HelidonTest; + +import org.junit.jupiter.api.Test; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.not; + +@HelidonTest +public class TestObservers { + + @Test + void testDiscoveryObserver() { + TestDiscoveryObserverImpl observer = TestDiscoveryObserverImpl.Provider.instance(); + assertThat("Observer's discoveries", observer.discoveries().size(), is(not(0))); + } + + @Test + void testRegistrationObserver() { + TestRegistrationObserverImpl observer = TestRegistrationObserverImpl.Provider.instance(); + assertThat("Observer's registrations", observer.registrations(), is(not(0))); + } +} diff --git a/microprofile/metrics/src/test/java/io/helidon/microprofile/metrics/TestRegistrationObserverImpl.java b/microprofile/metrics/src/test/java/io/helidon/microprofile/metrics/TestRegistrationObserverImpl.java new file mode 100644 index 00000000000..269c269901c --- /dev/null +++ b/microprofile/metrics/src/test/java/io/helidon/microprofile/metrics/TestRegistrationObserverImpl.java @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2022 Oracle and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.helidon.microprofile.metrics; + +import io.helidon.common.LazyValue; +import io.helidon.microprofile.metrics.api.MetricRegistrationObserverProvider; + +import org.eclipse.microprofile.metrics.Metadata; +import org.eclipse.microprofile.metrics.Metric; +import org.eclipse.microprofile.metrics.MetricID; + +public class TestRegistrationObserverImpl implements MetricRegistrationObserver { + + public static class Provider implements MetricRegistrationObserverProvider { + + private static final LazyValue instance = + LazyValue.create(TestRegistrationObserverImpl::new); + + @Override + public TestRegistrationObserverImpl get() { + return instance(); + } + + static TestRegistrationObserverImpl instance() { + return instance.get(); + } + } + private int registrations; + + @Override + public void onRegistration(MetricAnnotationDiscoveryObserver.MetricAnnotationDiscovery discovery, + Metadata metadata, + MetricID metricId, + Metric metric) { + registrations++; + } + + int registrations() { + return registrations; + } +} diff --git a/microprofile/metrics/src/test/resources/META-INF/services/io.helidon.microprofile.metrics.api.MetricAnnotationDiscoveryObserverProvider b/microprofile/metrics/src/test/resources/META-INF/services/io.helidon.microprofile.metrics.api.MetricAnnotationDiscoveryObserverProvider new file mode 100644 index 00000000000..9219aec9e5c --- /dev/null +++ b/microprofile/metrics/src/test/resources/META-INF/services/io.helidon.microprofile.metrics.api.MetricAnnotationDiscoveryObserverProvider @@ -0,0 +1,17 @@ +# +# Copyright (c) 2022 Oracle and/or its affiliates. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +io.helidon.microprofile.metrics.TestDiscoveryObserverImpl$Provider \ No newline at end of file diff --git a/microprofile/metrics/src/test/resources/META-INF/services/io.helidon.microprofile.metrics.api.MetricRegistrationObserverProvider b/microprofile/metrics/src/test/resources/META-INF/services/io.helidon.microprofile.metrics.api.MetricRegistrationObserverProvider new file mode 100644 index 00000000000..830cdf15475 --- /dev/null +++ b/microprofile/metrics/src/test/resources/META-INF/services/io.helidon.microprofile.metrics.api.MetricRegistrationObserverProvider @@ -0,0 +1,17 @@ +# +# Copyright (c) 2022 Oracle and/or its affiliates. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +io.helidon.microprofile.metrics.TestRegistrationObserverImpl$Provider \ No newline at end of file diff --git a/tests/integration/mp-grpc/pom.xml b/tests/integration/mp-grpc/pom.xml index 606d03a0be2..76fb280d474 100644 --- a/tests/integration/mp-grpc/pom.xml +++ b/tests/integration/mp-grpc/pom.xml @@ -44,11 +44,20 @@ helidon-microprofile-server test + + io.helidon.metrics + helidon-metrics-api + io.helidon.microprofile.metrics helidon-microprofile-metrics provided + + io.helidon.microprofile.tests + helidon-microprofile-tests-junit5 + test + org.junit.jupiter junit-jupiter-api @@ -91,8 +100,8 @@ test - org.jboss.weld - weld-junit5 + io.helidon.microprofile.weld + weld-se-core test diff --git a/tests/integration/mp-grpc/src/test/java/io/helidon/microprofile/grpc/metrics/MetricsConfigurerTest.java b/tests/integration/mp-grpc/src/test/java/io/helidon/microprofile/grpc/metrics/MetricsConfigurerTest.java index 258f497b856..c5060f76c28 100644 --- a/tests/integration/mp-grpc/src/test/java/io/helidon/microprofile/grpc/metrics/MetricsConfigurerTest.java +++ b/tests/integration/mp-grpc/src/test/java/io/helidon/microprofile/grpc/metrics/MetricsConfigurerTest.java @@ -23,13 +23,20 @@ import io.helidon.grpc.server.GrpcService; import io.helidon.grpc.server.MethodDescriptor; import io.helidon.grpc.server.ServiceDescriptor; -import io.helidon.metrics.RegistryFactory; +import io.helidon.metrics.api.RegistryFactory; import io.helidon.microprofile.grpc.core.Grpc; import io.helidon.microprofile.grpc.core.Unary; import io.grpc.ServerInterceptor; import io.grpc.stub.StreamObserver; + import io.helidon.microprofile.grpc.server.JavaMarshaller; +import io.helidon.microprofile.tests.junit5.AddBean; +import io.helidon.microprofile.tests.junit5.DisableDiscovery; +import io.helidon.microprofile.tests.junit5.HelidonTest; + +import jakarta.enterprise.inject.spi.CDI; +import jakarta.inject.Inject; import org.eclipse.microprofile.metrics.MetricID; import org.eclipse.microprofile.metrics.MetricRegistry; import org.eclipse.microprofile.metrics.MetricType; @@ -39,6 +46,7 @@ import org.eclipse.microprofile.metrics.annotation.SimplyTimed; import org.eclipse.microprofile.metrics.annotation.Timed; import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import static org.hamcrest.CoreMatchers.instanceOf; @@ -48,10 +56,18 @@ import static org.hamcrest.collection.IsEmptyIterable.emptyIterable; +@HelidonTest public class MetricsConfigurerTest { private static MetricRegistry registry; + private CDI weld; + + @BeforeEach + void setupPerTest() { + weld = CDI.current(); + } + @BeforeAll public static void setup() { registry = RegistryFactory.getInstance().getRegistry(MetricRegistry.Type.APPLICATION); @@ -410,18 +426,7 @@ public void timed(String request, StreamObserver response) { } private static MetricRegistry updReg() { - MyMetricsCdiExtension.registerGrpcMetrics(); +// MyMetricsCdiExtension.registerGrpcMetrics(); return registry; } - - /** - * Used only for very limited testing purposes. - */ - @Deprecated - private static class MyMetricsCdiExtension extends io.helidon.microprofile.metrics.MetricsCdiExtension { - - static void registerGrpcMetrics() { - MyMetricsCdiExtension.registerMetricsForAnnotatedSitesFromGrpcTest(); - } - } } diff --git a/tests/integration/mp-grpc/src/test/java/io/helidon/microprofile/grpc/server/GrpcServerTestProducer.java b/tests/integration/mp-grpc/src/test/java/io/helidon/microprofile/grpc/server/GrpcServerTestProducer.java new file mode 100644 index 00000000000..6a89183b4be --- /dev/null +++ b/tests/integration/mp-grpc/src/test/java/io/helidon/microprofile/grpc/server/GrpcServerTestProducer.java @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2022 Oracle and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.helidon.microprofile.grpc.server; + +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeoutException; + +import io.helidon.grpc.server.GrpcServer; + +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.enterprise.inject.Produces; + +@ApplicationScoped +public class GrpcServerTestProducer { + + +// GrpcServer serverFactory() throws ExecutionException, InterruptedException, TimeoutException { +// return AnnotatedServiceTest.createServer(); +// } +} diff --git a/tests/integration/mp-grpc/src/test/java/io/helidon/microprofile/grpc/server/InterceptorsTest.java b/tests/integration/mp-grpc/src/test/java/io/helidon/microprofile/grpc/server/InterceptorsTest.java index 2c45c7e01ac..632c73646b1 100644 --- a/tests/integration/mp-grpc/src/test/java/io/helidon/microprofile/grpc/server/InterceptorsTest.java +++ b/tests/integration/mp-grpc/src/test/java/io/helidon/microprofile/grpc/server/InterceptorsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019,2020 Oracle and/or its affiliates. + * Copyright (c) 2019, 2022 Oracle and/or its affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -27,6 +27,7 @@ import io.helidon.microprofile.grpc.core.GrpcInterceptorBinding; import io.helidon.microprofile.grpc.core.GrpcInterceptors; import io.helidon.microprofile.grpc.core.Unary; +import io.helidon.microprofile.tests.junit5.HelidonTest; import io.grpc.Metadata; import io.grpc.ServerCall; @@ -34,11 +35,9 @@ import io.grpc.ServerInterceptor; import jakarta.enterprise.context.ApplicationScoped; import jakarta.enterprise.inject.spi.BeanManager; -import org.jboss.weld.junit5.WeldInitiator; -import org.jboss.weld.junit5.WeldJunit5Extension; -import org.jboss.weld.junit5.WeldSetup; +import jakarta.enterprise.inject.spi.CDI; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; import static java.lang.annotation.ElementType.METHOD; import static java.lang.annotation.ElementType.TYPE; @@ -49,22 +48,16 @@ /** * Functional test for server side interceptors using annotations. */ -@ExtendWith(WeldJunit5Extension.class) +@HelidonTest @SuppressWarnings("unchecked") public class InterceptorsTest { - @WeldSetup - public WeldInitiator weld = WeldInitiator.of(ServerInterceptorOne.class, - ServerInterceptorTwo.class, - ServerInterceptorThree.class, - ServerInterceptorFour.class, - InterceptedServiceOne.class, - InterceptedServiceTwo.class, - InterceptedServiceThree.class, - InterceptedServiceFour.class, - InterceptedServiceFive.class, - InterceptedServiceSix.class); + private CDI weld; + @BeforeEach + void setup() { + weld = CDI.current(); + } @Test public void shouldDiscoverServiceInterceptor() { BeanManager beanManager = weld.getBeanManager(); diff --git a/tests/integration/mp-grpc/src/test/resources/META-INF/microprofile-config.properties b/tests/integration/mp-grpc/src/test/resources/META-INF/microprofile-config.properties new file mode 100644 index 00000000000..da7e8dad824 --- /dev/null +++ b/tests/integration/mp-grpc/src/test/resources/META-INF/microprofile-config.properties @@ -0,0 +1,17 @@ +# +# Copyright (c) 2022 Oracle and/or its affiliates. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +grpc.port=0 \ No newline at end of file From ddbb83d5ba38b68cf5c2cfe93e11ef7318d72ae6 Mon Sep 17 00:00:00 2001 From: "tim.quinn@oracle.com" Date: Fri, 8 Jul 2022 00:33:56 -0500 Subject: [PATCH 2/9] Add ability for observers to prevent registration of metrics; fix ambig resolution of gRPC metrics integration test beans --- ...MetricAnnotationDiscoveryObserverImpl.java | 31 ++++++++---- .../MetricRegistrationObserverImpl.java | 12 +++-- .../grpc/metrics/MetricsConfigurer.java | 27 ++-------- .../MetricAnnotationDiscoveryImpl.java | 10 ++++ .../MetricAnnotationDiscoveryObserver.java | 5 ++ .../metrics/MetricsCdiExtension.java | 38 +++++++------- .../grpc/metrics/MetricsConfigurerTest.java | 49 +++++++++++-------- 7 files changed, 99 insertions(+), 73 deletions(-) diff --git a/microprofile/grpc/metrics/src/main/java/io/helidon/microprofile/grpc/metrics/MetricAnnotationDiscoveryObserverImpl.java b/microprofile/grpc/metrics/src/main/java/io/helidon/microprofile/grpc/metrics/MetricAnnotationDiscoveryObserverImpl.java index f577ceb8c49..e7b131a5e8f 100644 --- a/microprofile/grpc/metrics/src/main/java/io/helidon/microprofile/grpc/metrics/MetricAnnotationDiscoveryObserverImpl.java +++ b/microprofile/grpc/metrics/src/main/java/io/helidon/microprofile/grpc/metrics/MetricAnnotationDiscoveryObserverImpl.java @@ -36,28 +36,36 @@ static MetricAnnotationDiscoveryObserverImpl instance() { return MetricAnnotationDiscoveryObserverImplFactory.instance(); } - public MetricAnnotationDiscoveryObserverImpl() { - int i = 3; - } private final Map, MetricAnnotationDiscovery.OfMethod>> discoveriesByMethod = new HashMap<>(); @Override - public void onDiscovery(MetricAnnotationDiscovery metricAnnotationDiscovery) { - if (metricAnnotationDiscovery instanceof MetricAnnotationDiscovery.OfMethod discovery) { - if (isRpcMethod(discovery.configurator(), discovery.annotation().annotationType())) { + public void onDiscovery(MetricAnnotationDiscovery discovery) { + if (discovery instanceof MetricAnnotationDiscovery.OfMethod methodDiscovery + && !isServiceAnnotated(discovery.annotatedTypeConfigurator() + .getAnnotated() + .getJavaClass(), + methodDiscovery.configurator() + .getAnnotated(), + discovery.annotation().annotationType())) { + discovery.discard(); + return; + } + + if (discovery instanceof MetricAnnotationDiscovery.OfMethod methodDiscovery) { + if (isRpcMethod(methodDiscovery.configurator(), discovery.annotation().annotationType())) { discovery.disableDefaultInterceptor(); - discoveriesByMethod.computeIfAbsent(discovery.configurator().getAnnotated().getJavaMember(), + discoveriesByMethod.computeIfAbsent(methodDiscovery.configurator().getAnnotated().getJavaMember(), key -> new HashMap<>()) .putIfAbsent(discovery.annotation().annotationType(), - discovery); + methodDiscovery); } } } - Map, MetricAnnotationDiscovery.OfMethod> discovery(Method method) { + Map, MetricAnnotationDiscovery.OfMethod> discoveries(Method method) { return discoveriesByMethod.get(method); } @@ -83,4 +91,9 @@ private static boolean isRpcMethod(AnnotatedMethodConfigurator configurator, } return false; } + + private boolean isServiceAnnotated(Class cls, jakarta.enterprise.inject.spi.AnnotatedMethod annotatedMethod, Class annotation) { + Method method = annotatedMethod.getJavaMember(); + return method.getDeclaringClass().equals(cls) && method.isAnnotationPresent(annotation); + } } diff --git a/microprofile/grpc/metrics/src/main/java/io/helidon/microprofile/grpc/metrics/MetricRegistrationObserverImpl.java b/microprofile/grpc/metrics/src/main/java/io/helidon/microprofile/grpc/metrics/MetricRegistrationObserverImpl.java index b3bb6cb39b4..551f4344c1a 100644 --- a/microprofile/grpc/metrics/src/main/java/io/helidon/microprofile/grpc/metrics/MetricRegistrationObserverImpl.java +++ b/microprofile/grpc/metrics/src/main/java/io/helidon/microprofile/grpc/metrics/MetricRegistrationObserverImpl.java @@ -15,12 +15,15 @@ */ package io.helidon.microprofile.grpc.metrics; +import java.lang.annotation.Annotation; +import java.lang.reflect.Method; import java.util.HashMap; import java.util.Map; import io.helidon.microprofile.metrics.MetricAnnotationDiscoveryObserver.MetricAnnotationDiscovery; import io.helidon.microprofile.metrics.MetricRegistrationObserver; +import jakarta.enterprise.inject.spi.AnnotatedMethod; import org.eclipse.microprofile.metrics.Metadata; import org.eclipse.microprofile.metrics.Metric; import org.eclipse.microprofile.metrics.MetricID; @@ -33,15 +36,16 @@ class MetricRegistrationObserverImpl implements MetricRegistrationObserver { private final Map metadataByDiscovery = new HashMap<>(); - public MetricRegistrationObserverImpl() { - int i = 4; - } - @Override public void onRegistration(MetricAnnotationDiscovery discovery, Metadata metadata, MetricID metricId, Metric metric) { + for (MetricAnnotationDiscovery d : metadataByDiscovery.keySet()) { + if (d.equals(discovery)) { + int x = 2; + } + } metadataByDiscovery.put(discovery, metadata); } diff --git a/microprofile/grpc/metrics/src/main/java/io/helidon/microprofile/grpc/metrics/MetricsConfigurer.java b/microprofile/grpc/metrics/src/main/java/io/helidon/microprofile/grpc/metrics/MetricsConfigurer.java index 9c2bc35a1ef..e863ce204c4 100644 --- a/microprofile/grpc/metrics/src/main/java/io/helidon/microprofile/grpc/metrics/MetricsConfigurer.java +++ b/microprofile/grpc/metrics/src/main/java/io/helidon/microprofile/grpc/metrics/MetricsConfigurer.java @@ -92,8 +92,8 @@ public void accept(Class serviceClass, Class annotatedClass, ServiceDescri .forEach(annotatedMethod -> discoveries(annotatedMethod.method()) .forEach((annotationClass, discovery) -> - metadata(annotatedMethod.method()) - .forEach(metadata -> +// metadata(annotatedMethod.method()) +// .forEach(metadata -> processMetricAnnotationSite( builder, annotatedMethod, @@ -102,17 +102,12 @@ public void accept(Class serviceClass, Class annotatedClass, ServiceDescri .grpcMetricsSupplier .get(), discovery.annotation(), - metadata) + metadata(discovery) ) ) ); } - private boolean isServiceAnnotated(Class cls, AnnotatedMethod annotatedMethod, Class annotation) { - Method method = annotatedMethod.declaredMethod(); - return method.getDeclaringClass().equals(cls) && method.isAnnotationPresent(annotation); - } - private void processMetricAnnotationSite(ServiceDescriptor.Builder builder, AnnotatedMethod annotatedMethod, GrpcMetrics interceptor, @@ -167,23 +162,11 @@ private boolean isDiscovered(Method method) { return MetricAnnotationDiscoveryObserverImpl.instance().isDiscovered(method); } - private Map, MetricAnnotationDiscoveryObserver.MetricAnnotationDiscovery.OfMethod> discovery(Method method) { - return MetricAnnotationDiscoveryObserverImpl.instance().discovery(method); - } - private Metadata metadata(MetricAnnotationDiscoveryObserver.MetricAnnotationDiscovery discovery) { return MetricRegistrationObserverImpl.instance().metadata(discovery); } - Iterable metadata(Method method){ - return discovery(method) - .values() - .stream() - .map(this::metadata) - .collect(Collectors.toList()); - } - - Map, MetricAnnotationDiscoveryObserver.MetricAnnotationDiscovery.OfMethod> discoveries(Method method) { - return discovery(method); + private Map, MetricAnnotationDiscoveryObserver.MetricAnnotationDiscovery.OfMethod> discoveries(Method method) { + return MetricAnnotationDiscoveryObserverImpl.instance().discoveries(method); } } diff --git a/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/MetricAnnotationDiscoveryImpl.java b/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/MetricAnnotationDiscoveryImpl.java index db918288086..4ddc04cf935 100644 --- a/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/MetricAnnotationDiscoveryImpl.java +++ b/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/MetricAnnotationDiscoveryImpl.java @@ -58,6 +58,7 @@ static MetricAnnotationDiscoveryImpl create( private final AnnotatedTypeConfigurator annotatedTypeConfigurator; private final Annotation annotation; + private boolean keepDiscovery = true; private boolean disableDefaultInterceptor = false; private MetricAnnotationDiscoveryImpl(AnnotatedTypeConfigurator annotatedTypeConfigurator, @@ -76,11 +77,20 @@ public Annotation annotation() { return annotation; } + @Override + public void discard() { + keepDiscovery = false; + } + @Override public void disableDefaultInterceptor() { disableDefaultInterceptor = true; } + boolean isValid() { + return keepDiscovery; + } + boolean isDisableDefaultInterceptor() { return disableDefaultInterceptor; } diff --git a/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/MetricAnnotationDiscoveryObserver.java b/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/MetricAnnotationDiscoveryObserver.java index ae4c1511a48..d3572af975e 100644 --- a/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/MetricAnnotationDiscoveryObserver.java +++ b/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/MetricAnnotationDiscoveryObserver.java @@ -70,6 +70,11 @@ interface MetricAnnotationDiscovery { */ Annotation annotation(); + /** + * Requests that the discovery be discarded, triggering no metric registration. + */ + void discard(); + /** * Requests that the default metrics interceptor not be used for the metric corresponding to the indicated annotation * which appears on this method. diff --git a/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/MetricsCdiExtension.java b/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/MetricsCdiExtension.java index 1f4a5a76032..601ddc7908c 100644 --- a/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/MetricsCdiExtension.java +++ b/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/MetricsCdiExtension.java @@ -196,7 +196,7 @@ public class MetricsCdiExtension extends HelidonRestCdiExtension private final List metricAnnotationDiscoveryObservers = new ArrayList<>(); private final List metricRegistrationObservers = new ArrayList<>(); - private final Map metricAnnotationDiscoveriesByExecutable = new HashMap<>(); + private final Map> metricAnnotationDiscoveriesByExecutable = new HashMap<>(); @SuppressWarnings("unchecked") @@ -230,22 +230,23 @@ private static void recordAnnotatedSite( private void registerMetricsForAnnotatedSites() { MetricRegistry registry = getMetricRegistry(); - for (RegistrationPrep registrationPrep : annotatedSites) { - org.eclipse.microprofile.metrics.Metric metric = registrationPrep.register(registry); - MetricID metricID = new MetricID(registrationPrep.metricName(), registrationPrep.tags()); - MetricAnnotationDiscoveryObserver.MetricAnnotationDiscovery discovery = - metricAnnotationDiscoveriesByExecutable.get(registrationPrep.executable()); - metricRegistrationObservers.forEach(o -> o.onRegistration(discovery, - registrationPrep.metadata(), - metricID, - metric)); - workItemsManager.put(registrationPrep.executable(), registrationPrep.annotationType(), - BasicMetricWorkItem - .create(new MetricID(registrationPrep.metricName(), - registrationPrep.tags()), - metric)); - } - annotatedSites.clear(); + for (RegistrationPrep registrationPrep : annotatedSites) { + metricAnnotationDiscoveriesByExecutable.get(registrationPrep.executable()) + .forEach(discovery -> { + if (discovery.isValid()) { // All annotation observers agreed to preserve the discovery. + org.eclipse.microprofile.metrics.Metric metric = registrationPrep.register(registry); + MetricID metricID = new MetricID(registrationPrep.metricName(), registrationPrep.tags()); + metricRegistrationObservers.forEach( + o -> o.onRegistration(discovery, registrationPrep.metadata(), metricID, metric)); + workItemsManager.put(registrationPrep.executable(), registrationPrep.annotationType(), + BasicMetricWorkItem + .create(new MetricID(registrationPrep.metricName(), + registrationPrep.tags()), + metric)); + } + }); + } + annotatedSites.clear(); } @Override @@ -440,7 +441,8 @@ private > void bindInterceptorsAndRecordDis executableConfigurator, lookupResult.getAnnotation()); if (exec != null) { - metricAnnotationDiscoveriesByExecutable.put(exec, discoveryEvent); + metricAnnotationDiscoveriesByExecutable.computeIfAbsent(exec, o -> new ArrayList<>()) + .add(discoveryEvent); metricAnnotationDiscoveryObservers.forEach(observer -> observer.onDiscovery(discoveryEvent)); } if (!discoveryEvent.isDisableDefaultInterceptor()) { diff --git a/tests/integration/mp-grpc/src/test/java/io/helidon/microprofile/grpc/metrics/MetricsConfigurerTest.java b/tests/integration/mp-grpc/src/test/java/io/helidon/microprofile/grpc/metrics/MetricsConfigurerTest.java index c5060f76c28..2c0a3ad5302 100644 --- a/tests/integration/mp-grpc/src/test/java/io/helidon/microprofile/grpc/metrics/MetricsConfigurerTest.java +++ b/tests/integration/mp-grpc/src/test/java/io/helidon/microprofile/grpc/metrics/MetricsConfigurerTest.java @@ -31,12 +31,16 @@ import io.grpc.stub.StreamObserver; import io.helidon.microprofile.grpc.server.JavaMarshaller; +import io.helidon.microprofile.grpc.server.test.Services; import io.helidon.microprofile.tests.junit5.AddBean; -import io.helidon.microprofile.tests.junit5.DisableDiscovery; import io.helidon.microprofile.tests.junit5.HelidonTest; +import jakarta.annotation.Priority; +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.enterprise.inject.Alternative; +import jakarta.enterprise.inject.Produces; import jakarta.enterprise.inject.spi.CDI; -import jakarta.inject.Inject; +import jakarta.interceptor.Interceptor; import org.eclipse.microprofile.metrics.MetricID; import org.eclipse.microprofile.metrics.MetricRegistry; import org.eclipse.microprofile.metrics.MetricType; @@ -57,6 +61,9 @@ @HelidonTest +@AddBean(MetricsConfigurerTest.ServiceOne.class) +@AddBean(MetricsConfigurerTest.ServiceTwo.class) +@AddBean(MetricsConfigurerTest.ServiceThree.class) public class MetricsConfigurerTest { private static MetricRegistry registry; @@ -313,8 +320,9 @@ public void shouldIgnoreConcurrentGaugeMetricFromInterfaceAnnotation() { assertThat(methodInterceptors, is(emptyIterable())); } - @Grpc + @Priority(Interceptor.Priority.APPLICATION + 1) // resolves CDI ambiguity with ServiceThree (which extends ServiceOne) + @Alternative public static class ServiceOne implements GrpcService { @Override @@ -329,27 +337,27 @@ public void update(ServiceDescriptor.Rules rules) { @Unary @Counted - public void counted(String request, StreamObserver response) { + public void counted(Services.TestRequest request, StreamObserver response) { } @Unary @Timed - public void timed(String request, StreamObserver response) { + public void timed(Services.TestRequest request, StreamObserver response) { } @Unary @Metered - public void metered(String request, StreamObserver response) { + public void metered(Services.TestRequest request, StreamObserver response) { } @Unary @SimplyTimed - public void simplyTimed(String request, StreamObserver response) { + public void simplyTimed(Services.TestRequest request, StreamObserver response) { } @Unary @ConcurrentGauge - public void concurrentGauge(String request, StreamObserver response) { + public void concurrentGauge(Services.TestRequest request, StreamObserver response) { } } @@ -359,23 +367,23 @@ public interface ServiceTwo { @Unary @Counted - void counted(String request, StreamObserver response); + void counted(Services.TestRequest request, StreamObserver response); @Unary @Timed - void timed(String request, StreamObserver response); + void timed(Services.TestRequest request, StreamObserver response); @Unary @Metered - void metered(String request, StreamObserver response); + void metered(Services.TestRequest request, StreamObserver response); @Unary @SimplyTimed - void simplyTimed(String request, StreamObserver response); + void simplyTimed(Services.TestRequest request, StreamObserver response); @Unary @ConcurrentGauge - void concurrentGauge(String request, StreamObserver response); + void concurrentGauge(Services.TestRequest request, StreamObserver response); } public static class ServiceTwoImpl @@ -391,36 +399,37 @@ public void update(ServiceDescriptor.Rules rules) { } @Override - public void counted(String request, StreamObserver response) { + public void counted(Services.TestRequest request, StreamObserver response) { } @Override - public void timed(String request, StreamObserver response) { + public void timed(Services.TestRequest request, StreamObserver response) { } @Override - public void metered(String request, StreamObserver response) { + public void metered(Services.TestRequest request, StreamObserver response) { } @Override - public void simplyTimed(String request, StreamObserver response) { + public void simplyTimed(Services.TestRequest request, StreamObserver response) { } @Override - public void concurrentGauge(String request, StreamObserver response) { + public void concurrentGauge(Services.TestRequest request, StreamObserver response) { } } + @Alternative public static class ServiceThree extends ServiceOne { @Override @Counted(name = "foo") - public void counted(String request, StreamObserver response) { + public void counted(Services.TestRequest request, StreamObserver response) { super.counted(request, response); } @Override - public void timed(String request, StreamObserver response) { + public void timed(Services.TestRequest request, StreamObserver response) { super.timed(request, response); } } From 48ba80252cd7f7d1be1dbeb432b0bab1756b3488 Mon Sep 17 00:00:00 2001 From: "tim.quinn@oracle.com" Date: Fri, 8 Jul 2022 16:24:10 -0500 Subject: [PATCH 3/9] Mostly adjustments to gRPC metrics configurer test set-up; a bit of doc, style clean-up --- ...etricAnnotationDiscoveryObserverImpl.java} | 42 +++++------ ...notationDiscoveryObserverImplFactory.java} | 18 +++-- ...> GrpcMetricRegistrationObserverImpl.java} | 14 +--- ...etricRegistrationObserverImplFactory.java} | 16 +++-- .../grpc/metrics/GrpcMetricsCdiExtension.java | 71 ------------------- .../grpc/metrics/MetricsConfigurer.java | 66 +++++++++-------- .../metrics/src/main/java/module-info.java | 10 +-- .../grpc/metrics/TestMetricsCoverage.java | 2 +- .../MetricAnnotationDiscoveryImpl.java | 44 +++++++++--- .../MetricAnnotationDiscoveryObserver.java | 6 +- .../metrics/MetricsCdiExtension.java | 4 +- .../grpc/metrics/MetricsConfigurerTest.java | 65 +++++++++-------- 12 files changed, 160 insertions(+), 198 deletions(-) rename microprofile/grpc/metrics/src/main/java/io/helidon/microprofile/grpc/metrics/{MetricAnnotationDiscoveryObserverImpl.java => GrpcMetricAnnotationDiscoveryObserverImpl.java} (65%) rename microprofile/grpc/metrics/src/main/java/io/helidon/microprofile/grpc/metrics/{MetricAnnotationDiscoveryObserverImplFactory.java => GrpcMetricAnnotationDiscoveryObserverImplFactory.java} (59%) rename microprofile/grpc/metrics/src/main/java/io/helidon/microprofile/grpc/metrics/{MetricRegistrationObserverImpl.java => GrpcMetricRegistrationObserverImpl.java} (77%) rename microprofile/grpc/metrics/src/main/java/io/helidon/microprofile/grpc/metrics/{MetricRegistrationObserverImplFactory.java => GrpcMetricRegistrationObserverImplFactory.java} (62%) delete mode 100644 microprofile/grpc/metrics/src/main/java/io/helidon/microprofile/grpc/metrics/GrpcMetricsCdiExtension.java diff --git a/microprofile/grpc/metrics/src/main/java/io/helidon/microprofile/grpc/metrics/MetricAnnotationDiscoveryObserverImpl.java b/microprofile/grpc/metrics/src/main/java/io/helidon/microprofile/grpc/metrics/GrpcMetricAnnotationDiscoveryObserverImpl.java similarity index 65% rename from microprofile/grpc/metrics/src/main/java/io/helidon/microprofile/grpc/metrics/MetricAnnotationDiscoveryObserverImpl.java rename to microprofile/grpc/metrics/src/main/java/io/helidon/microprofile/grpc/metrics/GrpcMetricAnnotationDiscoveryObserverImpl.java index e7b131a5e8f..44fe772caac 100644 --- a/microprofile/grpc/metrics/src/main/java/io/helidon/microprofile/grpc/metrics/MetricAnnotationDiscoveryObserverImpl.java +++ b/microprofile/grpc/metrics/src/main/java/io/helidon/microprofile/grpc/metrics/GrpcMetricAnnotationDiscoveryObserverImpl.java @@ -27,40 +27,38 @@ import jakarta.enterprise.inject.spi.configurator.AnnotatedMethodConfigurator; /** - * The gRPC implementation of {@link io.helidon.microprofile.metrics.MetricAnnotationDiscoveryObserver} with a static factory - * method. + * The gRPC implementation of {@link io.helidon.microprofile.metrics.MetricAnnotationDiscoveryObserver}. + * + *

+ * This implementation + *

*/ -class MetricAnnotationDiscoveryObserverImpl implements MetricAnnotationDiscoveryObserver { +class GrpcMetricAnnotationDiscoveryObserverImpl implements MetricAnnotationDiscoveryObserver { - static MetricAnnotationDiscoveryObserverImpl instance() { - return MetricAnnotationDiscoveryObserverImplFactory.instance(); + static GrpcMetricAnnotationDiscoveryObserverImpl instance() { + return GrpcMetricAnnotationDiscoveryObserverImplFactory.instance(); } private final Map, - MetricAnnotationDiscovery.OfMethod>> discoveriesByMethod = + Map, MetricAnnotationDiscovery.OfMethod>> discoveriesByMethod = new HashMap<>(); @Override public void onDiscovery(MetricAnnotationDiscovery discovery) { if (discovery instanceof MetricAnnotationDiscovery.OfMethod methodDiscovery - && !isServiceAnnotated(discovery.annotatedTypeConfigurator() - .getAnnotated() - .getJavaClass(), - methodDiscovery.configurator() - .getAnnotated(), - discovery.annotation().annotationType())) { - discovery.discard(); - return; - } + && isRpcMethod(methodDiscovery.configurator(), discovery.annotation().annotationType())) { - if (discovery instanceof MetricAnnotationDiscovery.OfMethod methodDiscovery) { - if (isRpcMethod(methodDiscovery.configurator(), discovery.annotation().annotationType())) { + if (!MetricsConfigurer.isServiceAnnotated(methodDiscovery.annotatedTypeConfigurator().getAnnotated().getJavaClass(), + methodDiscovery.configurator().getAnnotated().getJavaMember(), + discovery.annotation().annotationType())) { + // This endpoint should not give rise to a gRPC-inspired metric. + discovery.deactivate(); + } else { + // This endpoint SHOULD give rise to a gRPC-inspired metric. discovery.disableDefaultInterceptor(); discoveriesByMethod.computeIfAbsent(methodDiscovery.configurator().getAnnotated().getJavaMember(), key -> new HashMap<>()) - .putIfAbsent(discovery.annotation().annotationType(), - methodDiscovery); + .putIfAbsent(discovery.annotation().annotationType(), methodDiscovery); } } } @@ -92,8 +90,4 @@ private static boolean isRpcMethod(AnnotatedMethodConfigurator configurator, return false; } - private boolean isServiceAnnotated(Class cls, jakarta.enterprise.inject.spi.AnnotatedMethod annotatedMethod, Class annotation) { - Method method = annotatedMethod.getJavaMember(); - return method.getDeclaringClass().equals(cls) && method.isAnnotationPresent(annotation); - } } diff --git a/microprofile/grpc/metrics/src/main/java/io/helidon/microprofile/grpc/metrics/MetricAnnotationDiscoveryObserverImplFactory.java b/microprofile/grpc/metrics/src/main/java/io/helidon/microprofile/grpc/metrics/GrpcMetricAnnotationDiscoveryObserverImplFactory.java similarity index 59% rename from microprofile/grpc/metrics/src/main/java/io/helidon/microprofile/grpc/metrics/MetricAnnotationDiscoveryObserverImplFactory.java rename to microprofile/grpc/metrics/src/main/java/io/helidon/microprofile/grpc/metrics/GrpcMetricAnnotationDiscoveryObserverImplFactory.java index 1291d42202b..6ffd69a526e 100644 --- a/microprofile/grpc/metrics/src/main/java/io/helidon/microprofile/grpc/metrics/MetricAnnotationDiscoveryObserverImplFactory.java +++ b/microprofile/grpc/metrics/src/main/java/io/helidon/microprofile/grpc/metrics/GrpcMetricAnnotationDiscoveryObserverImplFactory.java @@ -18,17 +18,21 @@ import io.helidon.common.LazyValue; import io.helidon.microprofile.metrics.api.MetricAnnotationDiscoveryObserverProvider; -public class MetricAnnotationDiscoveryObserverImplFactory - implements MetricAnnotationDiscoveryObserverProvider { +/** + * Factory for the gRPC metrics observer of metric annotation discoveries. + */ +public class GrpcMetricAnnotationDiscoveryObserverImplFactory + implements MetricAnnotationDiscoveryObserverProvider { - private static final LazyValue instance = - LazyValue.create(MetricAnnotationDiscoveryObserverImpl::new); + private static final LazyValue INSTANCE = + LazyValue.create(GrpcMetricAnnotationDiscoveryObserverImpl::new); - static MetricAnnotationDiscoveryObserverImpl instance() { - return instance.get(); + static GrpcMetricAnnotationDiscoveryObserverImpl instance() { + return INSTANCE.get(); } + @Override - public MetricAnnotationDiscoveryObserverImpl get() { + public GrpcMetricAnnotationDiscoveryObserverImpl get() { return instance(); } } diff --git a/microprofile/grpc/metrics/src/main/java/io/helidon/microprofile/grpc/metrics/MetricRegistrationObserverImpl.java b/microprofile/grpc/metrics/src/main/java/io/helidon/microprofile/grpc/metrics/GrpcMetricRegistrationObserverImpl.java similarity index 77% rename from microprofile/grpc/metrics/src/main/java/io/helidon/microprofile/grpc/metrics/MetricRegistrationObserverImpl.java rename to microprofile/grpc/metrics/src/main/java/io/helidon/microprofile/grpc/metrics/GrpcMetricRegistrationObserverImpl.java index 551f4344c1a..e379d1cbdf2 100644 --- a/microprofile/grpc/metrics/src/main/java/io/helidon/microprofile/grpc/metrics/MetricRegistrationObserverImpl.java +++ b/microprofile/grpc/metrics/src/main/java/io/helidon/microprofile/grpc/metrics/GrpcMetricRegistrationObserverImpl.java @@ -15,15 +15,12 @@ */ package io.helidon.microprofile.grpc.metrics; -import java.lang.annotation.Annotation; -import java.lang.reflect.Method; import java.util.HashMap; import java.util.Map; import io.helidon.microprofile.metrics.MetricAnnotationDiscoveryObserver.MetricAnnotationDiscovery; import io.helidon.microprofile.metrics.MetricRegistrationObserver; -import jakarta.enterprise.inject.spi.AnnotatedMethod; import org.eclipse.microprofile.metrics.Metadata; import org.eclipse.microprofile.metrics.Metric; import org.eclipse.microprofile.metrics.MetricID; @@ -31,7 +28,7 @@ /** * The gRPC implementation of {@link io.helidon.microprofile.metrics.MetricRegistrationObserver} with a static factory method. */ -class MetricRegistrationObserverImpl implements MetricRegistrationObserver { +class GrpcMetricRegistrationObserverImpl implements MetricRegistrationObserver { private final Map metadataByDiscovery = new HashMap<>(); @@ -41,11 +38,6 @@ public void onRegistration(MetricAnnotationDiscovery discovery, Metadata metadata, MetricID metricId, Metric metric) { - for (MetricAnnotationDiscovery d : metadataByDiscovery.keySet()) { - if (d.equals(discovery)) { - int x = 2; - } - } metadataByDiscovery.put(discovery, metadata); } @@ -53,7 +45,7 @@ Metadata metadata(MetricAnnotationDiscovery discovery) { return metadataByDiscovery.get(discovery); } - static MetricRegistrationObserverImpl instance() { - return MetricRegistrationObserverImplFactory.instance(); + static GrpcMetricRegistrationObserverImpl instance() { + return GrpcMetricRegistrationObserverImplFactory.instance(); } } diff --git a/microprofile/grpc/metrics/src/main/java/io/helidon/microprofile/grpc/metrics/MetricRegistrationObserverImplFactory.java b/microprofile/grpc/metrics/src/main/java/io/helidon/microprofile/grpc/metrics/GrpcMetricRegistrationObserverImplFactory.java similarity index 62% rename from microprofile/grpc/metrics/src/main/java/io/helidon/microprofile/grpc/metrics/MetricRegistrationObserverImplFactory.java rename to microprofile/grpc/metrics/src/main/java/io/helidon/microprofile/grpc/metrics/GrpcMetricRegistrationObserverImplFactory.java index e1094734e79..495b43157f7 100644 --- a/microprofile/grpc/metrics/src/main/java/io/helidon/microprofile/grpc/metrics/MetricRegistrationObserverImplFactory.java +++ b/microprofile/grpc/metrics/src/main/java/io/helidon/microprofile/grpc/metrics/GrpcMetricRegistrationObserverImplFactory.java @@ -18,17 +18,21 @@ import io.helidon.common.LazyValue; import io.helidon.microprofile.metrics.api.MetricRegistrationObserverProvider; -public class MetricRegistrationObserverImplFactory implements MetricRegistrationObserverProvider { +/** + * Factory for the gRPC metric registration observer. + */ +public class GrpcMetricRegistrationObserverImplFactory + implements MetricRegistrationObserverProvider { - private static final LazyValue instance = - LazyValue.create(MetricRegistrationObserverImpl::new); + private static final LazyValue INSTANCE = + LazyValue.create(GrpcMetricRegistrationObserverImpl::new); - static MetricRegistrationObserverImpl instance() { - return instance.get(); + static GrpcMetricRegistrationObserverImpl instance() { + return INSTANCE.get(); } @Override - public MetricRegistrationObserverImpl get() { + public GrpcMetricRegistrationObserverImpl get() { return instance(); } } diff --git a/microprofile/grpc/metrics/src/main/java/io/helidon/microprofile/grpc/metrics/GrpcMetricsCdiExtension.java b/microprofile/grpc/metrics/src/main/java/io/helidon/microprofile/grpc/metrics/GrpcMetricsCdiExtension.java deleted file mode 100644 index 099bd1c522a..00000000000 --- a/microprofile/grpc/metrics/src/main/java/io/helidon/microprofile/grpc/metrics/GrpcMetricsCdiExtension.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright (c) 2019, 2022 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.microprofile.grpc.metrics; - -import java.lang.annotation.Annotation; -import java.lang.reflect.Method; -import java.util.List; -import java.util.Map; -import java.util.ServiceLoader; -import java.util.stream.Collectors; - -import io.helidon.common.serviceloader.HelidonServiceLoader; -import io.helidon.microprofile.grpc.core.AnnotatedMethod; -import io.helidon.microprofile.grpc.core.GrpcMethod; -import io.helidon.microprofile.metrics.MetricAnnotationDiscoveryObserver; -import io.helidon.microprofile.metrics.MetricAnnotationDiscoveryObserver.MetricAnnotationDiscovery; -import io.helidon.microprofile.metrics.MetricRegistrationObserver; - -import jakarta.enterprise.event.Observes; -import jakarta.enterprise.inject.spi.BeforeBeanDiscovery; -import jakarta.enterprise.inject.spi.Extension; -import jakarta.enterprise.inject.spi.configurator.AnnotatedMethodConfigurator; -import jakarta.interceptor.Interceptor; -import org.eclipse.microprofile.metrics.Metadata; - -/** - * A CDI extension for gRPC metrics. - *

- * This extension will process annotated types that are gRPC methods and - * ensure that those methods re properly intercepted with a gRPC metrics - * {@link io.grpc.ServerInterceptor}. - *

- * If a method is discovered that is annotated with both a metrics annotation and a gRPC - * method type annotation they metrics annotation will be effectively removed from the CDI - * bean so that normal Helidon metrics interceptors do not also intercept that method. - */ -public class GrpcMetricsCdiExtension implements Extension { - -// /** -// * Determine whether a method is annotated with both a metrics annotation -// * and an annotation of type {@link io.helidon.microprofile.grpc.core.GrpcMethod}. -// * -// * @param configurator the {@link AnnotatedMethodConfigurator} representing -// * the annotated method -// * -// * @return {@code true} if the method is a timed gRPC method -// */ -// static boolean isRpcMethod(AnnotatedMethodConfigurator configurator, Class type) { -// AnnotatedMethod method = AnnotatedMethod.create(configurator.getAnnotated().getJavaMember()); -// GrpcMethod rpcMethod = method.firstAnnotationOrMetaAnnotation(GrpcMethod.class); -// if (rpcMethod != null) { -// Annotation annotation = method.firstAnnotationOrMetaAnnotation(type); -// return annotation != null; -// } -// return false; -// } -} diff --git a/microprofile/grpc/metrics/src/main/java/io/helidon/microprofile/grpc/metrics/MetricsConfigurer.java b/microprofile/grpc/metrics/src/main/java/io/helidon/microprofile/grpc/metrics/MetricsConfigurer.java index e863ce204c4..15da66920d5 100644 --- a/microprofile/grpc/metrics/src/main/java/io/helidon/microprofile/grpc/metrics/MetricsConfigurer.java +++ b/microprofile/grpc/metrics/src/main/java/io/helidon/microprofile/grpc/metrics/MetricsConfigurer.java @@ -22,7 +22,6 @@ import java.util.function.Supplier; import java.util.logging.Level; import java.util.logging.Logger; -import java.util.stream.Collectors; import io.helidon.grpc.metrics.GrpcMetrics; import io.helidon.grpc.server.ServiceDescriptor; @@ -69,15 +68,6 @@ public class MetricsConfigurer SimplyTimed.class, MetricInfo.create(GrpcMetrics::simplyTimed, SimpleTimer.class) ); - // Package-private for testing. - record MetricInfo(Supplier grpcMetricsSupplier, - Class metricClass) { - private static MetricInfo create(Supplier grpcMetricsSupplier, Class metricClass) { - return new MetricInfo(grpcMetricsSupplier, metricClass); - } - } - - @Override public void accept(Class serviceClass, Class annotatedClass, ServiceDescriptor.Builder builder) { @@ -91,23 +81,42 @@ public void accept(Class serviceClass, Class annotatedClass, ServiceDescri .filter(am -> isDiscovered(am.method())) .forEach(annotatedMethod -> discoveries(annotatedMethod.method()) - .forEach((annotationClass, discovery) -> -// metadata(annotatedMethod.method()) -// .forEach(metadata -> - processMetricAnnotationSite( - builder, - annotatedMethod, - METRIC_ANNOTATION_INFO - .get(annotationClass) - .grpcMetricsSupplier - .get(), - discovery.annotation(), - metadata(discovery) - ) - ) + .forEach((annotationClass, discovery) -> { + if (isServiceAnnotated(serviceClass, + annotatedMethod.declaredMethod(), + annotationClass)) { + processMetricAnnotationSite( + builder, + annotatedMethod, + METRIC_ANNOTATION_INFO + .get(annotationClass) + .grpcMetricsSupplier + .get(), + discovery.annotation(), + metadata(discovery) + ); + } + }) ); } + static boolean isServiceAnnotated(Class cls, + Method method, + Class annotation) { + return method.getDeclaringClass().equals(cls) && method.isAnnotationPresent(annotation); + } + + record MetricInfo(Supplier grpcMetricsSupplier, + Class metricClass) { + private static MetricInfo create(Supplier grpcMetricsSupplier, Class metricClass) { + return new MetricInfo(grpcMetricsSupplier, metricClass); + } + } + + + + // Package-private for testing. + private void processMetricAnnotationSite(ServiceDescriptor.Builder builder, AnnotatedMethod annotatedMethod, GrpcMetrics interceptor, @@ -159,14 +168,15 @@ public String createName(ServiceDescriptor service, String methodName, MetricTyp } private boolean isDiscovered(Method method) { - return MetricAnnotationDiscoveryObserverImpl.instance().isDiscovered(method); + return GrpcMetricAnnotationDiscoveryObserverImpl.instance().isDiscovered(method); } private Metadata metadata(MetricAnnotationDiscoveryObserver.MetricAnnotationDiscovery discovery) { - return MetricRegistrationObserverImpl.instance().metadata(discovery); + return GrpcMetricRegistrationObserverImpl.instance().metadata(discovery); } - private Map, MetricAnnotationDiscoveryObserver.MetricAnnotationDiscovery.OfMethod> discoveries(Method method) { - return MetricAnnotationDiscoveryObserverImpl.instance().discoveries(method); + private Map, + MetricAnnotationDiscoveryObserver.MetricAnnotationDiscovery.OfMethod> discoveries(Method method) { + return GrpcMetricAnnotationDiscoveryObserverImpl.instance().discoveries(method); } } diff --git a/microprofile/grpc/metrics/src/main/java/module-info.java b/microprofile/grpc/metrics/src/main/java/module-info.java index 821d3f8a012..ce7f7db0331 100644 --- a/microprofile/grpc/metrics/src/main/java/module-info.java +++ b/microprofile/grpc/metrics/src/main/java/module-info.java @@ -14,6 +14,9 @@ * limitations under the License. */ +import io.helidon.microprofile.grpc.metrics.GrpcMetricAnnotationDiscoveryObserverImplFactory; +import io.helidon.microprofile.grpc.metrics.GrpcMetricRegistrationObserverImplFactory; + /** * gRPC microprofile metrics module */ @@ -34,12 +37,9 @@ provides io.helidon.microprofile.grpc.server.AnnotatedServiceConfigurer with io.helidon.microprofile.grpc.metrics.MetricsConfigurer; - provides jakarta.enterprise.inject.spi.Extension - with io.helidon.microprofile.grpc.metrics.GrpcMetricsCdiExtension; - provides io.helidon.microprofile.metrics.api.MetricAnnotationDiscoveryObserverProvider - with io.helidon.microprofile.grpc.metrics.MetricAnnotationDiscoveryObserverImplFactory; + with GrpcMetricAnnotationDiscoveryObserverImplFactory; provides io.helidon.microprofile.metrics.api.MetricRegistrationObserverProvider - with io.helidon.microprofile.grpc.metrics.MetricRegistrationObserverImplFactory; + with GrpcMetricRegistrationObserverImplFactory; } \ No newline at end of file diff --git a/microprofile/grpc/metrics/src/test/java/io/helidon/microprofile/grpc/metrics/TestMetricsCoverage.java b/microprofile/grpc/metrics/src/test/java/io/helidon/microprofile/grpc/metrics/TestMetricsCoverage.java index 8920722de7e..ddbec44084a 100644 --- a/microprofile/grpc/metrics/src/test/java/io/helidon/microprofile/grpc/metrics/TestMetricsCoverage.java +++ b/microprofile/grpc/metrics/src/test/java/io/helidon/microprofile/grpc/metrics/TestMetricsCoverage.java @@ -112,7 +112,7 @@ public void checkForAllMetricTypesMappedToAnnotationType() { .toList() .forEach(incorrectlySkippedMetricTypes::remove); assertThat("At least one MicroProfile metric with an annotation exists that is not present in " - + "GrpcMetricsCdiExtension.METRICS_ANNOTATIONS", + + "MetricsConfigurer.METRIC_ANNOTATION_INFO", incorrectlySkippedMetricTypes, is(empty())); } } diff --git a/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/MetricAnnotationDiscoveryImpl.java b/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/MetricAnnotationDiscoveryImpl.java index 4ddc04cf935..022d361a854 100644 --- a/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/MetricAnnotationDiscoveryImpl.java +++ b/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/MetricAnnotationDiscoveryImpl.java @@ -17,6 +17,8 @@ package io.helidon.microprofile.metrics; import java.lang.annotation.Annotation; +import java.lang.reflect.Member; +import java.util.StringJoiner; import jakarta.enterprise.inject.spi.configurator.AnnotatedConstructorConfigurator; import jakarta.enterprise.inject.spi.configurator.AnnotatedMethodConfigurator; @@ -54,12 +56,11 @@ static MetricAnnotationDiscoveryImpl create( } } - private final AnnotatedTypeConfigurator annotatedTypeConfigurator; private final Annotation annotation; - private boolean keepDiscovery = true; - private boolean disableDefaultInterceptor = false; + private boolean isActive = true; + private boolean useDefaultInterceptor = true; private MetricAnnotationDiscoveryImpl(AnnotatedTypeConfigurator annotatedTypeConfigurator, Annotation annotation) { @@ -78,23 +79,36 @@ public Annotation annotation() { } @Override - public void discard() { - keepDiscovery = false; + public void deactivate() { + isActive = false; } @Override public void disableDefaultInterceptor() { - disableDefaultInterceptor = true; + useDefaultInterceptor = false; + } + + @Override + public String toString() { + return new StringJoiner(", ", getClass().getSimpleName() + "[", "]") + .add("annotatedConfigurator=" + annotatedMember()) + .add("annotatedTypeConfigurator=" + annotatedTypeConfigurator.getAnnotated().getJavaClass().getName()) + .add("annotation=" + annotation) + .add("isActive=" + isActive) + .add("useDefaultInterceptor=" + useDefaultInterceptor) + .toString(); } - boolean isValid() { - return keepDiscovery; + boolean isActive() { + return isActive; } - boolean isDisableDefaultInterceptor() { - return disableDefaultInterceptor; + boolean shouldUseDefaultInterceptor() { + return useDefaultInterceptor; } + protected abstract Member annotatedMember(); + private static class OfConstructor extends MetricAnnotationDiscoveryImpl implements MetricAnnotationDiscoveryObserver.MetricAnnotationDiscovery.OfConstructor { @@ -112,6 +126,11 @@ private OfConstructor( public AnnotatedConstructorConfigurator configurator() { return configurator; } + + @Override + protected Member annotatedMember() { + return configurator.getAnnotated().getJavaMember(); + } } private static class OfMethod extends MetricAnnotationDiscoveryImpl @@ -131,5 +150,10 @@ private OfMethod( public AnnotatedMethodConfigurator configurator() { return configurator; } + + @Override + protected Member annotatedMember() { + return configurator.getAnnotated().getJavaMember(); + } } } diff --git a/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/MetricAnnotationDiscoveryObserver.java b/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/MetricAnnotationDiscoveryObserver.java index d3572af975e..de661c861d7 100644 --- a/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/MetricAnnotationDiscoveryObserver.java +++ b/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/MetricAnnotationDiscoveryObserver.java @@ -28,7 +28,7 @@ * Implementations make themselves known via the Java service loader mechanism. *

*

- * Once registered, the observer is notified later, during {@code ProcessAnnotatedType}, for each metric annotation that is + * Observers are notified during {@code ProcessAnnotatedType}, for each metric annotation that is * discovered to apply to an executable, via a * {@link io.helidon.microprofile.metrics.MetricAnnotationDiscoveryObserver.MetricAnnotationDiscovery} event. *

@@ -71,9 +71,9 @@ interface MetricAnnotationDiscovery { Annotation annotation(); /** - * Requests that the discovery be discarded, triggering no metric registration. + * Requests that the discovery be deactivated, thereby preventing it from triggering a metric registration. */ - void discard(); + void deactivate(); /** * Requests that the default metrics interceptor not be used for the metric corresponding to the indicated annotation diff --git a/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/MetricsCdiExtension.java b/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/MetricsCdiExtension.java index 601ddc7908c..163c6db5ce8 100644 --- a/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/MetricsCdiExtension.java +++ b/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/MetricsCdiExtension.java @@ -233,7 +233,7 @@ private void registerMetricsForAnnotatedSites() { for (RegistrationPrep registrationPrep : annotatedSites) { metricAnnotationDiscoveriesByExecutable.get(registrationPrep.executable()) .forEach(discovery -> { - if (discovery.isValid()) { // All annotation observers agreed to preserve the discovery. + if (discovery.isActive()) { // All annotation discovery observers agreed to preserve the discovery. org.eclipse.microprofile.metrics.Metric metric = registrationPrep.register(registry); MetricID metricID = new MetricID(registrationPrep.metricName(), registrationPrep.tags()); metricRegistrationObservers.forEach( @@ -445,7 +445,7 @@ private > void bindInterceptorsAndRecordDis .add(discoveryEvent); metricAnnotationDiscoveryObservers.forEach(observer -> observer.onDiscovery(discoveryEvent)); } - if (!discoveryEvent.isDisableDefaultInterceptor()) { + if (discoveryEvent.shouldUseDefaultInterceptor()) { Class metricAnnotationClass = lookupResult.getAnnotation().annotationType(); annotationAdder.apply(executableConfigurator, INTERCEPTED_METRIC_ANNOTATIONS.get(metricAnnotationClass)); diff --git a/tests/integration/mp-grpc/src/test/java/io/helidon/microprofile/grpc/metrics/MetricsConfigurerTest.java b/tests/integration/mp-grpc/src/test/java/io/helidon/microprofile/grpc/metrics/MetricsConfigurerTest.java index 2c0a3ad5302..93ebcc813c8 100644 --- a/tests/integration/mp-grpc/src/test/java/io/helidon/microprofile/grpc/metrics/MetricsConfigurerTest.java +++ b/tests/integration/mp-grpc/src/test/java/io/helidon/microprofile/grpc/metrics/MetricsConfigurerTest.java @@ -32,15 +32,16 @@ import io.helidon.microprofile.grpc.server.JavaMarshaller; import io.helidon.microprofile.grpc.server.test.Services; +import io.helidon.microprofile.metrics.MetricsCdiExtension; +import io.helidon.microprofile.server.JaxRsCdiExtension; +import io.helidon.microprofile.server.ServerCdiExtension; import io.helidon.microprofile.tests.junit5.AddBean; +import io.helidon.microprofile.tests.junit5.AddExtension; +import io.helidon.microprofile.tests.junit5.DisableDiscovery; import io.helidon.microprofile.tests.junit5.HelidonTest; -import jakarta.annotation.Priority; -import jakarta.enterprise.context.ApplicationScoped; -import jakarta.enterprise.inject.Alternative; -import jakarta.enterprise.inject.Produces; -import jakarta.enterprise.inject.spi.CDI; -import jakarta.interceptor.Interceptor; +import jakarta.enterprise.inject.Typed; +import jakarta.ws.rs.Produces; import org.eclipse.microprofile.metrics.MetricID; import org.eclipse.microprofile.metrics.MetricRegistry; import org.eclipse.microprofile.metrics.MetricType; @@ -50,7 +51,6 @@ import org.eclipse.microprofile.metrics.annotation.SimplyTimed; import org.eclipse.microprofile.metrics.annotation.Timed; import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import static org.hamcrest.CoreMatchers.instanceOf; @@ -59,22 +59,26 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.collection.IsEmptyIterable.emptyIterable; - +/** + * Exercises the metrics configurer. + * + * Because the metrics CDI extension is (as of 3.x) responsible for registering metrics, even gRPC-inspired ones, we need to + * start the container. We cannot currently allow the gRPC CDI extension to start because it tries to register both ServiceOne and + * ServiceThree under the same name, ServiceOne, because ServiceThree extends ServiceOne. The attempt to register two services + * with the same name fails. So we turn off discovery and explicitly add in the beans and extensions we need. + */ @HelidonTest +@DisableDiscovery @AddBean(MetricsConfigurerTest.ServiceOne.class) -@AddBean(MetricsConfigurerTest.ServiceTwo.class) @AddBean(MetricsConfigurerTest.ServiceThree.class) +@AddBean(MetricsConfigurerTest.ServiceTwoProducer.class) +@AddExtension(MetricsCdiExtension.class) +@AddExtension(ServerCdiExtension.class) // needed for MetricsCdiExtension +@AddExtension(JaxRsCdiExtension.class) public class MetricsConfigurerTest { private static MetricRegistry registry; - private CDI weld; - - @BeforeEach - void setupPerTest() { - weld = CDI.current(); - } - @BeforeAll public static void setup() { registry = RegistryFactory.getInstance().getRegistry(MetricRegistry.Type.APPLICATION); @@ -97,7 +101,7 @@ public void shouldAddCounterMetricFromClassAnnotation() { assertThat(methodInterceptors.size(), is(1)); assertThat(methodInterceptors.get(0), is(instanceOf(GrpcMetrics.class))); assertThat(((GrpcMetrics) methodInterceptors.get(0)).metricType(), is(MetricType.COUNTER)); - assertThat(updReg().getCounters().get(new MetricID(ServiceOne.class.getName() + ".counted")), is(notNullValue())); + assertThat(registry.getCounters().get(new MetricID(ServiceOne.class.getName() + ".counted")), is(notNullValue())); } @Test @@ -117,7 +121,7 @@ public void shouldAddMeterMetricFromClassAnnotation() { assertThat(methodInterceptors.size(), is(1)); assertThat(methodInterceptors.get(0), is(instanceOf(GrpcMetrics.class))); assertThat(((GrpcMetrics) methodInterceptors.get(0)).metricType(), is(MetricType.METERED)); - assertThat(updReg().getMeters().get(new MetricID(ServiceOne.class.getName() + ".metered")), is(notNullValue())); + assertThat(registry.getMeters().get(new MetricID(ServiceOne.class.getName() + ".metered")), is(notNullValue())); } @Test @@ -137,7 +141,7 @@ public void shouldAddTimerMetricFromClassAnnotation() { assertThat(methodInterceptors.size(), is(1)); assertThat(methodInterceptors.get(0), is(instanceOf(GrpcMetrics.class))); assertThat(((GrpcMetrics) methodInterceptors.get(0)).metricType(), is(MetricType.TIMER)); - assertThat(updReg().getTimers().get(new MetricID(ServiceOne.class.getName() + ".timed")), is(notNullValue())); + assertThat(registry.getTimers().get(new MetricID(ServiceOne.class.getName() + ".timed")), is(notNullValue())); } @Test @@ -157,7 +161,7 @@ public void shouldAddSimpleTimerMetricFromClassAnnotation() { assertThat(methodInterceptors.size(), is(1)); assertThat(methodInterceptors.get(0), is(instanceOf(GrpcMetrics.class))); assertThat(((GrpcMetrics) methodInterceptors.get(0)).metricType(), is(MetricType.SIMPLE_TIMER)); - assertThat(updReg().getSimpleTimers().get(new MetricID(ServiceOne.class.getName() + ".simplyTimed")), is(notNullValue())); + assertThat(registry.getSimpleTimers().get(new MetricID(ServiceOne.class.getName() + ".simplyTimed")), is(notNullValue())); } @Test @@ -177,7 +181,7 @@ public void shouldAddConcurrentGaugeMetricFromClassAnnotation() { assertThat(methodInterceptors.size(), is(1)); assertThat(methodInterceptors.get(0), is(instanceOf(GrpcMetrics.class))); assertThat(((GrpcMetrics) methodInterceptors.get(0)).metricType(), is(MetricType.CONCURRENT_GAUGE)); - assertThat(updReg().getConcurrentGauges().get(new MetricID(ServiceOne.class.getName() + ".concurrentGauge")), + assertThat(registry.getConcurrentGauges().get(new MetricID(ServiceOne.class.getName() + ".concurrentGauge")), is(notNullValue())); } @@ -198,7 +202,7 @@ public void shouldAddOverriddenCounterMetricFromSuperClassAnnotation() { assertThat(methodInterceptors.size(), is(1)); assertThat(methodInterceptors.get(0), is(instanceOf(GrpcMetrics.class))); assertThat(((GrpcMetrics) methodInterceptors.get(0)).metricType(), is(MetricType.COUNTER)); - assertThat(updReg().getCounters().get(new MetricID(ServiceThree.class.getName() + ".foo")), is(notNullValue())); + assertThat(registry.getCounters().get(new MetricID(ServiceThree.class.getName() + ".foo")), is(notNullValue())); } @Test @@ -321,8 +325,6 @@ public void shouldIgnoreConcurrentGaugeMetricFromInterfaceAnnotation() { } @Grpc - @Priority(Interceptor.Priority.APPLICATION + 1) // resolves CDI ambiguity with ServiceThree (which extends ServiceOne) - @Alternative public static class ServiceOne implements GrpcService { @Override @@ -363,7 +365,7 @@ public void concurrentGauge(Services.TestRequest request, StreamObserver Date: Fri, 8 Jul 2022 17:38:01 -0500 Subject: [PATCH 4/9] Refactoring, mostly --- ...MetricAnnotationDiscoveryObserverImpl.java | 5 +- ...nnotationDiscoveryObserverImplFactory.java | 2 +- .../GrpcMetricRegistrationObserverImpl.java | 6 +- ...MetricRegistrationObserverImplFactory.java | 2 +- .../grpc/metrics/MetricsConfigurer.java | 6 +- .../metrics/src/main/java/module-info.java | 4 +- .../metrics/MetricAnnotationDiscovery.java | 84 ++++++++++++++ .../MetricAnnotationDiscoveryImpl.java | 9 +- .../MetricAnnotationDiscoveryObserver.java | 108 ------------------ .../metrics/MetricsCdiExtension.java | 6 +- .../MetricAnnotationDiscoveryObserver.java | 40 +++++++ ...icAnnotationDiscoveryObserverProvider.java | 6 +- .../{ => spi}/MetricRegistrationObserver.java | 7 +- .../MetricRegistrationObserverProvider.java | 6 +- .../metrics/{api => spi}/package-info.java | 2 +- .../metrics/src/main/java/module-info.java | 7 +- .../metrics/TestDiscoveryObserverImpl.java | 9 +- .../metrics/TestRegistrationObserverImpl.java | 5 +- ...MetricAnnotationDiscoveryObserverProvider} | 0 ...cs.spi.MetricRegistrationObserverProvider} | 0 20 files changed, 166 insertions(+), 148 deletions(-) create mode 100644 microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/MetricAnnotationDiscovery.java delete mode 100644 microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/MetricAnnotationDiscoveryObserver.java create mode 100644 microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/spi/MetricAnnotationDiscoveryObserver.java rename microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/{api => spi}/MetricAnnotationDiscoveryObserverProvider.java (81%) rename microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/{ => spi}/MetricRegistrationObserver.java (92%) rename microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/{api => spi}/MetricRegistrationObserverProvider.java (81%) rename microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/{api => spi}/package-info.java (94%) rename microprofile/metrics/src/test/resources/META-INF/services/{io.helidon.microprofile.metrics.api.MetricAnnotationDiscoveryObserverProvider => io.helidon.microprofile.metrics.spi.MetricAnnotationDiscoveryObserverProvider} (100%) rename microprofile/metrics/src/test/resources/META-INF/services/{io.helidon.microprofile.metrics.api.MetricRegistrationObserverProvider => io.helidon.microprofile.metrics.spi.MetricRegistrationObserverProvider} (100%) diff --git a/microprofile/grpc/metrics/src/main/java/io/helidon/microprofile/grpc/metrics/GrpcMetricAnnotationDiscoveryObserverImpl.java b/microprofile/grpc/metrics/src/main/java/io/helidon/microprofile/grpc/metrics/GrpcMetricAnnotationDiscoveryObserverImpl.java index 44fe772caac..d503f5853c8 100644 --- a/microprofile/grpc/metrics/src/main/java/io/helidon/microprofile/grpc/metrics/GrpcMetricAnnotationDiscoveryObserverImpl.java +++ b/microprofile/grpc/metrics/src/main/java/io/helidon/microprofile/grpc/metrics/GrpcMetricAnnotationDiscoveryObserverImpl.java @@ -22,12 +22,13 @@ import io.helidon.microprofile.grpc.core.AnnotatedMethod; import io.helidon.microprofile.grpc.core.GrpcMethod; -import io.helidon.microprofile.metrics.MetricAnnotationDiscoveryObserver; +import io.helidon.microprofile.metrics.MetricAnnotationDiscovery; +import io.helidon.microprofile.metrics.spi.MetricAnnotationDiscoveryObserver; import jakarta.enterprise.inject.spi.configurator.AnnotatedMethodConfigurator; /** - * The gRPC implementation of {@link io.helidon.microprofile.metrics.MetricAnnotationDiscoveryObserver}. + * The gRPC implementation of {@link io.helidon.microprofile.metrics.spi.MetricAnnotationDiscoveryObserver}. * *

* This implementation diff --git a/microprofile/grpc/metrics/src/main/java/io/helidon/microprofile/grpc/metrics/GrpcMetricAnnotationDiscoveryObserverImplFactory.java b/microprofile/grpc/metrics/src/main/java/io/helidon/microprofile/grpc/metrics/GrpcMetricAnnotationDiscoveryObserverImplFactory.java index 6ffd69a526e..5447dec8364 100644 --- a/microprofile/grpc/metrics/src/main/java/io/helidon/microprofile/grpc/metrics/GrpcMetricAnnotationDiscoveryObserverImplFactory.java +++ b/microprofile/grpc/metrics/src/main/java/io/helidon/microprofile/grpc/metrics/GrpcMetricAnnotationDiscoveryObserverImplFactory.java @@ -16,7 +16,7 @@ package io.helidon.microprofile.grpc.metrics; import io.helidon.common.LazyValue; -import io.helidon.microprofile.metrics.api.MetricAnnotationDiscoveryObserverProvider; +import io.helidon.microprofile.metrics.spi.MetricAnnotationDiscoveryObserverProvider; /** * Factory for the gRPC metrics observer of metric annotation discoveries. diff --git a/microprofile/grpc/metrics/src/main/java/io/helidon/microprofile/grpc/metrics/GrpcMetricRegistrationObserverImpl.java b/microprofile/grpc/metrics/src/main/java/io/helidon/microprofile/grpc/metrics/GrpcMetricRegistrationObserverImpl.java index e379d1cbdf2..b2e39097132 100644 --- a/microprofile/grpc/metrics/src/main/java/io/helidon/microprofile/grpc/metrics/GrpcMetricRegistrationObserverImpl.java +++ b/microprofile/grpc/metrics/src/main/java/io/helidon/microprofile/grpc/metrics/GrpcMetricRegistrationObserverImpl.java @@ -18,15 +18,15 @@ import java.util.HashMap; import java.util.Map; -import io.helidon.microprofile.metrics.MetricAnnotationDiscoveryObserver.MetricAnnotationDiscovery; -import io.helidon.microprofile.metrics.MetricRegistrationObserver; +import io.helidon.microprofile.metrics.MetricAnnotationDiscovery; +import io.helidon.microprofile.metrics.spi.MetricRegistrationObserver; import org.eclipse.microprofile.metrics.Metadata; import org.eclipse.microprofile.metrics.Metric; import org.eclipse.microprofile.metrics.MetricID; /** - * The gRPC implementation of {@link io.helidon.microprofile.metrics.MetricRegistrationObserver} with a static factory method. + * The gRPC implementation of {@link io.helidon.microprofile.metrics.spi.MetricRegistrationObserver} with a static factory method. */ class GrpcMetricRegistrationObserverImpl implements MetricRegistrationObserver { diff --git a/microprofile/grpc/metrics/src/main/java/io/helidon/microprofile/grpc/metrics/GrpcMetricRegistrationObserverImplFactory.java b/microprofile/grpc/metrics/src/main/java/io/helidon/microprofile/grpc/metrics/GrpcMetricRegistrationObserverImplFactory.java index 495b43157f7..f254565e95c 100644 --- a/microprofile/grpc/metrics/src/main/java/io/helidon/microprofile/grpc/metrics/GrpcMetricRegistrationObserverImplFactory.java +++ b/microprofile/grpc/metrics/src/main/java/io/helidon/microprofile/grpc/metrics/GrpcMetricRegistrationObserverImplFactory.java @@ -16,7 +16,7 @@ package io.helidon.microprofile.grpc.metrics; import io.helidon.common.LazyValue; -import io.helidon.microprofile.metrics.api.MetricRegistrationObserverProvider; +import io.helidon.microprofile.metrics.spi.MetricRegistrationObserverProvider; /** * Factory for the gRPC metric registration observer. diff --git a/microprofile/grpc/metrics/src/main/java/io/helidon/microprofile/grpc/metrics/MetricsConfigurer.java b/microprofile/grpc/metrics/src/main/java/io/helidon/microprofile/grpc/metrics/MetricsConfigurer.java index 15da66920d5..929f55c1110 100644 --- a/microprofile/grpc/metrics/src/main/java/io/helidon/microprofile/grpc/metrics/MetricsConfigurer.java +++ b/microprofile/grpc/metrics/src/main/java/io/helidon/microprofile/grpc/metrics/MetricsConfigurer.java @@ -30,7 +30,7 @@ import io.helidon.microprofile.grpc.core.GrpcMethod; import io.helidon.microprofile.grpc.server.AnnotatedServiceConfigurer; import io.helidon.microprofile.grpc.server.GrpcServiceBuilder; -import io.helidon.microprofile.metrics.MetricAnnotationDiscoveryObserver; +import io.helidon.microprofile.metrics.MetricAnnotationDiscovery; import org.eclipse.microprofile.metrics.Counter; import org.eclipse.microprofile.metrics.Metadata; @@ -171,12 +171,12 @@ private boolean isDiscovered(Method method) { return GrpcMetricAnnotationDiscoveryObserverImpl.instance().isDiscovered(method); } - private Metadata metadata(MetricAnnotationDiscoveryObserver.MetricAnnotationDiscovery discovery) { + private Metadata metadata(MetricAnnotationDiscovery discovery) { return GrpcMetricRegistrationObserverImpl.instance().metadata(discovery); } private Map, - MetricAnnotationDiscoveryObserver.MetricAnnotationDiscovery.OfMethod> discoveries(Method method) { + MetricAnnotationDiscovery.OfMethod> discoveries(Method method) { return GrpcMetricAnnotationDiscoveryObserverImpl.instance().discoveries(method); } } diff --git a/microprofile/grpc/metrics/src/main/java/module-info.java b/microprofile/grpc/metrics/src/main/java/module-info.java index ce7f7db0331..3ecba534981 100644 --- a/microprofile/grpc/metrics/src/main/java/module-info.java +++ b/microprofile/grpc/metrics/src/main/java/module-info.java @@ -37,9 +37,9 @@ provides io.helidon.microprofile.grpc.server.AnnotatedServiceConfigurer with io.helidon.microprofile.grpc.metrics.MetricsConfigurer; - provides io.helidon.microprofile.metrics.api.MetricAnnotationDiscoveryObserverProvider + provides io.helidon.microprofile.metrics.spi.MetricAnnotationDiscoveryObserverProvider with GrpcMetricAnnotationDiscoveryObserverImplFactory; - provides io.helidon.microprofile.metrics.api.MetricRegistrationObserverProvider + provides io.helidon.microprofile.metrics.spi.MetricRegistrationObserverProvider with GrpcMetricRegistrationObserverImplFactory; } \ No newline at end of file diff --git a/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/MetricAnnotationDiscovery.java b/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/MetricAnnotationDiscovery.java new file mode 100644 index 00000000000..978f12c480b --- /dev/null +++ b/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/MetricAnnotationDiscovery.java @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2022 Oracle and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.helidon.microprofile.metrics; + +import java.lang.annotation.Annotation; + +import jakarta.enterprise.inject.spi.configurator.AnnotatedConstructorConfigurator; +import jakarta.enterprise.inject.spi.configurator.AnnotatedMethodConfigurator; +import jakarta.enterprise.inject.spi.configurator.AnnotatedTypeConfigurator; + +/** + * Conveys information about the discovery of a metric annotation as it applies to an executable. + *

+ * The discovery event describes the executable to which the metric annotation applies. + * This is not necessarily where the annotation appears, because a metric annotation which appears on the + * type applies to all methods and constructors on that type. + * In that case, the discovery event describes the discovery of the metric as applied + * to the method or constructor, not to the type itself. + * Further, a metric annotation declared at the type level triggers a separate discovery event for each constructor + * and method on the type. + *

+ */ +public interface MetricAnnotationDiscovery { + + /** + * Returns the configurator for the annotated type containing the site to which the metric annotation applies. + * + * @return the configurator for the annotated type + */ + AnnotatedTypeConfigurator annotatedTypeConfigurator(); + + /** + * Returns the {@link java.lang.annotation.Annotation} object for the metric annotation discovered. + * + * @return the annotation object for the metrics annotation + */ + Annotation annotation(); + + /** + * Requests that the discovery be deactivated, thereby preventing it from triggering a metric registration. + */ + void deactivate(); + + /** + * Requests that the default metrics interceptor not be used for the metric corresponding to the indicated annotation + * which appears on this method. + */ + void disableDefaultInterceptor(); + + /** + * Discovery of an annotation of interest on a constructor. + */ + interface OfConstructor extends MetricAnnotationDiscovery { + + /** + * @return the configurator for the constructor on which an annotation of interest appears + */ + AnnotatedConstructorConfigurator configurator(); + } + + /** + * Discovery of an annotation of interest on a method. + */ + interface OfMethod extends MetricAnnotationDiscovery { + + /** + * @return the configurotor for the method on which an annotation of interest appears + */ + AnnotatedMethodConfigurator configurator(); + } +} diff --git a/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/MetricAnnotationDiscoveryImpl.java b/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/MetricAnnotationDiscoveryImpl.java index 022d361a854..f77387e5b8b 100644 --- a/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/MetricAnnotationDiscoveryImpl.java +++ b/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/MetricAnnotationDiscoveryImpl.java @@ -31,11 +31,11 @@ * {@link jakarta.enterprise.inject.spi.configurator.AnnotatedMethodConfigurator} interfaces share no common ancestor, so * we have two subtypes of discovery, one for each: * {@link io.helidon.microprofile.metrics.MetricAnnotationDiscoveryImpl.OfConstructor OfConstructor} and - * {@link io.helidon.microprofile.metrics.MetricAnnotationDiscoveryObserver.MetricAnnotationDiscovery.OfMethod ofMethod}. + * {@link MetricAnnotationDiscovery.OfMethod ofMethod}. *

* */ -abstract class MetricAnnotationDiscoveryImpl implements MetricAnnotationDiscoveryObserver.MetricAnnotationDiscovery { +abstract class MetricAnnotationDiscoveryImpl implements MetricAnnotationDiscovery { static MetricAnnotationDiscoveryImpl create( AnnotatedTypeConfigurator annotatedTypeConfigurator, @@ -81,6 +81,7 @@ public Annotation annotation() { @Override public void deactivate() { isActive = false; + disableDefaultInterceptor(); } @Override @@ -110,7 +111,7 @@ boolean shouldUseDefaultInterceptor() { protected abstract Member annotatedMember(); private static class OfConstructor extends MetricAnnotationDiscoveryImpl - implements MetricAnnotationDiscoveryObserver.MetricAnnotationDiscovery.OfConstructor { + implements MetricAnnotationDiscovery.OfConstructor { private final AnnotatedConstructorConfigurator configurator; @@ -134,7 +135,7 @@ protected Member annotatedMember() { } private static class OfMethod extends MetricAnnotationDiscoveryImpl - implements MetricAnnotationDiscoveryObserver.MetricAnnotationDiscovery.OfMethod { + implements MetricAnnotationDiscovery.OfMethod { private final AnnotatedMethodConfigurator configurator; diff --git a/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/MetricAnnotationDiscoveryObserver.java b/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/MetricAnnotationDiscoveryObserver.java deleted file mode 100644 index de661c861d7..00000000000 --- a/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/MetricAnnotationDiscoveryObserver.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright (c) 2022 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -package io.helidon.microprofile.metrics; - -import java.lang.annotation.Annotation; - -import jakarta.enterprise.inject.spi.configurator.AnnotatedConstructorConfigurator; -import jakarta.enterprise.inject.spi.configurator.AnnotatedMethodConfigurator; -import jakarta.enterprise.inject.spi.configurator.AnnotatedTypeConfigurator; - -/** - * Observer of the discovery of metric annotations which are applied to constructors and methods. - *

- * Implementations make themselves known via the Java service loader mechanism. - *

- *

- * Observers are notified during {@code ProcessAnnotatedType}, for each metric annotation that is - * discovered to apply to an executable, via a - * {@link io.helidon.microprofile.metrics.MetricAnnotationDiscoveryObserver.MetricAnnotationDiscovery} event. - *

- */ -public interface MetricAnnotationDiscoveryObserver { - - /** - * Notifies the observer that a metric annotation has been discovered to apply to a constructor or method. - * - * @param metricAnnotationDiscovery the discovery event - */ - void onDiscovery(MetricAnnotationDiscovery metricAnnotationDiscovery); - - /** - * Conveys information about the discovery of a metric annotation as it applies to an executable. - *

- * The discovery event describes the executable to which the metric annotation applies. - * This is not necessarily where the annotation appears, because a metric annotation which appears on the - * type applies to all methods and constructors on that type. - * In that case, the discovery event describes the discovery of the metric as applied - * to the method or constructor, not to the type itself. - * Further, a metric annotation declared at the type level triggers a separate discovery event for each constructor - * and method on the type. - *

- */ - interface MetricAnnotationDiscovery { - - /** - * Returns the configurator for the annotated type containing the site to which the metric annotation applies. - * - * @return the configurator for the annotated type - */ - AnnotatedTypeConfigurator annotatedTypeConfigurator(); - - /** - * Returns the {@link java.lang.annotation.Annotation} object for the metric annotation discovered. - * - * @return the annotation object for the metrics annotation - */ - Annotation annotation(); - - /** - * Requests that the discovery be deactivated, thereby preventing it from triggering a metric registration. - */ - void deactivate(); - - /** - * Requests that the default metrics interceptor not be used for the metric corresponding to the indicated annotation - * which appears on this method. - */ - void disableDefaultInterceptor(); - - /** - * Discovery of an annotation of interest on a constructor. - */ - interface OfConstructor extends MetricAnnotationDiscovery { - - /** - * - * @return the configurator for the constructor on which an annotation of interest appears - */ - AnnotatedConstructorConfigurator configurator(); - } - - /** - * Discovery of an annotation of interest on a method. - */ - interface OfMethod extends MetricAnnotationDiscovery { - - /** - * - * @return the configurotor for the method on which an annotation of interest appears - */ - AnnotatedMethodConfigurator configurator(); - } - } -} diff --git a/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/MetricsCdiExtension.java b/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/MetricsCdiExtension.java index 163c6db5ce8..bea1f437c18 100644 --- a/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/MetricsCdiExtension.java +++ b/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/MetricsCdiExtension.java @@ -51,8 +51,10 @@ import io.helidon.metrics.serviceapi.MetricsSupport; import io.helidon.microprofile.metrics.MetricAnnotationInfo.RegistrationPrep; import io.helidon.microprofile.metrics.MetricUtil.LookupResult; -import io.helidon.microprofile.metrics.api.MetricAnnotationDiscoveryObserverProvider; -import io.helidon.microprofile.metrics.api.MetricRegistrationObserverProvider; +import io.helidon.microprofile.metrics.spi.MetricAnnotationDiscoveryObserver; +import io.helidon.microprofile.metrics.spi.MetricAnnotationDiscoveryObserverProvider; +import io.helidon.microprofile.metrics.spi.MetricRegistrationObserver; +import io.helidon.microprofile.metrics.spi.MetricRegistrationObserverProvider; import io.helidon.microprofile.server.ServerCdiExtension; import io.helidon.servicecommon.restcdi.HelidonRestCdiExtension; import io.helidon.webserver.Routing; diff --git a/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/spi/MetricAnnotationDiscoveryObserver.java b/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/spi/MetricAnnotationDiscoveryObserver.java new file mode 100644 index 00000000000..19d6e2431e3 --- /dev/null +++ b/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/spi/MetricAnnotationDiscoveryObserver.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2022 Oracle and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.helidon.microprofile.metrics.spi; + +import io.helidon.microprofile.metrics.MetricAnnotationDiscovery; + +/** + * Observer of the discovery of metric annotations which are applied to constructors and methods. + *

+ * Implementations make themselves known via the Java service loader mechanism. + *

+ *

+ * Observers are notified during {@code ProcessAnnotatedType}, for each metric annotation that is + * discovered to apply to an executable, via a + * {@link io.helidon.microprofile.metrics.MetricAnnotationDiscovery} event. + *

+ */ +public interface MetricAnnotationDiscoveryObserver { + + /** + * Notifies the observer that a metric annotation has been discovered to apply to a constructor or method. + * + * @param metricAnnotationDiscovery the discovery event + */ + void onDiscovery(MetricAnnotationDiscovery metricAnnotationDiscovery); + +} diff --git a/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/api/MetricAnnotationDiscoveryObserverProvider.java b/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/spi/MetricAnnotationDiscoveryObserverProvider.java similarity index 81% rename from microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/api/MetricAnnotationDiscoveryObserverProvider.java rename to microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/spi/MetricAnnotationDiscoveryObserverProvider.java index 759c2a62300..08acdf96959 100644 --- a/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/api/MetricAnnotationDiscoveryObserverProvider.java +++ b/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/spi/MetricAnnotationDiscoveryObserverProvider.java @@ -13,16 +13,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package io.helidon.microprofile.metrics.api; +package io.helidon.microprofile.metrics.spi; import java.util.function.Supplier; -import io.helidon.microprofile.metrics.MetricAnnotationDiscoveryObserver; - /** * Specifies behavior of a provider for a metric annotation discovery observer. * - * @param specific type of {@link io.helidon.microprofile.metrics.MetricAnnotationDiscoveryObserver} + * @param specific type of {@link MetricAnnotationDiscoveryObserver} */ public interface MetricAnnotationDiscoveryObserverProvider extends Supplier { diff --git a/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/MetricRegistrationObserver.java b/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/spi/MetricRegistrationObserver.java similarity index 92% rename from microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/MetricRegistrationObserver.java rename to microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/spi/MetricRegistrationObserver.java index 16c13b49f24..0a223276522 100644 --- a/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/MetricRegistrationObserver.java +++ b/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/spi/MetricRegistrationObserver.java @@ -12,11 +12,10 @@ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. - * */ -package io.helidon.microprofile.metrics; +package io.helidon.microprofile.metrics.spi; -import io.helidon.microprofile.metrics.MetricAnnotationDiscoveryObserver.MetricAnnotationDiscovery; +import io.helidon.microprofile.metrics.MetricAnnotationDiscovery; import org.eclipse.microprofile.metrics.Metadata; import org.eclipse.microprofile.metrics.Metric; @@ -36,7 +35,7 @@ public interface MetricRegistrationObserver { /** * Notifies the observer that a metric has been registered due to a metric annotation that applies to an executable. * - * @param discovery the {@link MetricAnnotationDiscovery} + * @param discovery the {@link io.helidon.microprofile.metrics.MetricAnnotationDiscovery} * triggering this metric registration * @param metadata the metrics {@link org.eclipse.microprofile.metrics.Metadata} for the indicated metric * @param metricId the {@link org.eclipse.microprofile.metrics.MetricID} for the indicated metric diff --git a/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/api/MetricRegistrationObserverProvider.java b/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/spi/MetricRegistrationObserverProvider.java similarity index 81% rename from microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/api/MetricRegistrationObserverProvider.java rename to microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/spi/MetricRegistrationObserverProvider.java index e6453e187cf..f0a5a57e0f2 100644 --- a/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/api/MetricRegistrationObserverProvider.java +++ b/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/spi/MetricRegistrationObserverProvider.java @@ -13,16 +13,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package io.helidon.microprofile.metrics.api; +package io.helidon.microprofile.metrics.spi; import java.util.function.Supplier; -import io.helidon.microprofile.metrics.MetricRegistrationObserver; - /** * Specifies behavior of a provider for a metric annotation discovery observer. * - * @param specific type of {@link io.helidon.microprofile.metrics.MetricRegistrationObserver} + * @param specific type of {@link MetricRegistrationObserver} */ public interface MetricRegistrationObserverProvider extends Supplier { diff --git a/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/api/package-info.java b/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/spi/package-info.java similarity index 94% rename from microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/api/package-info.java rename to microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/spi/package-info.java index 6fa8117119e..402d15257d8 100644 --- a/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/api/package-info.java +++ b/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/spi/package-info.java @@ -17,4 +17,4 @@ /** * Interfaces optionally implemented by other components interested in key metrics processing events. */ -package io.helidon.microprofile.metrics.api; +package io.helidon.microprofile.metrics.spi; diff --git a/microprofile/metrics/src/main/java/module-info.java b/microprofile/metrics/src/main/java/module-info.java index c61298d8dee..9e7a90eb59b 100644 --- a/microprofile/metrics/src/main/java/module-info.java +++ b/microprofile/metrics/src/main/java/module-info.java @@ -40,13 +40,14 @@ requires io.helidon.config.mp; exports io.helidon.microprofile.metrics; - exports io.helidon.microprofile.metrics.api; + exports io.helidon.microprofile.metrics.spi; // this is needed for CDI extensions that use non-public observer methods opens io.helidon.microprofile.metrics to weld.core.impl, io.helidon.microprofile.cdi; + opens io.helidon.microprofile.metrics.spi to io.helidon.microprofile.cdi, weld.core.impl; provides jakarta.enterprise.inject.spi.Extension with io.helidon.microprofile.metrics.MetricsCdiExtension; - uses io.helidon.microprofile.metrics.api.MetricAnnotationDiscoveryObserverProvider; - uses io.helidon.microprofile.metrics.api.MetricRegistrationObserverProvider; + uses io.helidon.microprofile.metrics.spi.MetricAnnotationDiscoveryObserverProvider; + uses io.helidon.microprofile.metrics.spi.MetricRegistrationObserverProvider; } diff --git a/microprofile/metrics/src/test/java/io/helidon/microprofile/metrics/TestDiscoveryObserverImpl.java b/microprofile/metrics/src/test/java/io/helidon/microprofile/metrics/TestDiscoveryObserverImpl.java index ad81925a72a..40d7c13e167 100644 --- a/microprofile/metrics/src/test/java/io/helidon/microprofile/metrics/TestDiscoveryObserverImpl.java +++ b/microprofile/metrics/src/test/java/io/helidon/microprofile/metrics/TestDiscoveryObserverImpl.java @@ -19,7 +19,8 @@ import java.util.List; import io.helidon.common.LazyValue; -import io.helidon.microprofile.metrics.api.MetricAnnotationDiscoveryObserverProvider; +import io.helidon.microprofile.metrics.spi.MetricAnnotationDiscoveryObserver; +import io.helidon.microprofile.metrics.spi.MetricAnnotationDiscoveryObserverProvider; public class TestDiscoveryObserverImpl implements MetricAnnotationDiscoveryObserver { @@ -36,14 +37,14 @@ static TestDiscoveryObserverImpl instance() { return instance.get(); } } - private List discoveries = new ArrayList<>(); + private List discoveries = new ArrayList<>(); @Override - public void onDiscovery(MetricAnnotationDiscoveryObserver.MetricAnnotationDiscovery metricAnnotationDiscovery) { + public void onDiscovery(MetricAnnotationDiscovery metricAnnotationDiscovery) { discoveries.add(metricAnnotationDiscovery); } - List discoveries() { + List discoveries() { return discoveries; } } diff --git a/microprofile/metrics/src/test/java/io/helidon/microprofile/metrics/TestRegistrationObserverImpl.java b/microprofile/metrics/src/test/java/io/helidon/microprofile/metrics/TestRegistrationObserverImpl.java index 269c269901c..a21b23ef70b 100644 --- a/microprofile/metrics/src/test/java/io/helidon/microprofile/metrics/TestRegistrationObserverImpl.java +++ b/microprofile/metrics/src/test/java/io/helidon/microprofile/metrics/TestRegistrationObserverImpl.java @@ -16,7 +16,8 @@ package io.helidon.microprofile.metrics; import io.helidon.common.LazyValue; -import io.helidon.microprofile.metrics.api.MetricRegistrationObserverProvider; +import io.helidon.microprofile.metrics.spi.MetricRegistrationObserver; +import io.helidon.microprofile.metrics.spi.MetricRegistrationObserverProvider; import org.eclipse.microprofile.metrics.Metadata; import org.eclipse.microprofile.metrics.Metric; @@ -41,7 +42,7 @@ static TestRegistrationObserverImpl instance() { private int registrations; @Override - public void onRegistration(MetricAnnotationDiscoveryObserver.MetricAnnotationDiscovery discovery, + public void onRegistration(MetricAnnotationDiscovery discovery, Metadata metadata, MetricID metricId, Metric metric) { diff --git a/microprofile/metrics/src/test/resources/META-INF/services/io.helidon.microprofile.metrics.api.MetricAnnotationDiscoveryObserverProvider b/microprofile/metrics/src/test/resources/META-INF/services/io.helidon.microprofile.metrics.spi.MetricAnnotationDiscoveryObserverProvider similarity index 100% rename from microprofile/metrics/src/test/resources/META-INF/services/io.helidon.microprofile.metrics.api.MetricAnnotationDiscoveryObserverProvider rename to microprofile/metrics/src/test/resources/META-INF/services/io.helidon.microprofile.metrics.spi.MetricAnnotationDiscoveryObserverProvider diff --git a/microprofile/metrics/src/test/resources/META-INF/services/io.helidon.microprofile.metrics.api.MetricRegistrationObserverProvider b/microprofile/metrics/src/test/resources/META-INF/services/io.helidon.microprofile.metrics.spi.MetricRegistrationObserverProvider similarity index 100% rename from microprofile/metrics/src/test/resources/META-INF/services/io.helidon.microprofile.metrics.api.MetricRegistrationObserverProvider rename to microprofile/metrics/src/test/resources/META-INF/services/io.helidon.microprofile.metrics.spi.MetricRegistrationObserverProvider From f12ec36f761bd892534a21263f8fe71d1c325fc6 Mon Sep 17 00:00:00 2001 From: "tim.quinn@oracle.com" Date: Sat, 9 Jul 2022 07:06:47 -0500 Subject: [PATCH 5/9] Remove the observer factory SPI interfaces; rely only on the observer interfaces --- ...MetricAnnotationDiscoveryObserverImpl.java | 17 ++++++++- ...nnotationDiscoveryObserverImplFactory.java | 38 ------------------- .../GrpcMetricRegistrationObserverImpl.java | 22 ++++++++--- ...MetricRegistrationObserverImplFactory.java | 38 ------------------- .../metrics/src/main/java/module-info.java | 11 ++---- .../metrics/MetricsCdiExtension.java | 10 ++--- ...icAnnotationDiscoveryObserverProvider.java | 32 ---------------- .../MetricRegistrationObserverProvider.java | 32 ---------------- .../metrics/src/main/java/module-info.java | 4 +- .../metrics/TestDiscoveryObserverImpl.java | 23 ++++++----- .../microprofile/metrics/TestObservers.java | 4 +- .../metrics/TestRegistrationObserverImpl.java | 23 +++++------ ...ics.spi.MetricAnnotationDiscoveryObserver} | 2 +- ...le.metrics.spi.MetricRegistrationObserver} | 2 +- 14 files changed, 67 insertions(+), 191 deletions(-) delete mode 100644 microprofile/grpc/metrics/src/main/java/io/helidon/microprofile/grpc/metrics/GrpcMetricAnnotationDiscoveryObserverImplFactory.java delete mode 100644 microprofile/grpc/metrics/src/main/java/io/helidon/microprofile/grpc/metrics/GrpcMetricRegistrationObserverImplFactory.java delete mode 100644 microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/spi/MetricAnnotationDiscoveryObserverProvider.java delete mode 100644 microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/spi/MetricRegistrationObserverProvider.java rename microprofile/metrics/src/test/resources/META-INF/services/{io.helidon.microprofile.metrics.spi.MetricAnnotationDiscoveryObserverProvider => io.helidon.microprofile.metrics.spi.MetricAnnotationDiscoveryObserver} (90%) rename microprofile/metrics/src/test/resources/META-INF/services/{io.helidon.microprofile.metrics.spi.MetricRegistrationObserverProvider => io.helidon.microprofile.metrics.spi.MetricRegistrationObserver} (89%) diff --git a/microprofile/grpc/metrics/src/main/java/io/helidon/microprofile/grpc/metrics/GrpcMetricAnnotationDiscoveryObserverImpl.java b/microprofile/grpc/metrics/src/main/java/io/helidon/microprofile/grpc/metrics/GrpcMetricAnnotationDiscoveryObserverImpl.java index d503f5853c8..e62c85fc551 100644 --- a/microprofile/grpc/metrics/src/main/java/io/helidon/microprofile/grpc/metrics/GrpcMetricAnnotationDiscoveryObserverImpl.java +++ b/microprofile/grpc/metrics/src/main/java/io/helidon/microprofile/grpc/metrics/GrpcMetricAnnotationDiscoveryObserverImpl.java @@ -34,16 +34,29 @@ * This implementation *

*/ -class GrpcMetricAnnotationDiscoveryObserverImpl implements MetricAnnotationDiscoveryObserver { +public class GrpcMetricAnnotationDiscoveryObserverImpl implements MetricAnnotationDiscoveryObserver { + + private static GrpcMetricAnnotationDiscoveryObserverImpl instance; static GrpcMetricAnnotationDiscoveryObserverImpl instance() { - return GrpcMetricAnnotationDiscoveryObserverImplFactory.instance(); + return instance; + } + + private static void instance(GrpcMetricAnnotationDiscoveryObserverImpl value) { + instance = value; } private final Map, MetricAnnotationDiscovery.OfMethod>> discoveriesByMethod = new HashMap<>(); + /** + * Creates a new instance. + */ + public GrpcMetricAnnotationDiscoveryObserverImpl() { + instance(this); + } + @Override public void onDiscovery(MetricAnnotationDiscovery discovery) { if (discovery instanceof MetricAnnotationDiscovery.OfMethod methodDiscovery diff --git a/microprofile/grpc/metrics/src/main/java/io/helidon/microprofile/grpc/metrics/GrpcMetricAnnotationDiscoveryObserverImplFactory.java b/microprofile/grpc/metrics/src/main/java/io/helidon/microprofile/grpc/metrics/GrpcMetricAnnotationDiscoveryObserverImplFactory.java deleted file mode 100644 index 5447dec8364..00000000000 --- a/microprofile/grpc/metrics/src/main/java/io/helidon/microprofile/grpc/metrics/GrpcMetricAnnotationDiscoveryObserverImplFactory.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2022 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.helidon.microprofile.grpc.metrics; - -import io.helidon.common.LazyValue; -import io.helidon.microprofile.metrics.spi.MetricAnnotationDiscoveryObserverProvider; - -/** - * Factory for the gRPC metrics observer of metric annotation discoveries. - */ -public class GrpcMetricAnnotationDiscoveryObserverImplFactory - implements MetricAnnotationDiscoveryObserverProvider { - - private static final LazyValue INSTANCE = - LazyValue.create(GrpcMetricAnnotationDiscoveryObserverImpl::new); - - static GrpcMetricAnnotationDiscoveryObserverImpl instance() { - return INSTANCE.get(); - } - - @Override - public GrpcMetricAnnotationDiscoveryObserverImpl get() { - return instance(); - } -} diff --git a/microprofile/grpc/metrics/src/main/java/io/helidon/microprofile/grpc/metrics/GrpcMetricRegistrationObserverImpl.java b/microprofile/grpc/metrics/src/main/java/io/helidon/microprofile/grpc/metrics/GrpcMetricRegistrationObserverImpl.java index b2e39097132..d3a8ccb46c0 100644 --- a/microprofile/grpc/metrics/src/main/java/io/helidon/microprofile/grpc/metrics/GrpcMetricRegistrationObserverImpl.java +++ b/microprofile/grpc/metrics/src/main/java/io/helidon/microprofile/grpc/metrics/GrpcMetricRegistrationObserverImpl.java @@ -28,11 +28,27 @@ /** * The gRPC implementation of {@link io.helidon.microprofile.metrics.spi.MetricRegistrationObserver} with a static factory method. */ -class GrpcMetricRegistrationObserverImpl implements MetricRegistrationObserver { +public class GrpcMetricRegistrationObserverImpl implements MetricRegistrationObserver { + private static GrpcMetricRegistrationObserverImpl instance; + + static GrpcMetricRegistrationObserverImpl instance() { + return instance; + } + + private static void instance(GrpcMetricRegistrationObserverImpl value) { + instance = value; + } private final Map metadataByDiscovery = new HashMap<>(); + /** + * Creates a new instance of the observer. + */ + public GrpcMetricRegistrationObserverImpl() { + instance(this); + } + @Override public void onRegistration(MetricAnnotationDiscovery discovery, Metadata metadata, @@ -44,8 +60,4 @@ public void onRegistration(MetricAnnotationDiscovery discovery, Metadata metadata(MetricAnnotationDiscovery discovery) { return metadataByDiscovery.get(discovery); } - - static GrpcMetricRegistrationObserverImpl instance() { - return GrpcMetricRegistrationObserverImplFactory.instance(); - } } diff --git a/microprofile/grpc/metrics/src/main/java/io/helidon/microprofile/grpc/metrics/GrpcMetricRegistrationObserverImplFactory.java b/microprofile/grpc/metrics/src/main/java/io/helidon/microprofile/grpc/metrics/GrpcMetricRegistrationObserverImplFactory.java deleted file mode 100644 index f254565e95c..00000000000 --- a/microprofile/grpc/metrics/src/main/java/io/helidon/microprofile/grpc/metrics/GrpcMetricRegistrationObserverImplFactory.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2022 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.helidon.microprofile.grpc.metrics; - -import io.helidon.common.LazyValue; -import io.helidon.microprofile.metrics.spi.MetricRegistrationObserverProvider; - -/** - * Factory for the gRPC metric registration observer. - */ -public class GrpcMetricRegistrationObserverImplFactory - implements MetricRegistrationObserverProvider { - - private static final LazyValue INSTANCE = - LazyValue.create(GrpcMetricRegistrationObserverImpl::new); - - static GrpcMetricRegistrationObserverImpl instance() { - return INSTANCE.get(); - } - - @Override - public GrpcMetricRegistrationObserverImpl get() { - return instance(); - } -} diff --git a/microprofile/grpc/metrics/src/main/java/module-info.java b/microprofile/grpc/metrics/src/main/java/module-info.java index 3ecba534981..4d01b52d7cf 100644 --- a/microprofile/grpc/metrics/src/main/java/module-info.java +++ b/microprofile/grpc/metrics/src/main/java/module-info.java @@ -14,9 +14,6 @@ * limitations under the License. */ -import io.helidon.microprofile.grpc.metrics.GrpcMetricAnnotationDiscoveryObserverImplFactory; -import io.helidon.microprofile.grpc.metrics.GrpcMetricRegistrationObserverImplFactory; - /** * gRPC microprofile metrics module */ @@ -37,9 +34,9 @@ provides io.helidon.microprofile.grpc.server.AnnotatedServiceConfigurer with io.helidon.microprofile.grpc.metrics.MetricsConfigurer; - provides io.helidon.microprofile.metrics.spi.MetricAnnotationDiscoveryObserverProvider - with GrpcMetricAnnotationDiscoveryObserverImplFactory; + provides io.helidon.microprofile.metrics.spi.MetricAnnotationDiscoveryObserver + with io.helidon.microprofile.grpc.metrics.GrpcMetricAnnotationDiscoveryObserverImpl; - provides io.helidon.microprofile.metrics.spi.MetricRegistrationObserverProvider - with GrpcMetricRegistrationObserverImplFactory; + provides io.helidon.microprofile.metrics.spi.MetricRegistrationObserver + with io.helidon.microprofile.grpc.metrics.GrpcMetricRegistrationObserverImpl; } \ No newline at end of file diff --git a/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/MetricsCdiExtension.java b/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/MetricsCdiExtension.java index bea1f437c18..86ba6ad27ec 100644 --- a/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/MetricsCdiExtension.java +++ b/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/MetricsCdiExtension.java @@ -52,9 +52,7 @@ import io.helidon.microprofile.metrics.MetricAnnotationInfo.RegistrationPrep; import io.helidon.microprofile.metrics.MetricUtil.LookupResult; import io.helidon.microprofile.metrics.spi.MetricAnnotationDiscoveryObserver; -import io.helidon.microprofile.metrics.spi.MetricAnnotationDiscoveryObserverProvider; import io.helidon.microprofile.metrics.spi.MetricRegistrationObserver; -import io.helidon.microprofile.metrics.spi.MetricRegistrationObserverProvider; import io.helidon.microprofile.server.ServerCdiExtension; import io.helidon.servicecommon.restcdi.HelidonRestCdiExtension; import io.helidon.webserver.Routing; @@ -357,10 +355,10 @@ void before(@Observes BeforeBeanDiscovery discovery) { restEndpointsMetricsEnabled = restEndpointsMetricsEnabled(); - HelidonServiceLoader.create(ServiceLoader.load(MetricAnnotationDiscoveryObserverProvider.class)) - .forEach(p -> metricAnnotationDiscoveryObservers.add(p.get())); - HelidonServiceLoader.create(ServiceLoader.load(MetricRegistrationObserverProvider.class)) - .forEach(p -> metricRegistrationObservers.add(p.get())); + HelidonServiceLoader.create(ServiceLoader.load(MetricAnnotationDiscoveryObserver.class)) + .forEach(metricAnnotationDiscoveryObservers::add); + HelidonServiceLoader.create(ServiceLoader.load(MetricRegistrationObserver.class)) + .forEach(metricRegistrationObservers::add); } @Override diff --git a/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/spi/MetricAnnotationDiscoveryObserverProvider.java b/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/spi/MetricAnnotationDiscoveryObserverProvider.java deleted file mode 100644 index 08acdf96959..00000000000 --- a/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/spi/MetricAnnotationDiscoveryObserverProvider.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (c) 2022 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.helidon.microprofile.metrics.spi; - -import java.util.function.Supplier; - -/** - * Specifies behavior of a provider for a metric annotation discovery observer. - * - * @param specific type of {@link MetricAnnotationDiscoveryObserver} - */ -public interface MetricAnnotationDiscoveryObserverProvider extends Supplier { - - /** - * - * @return the new or pre-existing instance of the observer - */ - T get(); -} diff --git a/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/spi/MetricRegistrationObserverProvider.java b/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/spi/MetricRegistrationObserverProvider.java deleted file mode 100644 index f0a5a57e0f2..00000000000 --- a/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/spi/MetricRegistrationObserverProvider.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (c) 2022 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.helidon.microprofile.metrics.spi; - -import java.util.function.Supplier; - -/** - * Specifies behavior of a provider for a metric annotation discovery observer. - * - * @param specific type of {@link MetricRegistrationObserver} - */ -public interface MetricRegistrationObserverProvider extends Supplier { - - /** - * - * @return new or pre-existing instance of the observer - */ - T get(); -} diff --git a/microprofile/metrics/src/main/java/module-info.java b/microprofile/metrics/src/main/java/module-info.java index 9e7a90eb59b..78aa4d5a02c 100644 --- a/microprofile/metrics/src/main/java/module-info.java +++ b/microprofile/metrics/src/main/java/module-info.java @@ -48,6 +48,6 @@ provides jakarta.enterprise.inject.spi.Extension with io.helidon.microprofile.metrics.MetricsCdiExtension; - uses io.helidon.microprofile.metrics.spi.MetricAnnotationDiscoveryObserverProvider; - uses io.helidon.microprofile.metrics.spi.MetricRegistrationObserverProvider; + uses io.helidon.microprofile.metrics.spi.MetricAnnotationDiscoveryObserver; + uses io.helidon.microprofile.metrics.spi.MetricRegistrationObserver; } diff --git a/microprofile/metrics/src/test/java/io/helidon/microprofile/metrics/TestDiscoveryObserverImpl.java b/microprofile/metrics/src/test/java/io/helidon/microprofile/metrics/TestDiscoveryObserverImpl.java index 40d7c13e167..90046d4682b 100644 --- a/microprofile/metrics/src/test/java/io/helidon/microprofile/metrics/TestDiscoveryObserverImpl.java +++ b/microprofile/metrics/src/test/java/io/helidon/microprofile/metrics/TestDiscoveryObserverImpl.java @@ -18,27 +18,26 @@ import java.util.ArrayList; import java.util.List; -import io.helidon.common.LazyValue; import io.helidon.microprofile.metrics.spi.MetricAnnotationDiscoveryObserver; -import io.helidon.microprofile.metrics.spi.MetricAnnotationDiscoveryObserverProvider; public class TestDiscoveryObserverImpl implements MetricAnnotationDiscoveryObserver { - public static class Provider implements MetricAnnotationDiscoveryObserverProvider { + private static TestDiscoveryObserverImpl instance; - private static final LazyValue instance = LazyValue.create(TestDiscoveryObserverImpl::new); - - @Override - public TestDiscoveryObserverImpl get() { - return instance(); - } + static TestDiscoveryObserverImpl instance() { + return instance; + } - static TestDiscoveryObserverImpl instance() { - return instance.get(); - } + private static void instance(TestDiscoveryObserverImpl value) { + instance = value; } + private List discoveries = new ArrayList<>(); + public TestDiscoveryObserverImpl() { + instance(this); + } + @Override public void onDiscovery(MetricAnnotationDiscovery metricAnnotationDiscovery) { discoveries.add(metricAnnotationDiscovery); diff --git a/microprofile/metrics/src/test/java/io/helidon/microprofile/metrics/TestObservers.java b/microprofile/metrics/src/test/java/io/helidon/microprofile/metrics/TestObservers.java index 784cce19422..724a171fbf2 100644 --- a/microprofile/metrics/src/test/java/io/helidon/microprofile/metrics/TestObservers.java +++ b/microprofile/metrics/src/test/java/io/helidon/microprofile/metrics/TestObservers.java @@ -28,13 +28,13 @@ public class TestObservers { @Test void testDiscoveryObserver() { - TestDiscoveryObserverImpl observer = TestDiscoveryObserverImpl.Provider.instance(); + TestDiscoveryObserverImpl observer = TestDiscoveryObserverImpl.instance(); assertThat("Observer's discoveries", observer.discoveries().size(), is(not(0))); } @Test void testRegistrationObserver() { - TestRegistrationObserverImpl observer = TestRegistrationObserverImpl.Provider.instance(); + TestRegistrationObserverImpl observer = TestRegistrationObserverImpl.instance(); assertThat("Observer's registrations", observer.registrations(), is(not(0))); } } diff --git a/microprofile/metrics/src/test/java/io/helidon/microprofile/metrics/TestRegistrationObserverImpl.java b/microprofile/metrics/src/test/java/io/helidon/microprofile/metrics/TestRegistrationObserverImpl.java index a21b23ef70b..e4bd200238f 100644 --- a/microprofile/metrics/src/test/java/io/helidon/microprofile/metrics/TestRegistrationObserverImpl.java +++ b/microprofile/metrics/src/test/java/io/helidon/microprofile/metrics/TestRegistrationObserverImpl.java @@ -15,9 +15,7 @@ */ package io.helidon.microprofile.metrics; -import io.helidon.common.LazyValue; import io.helidon.microprofile.metrics.spi.MetricRegistrationObserver; -import io.helidon.microprofile.metrics.spi.MetricRegistrationObserverProvider; import org.eclipse.microprofile.metrics.Metadata; import org.eclipse.microprofile.metrics.Metric; @@ -25,22 +23,21 @@ public class TestRegistrationObserverImpl implements MetricRegistrationObserver { - public static class Provider implements MetricRegistrationObserverProvider { + private static TestRegistrationObserverImpl instance; - private static final LazyValue instance = - LazyValue.create(TestRegistrationObserverImpl::new); - - @Override - public TestRegistrationObserverImpl get() { - return instance(); - } + private static void instance(TestRegistrationObserverImpl value) { + instance = value; + } - static TestRegistrationObserverImpl instance() { - return instance.get(); - } + static TestRegistrationObserverImpl instance() { + return instance; } + private int registrations; + public TestRegistrationObserverImpl() { + instance(this); + } @Override public void onRegistration(MetricAnnotationDiscovery discovery, Metadata metadata, diff --git a/microprofile/metrics/src/test/resources/META-INF/services/io.helidon.microprofile.metrics.spi.MetricAnnotationDiscoveryObserverProvider b/microprofile/metrics/src/test/resources/META-INF/services/io.helidon.microprofile.metrics.spi.MetricAnnotationDiscoveryObserver similarity index 90% rename from microprofile/metrics/src/test/resources/META-INF/services/io.helidon.microprofile.metrics.spi.MetricAnnotationDiscoveryObserverProvider rename to microprofile/metrics/src/test/resources/META-INF/services/io.helidon.microprofile.metrics.spi.MetricAnnotationDiscoveryObserver index 9219aec9e5c..baa80eaa891 100644 --- a/microprofile/metrics/src/test/resources/META-INF/services/io.helidon.microprofile.metrics.spi.MetricAnnotationDiscoveryObserverProvider +++ b/microprofile/metrics/src/test/resources/META-INF/services/io.helidon.microprofile.metrics.spi.MetricAnnotationDiscoveryObserver @@ -14,4 +14,4 @@ # limitations under the License. # -io.helidon.microprofile.metrics.TestDiscoveryObserverImpl$Provider \ No newline at end of file +io.helidon.microprofile.metrics.TestDiscoveryObserverImpl \ No newline at end of file diff --git a/microprofile/metrics/src/test/resources/META-INF/services/io.helidon.microprofile.metrics.spi.MetricRegistrationObserverProvider b/microprofile/metrics/src/test/resources/META-INF/services/io.helidon.microprofile.metrics.spi.MetricRegistrationObserver similarity index 89% rename from microprofile/metrics/src/test/resources/META-INF/services/io.helidon.microprofile.metrics.spi.MetricRegistrationObserverProvider rename to microprofile/metrics/src/test/resources/META-INF/services/io.helidon.microprofile.metrics.spi.MetricRegistrationObserver index 830cdf15475..38e2a9301f6 100644 --- a/microprofile/metrics/src/test/resources/META-INF/services/io.helidon.microprofile.metrics.spi.MetricRegistrationObserverProvider +++ b/microprofile/metrics/src/test/resources/META-INF/services/io.helidon.microprofile.metrics.spi.MetricRegistrationObserver @@ -14,4 +14,4 @@ # limitations under the License. # -io.helidon.microprofile.metrics.TestRegistrationObserverImpl$Provider \ No newline at end of file +io.helidon.microprofile.metrics.TestRegistrationObserverImpl \ No newline at end of file From f5927368aa177bfe9824c711207e36747f51b73a Mon Sep 17 00:00:00 2001 From: "tim.quinn@oracle.com" Date: Sat, 9 Jul 2022 18:41:56 -0500 Subject: [PATCH 6/9] Add test to make sure normal non-gRPC metrics are handled correctly --- .../grpc/metrics/HelloWorldApp.java | 32 +++++++++++ .../grpc/metrics/HelloWorldResource.java | 53 +++++++++++++++++++ .../grpc/metrics/MetricsConfigurerTest.java | 24 +++++++++ 3 files changed, 109 insertions(+) create mode 100644 tests/integration/mp-grpc/src/test/java/io/helidon/microprofile/grpc/metrics/HelloWorldApp.java create mode 100644 tests/integration/mp-grpc/src/test/java/io/helidon/microprofile/grpc/metrics/HelloWorldResource.java diff --git a/tests/integration/mp-grpc/src/test/java/io/helidon/microprofile/grpc/metrics/HelloWorldApp.java b/tests/integration/mp-grpc/src/test/java/io/helidon/microprofile/grpc/metrics/HelloWorldApp.java new file mode 100644 index 00000000000..2f55281aaac --- /dev/null +++ b/tests/integration/mp-grpc/src/test/java/io/helidon/microprofile/grpc/metrics/HelloWorldApp.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2022 Oracle and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.helidon.microprofile.grpc.metrics; + +import java.util.Set; + +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.ws.rs.ApplicationPath; +import jakarta.ws.rs.core.Application; + +@ApplicationScoped +@ApplicationPath("/") +public class HelloWorldApp extends Application { + + @Override + public Set> getClasses() { + return Set.of(HelloWorldResource.class); + } +} diff --git a/tests/integration/mp-grpc/src/test/java/io/helidon/microprofile/grpc/metrics/HelloWorldResource.java b/tests/integration/mp-grpc/src/test/java/io/helidon/microprofile/grpc/metrics/HelloWorldResource.java new file mode 100644 index 00000000000..789dce17036 --- /dev/null +++ b/tests/integration/mp-grpc/src/test/java/io/helidon/microprofile/grpc/metrics/HelloWorldResource.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2022 Oracle and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.helidon.microprofile.grpc.metrics; + +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.inject.Inject; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.PathParam; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.core.MediaType; +import org.eclipse.microprofile.metrics.MetricRegistry; +import org.eclipse.microprofile.metrics.annotation.Counted; +import org.eclipse.microprofile.metrics.annotation.SimplyTimed; + +@ApplicationScoped +@Counted +public class HelloWorldResource { + + static final String MESSAGE_SIMPLE_TIMER = "messageSimpleTimer"; + + @Inject + private MetricRegistry metricRegistry; + + // Do not add other metrics annotations to this method! + @GET + @Produces(MediaType.TEXT_PLAIN) + public String message() { + metricRegistry.counter("helloCounter").inc(); + return "Hello World"; + } + + @GET + @SimplyTimed(name = MESSAGE_SIMPLE_TIMER, absolute = true) + @Path("/withArg/{name}") + @Produces(MediaType.TEXT_PLAIN) + public String messageWithArg(@PathParam("name") String input){ + return "Hello World, " + input; + } +} diff --git a/tests/integration/mp-grpc/src/test/java/io/helidon/microprofile/grpc/metrics/MetricsConfigurerTest.java b/tests/integration/mp-grpc/src/test/java/io/helidon/microprofile/grpc/metrics/MetricsConfigurerTest.java index 93ebcc813c8..21d97b9c03d 100644 --- a/tests/integration/mp-grpc/src/test/java/io/helidon/microprofile/grpc/metrics/MetricsConfigurerTest.java +++ b/tests/integration/mp-grpc/src/test/java/io/helidon/microprofile/grpc/metrics/MetricsConfigurerTest.java @@ -42,9 +42,11 @@ import jakarta.enterprise.inject.Typed; import jakarta.ws.rs.Produces; +import org.eclipse.microprofile.metrics.Counter; import org.eclipse.microprofile.metrics.MetricID; import org.eclipse.microprofile.metrics.MetricRegistry; import org.eclipse.microprofile.metrics.MetricType; +import org.eclipse.microprofile.metrics.SimpleTimer; import org.eclipse.microprofile.metrics.annotation.ConcurrentGauge; import org.eclipse.microprofile.metrics.annotation.Counted; import org.eclipse.microprofile.metrics.annotation.Metered; @@ -72,9 +74,12 @@ @AddBean(MetricsConfigurerTest.ServiceOne.class) @AddBean(MetricsConfigurerTest.ServiceThree.class) @AddBean(MetricsConfigurerTest.ServiceTwoProducer.class) +@AddBean(HelloWorldApp.class) +@AddBean(HelloWorldResource.class) @AddExtension(MetricsCdiExtension.class) @AddExtension(ServerCdiExtension.class) // needed for MetricsCdiExtension @AddExtension(JaxRsCdiExtension.class) +@AddExtension(org.glassfish.jersey.ext.cdi1x.internal.CdiComponentProvider.class) public class MetricsConfigurerTest { private static MetricRegistry registry; @@ -82,6 +87,7 @@ public class MetricsConfigurerTest { @BeforeAll public static void setup() { registry = RegistryFactory.getInstance().getRegistry(MetricRegistry.Type.APPLICATION); + } @Test @@ -324,6 +330,24 @@ public void shouldIgnoreConcurrentGaugeMetricFromInterfaceAnnotation() { assertThat(methodInterceptors, is(emptyIterable())); } + @Test + void checkNonGrpcResourceForMetrics() { + + Counter helloWorldClassLevelMessage = registry.getCounter( + new MetricID(HelloWorldResource.class.getName() + ".message")); + assertThat("message counter declared at class level", helloWorldClassLevelMessage, is(notNullValue())); + + SimpleTimer messageWithArgSimpleTimer = registry.getSimpleTimer( + new MetricID(HelloWorldResource.MESSAGE_SIMPLE_TIMER)); + assertThat("messageWithArg simple timer at method level", messageWithArgSimpleTimer, is(notNullValue())); + + Counter helloWorldClassLevelMessageWithArg = registry.getCounter( + new MetricID(HelloWorldResource.class.getName() + ".messageWithArg")); + assertThat("messageWithArg counter declared at class level", + helloWorldClassLevelMessageWithArg, + is(notNullValue())); + } + @Grpc public static class ServiceOne implements GrpcService { From 2e2efc0647bb3229ed09fecd59baa242a5ce85b4 Mon Sep 17 00:00:00 2001 From: "tim.quinn@oracle.com" Date: Sun, 10 Jul 2022 13:47:03 -0500 Subject: [PATCH 7/9] Enhance test for regularly-handed metrics annotations; don't rely on JAX-RS services, instead inject a test bean and invoke annotated methods to test interceptors --- tests/integration/mp-grpc/pom.xml | 5 --- .../grpc/metrics/HelloWorldApp.java | 32 ------------------- .../grpc/metrics/MetricsConfigurerTest.java | 30 +++++++++++++---- ...e.java => NonGrpcMetricAnnotatedBean.java} | 20 ++---------- 4 files changed, 26 insertions(+), 61 deletions(-) delete mode 100644 tests/integration/mp-grpc/src/test/java/io/helidon/microprofile/grpc/metrics/HelloWorldApp.java rename tests/integration/mp-grpc/src/test/java/io/helidon/microprofile/grpc/metrics/{HelloWorldResource.java => NonGrpcMetricAnnotatedBean.java} (67%) diff --git a/tests/integration/mp-grpc/pom.xml b/tests/integration/mp-grpc/pom.xml index 76fb280d474..f7f00467cf6 100644 --- a/tests/integration/mp-grpc/pom.xml +++ b/tests/integration/mp-grpc/pom.xml @@ -104,11 +104,6 @@ weld-se-core test - - org.glassfish.jersey.core - jersey-client - test -