From 66997dc7b277096927fdcd8102923ee3dd154719 Mon Sep 17 00:00:00 2001 From: Jonathan Gallimore Date: Thu, 23 Jun 2022 11:12:02 +0100 Subject: [PATCH] Allow different Micrometer backends to be configured --- implementation/pom.xml | 80 +++ .../legacyapi/LegacyMetricsExtension.java | 44 +- .../smallrye/metrics/micrometer/Backend.java | 30 ++ .../micrometer/MicrometerBackends.java | 510 ++++++++++++++++++ .../metrics/micrometer/RequiresClass.java | 28 + pom.xml | 80 +++ 6 files changed, 755 insertions(+), 17 deletions(-) create mode 100644 implementation/src/main/java/io/smallrye/metrics/micrometer/Backend.java create mode 100644 implementation/src/main/java/io/smallrye/metrics/micrometer/MicrometerBackends.java create mode 100644 implementation/src/main/java/io/smallrye/metrics/micrometer/RequiresClass.java diff --git a/implementation/pom.xml b/implementation/pom.xml index 68fda634..172791bd 100644 --- a/implementation/pom.xml +++ b/implementation/pom.xml @@ -133,6 +133,86 @@ micrometer-registry-prometheus true + + io.micrometer + micrometer-registry-appoptics + true + + + io.micrometer + micrometer-registry-atlas + true + + + io.micrometer + micrometer-registry-datadog + true + + + io.micrometer + micrometer-registry-dynatrace + true + + + io.micrometer + micrometer-registry-elastic + true + + + io.micrometer + micrometer-registry-ganglia + true + + + io.micrometer + micrometer-registry-graphite + true + + + io.micrometer + micrometer-registry-humio + true + + + io.micrometer + micrometer-registry-influx + true + + + io.micrometer + micrometer-registry-jmx + true + + + io.micrometer + micrometer-registry-kairos + true + + + io.micrometer + micrometer-registry-new-relic + true + + + io.micrometer + micrometer-registry-stackdriver + true + + + io.micrometer + micrometer-registry-signalfx + true + + + io.micrometer + micrometer-registry-statsd + true + + + io.micrometer + micrometer-registry-wavefront + true + diff --git a/implementation/src/main/java/io/smallrye/metrics/legacyapi/LegacyMetricsExtension.java b/implementation/src/main/java/io/smallrye/metrics/legacyapi/LegacyMetricsExtension.java index eaf82e8c..2d799002 100644 --- a/implementation/src/main/java/io/smallrye/metrics/legacyapi/LegacyMetricsExtension.java +++ b/implementation/src/main/java/io/smallrye/metrics/legacyapi/LegacyMetricsExtension.java @@ -6,25 +6,10 @@ import java.lang.reflect.Modifier; import java.security.AccessController; import java.security.PrivilegedAction; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.Properties; +import java.util.*; import javax.enterprise.event.Observes; -import javax.enterprise.inject.spi.AfterDeploymentValidation; -import javax.enterprise.inject.spi.AnnotatedMember; -import javax.enterprise.inject.spi.AnnotatedMethod; -import javax.enterprise.inject.spi.Bean; -import javax.enterprise.inject.spi.BeanManager; -import javax.enterprise.inject.spi.BeforeBeanDiscovery; -import javax.enterprise.inject.spi.BeforeShutdown; -import javax.enterprise.inject.spi.Extension; -import javax.enterprise.inject.spi.ProcessAnnotatedType; -import javax.enterprise.inject.spi.ProcessManagedBean; -import javax.enterprise.inject.spi.WithAnnotations; +import javax.enterprise.inject.spi.*; import javax.enterprise.util.AnnotationLiteral; import org.eclipse.microprofile.metrics.MetricID; @@ -33,6 +18,8 @@ import org.eclipse.microprofile.metrics.annotation.Gauge; import org.eclipse.microprofile.metrics.annotation.Timed; +import io.micrometer.core.instrument.MeterRegistry; +import io.micrometer.core.instrument.Metrics; import io.smallrye.metrics.MetricProducer; import io.smallrye.metrics.MetricRegistries; import io.smallrye.metrics.MetricsRequestHandler; @@ -46,6 +33,9 @@ import io.smallrye.metrics.legacyapi.interceptors.MetricResolver; import io.smallrye.metrics.legacyapi.interceptors.MetricsBinding; import io.smallrye.metrics.legacyapi.interceptors.TimedInterceptor; +import io.smallrye.metrics.micrometer.Backend; +import io.smallrye.metrics.micrometer.MicrometerBackends; +import io.smallrye.metrics.micrometer.RequiresClass; import io.smallrye.metrics.setup.MetricsMetadata; /** @@ -106,6 +96,16 @@ void registerAnnotatedTypes(@Observes BeforeBeanDiscovery bbd, BeanManager manag }) { bbd.addAnnotatedType(manager.createAnnotatedType(clazz), extensionName + "_" + clazz.getName()); } + + for (Class clazz : MicrometerBackends.classes()) { + try { + final RequiresClass requiresClass = (RequiresClass) clazz.getAnnotation(RequiresClass.class); + final Class[] requiredClass = requiresClass.value(); + bbd.addAnnotatedType(manager.createAnnotatedType(clazz), extensionName + "_" + clazz.getName()); + } catch (Exception e) { + // ignore and don't add + } + } } /* @@ -169,6 +169,16 @@ private void findAnnotatedMethods(@Observes ProcessManagedBean bean) { void registerMetrics(@Observes AfterDeploymentValidation adv, BeanManager manager) { + // register configured meter registries + + final Set> beans = manager.getBeans(MeterRegistry.class, MicrometerBackends.class.getAnnotation(Backend.class)); + for (Bean bean : beans) { + final Object reference = manager.getReference(bean, MeterRegistry.class, manager.createCreationalContext(bean)); + if (MeterRegistry.class.isInstance(reference)) { + Metrics.globalRegistry.add(MeterRegistry.class.cast(reference)); + } + } + // Produce and register custom metrics MetricRegistry registry = MetricRegistries.getOrCreate(MetricRegistry.Type.APPLICATION); BeanInfoAdapter> beanInfoAdapter = new CDIBeanInfoAdapter(); diff --git a/implementation/src/main/java/io/smallrye/metrics/micrometer/Backend.java b/implementation/src/main/java/io/smallrye/metrics/micrometer/Backend.java new file mode 100644 index 00000000..b1cbf314 --- /dev/null +++ b/implementation/src/main/java/io/smallrye/metrics/micrometer/Backend.java @@ -0,0 +1,30 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.smallrye.metrics.micrometer; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import javax.inject.Qualifier; + +@Qualifier +@Target({ ElementType.TYPE, ElementType.METHOD }) +@Retention(RetentionPolicy.RUNTIME) +public @interface Backend { +} diff --git a/implementation/src/main/java/io/smallrye/metrics/micrometer/MicrometerBackends.java b/implementation/src/main/java/io/smallrye/metrics/micrometer/MicrometerBackends.java new file mode 100644 index 00000000..eb4f285c --- /dev/null +++ b/implementation/src/main/java/io/smallrye/metrics/micrometer/MicrometerBackends.java @@ -0,0 +1,510 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.smallrye.metrics.micrometer; + +import javax.enterprise.inject.Produces; +import javax.inject.Inject; + +import org.eclipse.microprofile.config.Config; + +import com.netflix.spectator.atlas.AtlasConfig; + +import io.micrometer.appoptics.AppOpticsConfig; +import io.micrometer.appoptics.AppOpticsMeterRegistry; +import io.micrometer.atlas.AtlasMeterRegistry; +import io.micrometer.core.instrument.MeterRegistry; +import io.micrometer.core.instrument.simple.SimpleConfig; +import io.micrometer.core.instrument.simple.SimpleMeterRegistry; +import io.micrometer.datadog.DatadogConfig; +import io.micrometer.datadog.DatadogMeterRegistry; +import io.micrometer.dynatrace.DynatraceConfig; +import io.micrometer.dynatrace.DynatraceMeterRegistry; +import io.micrometer.elastic.ElasticConfig; +import io.micrometer.elastic.ElasticMeterRegistry; +import io.micrometer.ganglia.GangliaConfig; +import io.micrometer.ganglia.GangliaMeterRegistry; +import io.micrometer.graphite.GraphiteConfig; +import io.micrometer.graphite.GraphiteMeterRegistry; +import io.micrometer.humio.HumioConfig; +import io.micrometer.humio.HumioMeterRegistry; +import io.micrometer.influx.InfluxConfig; +import io.micrometer.influx.InfluxMeterRegistry; +import io.micrometer.jmx.JmxConfig; +import io.micrometer.jmx.JmxMeterRegistry; +import io.micrometer.kairos.KairosConfig; +import io.micrometer.kairos.KairosMeterRegistry; +import io.micrometer.newrelic.NewRelicConfig; +import io.micrometer.newrelic.NewRelicMeterRegistry; +import io.micrometer.prometheus.PrometheusConfig; +import io.micrometer.prometheus.PrometheusMeterRegistry; +import io.micrometer.signalfx.SignalFxConfig; +import io.micrometer.signalfx.SignalFxMeterRegistry; +import io.micrometer.stackdriver.StackdriverConfig; +import io.micrometer.stackdriver.StackdriverMeterRegistry; +import io.micrometer.statsd.StatsdConfig; +import io.micrometer.statsd.StatsdMeterRegistry; +import io.micrometer.wavefront.WavefrontConfig; +import io.micrometer.wavefront.WavefrontMeterRegistry; + +@Backend +public class MicrometerBackends { + + public static Class[] classes() { + return new Class[] { + AppOpticsBackendProducer.class, + AtlasBackendProducer.class, + DatadogBackendProducer.class, + ElasticBackendProducer.class, + GraphiteBackendProducer.class, + GangliaBackendProducer.class, + HumioBackendProducer.class, + InfluxBackendProducer.class, + JmxBackendProducer.class, + KairosBackendProducer.class, + NewRelicBackendProducer.class, + PrometheusBackendProducer.class, + SignalFxBackendProducer.class, + StackdriverBackendProducer.class, + StatsdBackendProducer.class, + WavefrontBackendProducer.class + }; + } + + @RequiresClass({ AppOpticsMeterRegistry.class, AppOpticsConfig.class }) + public static class AppOpticsBackendProducer { + + @Inject + private Config config; + + @Produces + @Backend + public MeterRegistry produce() { + if (!Boolean.parseBoolean( + config.getOptionalValue("microprofile.metrics.appoptics.enabled", String.class).orElse("false"))) { + return null; + } + + return new AppOpticsMeterRegistry(new AppOpticsConfig() { + @Override + public String get(final String propertyName) { + return config.getOptionalValue("microprofile.metrics." + propertyName, String.class) + .orElse(null); + } + }, io.micrometer.core.instrument.Clock.SYSTEM); + } + } + + @RequiresClass({ AtlasMeterRegistry.class, AtlasConfig.class }) + public static class AtlasBackendProducer { + + @Inject + private Config config; + + @Produces + @Backend + public MeterRegistry produce() { + if (!Boolean.parseBoolean( + config.getOptionalValue("microprofile.metrics.atlas.enabled", String.class).orElse("false"))) { + return null; + } + + return new AtlasMeterRegistry(new AtlasConfig() { + @Override + public String get(final String propertyName) { + return config.getOptionalValue("microprofile.metrics." + propertyName, String.class) + .orElse(null); + } + }, io.micrometer.core.instrument.Clock.SYSTEM); + } + } + + @RequiresClass({ DatadogMeterRegistry.class, DatadogConfig.class }) + public static class DatadogBackendProducer { + + @Inject + private Config config; + + @Produces + @Backend + public MeterRegistry produce() { + if (!Boolean.parseBoolean( + config.getOptionalValue("microprofile.metrics.datadog.enabled", String.class).orElse("false"))) { + return null; + } + + return new DatadogMeterRegistry(new DatadogConfig() { + @Override + public String get(final String propertyName) { + return config.getOptionalValue("microprofile.metrics." + propertyName, String.class) + .orElse(null); + } + }, io.micrometer.core.instrument.Clock.SYSTEM); + } + } + + @RequiresClass({ DynatraceMeterRegistry.class, DynatraceConfig.class }) + public static class DynatraceBackendProducer { + + @Inject + private Config config; + + @Produces + @Backend + public MeterRegistry produce() { + if (!Boolean.parseBoolean( + config.getOptionalValue("microprofile.metrics.dynatrace.enabled", String.class).orElse("false"))) { + return null; + } + + return new DynatraceMeterRegistry(new DynatraceConfig() { + @Override + public String get(final String propertyName) { + return config.getOptionalValue("microprofile.metrics." + propertyName, String.class) + .orElse(null); + } + }, io.micrometer.core.instrument.Clock.SYSTEM); + } + } + + @RequiresClass({ ElasticMeterRegistry.class, ElasticConfig.class }) + public static class ElasticBackendProducer { + + @Inject + private Config config; + + @Produces + @Backend + public MeterRegistry produce() { + if (!Boolean.parseBoolean( + config.getOptionalValue("microprofile.metrics.elastic.enabled", String.class).orElse("false"))) { + return null; + } + + return new ElasticMeterRegistry(new ElasticConfig() { + @Override + public String get(final String propertyName) { + return config.getOptionalValue("microprofile.metrics." + propertyName, String.class) + .orElse(null); + } + }, io.micrometer.core.instrument.Clock.SYSTEM); + } + } + + @RequiresClass({ GangliaMeterRegistry.class, GangliaConfig.class }) + public static class GangliaBackendProducer { + + @Inject + private Config config; + + @Produces + @Backend + public MeterRegistry produce() { + if (!Boolean.parseBoolean( + config.getOptionalValue("microprofile.metrics.ganglia.enabled", String.class).orElse("false"))) { + return null; + } + + return new GangliaMeterRegistry(new GangliaConfig() { + @Override + public String get(final String propertyName) { + return config.getOptionalValue("microprofile.metrics." + propertyName, String.class) + .orElse(null); + } + }, io.micrometer.core.instrument.Clock.SYSTEM); + } + } + + @RequiresClass({ GraphiteMeterRegistry.class, GraphiteConfig.class }) + public static class GraphiteBackendProducer { + + @Inject + private Config config; + + @Produces + @Backend + public MeterRegistry produce() { + if (!Boolean.parseBoolean( + config.getOptionalValue("microprofile.metrics.graphite.enabled", String.class).orElse("false"))) { + return null; + } + + return new GraphiteMeterRegistry(new GraphiteConfig() { + @Override + public String get(final String propertyName) { + return config.getOptionalValue("microprofile.metrics." + propertyName, String.class) + .orElse(null); + } + }, io.micrometer.core.instrument.Clock.SYSTEM); + } + } + + @RequiresClass({ HumioMeterRegistry.class, HumioConfig.class }) + public static class HumioBackendProducer { + + @Inject + private Config config; + + @Produces + @Backend + public MeterRegistry produce() { + if (!Boolean.parseBoolean( + config.getOptionalValue("microprofile.metrics.humio.enabled", String.class).orElse("false"))) { + return null; + } + + return new HumioMeterRegistry(new HumioConfig() { + @Override + public String get(final String propertyName) { + return config.getOptionalValue("microprofile.metrics." + propertyName, String.class) + .orElse(null); + } + }, io.micrometer.core.instrument.Clock.SYSTEM); + } + } + + @RequiresClass({ InfluxMeterRegistry.class, InfluxConfig.class }) + public static class InfluxBackendProducer { + + @Inject + private Config config; + + @Produces + @Backend + public MeterRegistry produce() { + if (!Boolean.parseBoolean( + config.getOptionalValue("microprofile.metrics.influx.enabled", String.class).orElse("false"))) { + return null; + } + + return new InfluxMeterRegistry(new InfluxConfig() { + @Override + public String get(final String propertyName) { + return config.getOptionalValue("microprofile.metrics." + propertyName, String.class) + .orElse(null); + } + }, io.micrometer.core.instrument.Clock.SYSTEM); + } + } + + @RequiresClass({ JmxMeterRegistry.class, JmxConfig.class }) + public static class JmxBackendProducer { + + @Inject + private Config config; + + @Produces + @Backend + public MeterRegistry produce() { + if (!Boolean + .parseBoolean(config.getOptionalValue("microprofile.metrics.jmx.enabled", String.class).orElse("false"))) { + return null; + } + + return new JmxMeterRegistry(new JmxConfig() { + @Override + public String get(final String propertyName) { + return config.getOptionalValue("microprofile.metrics." + propertyName, String.class) + .orElse(null); + } + }, io.micrometer.core.instrument.Clock.SYSTEM); + } + } + + @RequiresClass({ KairosMeterRegistry.class, KairosConfig.class }) + public static class KairosBackendProducer { + + @Inject + private Config config; + + @Produces + @Backend + public MeterRegistry produce() { + if (!Boolean.parseBoolean( + config.getOptionalValue("microprofile.metrics.kairos.enabled", String.class).orElse("false"))) { + return null; + } + + return new KairosMeterRegistry(new KairosConfig() { + @Override + public String get(final String propertyName) { + return config.getOptionalValue("microprofile.metrics." + propertyName, String.class) + .orElse(null); + } + }, io.micrometer.core.instrument.Clock.SYSTEM); + } + } + + @RequiresClass({ NewRelicMeterRegistry.class, NewRelicConfig.class }) + public static class NewRelicBackendProducer { + + @Inject + private Config config; + + @Produces + @Backend + public MeterRegistry produce() { + if (!Boolean.parseBoolean( + config.getOptionalValue("microprofile.metrics.newrelic.enabled", String.class).orElse("false"))) { + return null; + } + + return new NewRelicMeterRegistry(new NewRelicConfig() { + @Override + public String get(final String propertyName) { + return config.getOptionalValue("microprofile.metrics." + propertyName, String.class) + .orElse(null); + } + }, io.micrometer.core.instrument.Clock.SYSTEM); + } + } + + @RequiresClass({ PrometheusMeterRegistry.class, PrometheusConfig.class }) + public static class PrometheusBackendProducer { + + @Inject + private Config config; + + @Produces + @Backend + public MeterRegistry produce() { + if (!Boolean.parseBoolean( + config.getOptionalValue("microprofile.metrics.prometheus.enabled", String.class).orElse("true"))) { + return null; + } + + return new PrometheusMeterRegistry(new PrometheusConfig() { + @Override + public String get(final String propertyName) { + return config.getOptionalValue("microprofile.metrics." + propertyName, String.class) + .orElse(null); + } + }); + } + } + + @RequiresClass({ StackdriverMeterRegistry.class, StackdriverConfig.class }) + public static class StackdriverBackendProducer { + + @Inject + private Config config; + + @Produces + @Backend + public MeterRegistry produce() { + if (!Boolean.parseBoolean( + config.getOptionalValue("microprofile.metrics.stackdriver.enabled", String.class).orElse("false"))) { + return null; + } + + return new StackdriverMeterRegistry(new StackdriverConfig() { + @Override + public String get(final String propertyName) { + return config.getOptionalValue("microprofile.metrics." + propertyName, String.class) + .orElse(null); + } + }, io.micrometer.core.instrument.Clock.SYSTEM); + } + } + + @RequiresClass({ SignalFxMeterRegistry.class, SignalFxConfig.class }) + public static class SignalFxBackendProducer { + + @Inject + private Config config; + + @Produces + @Backend + public MeterRegistry produce() { + if (!Boolean.parseBoolean( + config.getOptionalValue("microprofile.metrics.signalfx.enabled", String.class).orElse("false"))) { + return null; + } + + return new SignalFxMeterRegistry(new SignalFxConfig() { + @Override + public String get(final String propertyName) { + return config.getOptionalValue("microprofile.metrics." + propertyName, String.class) + .orElse(null); + } + }, io.micrometer.core.instrument.Clock.SYSTEM); + } + } + + @RequiresClass({ StatsdMeterRegistry.class, StatsdConfig.class }) + public static class StatsdBackendProducer { + + @Inject + private Config config; + + @Produces + @Backend + public MeterRegistry produce() { + if (!Boolean.parseBoolean( + config.getOptionalValue("microprofile.metrics.statsd.enabled", String.class).orElse("false"))) { + return null; + } + + return new StatsdMeterRegistry(new StatsdConfig() { + @Override + public String get(final String propertyName) { + return config.getOptionalValue("microprofile.metrics." + propertyName, String.class) + .orElse(null); + } + }, io.micrometer.core.instrument.Clock.SYSTEM); + } + } + + @RequiresClass({ WavefrontMeterRegistry.class, WavefrontConfig.class }) + public static class WavefrontBackendProducer { + + @Inject + private Config config; + + @Produces + @Backend + public MeterRegistry produce() { + if (!Boolean.parseBoolean( + config.getOptionalValue("microprofile.metrics.wavefront.enabled", String.class).orElse("false"))) { + return null; + } + return new WavefrontMeterRegistry(new WavefrontConfig() { + @Override + public String get(final String propertyName) { + return config.getOptionalValue("microprofile.metrics." + propertyName, String.class) + .orElse(null); + } + }, io.micrometer.core.instrument.Clock.SYSTEM); + } + } + + public static class SimpleMeterRegistryProducer { + @Inject + private Config config; + + @Produces + @Backend + public MeterRegistry produce() { + return new SimpleMeterRegistry(new SimpleConfig() { + @Override + public String get(final String propertyName) { + return config.getOptionalValue("microprofile.metrics." + propertyName, String.class) + .orElse(null); + } + }, io.micrometer.core.instrument.Clock.SYSTEM); + } + } +} diff --git a/implementation/src/main/java/io/smallrye/metrics/micrometer/RequiresClass.java b/implementation/src/main/java/io/smallrye/metrics/micrometer/RequiresClass.java new file mode 100644 index 00000000..ff765411 --- /dev/null +++ b/implementation/src/main/java/io/smallrye/metrics/micrometer/RequiresClass.java @@ -0,0 +1,28 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.smallrye.metrics.micrometer; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target({ ElementType.TYPE, ElementType.METHOD }) +@Retention(RetentionPolicy.RUNTIME) +public @interface RequiresClass { + Class[] value() default {}; +} diff --git a/pom.xml b/pom.xml index 59d4c1ac..875233a0 100644 --- a/pom.xml +++ b/pom.xml @@ -83,6 +83,86 @@ micrometer-registry-prometheus ${version.micrometer} + + io.micrometer + micrometer-registry-appoptics + ${version.micrometer} + + + io.micrometer + micrometer-registry-atlas + ${version.micrometer} + + + io.micrometer + micrometer-registry-datadog + ${version.micrometer} + + + io.micrometer + micrometer-registry-dynatrace + ${version.micrometer} + + + io.micrometer + micrometer-registry-elastic + ${version.micrometer} + + + io.micrometer + micrometer-registry-ganglia + ${version.micrometer} + + + io.micrometer + micrometer-registry-graphite + ${version.micrometer} + + + io.micrometer + micrometer-registry-humio + ${version.micrometer} + + + io.micrometer + micrometer-registry-influx + ${version.micrometer} + + + io.micrometer + micrometer-registry-jmx + ${version.micrometer} + + + io.micrometer + micrometer-registry-kairos + ${version.micrometer} + + + io.micrometer + micrometer-registry-new-relic + ${version.micrometer} + + + io.micrometer + micrometer-registry-stackdriver + ${version.micrometer} + + + io.micrometer + micrometer-registry-signalfx + ${version.micrometer} + + + io.micrometer + micrometer-registry-statsd + ${version.micrometer} + + + io.micrometer + micrometer-registry-wavefront + ${version.micrometer} + org.eclipse.microprofile.config microprofile-config-api