From db10c3f538a30f936ef740f14281177ddc9e626c Mon Sep 17 00:00:00 2001 From: Tim Quinn Date: Wed, 30 Aug 2023 16:33:52 -0500 Subject: [PATCH] Save changes for safekeeping; also share it --- .../api/DistributionStatisticsConfig.java | 28 ++ .../java/io/helidon/metrics/api/Gauge.java | 7 + .../java/io/helidon/metrics/api/Meter.java | 8 + .../io/helidon/metrics/api/MeterRegistry.java | 44 +++ .../helidon/metrics/api/MetricsFactory.java | 49 ++- .../io/helidon/metrics/api/NoOpMeter.java | 34 ++ .../metrics/api/NoOpMeterRegistry.java | 32 ++ .../metrics/api/NoOpMetricsFactory.java | 5 + .../MDistributionStatisticsConfig.java | 57 ++- .../micrometer/MDistributionSummary.java | 17 + .../micrometer/MFunctionalCounter.java | 23 +- .../metrics/providers/micrometer/MGauge.java | 17 + .../metrics/providers/micrometer/MMeter.java | 12 +- .../providers/micrometer/MMeterRegistry.java | 328 +++++++++++++----- .../metrics/providers/micrometer/MTimer.java | 30 +- .../micrometer/MicrometerMetricsFactory.java | 81 ++++- .../MicrometerMetricsFactoryProvider.java | 10 +- 17 files changed, 659 insertions(+), 123 deletions(-) diff --git a/metrics/api/src/main/java/io/helidon/metrics/api/DistributionStatisticsConfig.java b/metrics/api/src/main/java/io/helidon/metrics/api/DistributionStatisticsConfig.java index a8931725af6..57dac96e8b5 100644 --- a/metrics/api/src/main/java/io/helidon/metrics/api/DistributionStatisticsConfig.java +++ b/metrics/api/src/main/java/io/helidon/metrics/api/DistributionStatisticsConfig.java @@ -126,5 +126,33 @@ interface Builder extends Wrapper, io.helidon.common.Builder buckets); + + /** + * Returns the minimum expected value setting. + * + * @return min expected value + */ + Optional minimumExpectedValue(); + + /** + * Returns the maximum expected value setting. + * + * @return max expected value + */ + Optional maximumExpectedValue(); + + /** + * Returns the percentiles. + * + * @return percentiles + */ + Iterable percentiles(); + + /** + * Returns the buckets. + * + * @return buckets + */ + Iterable buckets(); } } diff --git a/metrics/api/src/main/java/io/helidon/metrics/api/Gauge.java b/metrics/api/src/main/java/io/helidon/metrics/api/Gauge.java index 15649cea40f..565351757cc 100644 --- a/metrics/api/src/main/java/io/helidon/metrics/api/Gauge.java +++ b/metrics/api/src/main/java/io/helidon/metrics/api/Gauge.java @@ -68,5 +68,12 @@ static Builder builder(String name, Supplier numberSupp * @param specific subtype of {@code Number} for the gauge this builder will produce */ interface Builder extends Meter.Builder, Gauge> { + + /** + * Returns a {@link java.util.function.Supplier} for the values the gauge will produce. + * + * @return supplier for the values + */ + Supplier supplier(); } } diff --git a/metrics/api/src/main/java/io/helidon/metrics/api/Meter.java b/metrics/api/src/main/java/io/helidon/metrics/api/Meter.java index 9960b209e34..79059e3b85d 100644 --- a/metrics/api/src/main/java/io/helidon/metrics/api/Meter.java +++ b/metrics/api/src/main/java/io/helidon/metrics/api/Meter.java @@ -115,6 +115,14 @@ default B identity() { return (B) this; } +// /** +// * Use the settings in the current builder to prepare the target builder. +// * +// * @param target other builder to set up +// * @return updated other builder +// */ +// > T copyTo(T target); + /** * Sets the tags to use in identifying the build meter. * diff --git a/metrics/api/src/main/java/io/helidon/metrics/api/MeterRegistry.java b/metrics/api/src/main/java/io/helidon/metrics/api/MeterRegistry.java index 89a7f102581..971d9e7dfe7 100644 --- a/metrics/api/src/main/java/io/helidon/metrics/api/MeterRegistry.java +++ b/metrics/api/src/main/java/io/helidon/metrics/api/MeterRegistry.java @@ -22,6 +22,8 @@ import java.util.function.Consumer; import java.util.function.Predicate; +import io.helidon.common.Builder; + /** * Manages the look-up and registration of meters. */ @@ -219,4 +221,46 @@ default Optional timer(String name, Iterable tags) { * @return the meter registry */ MeterRegistry onMeterRemoved(Consumer onRemoveListener); + + /** + * Builder for creating a new meter registry. + * + * @param builder type + * @param meter registry type + */ + interface Builder, R extends MeterRegistry> extends io.helidon.common.Builder { + + /** + * Assigns the clock to be used within the meter registry (e.g., in timers), defaulting to a system clock. + * + * @param clock the {@link io.helidon.metrics.api.Clock} to be used + * @return updated builder + */ + B clock(Clock clock); + + /** + * Sets the {@link io.helidon.metrics.api.MetricsConfig} for the meter registry, defaulting to the + * metrics config with which the {@link io.helidon.metrics.api.MetricsFactory} was created. + * + * @param metricsConfig metrics config to control the meter registry + * @return updated builder + */ + B metricsConfig(MetricsConfig metricsConfig); + + /** + * Records a subscriber to meter-added events. + * + * @param addListener listener for meter-added events + * @return updated builder + */ + B onMeterAdded(Consumer addListener); + + /** + * Records a subscriber to meter-removed events. + * + * @param removeListener listener for meter-removal events + * @return updated builder + */ + B onMeterRemoved(Consumer removeListener); + } } diff --git a/metrics/api/src/main/java/io/helidon/metrics/api/MetricsFactory.java b/metrics/api/src/main/java/io/helidon/metrics/api/MetricsFactory.java index 861607dec55..e9f4c0ba2c7 100644 --- a/metrics/api/src/main/java/io/helidon/metrics/api/MetricsFactory.java +++ b/metrics/api/src/main/java/io/helidon/metrics/api/MetricsFactory.java @@ -100,6 +100,15 @@ static MetricsFactory getInstance(Config rootConfig) { */ MetricsConfig metricsConfig(); + /** + * Returns a builder for creating a new {@link io.helidon.metrics.api.MeterRegistry}. + * + * @return the new builder + * @param specific type of the builder + * @param specific type of the registry + */ + , M extends MeterRegistry> B meterRegistryBuilder(); + /** * Creates a new {@link io.helidon.metrics.api.MeterRegistry} using the provided metrics config. * @@ -264,16 +273,48 @@ MeterRegistry createMeterRegistry(Clock clock, */ HistogramSnapshot histogramSnapshotEmpty(long count, double total, double max); +// /** +// * Returns a no-op {@link io.helidon.metrics.api.Meter} of the type implied by the builder's type, initialized with +// * the builder's name and other required parameters. +// * +// * @param builder original builder +// * @param type of the builder +// * @param type of the meter the builder produces +// * @return corresponding no-op meter +// */ +// default > Meter noOpMeter(B builder) { +// if (builder instanceof Counter.Builder cb) { +// return NoOpMeter.Counter.builder(cb.name()).build(); +// } +// if (builder instanceof FunctionalCounter.Builder fcb) { +// return NoOpMeter.FunctionalCounter.builder(fcb.name(), fcb.stateObject(), fcb.fn()).build(); +// } +// if (builder instanceof DistributionSummary.Builder sb) { +// return NoOpMeter.DistributionSummary.builder(sb.name()).build(); +// } +// // if (builder instanceof Gauge.FunctionBasedBuilder gb) { +// // return NoOpMeter.Gauge.builder(gb.name(), gb.stateObject(), gb.fn()).build(); +// // } +// // if (builder instanceof Gauge.NumberBasedBuilder nb) { +// // return NoOpMeter.Gauge.builder(nb.name(), nb.number()); +// // } +// // if (builder instanceof Gauge.SupplierBased sb) { +// // return NoOpMeter.Gauge.builder(sb.name(), sb.supplier()); +// // } +// if (builder instanceof Timer.Builder tb) { +// return NoOpMeter.Timer.builder(tb.name()).build(); +// } +// throw new IllegalArgumentException("Unrecognized meter builder type " + builder.getClass().getName()); +// } + /** - * Returns a no-op {@link io.helidon.metrics.api.Meter} of the type implied by the builder's type, initialized with + * Returns a no-op {@link io.helidon.metrics.api.Meter} of the type implied by the builder's runtime type, initialized with * the builder's name and other required parameters. * * @param builder original builder - * @param type of the builder - * @param type of the meter the builder produces * @return corresponding no-op meter */ - default > Meter noOpMeter(B builder) { + default Meter noOpMeter(Meter.Builder builder) { if (builder instanceof Counter.Builder cb) { return NoOpMeter.Counter.builder(cb.name()).build(); } diff --git a/metrics/api/src/main/java/io/helidon/metrics/api/NoOpMeter.java b/metrics/api/src/main/java/io/helidon/metrics/api/NoOpMeter.java index fa74eeb656b..5c224b3c4ca 100644 --- a/metrics/api/src/main/java/io/helidon/metrics/api/NoOpMeter.java +++ b/metrics/api/src/main/java/io/helidon/metrics/api/NoOpMeter.java @@ -257,6 +257,10 @@ public Counter build() { return new NoOpMeter.Counter(this); } +// @Override +// public > T copyTo(T target) { +// return target; +// } } } @@ -487,6 +491,11 @@ public Double value() { } }; } + + @Override + public Supplier supplier() { + return () -> fn.applyAsDouble(stateObject); + } } static class SupplierBased extends Builder, N> { @@ -506,6 +515,11 @@ public N value() { } }; } + + @Override + public Supplier supplier() { + return supplier; + } } } } @@ -738,6 +752,26 @@ public io.helidon.metrics.api.DistributionStatisticsConfig.Builder buckets(doubl public io.helidon.metrics.api.DistributionStatisticsConfig.Builder buckets(Iterable buckets) { return identity(); } + + @Override + public Optional minimumExpectedValue() { + return Optional.empty(); + } + + @Override + public Optional maximumExpectedValue() { + return Optional.empty(); + } + + @Override + public Iterable percentiles() { + return Set.of(); + } + + @Override + public Iterable buckets() { + return Set.of(); + } } } } diff --git a/metrics/api/src/main/java/io/helidon/metrics/api/NoOpMeterRegistry.java b/metrics/api/src/main/java/io/helidon/metrics/api/NoOpMeterRegistry.java index fa4486450e3..820370470fd 100644 --- a/metrics/api/src/main/java/io/helidon/metrics/api/NoOpMeterRegistry.java +++ b/metrics/api/src/main/java/io/helidon/metrics/api/NoOpMeterRegistry.java @@ -32,6 +32,10 @@ */ class NoOpMeterRegistry implements MeterRegistry, NoOpWrapper { + static Builder builder() { + return new Builder(); + } + @Override public List meters() { return List.of(); @@ -115,6 +119,34 @@ public MeterRegistry onMeterRemoved(Consumer listener) { return this; } + static class Builder implements MeterRegistry.Builder { + + @Override + public NoOpMeterRegistry build() { + return new NoOpMeterRegistry(); + } + + @Override + public Builder clock(Clock clock) { + return identity(); + } + + @Override + public Builder metricsConfig(MetricsConfig metricsConfig) { + return identity(); + } + + @Override + public Builder onMeterAdded(Consumer addListener) { + return identity(); + } + + @Override + public Builder onMeterRemoved(Consumer removeListener) { + return identity(); + } + } + private Optional find(Meter.Id id, Class mClass) { return Optional.empty(); } diff --git a/metrics/api/src/main/java/io/helidon/metrics/api/NoOpMetricsFactory.java b/metrics/api/src/main/java/io/helidon/metrics/api/NoOpMetricsFactory.java index d9d4954c343..d047efce84b 100644 --- a/metrics/api/src/main/java/io/helidon/metrics/api/NoOpMetricsFactory.java +++ b/metrics/api/src/main/java/io/helidon/metrics/api/NoOpMetricsFactory.java @@ -63,6 +63,11 @@ public MetricsConfig metricsConfig() { return metricsConfig; } + @Override + public NoOpMeterRegistry.Builder meterRegistryBuilder() { + return NoOpMeterRegistry.builder(); + } + @Override public MeterRegistry createMeterRegistry(MetricsConfig metricsConfig) { return new NoOpMeterRegistry(); diff --git a/metrics/providers/micrometer/src/main/java/io/helidon/metrics/providers/micrometer/MDistributionStatisticsConfig.java b/metrics/providers/micrometer/src/main/java/io/helidon/metrics/providers/micrometer/MDistributionStatisticsConfig.java index b46d17453f4..20f89185042 100644 --- a/metrics/providers/micrometer/src/main/java/io/helidon/metrics/providers/micrometer/MDistributionStatisticsConfig.java +++ b/metrics/providers/micrometer/src/main/java/io/helidon/metrics/providers/micrometer/MDistributionStatisticsConfig.java @@ -15,9 +15,16 @@ */ package io.helidon.metrics.providers.micrometer; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; import java.util.Objects; import java.util.Optional; import java.util.function.Supplier; +import java.util.stream.StreamSupport; + +import io.helidon.metrics.api.DistributionStatisticsConfig; import io.micrometer.core.instrument.distribution.DistributionStatisticConfig; @@ -52,6 +59,13 @@ static T chooseOpt(T fromChild, Supplier> fromParent) { () -> fromParent.get().orElse(null)); } + static MDistributionStatisticsConfig.Builder builderFrom(DistributionStatisticsConfig.Builder other) { + MDistributionStatisticsConfig.Builder configBuilder = MDistributionStatisticsConfig.builder(); + configBuilder.from(other); + return configBuilder; + } + + @Override public Optional> percentiles() { return Optional.ofNullable(Util.iterable(delegate.getPercentiles())); @@ -84,6 +98,11 @@ io.micrometer.core.instrument.distribution.DistributionStatisticConfig delegate( static class Builder implements io.helidon.metrics.api.DistributionStatisticsConfig.Builder { private final DistributionStatisticConfig.Builder delegate; + private Optional min = Optional.empty(); + private Optional max = Optional.empty(); + private double[] percentiles; + private double[] buckets; + private Builder() { delegate = DistributionStatisticConfig.builder(); @@ -96,40 +115,66 @@ public MDistributionStatisticsConfig build() { @Override public Builder minimumExpectedValue(Double min) { + this.min = Optional.of(min); delegate.minimumExpectedValue(min); return this; } @Override public Builder maximumExpectedValue(Double max) { + this.max = Optional.of(max); delegate.maximumExpectedValue(max); return this; } @Override public Builder percentiles(double... percentiles) { + this.percentiles = percentiles; delegate.percentiles(percentiles); return this; } @Override public Builder percentiles(Iterable percentiles) { - delegate.percentiles(Util.doubleArray(percentiles)); + this.percentiles = Util.doubleArray(percentiles); + delegate.percentiles(this.percentiles); return this; } @Override public Builder buckets(double... buckets) { + this.buckets = buckets; delegate.serviceLevelObjectives(buckets); return this; } @Override public Builder buckets(Iterable buckets) { - delegate.serviceLevelObjectives(Util.doubleArray(buckets)); + this.buckets = Util.doubleArray(buckets); + delegate.serviceLevelObjectives(this.buckets); return this; } + @Override + public Optional minimumExpectedValue() { + return min; + } + + @Override + public Optional maximumExpectedValue() { + return max; + } + + @Override + public Iterable percentiles() { + return Util.iterable(percentiles); + } + + @Override + public Iterable buckets() { + return Util.iterable(buckets); + } + @Override public R unwrap(Class c) { return c.cast(delegate); @@ -138,5 +183,13 @@ public R unwrap(Class c) { DistributionStatisticConfig.Builder delegate() { return delegate; } + + public Builder from(DistributionStatisticsConfig.Builder other) { + other.minimumExpectedValue().ifPresent(this::minimumExpectedValue); + other.maximumExpectedValue().ifPresent(this::maximumExpectedValue); + buckets = Util.doubleArray(other.buckets()); + percentiles = Util.doubleArray(other.percentiles()); + return this; + } } } diff --git a/metrics/providers/micrometer/src/main/java/io/helidon/metrics/providers/micrometer/MDistributionSummary.java b/metrics/providers/micrometer/src/main/java/io/helidon/metrics/providers/micrometer/MDistributionSummary.java index 87bc2d9d771..035492630d2 100644 --- a/metrics/providers/micrometer/src/main/java/io/helidon/metrics/providers/micrometer/MDistributionSummary.java +++ b/metrics/providers/micrometer/src/main/java/io/helidon/metrics/providers/micrometer/MDistributionSummary.java @@ -18,6 +18,7 @@ import java.util.Optional; import io.helidon.metrics.api.DistributionStatisticsConfig; +import io.helidon.metrics.api.DistributionSummary; import io.helidon.metrics.api.HistogramSnapshot; import io.helidon.metrics.api.Meter; @@ -49,6 +50,17 @@ static Builder builder(String name, return new Builder(name, configBuilder); } + static Builder builderFrom(DistributionSummary.Builder sBuilder) { + + MDistributionStatisticsConfig.Builder configBuilder = sBuilder.distributionStatisticsConfig().isPresent() + ? MDistributionStatisticsConfig.builder() + : MDistributionStatisticsConfig.builderFrom(sBuilder.distributionStatisticsConfig().get()); + + MDistributionSummary.Builder b = MDistributionSummary.builder(sBuilder.name(), configBuilder); + b.from(sBuilder); + return b; + } + /** * Creates a new wrapper summary around an existing Micrometer summary, typically if the developer has registered a * summary directly using the Micrometer API rather than through the Helidon adapter but we need to expose the summary @@ -188,5 +200,10 @@ public Optional scale() { public Optional distributionStatisticsConfig() { return Optional.ofNullable(distributionStatisticsConfigBuilder); } + + protected Builder from(DistributionSummary.Builder other) { + other.scale().ifPresent(this::scale); + return this; + } } } diff --git a/metrics/providers/micrometer/src/main/java/io/helidon/metrics/providers/micrometer/MFunctionalCounter.java b/metrics/providers/micrometer/src/main/java/io/helidon/metrics/providers/micrometer/MFunctionalCounter.java index f63e7edf8cb..e3b198c7a5e 100644 --- a/metrics/providers/micrometer/src/main/java/io/helidon/metrics/providers/micrometer/MFunctionalCounter.java +++ b/metrics/providers/micrometer/src/main/java/io/helidon/metrics/providers/micrometer/MFunctionalCounter.java @@ -16,7 +16,7 @@ package io.helidon.metrics.providers.micrometer; import java.util.Optional; -import java.util.function.ToDoubleFunction; +import java.util.function.Function; import io.helidon.metrics.api.FunctionalCounter; import io.helidon.metrics.api.Meter; @@ -33,10 +33,6 @@ private MFunctionalCounter(Meter.Id id, super(id, delegate, builder); } - private MFunctionalCounter(Meter.Id id, io.micrometer.core.instrument.FunctionCounter delegate) { - super(id, delegate); - } - private MFunctionalCounter(Meter.Id id, io.micrometer.core.instrument.FunctionCounter delegate, Optional scope) { super(id, delegate, scope); } @@ -51,10 +47,17 @@ private MFunctionalCounter(Meter.Id id, io.micrometer.core.instrument.FunctionCo * @param type of the state object * @return new builder for a wrapper counter */ - static Builder builder(String name, T stateObject, ToDoubleFunction fn) { + static Builder builder(String name, T stateObject, Function fn) { return new Builder<>(name, stateObject, fn); } + static Builder builderFrom(FunctionalCounter.Builder origin) { + MFunctionalCounter.Builder builder = builder(origin.name(), + origin.stateObject(), + origin.fn()); + return builder.from(origin); + } + static MFunctionalCounter create(Meter.Id id, io.micrometer.core.instrument.FunctionCounter functionCounter, Optional scope) { @@ -79,10 +82,10 @@ static class Builder extends implements FunctionalCounter.Builder { private final T stateObject; - private final ToDoubleFunction fn; + private final Function fn; - Builder(String name, T stateObject, ToDoubleFunction fn) { - super(name, FunctionCounter.builder(name, stateObject, fn)); + Builder(String name, T stateObject, Function fn) { + super(name, FunctionCounter.builder(name, stateObject, t -> fn.apply(t).doubleValue())); this.stateObject = stateObject; this.fn = fn; } @@ -117,7 +120,7 @@ public T stateObject() { } @Override - public ToDoubleFunction fn() { + public Function fn() { return fn; } diff --git a/metrics/providers/micrometer/src/main/java/io/helidon/metrics/providers/micrometer/MGauge.java b/metrics/providers/micrometer/src/main/java/io/helidon/metrics/providers/micrometer/MGauge.java index 17be8d71c60..34424ed1ca5 100644 --- a/metrics/providers/micrometer/src/main/java/io/helidon/metrics/providers/micrometer/MGauge.java +++ b/metrics/providers/micrometer/src/main/java/io/helidon/metrics/providers/micrometer/MGauge.java @@ -20,6 +20,8 @@ import java.util.function.Supplier; import java.util.function.ToDoubleFunction; +import io.helidon.common.LazyValue; +import io.helidon.metrics.api.Gauge; import io.helidon.metrics.api.Meter; @@ -101,6 +103,11 @@ static SupplierBased.Builder builder(String name, Supplier return new SupplierBased.Builder<>(name, supplier); } + static SupplierBased.Builder builderFrom(Gauge.Builder gBuilder) { + return builder(gBuilder.name(), gBuilder.supplier()) + .from(gBuilder); + } + /** * Creates a new wrapper gauge around an existing Micrometer gauge, typically if the developer has registered a * gauge directly using the Micrometer API rather than through the Helidon adapter but we need to expose the gauge @@ -218,6 +225,11 @@ protected Builder delegateBaseUnit(String baseUnit) { protected MGauge build(Meter.Id id, io.micrometer.core.instrument.Gauge gauge) { return new SupplierBased<>(id, gauge, this); } + + @Override + public Supplier supplier() { + return supplier; + } } } @@ -297,6 +309,11 @@ protected Builder delegateBaseUnit(String baseUnit) { protected MGauge build(Meter.Id id, io.micrometer.core.instrument.Gauge gauge) { return new FunctionBased<>(id, gauge, this); } + + @Override + public Supplier supplier() { + return () -> fn.applyAsDouble(stateObject); + } } } } diff --git a/metrics/providers/micrometer/src/main/java/io/helidon/metrics/providers/micrometer/MMeter.java b/metrics/providers/micrometer/src/main/java/io/helidon/metrics/providers/micrometer/MMeter.java index cae63818d11..f77bd2e1841 100644 --- a/metrics/providers/micrometer/src/main/java/io/helidon/metrics/providers/micrometer/MMeter.java +++ b/metrics/providers/micrometer/src/main/java/io/helidon/metrics/providers/micrometer/MMeter.java @@ -160,7 +160,9 @@ protected StringJoiner stringJoiner() { * @param type of the Helidon meter builder which wraps the Micrometer meter builder * @param type of the Helidon meter which wraps the Micrometer meter */ - abstract static class Builder, + abstract static class Builder, HM extends MMeter> { private final String name; @@ -177,6 +179,14 @@ protected Builder(String name, B delegate) { this.delegate = delegate; } + HB from(Meter.Builder neutralBuilder) { + neutralBuilder.description().ifPresent(this::description); + neutralBuilder.baseUnit().ifPresent(this::baseUnit); + neutralBuilder.scope().ifPresent(this::scope); + neutralBuilder.tags().forEach((key, value) -> this.addTag(MTag.of(key, value))); + return identity(); + } + public HB tags(Iterable tags) { this.tags.clear(); tags.forEach(tag -> this.tags.put(tag.key(), tag.value())); diff --git a/metrics/providers/micrometer/src/main/java/io/helidon/metrics/providers/micrometer/MMeterRegistry.java b/metrics/providers/micrometer/src/main/java/io/helidon/metrics/providers/micrometer/MMeterRegistry.java index 36b5e125e8f..d0d17b0dd32 100644 --- a/metrics/providers/micrometer/src/main/java/io/helidon/metrics/providers/micrometer/MMeterRegistry.java +++ b/metrics/providers/micrometer/src/main/java/io/helidon/metrics/providers/micrometer/MMeterRegistry.java @@ -32,9 +32,11 @@ import io.helidon.metrics.api.Clock; import io.helidon.metrics.api.FunctionalCounter; import io.helidon.metrics.api.MetricsConfig; +import io.helidon.metrics.api.MetricsFactory; import io.helidon.metrics.api.ScopingConfig; import io.helidon.metrics.api.SystemTagsManager; import io.helidon.metrics.api.Tag; +import io.helidon.metrics.spi.MetersProvider; import io.micrometer.core.instrument.Counter; import io.micrometer.core.instrument.DistributionSummary; @@ -77,7 +79,7 @@ class MMeterRegistry implements io.helidon.metrics.api.MeterRegistry { private static final System.Logger LOGGER = System.getLogger(MMeterRegistry.class.getName()); - private final MeterRegistry delegate; + private final io.micrometer.core.instrument.MeterRegistry delegate; private final List> onAddListeners = new ArrayList<>(); private final List> onRemoveListeners = new ArrayList<>(); @@ -104,14 +106,15 @@ class MMeterRegistry implements io.helidon.metrics.api.MeterRegistry { private final Map> metersById = new HashMap<>(); private final ReentrantLock lock = new ReentrantLock(); - private MMeterRegistry(MeterRegistry delegate, - Clock clock, - MicrometerMetricsFactory metricsFactory) { + private MMeterRegistry(io.micrometer.core.instrument.MeterRegistry delegate, + MicrometerMetricsFactory metricsFactory, + MetricsConfig metricsConfig, + Clock clock) { this.delegate = delegate; this.clock = clock; this.metricsFactory = metricsFactory; - metricsConfig = metricsFactory.metricsConfig(); - scopingConfig = this.metricsConfig.scoping(); + this.metricsConfig = metricsConfig; + scopingConfig = metricsConfig.scoping(); delegate.config() .onMeterAdded(this::onMeterAdded) .onMeterRemoved(this::onMeterRemoved); @@ -121,59 +124,103 @@ private MMeterRegistry(MeterRegistry delegate, } } - /** - * Creates a new meter registry which wraps the specified Micrometer meter registry, ensuring that if - * the meter registry is a composite registry it has a Prometheus meter registry attached (adding a new one if needed). - *

- * The {@link io.helidon.metrics.api.MetricsConfig} does not override the settings of the pre-existing Micrometer - * meter registry but augments the behavior of this wrapper around it, for example specifying - * global tags. - *

- * - * @param meterRegistry existing Micrometer meter registry to wrap - * @param metricsFactory metrics factory - * @return new wrapper around the specified Micrometer meter registry - */ - static MMeterRegistry create(MeterRegistry meterRegistry, - MicrometerMetricsFactory metricsFactory) { - // The caller passed a pre-existing meter registry, with its own clock, so wrap that clock - // with a Helidon clock adapter (MClock). - return new MMeterRegistry(ensurePrometheusRegistryIsPresent(meterRegistry, metricsFactory.metricsConfig()), - MClock.create(meterRegistry.config().clock()), - metricsFactory); - } + static Builder builder( + MeterRegistry delegate, + MicrometerMetricsFactory metricsFactory) { - /** - * Creates a new meter registry which wraps an automatically-created new Micrometer - * {@link io.micrometer.core.instrument.composite.CompositeMeterRegistry} with a Prometheus meter registry - * automatically added. - * - * @param metricsConfig metrics config - * @return new wrapper around a new Micrometer composite meter registry - */ - static MMeterRegistry create(MetricsConfig metricsConfig) { - CompositeMeterRegistry delegate = new CompositeMeterRegistry(); - return create(ensurePrometheusRegistryIsPresent(delegate, metricsConfig), - MClock.create(delegate.config().clock()), - metricsConfig); + return new Builder(delegate, metricsFactory); } /** - * Creates a new meter registry which wraps an automatically-created new Micrometer + * Creates a new meter registry which wraps an newly-created Micrometer * {@link io.micrometer.core.instrument.composite.CompositeMeterRegistry} with a Prometheus meter registry * automatically added, using the specified clock. * - * @param clock default clock to associate with the new meter registry - * @param metricsConfig metrics config + * @param metricsFactory metrics factory the new meter registry should use in creating and registering meters + * @param clock default clock to associate with the new meter registry + * @param metersProviders providers of built-in meters to be registered upon creation of the meter registry * @return new wrapper around a new Micrometer composite meter registry */ - static MMeterRegistry create(Clock clock, - MetricsConfig metricsConfig) { + static MMeterRegistry create(MicrometerMetricsFactory metricsFactory, + Clock clock, + Collection metersProviders) { CompositeMeterRegistry delegate = new CompositeMeterRegistry(ClockWrapper.create(clock)); // The specified clock is already a Helidon one so pass it directly; no need to wrap it. - return create(ensurePrometheusRegistryIsPresent(delegate, metricsConfig), + return create(delegate, + metricsFactory, + metricsFactory.metricsConfig(), clock, - metricsConfig); + metersProviders); + } + + static MMeterRegistry create(io.micrometer.core.instrument.MeterRegistry delegate, + MicrometerMetricsFactory metricsFactory, + MetricsConfig metricsConfig, + Collection metersProviders) { + + return create(delegate, metricsFactory, metricsConfig, MClock.create(delegate.config().clock()), metersProviders); + } + + static MMeterRegistry create(io.micrometer.core.instrument.MeterRegistry delegate, + MicrometerMetricsFactory metricsFactory, + MetricsConfig metricsConfig, + Collection metersProviders, + Consumer onAddListener, + Consumer onRemoveListener) { + MMeterRegistry result = create(delegate, metricsFactory, metricsConfig, MClock.create(delegate.config().clock())); + result.onMeterAdded(onAddListener) + .onMeterRemoved(onRemoveListener); + return applyMetersProvidersToRegistry(metricsFactory, result, metersProviders); + } + + static MMeterRegistry create(io.micrometer.core.instrument.MeterRegistry delegate, + MicrometerMetricsFactory metricsFactory, + MetricsConfig metricsConfig, + Clock clock, + Collection metersProviders) { + + return applyMetersProvidersToRegistry(metricsFactory, + create(delegate, + metricsFactory, + metricsConfig, + clock), + metersProviders); + } + + static MMeterRegistry create(io.micrometer.core.instrument.MeterRegistry delegate, + MicrometerMetricsFactory metricsFactory, + MetricsConfig metricsConfig, + Clock clock) { + + io.micrometer.core.instrument.MeterRegistry preppedDelegate = + ensurePrometheusRegistryIsPresent(delegate, + metricsFactory.metricsConfig()); + + return new MMeterRegistry(preppedDelegate, + metricsFactory, + metricsConfig, + clock); + } + + static MMeterRegistry create(io.micrometer.core.instrument.MeterRegistry delegate, + MicrometerMetricsFactory metricsFactory, + Collection metersProviders) { + + return create(delegate, + metricsFactory, + metricsFactory.metricsConfig(), + MClock.create(delegate.config().clock()), + metersProviders); + } + + static MMeterRegistry applyMetersProvidersToRegistry(MetricsFactory factory, + MMeterRegistry registry, + Collection metersProviders) { + metersProviders.stream() + .flatMap(mp -> mp.meterBuilders(factory).stream()) + .forEach(registry::getOrCreateUntyped); + + return registry; } @Override @@ -211,11 +258,15 @@ public Clock clock() { @Override public , HM extends io.helidon.metrics.api.Meter> HM getOrCreate(HB builder) { - // Just cast the builder if it "one of ours." + // Just cast the builder if it "one of ours" because that means it was prepared using our MetricsFactory, and that + // would already have set the builder up with the correct Micrometer builder delegate. if (builder instanceof MMeter.Builder mBuilder) { - return getOrCreateTyped((HB) mBuilder); + return (HM) getOrCreateUntyped((HB) mBuilder); } - return getOrCreateTyped(convertNeutralBuilder(builder)); + + // If this is not "one of ours" then we need to create a new builder, based on the one passed in but with the correct + // Micrometer delegate builder assigned. + return (HM) getOrCreateUntyped((HB) convertNeutralBuilder(builder)); } @Override @@ -282,7 +333,7 @@ public R unwrap(Class c) { return c.cast(delegate); } - MeterRegistry delegate() { + io.micrometer.core.instrument.MeterRegistry delegate() { return delegate; } @@ -327,27 +378,7 @@ void erase() { } } - private static MMeterRegistry create(MeterRegistry delegate, - Clock neutralClock, - MetricsConfig metricsConfig) { - return new MMeterRegistry(delegate, neutralClock, metricsConfig); - } - - private static MeterRegistry ensurePrometheusRegistryIsPresent(MeterRegistry meterRegistry, - MetricsConfig metricsConfig) { - if (meterRegistry instanceof CompositeMeterRegistry compositeMeterRegistry) { - if (compositeMeterRegistry.getRegistries() - .stream() - .noneMatch(r -> r instanceof PrometheusMeterRegistry)) { - compositeMeterRegistry.add( - new PrometheusMeterRegistry(key -> metricsConfig.lookupConfig(key).orElse(null))); - } - } - return meterRegistry; - } - - private , HM extends io.helidon.metrics.api.Meter> - HM getOrCreateTyped(HB builder) { + io.helidon.metrics.api.Meter getOrCreateUntyped(io.helidon.metrics.api.Meter.Builder builder) { // The Micrometer builders do not have a shared inherited declaration of the register method. // Each type of builder declares its own so we need to decide here which specific one to invoke. @@ -361,10 +392,10 @@ HM getOrCreateTyped(HB builder) { try { if (!isMeterEnabled(builder.name(), builder.tags(), builder.scope())) { - return (HM) metricsFactory.noOpMeter(builder); + return metricsFactory.noOpMeter(builder); } - io.helidon.metrics.api.Meter helidonMeter = null; + io.helidon.metrics.api.Meter helidonMeter; if (builder instanceof MCounter.Builder cBuilder) { helidonMeter = getOrCreate(cBuilder, cBuilder::addTag, cBuilder.delegate()::register); @@ -385,16 +416,77 @@ HM getOrCreateTyped(HB builder) { MGauge.Builder.class.getName(), MTimer.Builder.class.getName()))); } - return (HM) helidonMeter; + return helidonMeter; } finally { lock.unlock(); } } + private static io.micrometer.core.instrument.MeterRegistry ensurePrometheusRegistryIsPresent( + io.micrometer.core.instrument.MeterRegistry meterRegistry, + MetricsConfig metricsConfig) { + + if (meterRegistry instanceof CompositeMeterRegistry compositeMeterRegistry) { + if (compositeMeterRegistry.getRegistries() + .stream() + .noneMatch(r -> r instanceof PrometheusMeterRegistry)) { + compositeMeterRegistry.add( + new PrometheusMeterRegistry(key -> metricsConfig.lookupConfig(key).orElse(null))); + } + } + return meterRegistry; + } + + // private , HM extends io.helidon.metrics.api.Meter> + // HM getOrCreateUntyped(HB builder) { + // + // // The Micrometer builders do not have a shared inherited declaration of the register method. + // // Each type of builder declares its own so we need to decide here which specific one to invoke. + // // That's so we can invoke the Micrometer builder's register method, which acts as + // // get-or-create. + // // Micrometer's register methods will throw an IllegalArgumentException if the caller specifies a builder that finds + // // a previously-registered meter of a different type from that implied by the builder. + // + // lock.lock(); + // + // try { + // + // if (!isMeterEnabled(builder.name(), builder.tags(), builder.scope())) { + // return (HM) metricsFactory.noOpMeter(builder); + // } + // + // io.helidon.metrics.api.Meter helidonMeter = null; + // + // if (builder instanceof MCounter.Builder cBuilder) { + // helidonMeter = getOrCreate(cBuilder, cBuilder::addTag, cBuilder.delegate()::register); + // } else if (builder instanceof MFunctionalCounter.Builder fcBuilder) { + // helidonMeter = getOrCreate(fcBuilder, fcBuilder::addTag, fcBuilder.delegate()::register); + // } else if (builder instanceof MDistributionSummary.Builder sBuilder) { + // helidonMeter = getOrCreate(sBuilder, sBuilder::addTag, sBuilder.delegate()::register); + // } else if (builder instanceof MGauge.Builder gBuilder) { + // helidonMeter = getOrCreate(gBuilder, gBuilder::addTag, ((MGauge.Builder) gBuilder).delegate() + // ::register); + // } else if (builder instanceof MTimer.Builder tBuilder) { + // helidonMeter = getOrCreate(tBuilder, tBuilder::addTag, tBuilder.delegate()::register); + // } else { + // throw new IllegalArgumentException(String.format("Unexpected builder type %s, expected one of %s", + // builder.getClass().getName(), + // List.of(MCounter.Builder.class.getName(), + // MFunctionalCounter.Builder.class.getName(), + // MDistributionSummary.Builder.class.getName(), + // MGauge.Builder.class.getName(), + // MTimer.Builder.class.getName()))); + // } + // return (HM) helidonMeter; + // } finally { + // lock.unlock(); + // } + // } + private , HM extends MMeter> HM getOrCreate( HB mBuilder, Function builderTagSetter, - Function registration) { + Function registration) { io.helidon.metrics.api.Meter.Id id = mBuilder.id(); @@ -481,27 +573,21 @@ HM extends MMeter> HM wrapMeter(io.helidon.metrics.api.Meter.Id id, HB extends MMeter.Builder, HM extends MMeter> HB convertNeutralBuilder(io.helidon.metrics.api.Meter.Builder builder) { if (builder instanceof io.helidon.metrics.api.Counter.Builder cBuilder) { - return (HB) MMeter.fillInBuilder(MCounter.builder(cBuilder.name()), builder); + return (HB) MCounter.builder(cBuilder.name()).from(cBuilder); } if (builder instanceof FunctionalCounter.Builder fcBuilder) { - return (HB) MMeter.fillInBuilder(MFunctionalCounter.builder(fcBuilder.name(), - fcBuilder.stateObject(), - fcBuilder.fn()), builder); + return (HB) MFunctionalCounter.builderFrom(fcBuilder); } if (builder instanceof io.helidon.metrics.api.Gauge.Builder gBuilder) { - return (HB) MMeter.fillInBuilder(MGauge.builder(gBuilder.name(), gBuilder.valueSupplier()); + return (HB) MGauge.builderFrom(gBuilder); } if (builder instanceof io.helidon.metrics.api.DistributionSummary.Builder sBuilder) { - MDistributionStatisticsConfig.Builder configBuilder = MDistributionStatisticsConfig.builder(); - sBuilder.distributionStatisticsConfig().ifPresent(statsBuilder -> { - statsBuilder. - }); - - MDistributionSummary.Builder b = MDistributionSummary.builder(sBuilder.name()); - - sBuilder.distributionStatisticsConfig().ifPresent(b::distributionStatisticsConfig); - return (HB) MMeter.fillInBuilder(MDistributionSummary.builder(sBuilder.name(), sBuilder.distributionStatisticsConfig())); + return (HB) MDistributionSummary.builderFrom(sBuilder); } + if (builder instanceof io.helidon.metrics.api.Timer.Builder tBuilder) { + return (HB) MTimer.builderFrom(tBuilder); + } + throw new IllegalArgumentException("Unexpected builder type: " + builder.getClass().getName()); } private Optional chooseScope(Meter meter, Optional reliableScope) { @@ -740,6 +826,68 @@ private MMeter recordRemove(MMeter removedHelidonMeter) { return removedHelidonMeter; } + static class Builder, R extends MMeterRegistry> + implements io.helidon.metrics.api.MeterRegistry.Builder { + + private final MeterRegistry delegate; + private final MicrometerMetricsFactory metricsFactory; + private final Collection metersProviders = new ArrayList<>(); + private MetricsConfig metricsConfig; + private Optional clock = Optional.empty(); + private Optional> onAddListener = Optional.empty(); + private Optional> onRemoveListener = Optional.empty(); + + private Builder(MeterRegistry delegate, MicrometerMetricsFactory metricsFactory) { + this.delegate = delegate; + this.metricsFactory = metricsFactory; + this.metricsConfig = metricsFactory.metricsConfig(); + } + + B metersProviders(Collection metersProviders) { + this.metersProviders.clear(); + this.metersProviders.addAll(metersProviders); + return identity(); + } + + @Override + public B metricsConfig(MetricsConfig metricsConfig) { + this.metricsConfig = metricsConfig; + return identity(); + } + + @Override + public B clock(Clock clock) { + this.clock = Optional.of(clock); + return identity(); + } + + @Override + public B onMeterAdded(Consumer listener) { + onAddListener = Optional.of(listener); + return identity(); + } + + @Override + public B onMeterRemoved(Consumer listener) { + onRemoveListener = Optional.of(listener); + return identity(); + } + + @Override + public R build() { + + MMeterRegistry result = new MMeterRegistry(delegate, + metricsFactory, + metricsConfig, + clock.orElse(MClock.create(delegate.config().clock()))); + + onAddListener.ifPresent(result::onMeterAdded); + onRemoveListener.ifPresent(result::onMeterRemoved); + + return (R) applyMetersProvidersToRegistry(metricsFactory, result, metersProviders); + } + } + /** * Micrometer-friendly wrapper around a Helidon clock. */ diff --git a/metrics/providers/micrometer/src/main/java/io/helidon/metrics/providers/micrometer/MTimer.java b/metrics/providers/micrometer/src/main/java/io/helidon/metrics/providers/micrometer/MTimer.java index bcee2209c31..39b50e772ab 100644 --- a/metrics/providers/micrometer/src/main/java/io/helidon/metrics/providers/micrometer/MTimer.java +++ b/metrics/providers/micrometer/src/main/java/io/helidon/metrics/providers/micrometer/MTimer.java @@ -16,14 +16,17 @@ package io.helidon.metrics.providers.micrometer; import java.time.Duration; +import java.util.Arrays; import java.util.List; import java.util.Optional; import java.util.concurrent.Callable; import java.util.concurrent.TimeUnit; import java.util.function.Supplier; +import java.util.stream.StreamSupport; import io.helidon.metrics.api.HistogramSnapshot; import io.helidon.metrics.api.Meter; +import io.helidon.metrics.api.Timer; import io.micrometer.core.instrument.Clock; @@ -45,10 +48,16 @@ static MTimer create(Meter.Id id, io.micrometer.core.instrument.Timer timer) { return new MTimer(id, timer); } - static io.helidon.metrics.api.Timer.Builder builder(String name) { + static Builder builder(String name) { return new Builder(name); } + static Builder builderFrom(Timer.Builder tBuilder) { + Builder builder = builder(tBuilder.name()); + + return builder.from(tBuilder); + } + static MTimer create(Meter.Id id, io.micrometer.core.instrument.Timer delegate, Optional scope) { return new MTimer(id, delegate, scope); } @@ -268,5 +277,24 @@ public Optional maximumExpectedValue() { protected MTimer build(Meter.Id id, io.micrometer.core.instrument.Timer meter) { return new MTimer(id, meter, this); } + + Builder from(Timer.Builder other) { + percentiles = iterToArray(other.percentiles()); + buckets = StreamSupport.stream(other.buckets().spliterator(), false).toList().toArray(new Duration[0]); + other.maximumExpectedValue().ifPresent(this::maximumExpectedValue); + other.minimumExpectedValue().ifPresent(this::minimumExpectedValue); + return super.from(other); + } + + private static double[] iterToArray(Iterable iter) { + List doubles = StreamSupport.stream(iter.spliterator(), false).toList(); + double[] d = new double[doubles.size()]; + for (int i = 0; i < doubles.size(); i++) { + d[i] = doubles.get(i); + } + return d; + } + + } } diff --git a/metrics/providers/micrometer/src/main/java/io/helidon/metrics/providers/micrometer/MicrometerMetricsFactory.java b/metrics/providers/micrometer/src/main/java/io/helidon/metrics/providers/micrometer/MicrometerMetricsFactory.java index fa230074de3..c8f8a4181fe 100644 --- a/metrics/providers/micrometer/src/main/java/io/helidon/metrics/providers/micrometer/MicrometerMetricsFactory.java +++ b/metrics/providers/micrometer/src/main/java/io/helidon/metrics/providers/micrometer/MicrometerMetricsFactory.java @@ -16,10 +16,13 @@ package io.helidon.metrics.providers.micrometer; import java.util.Collection; +import java.util.function.Consumer; +import java.util.function.Function; import java.util.function.Supplier; import java.util.function.ToDoubleFunction; import io.helidon.common.LazyValue; +import io.helidon.common.config.Config; import io.helidon.metrics.api.Clock; import io.helidon.metrics.api.Counter; import io.helidon.metrics.api.DistributionStatisticsConfig; @@ -33,6 +36,7 @@ import io.helidon.metrics.api.MetricsFactory; import io.helidon.metrics.api.Tag; import io.helidon.metrics.api.Timer; +import io.helidon.metrics.spi.MetersProvider; import io.micrometer.core.instrument.Metrics; import io.micrometer.core.instrument.composite.CompositeMeterRegistry; @@ -44,34 +48,85 @@ class MicrometerMetricsFactory implements MetricsFactory { private final LazyValue globalMeterRegistry; - private final MetricsConfig.Builder metricsConfigBuilder; - private Collection> initialMeterBuilders; + private final MetricsConfig metricsConfig; + private final Collection metersProviders; + + private MicrometerMetricsFactory(MetricsConfig metricsConfig, + Collection metersProviders) { + this.metricsConfig = metricsConfig; + this.metersProviders = metersProviders; - private MicrometerMetricsFactory(MetricsConfig metricsConfig) { - this.metricsConfigBuilder = MetricsConfig.builder(metricsConfig); globalMeterRegistry = LazyValue.create(() -> { ensurePrometheusRegistry(Metrics.globalRegistry, metricsConfig); - return MMeterRegistry.create(Metrics.globalRegistry, metricsConfig, initialMeterBuilders); + MMeterRegistry reg = MMeterRegistry.builder(Metrics.globalRegistry, this).build(); + return MMeterRegistry.applyMetersProvidersToRegistry(this, reg, metersProviders); }); } - static MicrometerMetricsFactory create(MetricsConfig metricsConfig) { - return new MicrometerMetricsFactory(metricsConfig); + static MicrometerMetricsFactory create(Config rootConfig, + MetricsConfig metricsConfig, + Collection metersProviders) { + + return new MicrometerMetricsFactory(metricsConfig, metersProviders); + } + + @Override + public MeterRegistry globalRegistry(Consumer onAddListener, Consumer onRemoveListener, boolean backfill) { + MeterRegistry result = globalMeterRegistry.get(); + result.onMeterAdded(onAddListener); + result.onMeterRemoved(onRemoveListener); + + if (backfill) { + result.meters().forEach(onAddListener); + } + return result; } @Override - public void initialMeterBuilders(Collection> builders) { - this.initialMeterBuilders = builders; + public MMeterRegistry.Builder meterRegistryBuilder() { + return MMeterRegistry.builder(Metrics.globalRegistry, this); } @Override public MeterRegistry createMeterRegistry(MetricsConfig metricsConfig) { - return MMeterRegistry.create(metricsConfig, initialMeterBuilders); + return MMeterRegistry.builder(Metrics.globalRegistry, this) + .metricsConfig(metricsConfig) + .build(); + } + + @Override + public MeterRegistry createMeterRegistry(MetricsConfig metricsConfig, + Consumer onAddListener, + Consumer onRemoveListener) { + return MMeterRegistry.builder(Metrics.globalRegistry, + this) + .metricsConfig(metricsConfig) + .onMeterAdded(onAddListener) + .onMeterRemoved(onRemoveListener) + .build(); + } + + @Override + public MeterRegistry createMeterRegistry(Clock clock, + MetricsConfig metricsConfig, + Consumer onAddListener, + Consumer onRemoveListener) { + + return MMeterRegistry.builder(Metrics.globalRegistry, + this) + .metricsConfig(metricsConfig) + .clock(clock) + .onMeterAdded(onAddListener) + .onMeterRemoved(onRemoveListener) + .build(); } @Override public MeterRegistry createMeterRegistry(Clock clock, MetricsConfig metricsConfig) { - return MMeterRegistry.create(clock, metricsConfig); + return MMeterRegistry.builder(Metrics.globalRegistry, this) + .clock(clock) + .metricsConfig(metricsConfig) + .build(); } @Override @@ -81,7 +136,7 @@ public MeterRegistry globalRegistry() { @Override public MetricsConfig metricsConfig() { - return metricsConfigBuilder; + return metricsConfig; } @Override @@ -115,7 +170,7 @@ public Counter.Builder counterBuilder(String name) { @Override public FunctionalCounter.Builder functionalCounterBuilder(String name, T stateObject, - ToDoubleFunction fn) { + Function fn) { return MFunctionalCounter.builder(name, stateObject, fn); } diff --git a/metrics/providers/micrometer/src/main/java/io/helidon/metrics/providers/micrometer/MicrometerMetricsFactoryProvider.java b/metrics/providers/micrometer/src/main/java/io/helidon/metrics/providers/micrometer/MicrometerMetricsFactoryProvider.java index 26a9313b1ca..d3fced0ac69 100644 --- a/metrics/providers/micrometer/src/main/java/io/helidon/metrics/providers/micrometer/MicrometerMetricsFactoryProvider.java +++ b/metrics/providers/micrometer/src/main/java/io/helidon/metrics/providers/micrometer/MicrometerMetricsFactoryProvider.java @@ -15,8 +15,12 @@ */ package io.helidon.metrics.providers.micrometer; +import java.util.Collection; + +import io.helidon.common.config.Config; import io.helidon.metrics.api.MetricsConfig; import io.helidon.metrics.api.MetricsFactory; +import io.helidon.metrics.spi.MetersProvider; import io.helidon.metrics.spi.MetricsFactoryProvider; /** @@ -31,7 +35,9 @@ public MicrometerMetricsFactoryProvider() { } @Override - public MetricsFactory create(MetricsConfig metricsConfig) { - return MicrometerMetricsFactory.create(metricsConfig); + public MetricsFactory create(Config rootConfig, MetricsConfig metricsConfig, Collection metersProviders) { + return MicrometerMetricsFactory.create(rootConfig, metricsConfig, metersProviders); } + + }