Stabilize MetricProducer, allow custom MetricReaders (#5835)

This commit is contained in:
jack-berg 2023-09-27 13:55:41 -05:00 committed by GitHub
parent 6c8f5435db
commit f421ef1e73
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 242 additions and 276 deletions

View File

@ -1,10 +1,21 @@
Comparing source compatibility of against Comparing source compatibility of against
*** MODIFIED INTERFACE: PUBLIC ABSTRACT io.opentelemetry.sdk.metrics.export.CollectionRegistration (not serializable)
=== CLASS FILE FORMAT VERSION: 52.0 <- 52.0
+++ NEW METHOD: PUBLIC(+) java.util.Collection<io.opentelemetry.sdk.metrics.data.MetricData> collectAllMetrics()
+++ NEW METHOD: PUBLIC(+) STATIC(+) io.opentelemetry.sdk.metrics.export.CollectionRegistration noop()
*** MODIFIED INTERFACE: PUBLIC ABSTRACT io.opentelemetry.sdk.metrics.export.MetricExporter (not serializable) *** MODIFIED INTERFACE: PUBLIC ABSTRACT io.opentelemetry.sdk.metrics.export.MetricExporter (not serializable)
=== CLASS FILE FORMAT VERSION: 52.0 <- 52.0 === CLASS FILE FORMAT VERSION: 52.0 <- 52.0
+++ NEW METHOD: PUBLIC(+) io.opentelemetry.sdk.common.export.MemoryMode getMemoryMode() +++ NEW METHOD: PUBLIC(+) io.opentelemetry.sdk.common.export.MemoryMode getMemoryMode()
+++ NEW INTERFACE: PUBLIC(+) ABSTRACT(+) io.opentelemetry.sdk.metrics.export.MetricProducer (not serializable)
+++ CLASS FILE FORMAT VERSION: 52.0 <- n.a.
+++ NEW SUPERCLASS: java.lang.Object
+++ NEW METHOD: PUBLIC(+) ABSTRACT(+) java.util.Collection<io.opentelemetry.sdk.metrics.data.MetricData> produce(io.opentelemetry.sdk.resources.Resource)
*** MODIFIED INTERFACE: PUBLIC ABSTRACT io.opentelemetry.sdk.metrics.export.MetricReader (not serializable) *** MODIFIED INTERFACE: PUBLIC ABSTRACT io.opentelemetry.sdk.metrics.export.MetricReader (not serializable)
=== CLASS FILE FORMAT VERSION: 52.0 <- 52.0 === CLASS FILE FORMAT VERSION: 52.0 <- 52.0
+++ NEW METHOD: PUBLIC(+) io.opentelemetry.sdk.common.export.MemoryMode getMemoryMode() +++ NEW METHOD: PUBLIC(+) io.opentelemetry.sdk.common.export.MemoryMode getMemoryMode()
*** MODIFIED CLASS: PUBLIC FINAL io.opentelemetry.sdk.metrics.export.PeriodicMetricReader (not serializable) *** MODIFIED CLASS: PUBLIC FINAL io.opentelemetry.sdk.metrics.export.PeriodicMetricReader (not serializable)
=== CLASS FILE FORMAT VERSION: 52.0 <- 52.0 === CLASS FILE FORMAT VERSION: 52.0 <- 52.0
+++ NEW METHOD: PUBLIC(+) io.opentelemetry.sdk.common.export.MemoryMode getMemoryMode() +++ NEW METHOD: PUBLIC(+) io.opentelemetry.sdk.common.export.MemoryMode getMemoryMode()
*** MODIFIED CLASS: PUBLIC FINAL io.opentelemetry.sdk.metrics.SdkMeterProviderBuilder (not serializable)
=== CLASS FILE FORMAT VERSION: 52.0 <- 52.0
+++ NEW METHOD: PUBLIC(+) io.opentelemetry.sdk.metrics.SdkMeterProviderBuilder registerMetricProducer(io.opentelemetry.sdk.metrics.export.MetricProducer)

View File

@ -22,7 +22,6 @@ import io.opentelemetry.sdk.metrics.data.AggregationTemporality;
import io.opentelemetry.sdk.metrics.data.MetricData; import io.opentelemetry.sdk.metrics.data.MetricData;
import io.opentelemetry.sdk.metrics.export.CollectionRegistration; import io.opentelemetry.sdk.metrics.export.CollectionRegistration;
import io.opentelemetry.sdk.metrics.export.MetricReader; import io.opentelemetry.sdk.metrics.export.MetricReader;
import io.opentelemetry.sdk.metrics.internal.export.MetricProducer;
import java.io.IOException; import java.io.IOException;
import java.io.OutputStream; import java.io.OutputStream;
import java.io.UncheckedIOException; import java.io.UncheckedIOException;
@ -60,7 +59,7 @@ public final class PrometheusHttpServer implements MetricReader {
private final HttpServer server; private final HttpServer server;
private final ExecutorService executor; private final ExecutorService executor;
private volatile MetricProducer metricProducer = MetricProducer.noop(); private volatile CollectionRegistration collectionRegistration = CollectionRegistration.noop();
/** /**
* Returns a new {@link PrometheusHttpServer} which can be registered to an {@link * Returns a new {@link PrometheusHttpServer} which can be registered to an {@link
@ -83,7 +82,7 @@ public final class PrometheusHttpServer implements MetricReader {
throw new UncheckedIOException("Could not create Prometheus HTTP server", e); throw new UncheckedIOException("Could not create Prometheus HTTP server", e);
} }
MetricsHandler metricsHandler = MetricsHandler metricsHandler =
new MetricsHandler(() -> getMetricProducer().collectAllMetrics()); new MetricsHandler(() -> collectionRegistration.collectAllMetrics());
server.createContext("/", metricsHandler); server.createContext("/", metricsHandler);
server.createContext("/metrics", metricsHandler); server.createContext("/metrics", metricsHandler);
server.createContext("/-/healthy", HealthHandler.INSTANCE); server.createContext("/-/healthy", HealthHandler.INSTANCE);
@ -110,10 +109,6 @@ public final class PrometheusHttpServer implements MetricReader {
throw exception; throw exception;
} }
private MetricProducer getMetricProducer() {
return metricProducer;
}
private void start() { private void start() {
// server.start must be called from a daemon thread for it to be a daemon. // server.start must be called from a daemon thread for it to be a daemon.
if (Thread.currentThread().isDaemon()) { if (Thread.currentThread().isDaemon()) {
@ -131,13 +126,13 @@ public final class PrometheusHttpServer implements MetricReader {
} }
@Override @Override
public void register(CollectionRegistration registration) { public AggregationTemporality getAggregationTemporality(InstrumentType instrumentType) {
this.metricProducer = MetricProducer.asMetricProducer(registration); return AggregationTemporality.CUMULATIVE;
} }
@Override @Override
public AggregationTemporality getAggregationTemporality(InstrumentType instrumentType) { public void register(CollectionRegistration registration) {
return AggregationTemporality.CUMULATIVE; this.collectionRegistration = registration;
} }
@Override @Override

View File

@ -26,17 +26,18 @@ import io.opentelemetry.internal.testing.slf4j.SuppressLogger;
import io.opentelemetry.sdk.common.InstrumentationScopeInfo; import io.opentelemetry.sdk.common.InstrumentationScopeInfo;
import io.opentelemetry.sdk.metrics.data.AggregationTemporality; import io.opentelemetry.sdk.metrics.data.AggregationTemporality;
import io.opentelemetry.sdk.metrics.data.MetricData; import io.opentelemetry.sdk.metrics.data.MetricData;
import io.opentelemetry.sdk.metrics.export.CollectionRegistration;
import io.opentelemetry.sdk.metrics.internal.data.ImmutableDoublePointData; import io.opentelemetry.sdk.metrics.internal.data.ImmutableDoublePointData;
import io.opentelemetry.sdk.metrics.internal.data.ImmutableGaugeData; import io.opentelemetry.sdk.metrics.internal.data.ImmutableGaugeData;
import io.opentelemetry.sdk.metrics.internal.data.ImmutableLongPointData; import io.opentelemetry.sdk.metrics.internal.data.ImmutableLongPointData;
import io.opentelemetry.sdk.metrics.internal.data.ImmutableMetricData; import io.opentelemetry.sdk.metrics.internal.data.ImmutableMetricData;
import io.opentelemetry.sdk.metrics.internal.data.ImmutableSumData; import io.opentelemetry.sdk.metrics.internal.data.ImmutableSumData;
import io.opentelemetry.sdk.metrics.internal.export.MetricProducer;
import io.opentelemetry.sdk.resources.Resource; import io.opentelemetry.sdk.resources.Resource;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.IOException; import java.io.IOException;
import java.net.ServerSocket; import java.net.ServerSocket;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
@ -56,7 +57,6 @@ import org.junit.jupiter.params.provider.ValueSource;
class PrometheusHttpServerTest { class PrometheusHttpServerTest {
private static final AtomicReference<List<MetricData>> metricData = new AtomicReference<>(); private static final AtomicReference<List<MetricData>> metricData = new AtomicReference<>();
private static final MetricProducer metricProducer = metricData::get;
static PrometheusHttpServer prometheusServer; static PrometheusHttpServer prometheusServer;
static WebClient client; static WebClient client;
@ -68,7 +68,13 @@ class PrometheusHttpServerTest {
static void beforeAll() { static void beforeAll() {
// Register the SDK metric producer with the prometheus reader. // Register the SDK metric producer with the prometheus reader.
prometheusServer = PrometheusHttpServer.builder().setHost("localhost").setPort(0).build(); prometheusServer = PrometheusHttpServer.builder().setHost("localhost").setPort(0).build();
prometheusServer.register(metricProducer); prometheusServer.register(
new CollectionRegistration() {
@Override
public Collection<MetricData> collectAllMetrics() {
return metricData.get();
}
});
client = client =
WebClient.builder("http://localhost:" + prometheusServer.getAddress().getPort()) WebClient.builder("http://localhost:" + prometheusServer.getAddress().getPort())

View File

@ -0,0 +1,53 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.opencensusshim;
import io.opencensus.metrics.Metrics;
import io.opencensus.metrics.export.MetricProducerManager;
import io.opentelemetry.opencensusshim.internal.metrics.MetricAdapter;
import io.opentelemetry.sdk.metrics.SdkMeterProviderBuilder;
import io.opentelemetry.sdk.metrics.data.MetricData;
import io.opentelemetry.sdk.metrics.export.MetricProducer;
import io.opentelemetry.sdk.metrics.export.MetricReader;
import io.opentelemetry.sdk.resources.Resource;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
/**
* {@link MetricProducer} for OpenCensus metrics, which allows {@link MetricReader}s to read from
* both OpenTelemetry and OpenCensus metrics.
*
* <p>To use, register with {@link SdkMeterProviderBuilder#registerMetricProducer(MetricProducer)}.
*/
public final class OpenCensusMetricProducer implements MetricProducer {
private final MetricProducerManager openCensusMetricStorage;
OpenCensusMetricProducer(MetricProducerManager openCensusMetricStorage) {
this.openCensusMetricStorage = openCensusMetricStorage;
}
/**
* Constructs a new {@link OpenCensusMetricProducer} that reports against the given {@link
* Resource}.
*/
public static MetricProducer create() {
return new OpenCensusMetricProducer(Metrics.getExportComponent().getMetricProducerManager());
}
@Override
public Collection<MetricData> produce(Resource resource) {
List<MetricData> result = new ArrayList<>();
openCensusMetricStorage
.getAllMetricProducer()
.forEach(
producer ->
producer
.getMetrics()
.forEach(metric -> result.add(MetricAdapter.convert(resource, metric))));
return result;
}
}

View File

@ -1,30 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.opencensusshim.metrics;
import io.opentelemetry.sdk.metrics.data.MetricData;
import io.opentelemetry.sdk.metrics.internal.export.MetricProducer;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
/** Class that wraps multiple metric producers into one. */
final class MultiMetricProducer implements MetricProducer {
private final Collection<MetricProducer> producers;
public MultiMetricProducer(Collection<MetricProducer> producers) {
this.producers = producers;
}
@Override
public Collection<MetricData> collectAllMetrics() {
List<MetricData> result = new ArrayList<>();
for (MetricProducer p : producers) {
result.addAll(p.collectAllMetrics());
}
return result;
}
}

View File

@ -1,49 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.opencensusshim.metrics;
import io.opentelemetry.sdk.common.CompletableResultCode;
import io.opentelemetry.sdk.metrics.InstrumentType;
import io.opentelemetry.sdk.metrics.data.AggregationTemporality;
import io.opentelemetry.sdk.metrics.export.CollectionRegistration;
import io.opentelemetry.sdk.metrics.export.MetricReader;
import io.opentelemetry.sdk.metrics.internal.export.MetricProducer;
import io.opentelemetry.sdk.resources.Resource;
import java.util.Arrays;
/** {@link MetricReader} that appends OpenCensus metrics to anything read. */
final class OpenCensusAttachingMetricReader implements MetricReader {
private final MetricReader adapted;
OpenCensusAttachingMetricReader(MetricReader adapted) {
this.adapted = adapted;
}
@Override
public void register(CollectionRegistration registration) {
// TODO: Find a way to pull the resource off of the SDK.
adapted.register(
new MultiMetricProducer(
Arrays.asList(
MetricProducer.asMetricProducer(registration),
OpenCensusMetricProducer.create(Resource.getDefault()))));
}
@Override
public AggregationTemporality getAggregationTemporality(InstrumentType instrumentType) {
return adapted.getAggregationTemporality(instrumentType);
}
@Override
public CompletableResultCode forceFlush() {
return adapted.forceFlush();
}
@Override
public CompletableResultCode shutdown() {
return adapted.shutdown();
}
}

View File

@ -1,58 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.opencensusshim.metrics;
import io.opencensus.metrics.Metrics;
import io.opencensus.metrics.export.MetricProducerManager;
import io.opentelemetry.opencensusshim.internal.metrics.MetricAdapter;
import io.opentelemetry.sdk.metrics.SdkMeterProvider;
import io.opentelemetry.sdk.metrics.data.MetricData;
import io.opentelemetry.sdk.metrics.export.MetricReader;
import io.opentelemetry.sdk.metrics.internal.export.MetricProducer;
import io.opentelemetry.sdk.resources.Resource;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
/**
* A producer instance of OpenCensus metrics.
*
* <p>The idea here is we can register a merged {@link MetricProducer} combining this with the
* {@link SdkMeterProvider} producer with a {@link MetricReader}, allowing the reader to pull
* metrics from both OpenTelemetry and OpenCensus backends.
*/
final class OpenCensusMetricProducer implements MetricProducer {
private final Resource resource;
private final MetricProducerManager openCensusMetricStorage;
OpenCensusMetricProducer(Resource resource, MetricProducerManager openCensusMetricStorage) {
this.resource = resource;
this.openCensusMetricStorage = openCensusMetricStorage;
}
/**
* Constructs a new {@link OpenCensusMetricProducer} that reports against the given {@link
* Resource}.
*/
static MetricProducer create(Resource resource) {
return new OpenCensusMetricProducer(
resource, Metrics.getExportComponent().getMetricProducerManager());
}
@Override
public Collection<MetricData> collectAllMetrics() {
List<MetricData> result = new ArrayList<>();
openCensusMetricStorage
.getAllMetricProducer()
.forEach(
producer -> {
producer
.getMetrics()
.forEach(metric -> result.add(MetricAdapter.convert(resource, metric)));
});
return result;
}
}

View File

@ -1,23 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.opencensusshim.metrics;
import io.opentelemetry.sdk.metrics.export.MetricReader;
/** Convenience methods for adapting OpenCensus metrics into OpenTelemetry. */
public final class OpenCensusMetrics {
private OpenCensusMetrics() {}
/**
* Attaches OpenCensus metrics to metrics read by the given input.
*
* @param input A {@link MetricReader} that will receive OpenCensus metrics.
* @return The adapted MetricReaderFactory.
*/
public static MetricReader attachTo(MetricReader input) {
return new OpenCensusAttachingMetricReader(input);
}
}

View File

@ -21,7 +21,8 @@ import io.opencensus.trace.TraceId;
import io.opencensus.trace.TraceOptions; import io.opencensus.trace.TraceOptions;
import io.opencensus.trace.Tracestate; import io.opencensus.trace.Tracestate;
import io.opentelemetry.api.common.Attributes; import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.sdk.metrics.internal.export.MetricProducer; import io.opentelemetry.opencensusshim.OpenCensusMetricProducer;
import io.opentelemetry.sdk.metrics.export.MetricProducer;
import io.opentelemetry.sdk.resources.Resource; import io.opentelemetry.sdk.resources.Resource;
import java.time.Duration; import java.time.Duration;
import java.util.Arrays; import java.util.Arrays;
@ -31,8 +32,7 @@ import org.awaitility.Awaitility;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
class OpenCensusMetricProducerTest { class OpenCensusMetricProducerTest {
private final MetricProducer openCensusMetrics = private final MetricProducer openCensusMetrics = OpenCensusMetricProducer.create();
OpenCensusMetricProducer.create(Resource.empty());
private static final Measure.MeasureLong LATENCY_MS = private static final Measure.MeasureLong LATENCY_MS =
Measure.MeasureLong.create("task_latency", "The task latency in milliseconds", "ms"); Measure.MeasureLong.create("task_latency", "The task latency in milliseconds", "ms");
@ -69,7 +69,7 @@ class OpenCensusMetricProducerTest {
.atMost(Duration.ofSeconds(10)) .atMost(Duration.ofSeconds(10))
.untilAsserted( .untilAsserted(
() -> () ->
assertThat(openCensusMetrics.collectAllMetrics()) assertThat(openCensusMetrics.produce(Resource.empty()))
.satisfiesExactly( .satisfiesExactly(
metric -> metric ->
assertThat(metric) assertThat(metric)

View File

@ -12,6 +12,7 @@ import io.opencensus.stats.Measure;
import io.opencensus.stats.Stats; import io.opencensus.stats.Stats;
import io.opencensus.stats.StatsRecorder; import io.opencensus.stats.StatsRecorder;
import io.opencensus.stats.View; import io.opencensus.stats.View;
import io.opentelemetry.opencensusshim.OpenCensusMetricProducer;
import io.opentelemetry.sdk.metrics.SdkMeterProvider; import io.opentelemetry.sdk.metrics.SdkMeterProvider;
import io.opentelemetry.sdk.testing.exporter.InMemoryMetricReader; import io.opentelemetry.sdk.testing.exporter.InMemoryMetricReader;
import java.time.Duration; import java.time.Duration;
@ -26,7 +27,10 @@ class OpenCensusMetricsTest {
void capturesOpenCensusAndOtelMetrics() throws InterruptedException { void capturesOpenCensusAndOtelMetrics() throws InterruptedException {
InMemoryMetricReader reader = InMemoryMetricReader.create(); InMemoryMetricReader reader = InMemoryMetricReader.create();
SdkMeterProvider otelMetrics = SdkMeterProvider otelMetrics =
SdkMeterProvider.builder().registerMetricReader(OpenCensusMetrics.attachTo(reader)).build(); SdkMeterProvider.builder()
.registerMetricReader(reader)
.registerMetricProducer(OpenCensusMetricProducer.create())
.build();
// Record an otel metric. // Record an otel metric.
otelMetrics.meterBuilder("otel").build().counterBuilder("otel.sum").build().add(1); otelMetrics.meterBuilder("otel").build().counterBuilder("otel.sum").build().add(1);
// Record an OpenCensus metric. // Record an OpenCensus metric.
@ -47,7 +51,7 @@ class OpenCensusMetricsTest {
.untilAsserted( .untilAsserted(
() -> () ->
assertThat(reader.collectAllMetrics()) assertThat(reader.collectAllMetrics())
.satisfiesExactly( .satisfiesExactlyInAnyOrder(
metric -> metric ->
assertThat(metric).hasName("otel.sum").hasLongSumSatisfying(sum -> {}), assertThat(metric).hasName("otel.sum").hasLongSumSatisfying(sum -> {}),
metric -> metric ->

View File

@ -421,6 +421,7 @@ class OpenTelemetrySdkTest {
+ "clock=SystemClock{}, " + "clock=SystemClock{}, "
+ "resource=Resource{schemaUrl=null, attributes={service.name=\"otel-test\"}}, " + "resource=Resource{schemaUrl=null, attributes={service.name=\"otel-test\"}}, "
+ "metricReaders=[PeriodicMetricReader{exporter=MockMetricExporter{}, intervalNanos=60000000000}], " + "metricReaders=[PeriodicMetricReader{exporter=MockMetricExporter{}, intervalNanos=60000000000}], "
+ "metricProducers=[], "
+ "views=[RegisteredView{instrumentSelector=InstrumentSelector{instrumentName=instrument}, view=View{name=new-instrument, aggregation=DefaultAggregation, attributesProcessor=NoopAttributesProcessor{}, cardinalityLimit=2000}}]" + "views=[RegisteredView{instrumentSelector=InstrumentSelector{instrumentName=instrument}, view=View{name=new-instrument, aggregation=DefaultAggregation, attributesProcessor=NoopAttributesProcessor{}, cardinalityLimit=2000}}]"
+ "}, " + "}, "
+ "loggerProvider=SdkLoggerProvider{" + "loggerProvider=SdkLoggerProvider{"

View File

@ -13,11 +13,12 @@ import io.opentelemetry.sdk.common.Clock;
import io.opentelemetry.sdk.common.CompletableResultCode; import io.opentelemetry.sdk.common.CompletableResultCode;
import io.opentelemetry.sdk.internal.ComponentRegistry; import io.opentelemetry.sdk.internal.ComponentRegistry;
import io.opentelemetry.sdk.metrics.data.MetricData; import io.opentelemetry.sdk.metrics.data.MetricData;
import io.opentelemetry.sdk.metrics.export.CollectionRegistration;
import io.opentelemetry.sdk.metrics.export.MetricProducer;
import io.opentelemetry.sdk.metrics.export.MetricReader; import io.opentelemetry.sdk.metrics.export.MetricReader;
import io.opentelemetry.sdk.metrics.internal.SdkMeterProviderUtil; import io.opentelemetry.sdk.metrics.internal.SdkMeterProviderUtil;
import io.opentelemetry.sdk.metrics.internal.exemplar.ExemplarFilter; import io.opentelemetry.sdk.metrics.internal.exemplar.ExemplarFilter;
import io.opentelemetry.sdk.metrics.internal.export.CardinalityLimitSelector; import io.opentelemetry.sdk.metrics.internal.export.CardinalityLimitSelector;
import io.opentelemetry.sdk.metrics.internal.export.MetricProducer;
import io.opentelemetry.sdk.metrics.internal.export.RegisteredReader; import io.opentelemetry.sdk.metrics.internal.export.RegisteredReader;
import io.opentelemetry.sdk.metrics.internal.state.MeterProviderSharedState; import io.opentelemetry.sdk.metrics.internal.state.MeterProviderSharedState;
import io.opentelemetry.sdk.metrics.internal.view.RegisteredView; import io.opentelemetry.sdk.metrics.internal.view.RegisteredView;
@ -45,6 +46,7 @@ public final class SdkMeterProvider implements MeterProvider, Closeable {
private final List<RegisteredView> registeredViews; private final List<RegisteredView> registeredViews;
private final List<RegisteredReader> registeredReaders; private final List<RegisteredReader> registeredReaders;
private final List<MetricProducer> metricProducers;
private final MeterProviderSharedState sharedState; private final MeterProviderSharedState sharedState;
private final ComponentRegistry<SdkMeter> registry; private final ComponentRegistry<SdkMeter> registry;
private final AtomicBoolean isClosed = new AtomicBoolean(false); private final AtomicBoolean isClosed = new AtomicBoolean(false);
@ -57,6 +59,7 @@ public final class SdkMeterProvider implements MeterProvider, Closeable {
SdkMeterProvider( SdkMeterProvider(
List<RegisteredView> registeredViews, List<RegisteredView> registeredViews,
IdentityHashMap<MetricReader, CardinalityLimitSelector> metricReaders, IdentityHashMap<MetricReader, CardinalityLimitSelector> metricReaders,
List<MetricProducer> metricProducers,
Clock clock, Clock clock,
Resource resource, Resource resource,
ExemplarFilter exemplarFilter) { ExemplarFilter exemplarFilter) {
@ -70,6 +73,7 @@ public final class SdkMeterProvider implements MeterProvider, Closeable {
entry.getKey(), entry.getKey(),
ViewRegistry.create(entry.getKey(), entry.getValue(), registeredViews))) ViewRegistry.create(entry.getKey(), entry.getValue(), registeredViews)))
.collect(toList()); .collect(toList());
this.metricProducers = metricProducers;
this.sharedState = this.sharedState =
MeterProviderSharedState.create(clock, resource, exemplarFilter, startEpochNanos); MeterProviderSharedState.create(clock, resource, exemplarFilter, startEpochNanos);
this.registry = this.registry =
@ -77,8 +81,11 @@ public final class SdkMeterProvider implements MeterProvider, Closeable {
instrumentationLibraryInfo -> instrumentationLibraryInfo ->
new SdkMeter(sharedState, instrumentationLibraryInfo, registeredReaders)); new SdkMeter(sharedState, instrumentationLibraryInfo, registeredReaders));
for (RegisteredReader registeredReader : registeredReaders) { for (RegisteredReader registeredReader : registeredReaders) {
MetricProducer producer = new LeasedMetricProducer(registry, sharedState, registeredReader); List<MetricProducer> readerMetricProducers = new ArrayList<>(metricProducers);
registeredReader.getReader().register(producer); readerMetricProducers.add(new LeasedMetricProducer(registry, sharedState, registeredReader));
registeredReader
.getReader()
.register(new SdkCollectionRegistration(readerMetricProducers, sharedState));
registeredReader.setLastCollectEpochNanos(startEpochNanos); registeredReader.setLastCollectEpochNanos(startEpochNanos);
} }
} }
@ -154,6 +161,8 @@ public final class SdkMeterProvider implements MeterProvider, Closeable {
+ sharedState.getResource() + sharedState.getResource()
+ ", metricReaders=" + ", metricReaders="
+ registeredReaders.stream().map(RegisteredReader::getReader).collect(toList()) + registeredReaders.stream().map(RegisteredReader::getReader).collect(toList())
+ ", metricProducers="
+ metricProducers
+ ", views=" + ", views="
+ registeredViews + registeredViews
+ "}"; + "}";
@ -176,7 +185,7 @@ public final class SdkMeterProvider implements MeterProvider, Closeable {
} }
@Override @Override
public Collection<MetricData> collectAllMetrics() { public Collection<MetricData> produce(Resource unused) {
Collection<SdkMeter> meters = registry.getComponents(); Collection<SdkMeter> meters = registry.getComponents();
List<MetricData> result = new ArrayList<>(); List<MetricData> result = new ArrayList<>();
long collectTime = sharedState.getClock().now(); long collectTime = sharedState.getClock().now();
@ -187,4 +196,31 @@ public final class SdkMeterProvider implements MeterProvider, Closeable {
return Collections.unmodifiableCollection(result); return Collections.unmodifiableCollection(result);
} }
} }
private static class SdkCollectionRegistration implements CollectionRegistration {
private final List<MetricProducer> metricProducers;
private final MeterProviderSharedState sharedState;
private SdkCollectionRegistration(
List<MetricProducer> metricProducers, MeterProviderSharedState sharedState) {
this.metricProducers = metricProducers;
this.sharedState = sharedState;
}
@Override
public Collection<MetricData> collectAllMetrics() {
if (metricProducers.isEmpty()) {
return Collections.emptyList();
}
Resource resource = sharedState.getResource();
if (metricProducers.size() == 1) {
return metricProducers.get(0).produce(resource);
}
List<MetricData> metricData = new ArrayList<>();
for (MetricProducer metricProducer : metricProducers) {
metricData.addAll(metricProducer.produce(resource));
}
return Collections.unmodifiableList(metricData);
}
}
} }

View File

@ -6,6 +6,7 @@
package io.opentelemetry.sdk.metrics; package io.opentelemetry.sdk.metrics;
import io.opentelemetry.sdk.common.Clock; import io.opentelemetry.sdk.common.Clock;
import io.opentelemetry.sdk.metrics.export.MetricProducer;
import io.opentelemetry.sdk.metrics.export.MetricReader; import io.opentelemetry.sdk.metrics.export.MetricReader;
import io.opentelemetry.sdk.metrics.internal.SdkMeterProviderUtil; import io.opentelemetry.sdk.metrics.internal.SdkMeterProviderUtil;
import io.opentelemetry.sdk.metrics.internal.debug.SourceInfo; import io.opentelemetry.sdk.metrics.internal.debug.SourceInfo;
@ -36,6 +37,7 @@ public final class SdkMeterProviderBuilder {
private Resource resource = Resource.getDefault(); private Resource resource = Resource.getDefault();
private final IdentityHashMap<MetricReader, CardinalityLimitSelector> metricReaders = private final IdentityHashMap<MetricReader, CardinalityLimitSelector> metricReaders =
new IdentityHashMap<>(); new IdentityHashMap<>();
private final List<MetricProducer> metricProducers = new ArrayList<>();
private final List<RegisteredView> registeredViews = new ArrayList<>(); private final List<RegisteredView> registeredViews = new ArrayList<>();
private ExemplarFilter exemplarFilter = DEFAULT_EXEMPLAR_FILTER; private ExemplarFilter exemplarFilter = DEFAULT_EXEMPLAR_FILTER;
@ -119,11 +121,7 @@ public final class SdkMeterProviderBuilder {
return this; return this;
} }
/** /** Registers a {@link MetricReader}. */
* Registers a {@link MetricReader}.
*
* <p>Note: custom implementations of {@link MetricReader} are not currently supported.
*/
public SdkMeterProviderBuilder registerMetricReader(MetricReader reader) { public SdkMeterProviderBuilder registerMetricReader(MetricReader reader) {
metricReaders.put(reader, CardinalityLimitSelector.defaultCardinalityLimitSelector()); metricReaders.put(reader, CardinalityLimitSelector.defaultCardinalityLimitSelector());
return this; return this;
@ -142,8 +140,19 @@ public final class SdkMeterProviderBuilder {
return this; return this;
} }
/**
* Registers a {@link MetricProducer}.
*
* @since 1.31.0
*/
public SdkMeterProviderBuilder registerMetricProducer(MetricProducer metricProducer) {
metricProducers.add(metricProducer);
return this;
}
/** Returns an {@link SdkMeterProvider} built with the configuration of this builder. */ /** Returns an {@link SdkMeterProvider} built with the configuration of this builder. */
public SdkMeterProvider build() { public SdkMeterProvider build() {
return new SdkMeterProvider(registeredViews, metricReaders, clock, resource, exemplarFilter); return new SdkMeterProvider(
registeredViews, metricReaders, metricProducers, clock, resource, exemplarFilter);
} }
} }

View File

@ -5,7 +5,11 @@
package io.opentelemetry.sdk.metrics.export; package io.opentelemetry.sdk.metrics.export;
import io.opentelemetry.sdk.common.export.MemoryMode;
import io.opentelemetry.sdk.metrics.SdkMeterProvider; import io.opentelemetry.sdk.metrics.SdkMeterProvider;
import io.opentelemetry.sdk.metrics.data.MetricData;
import java.util.Collection;
import java.util.Collections;
/** /**
* A {@link CollectionRegistration} is passed to each {@link MetricReader} registered with {@link * A {@link CollectionRegistration} is passed to each {@link MetricReader} registered with {@link
@ -13,5 +17,29 @@ import io.opentelemetry.sdk.metrics.SdkMeterProvider;
* *
* @since 1.14.0 * @since 1.14.0
*/ */
// TODO(jack-berg): Have methods when custom MetricReaders are supported public interface CollectionRegistration {
public interface CollectionRegistration {}
/**
* Returns a noop {@link CollectionRegistration}, useful for {@link MetricReader}s to hold before
* {@link MetricReader#register(CollectionRegistration)} is called.
*/
static CollectionRegistration noop() {
return new CollectionRegistration() {
@Override
public Collection<MetricData> collectAllMetrics() {
return Collections.emptyList();
}
};
}
/**
* Collect all metrics, including metrics from the SDK and any registered {@link MetricProducer}s.
*
* <p>If {@link MetricReader#getMemoryMode()} is configured to {@link MemoryMode#REUSABLE_DATA} do
* not keep the result or any of its contained objects as they are to be reused to return the
* result for the next call to this method.
*/
default Collection<MetricData> collectAllMetrics() {
return Collections.emptyList();
}
}

View File

@ -0,0 +1,42 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.sdk.metrics.export;
import io.opentelemetry.sdk.metrics.SdkMeterProviderBuilder;
import io.opentelemetry.sdk.metrics.data.MetricData;
import io.opentelemetry.sdk.resources.Resource;
import java.util.Collection;
import javax.annotation.concurrent.ThreadSafe;
/**
* {@link MetricProducer} is the interface that is used to make metric data available to the {@link
* MetricReader}s. The primary implementation is provided by {@link
* io.opentelemetry.sdk.metrics.SdkMeterProvider}.
*
* <p>Alternative {@link MetricProducer} implementations can be used to bridge aggregated metrics
* from other frameworks, and are registered with {@link
* SdkMeterProviderBuilder#registerMetricProducer(MetricProducer)}. NOTE: When possible, metrics
* from other frameworks SHOULD be bridged using the metric API, normally with asynchronous
* instruments which observe the aggregated state of the other framework. However, {@link
* MetricProducer} exists to accommodate scenarios where the metric API is insufficient. It should
* be used with caution as it requires the bridge to take a dependency on {@code
* opentelemetry-sdk-metrics}, which is generally not advised.
*
* <p>Implementations must be thread-safe.
*
* @since 1.31.0
*/
@ThreadSafe
public interface MetricProducer {
/**
* Returns a collection of produced {@link MetricData}s to be exported. This will only be those
* metrics that have been produced since the last time this method was called.
*
* @return a collection of produced {@link MetricData}s to be exported.
*/
Collection<MetricData> produce(Resource resource);
}

View File

@ -19,20 +19,15 @@ import java.util.concurrent.TimeUnit;
/** /**
* A metric reader reads metrics from an {@link SdkMeterProvider}. * A metric reader reads metrics from an {@link SdkMeterProvider}.
* *
* <p>Custom implementations of {@link MetricReader} are not currently supported. Please use one of
* the built-in readers such as {@link PeriodicMetricReader}.
*
* @since 1.14.0 * @since 1.14.0
*/ */
public interface MetricReader public interface MetricReader
extends AggregationTemporalitySelector, DefaultAggregationSelector, Closeable { extends AggregationTemporalitySelector, DefaultAggregationSelector, Closeable {
/** /**
* Called by {@link SdkMeterProvider} and supplies the {@link MetricReader} with a handle to * Called by {@link SdkMeterProvider} on initialization to supply the {@link MetricReader} with
* collect metrics. * {@link MetricProducer}s used to collect metrics. {@link MetricReader} implementations call
* * {@link CollectionRegistration#collectAllMetrics()} to read metrics.
* <p>{@link CollectionRegistration} is currently an empty interface because custom
* implementations of {@link MetricReader} are not currently supported.
*/ */
void register(CollectionRegistration registration); void register(CollectionRegistration registration);

View File

@ -13,7 +13,6 @@ import io.opentelemetry.sdk.metrics.SdkMeterProvider;
import io.opentelemetry.sdk.metrics.SdkMeterProviderBuilder; import io.opentelemetry.sdk.metrics.SdkMeterProviderBuilder;
import io.opentelemetry.sdk.metrics.data.AggregationTemporality; import io.opentelemetry.sdk.metrics.data.AggregationTemporality;
import io.opentelemetry.sdk.metrics.data.MetricData; import io.opentelemetry.sdk.metrics.data.MetricData;
import io.opentelemetry.sdk.metrics.internal.export.MetricProducer;
import java.util.Collection; import java.util.Collection;
import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture; import java.util.concurrent.ScheduledFuture;
@ -40,8 +39,8 @@ public final class PeriodicMetricReader implements MetricReader {
private final ScheduledExecutorService scheduler; private final ScheduledExecutorService scheduler;
private final Scheduled scheduled; private final Scheduled scheduled;
private final Object lock = new Object(); private final Object lock = new Object();
private volatile CollectionRegistration collectionRegistration = CollectionRegistration.noop();
private volatile MetricProducer metricProducer = MetricProducer.noop();
@Nullable private volatile ScheduledFuture<?> scheduledFuture; @Nullable private volatile ScheduledFuture<?> scheduledFuture;
/** /**
@ -117,8 +116,8 @@ public final class PeriodicMetricReader implements MetricReader {
} }
@Override @Override
public void register(CollectionRegistration registration) { public void register(CollectionRegistration collectionRegistration) {
this.metricProducer = MetricProducer.asMetricProducer(registration); this.collectionRegistration = collectionRegistration;
start(); start();
} }
@ -159,7 +158,7 @@ public final class PeriodicMetricReader implements MetricReader {
CompletableResultCode flushResult = new CompletableResultCode(); CompletableResultCode flushResult = new CompletableResultCode();
if (exportAvailable.compareAndSet(true, false)) { if (exportAvailable.compareAndSet(true, false)) {
try { try {
Collection<MetricData> metricData = metricProducer.collectAllMetrics(); Collection<MetricData> metricData = collectionRegistration.collectAllMetrics();
if (metricData.isEmpty()) { if (metricData.isEmpty()) {
logger.log(Level.FINE, "No metric data to export - skipping export."); logger.log(Level.FINE, "No metric data to export - skipping export.");
flushResult.succeed(); flushResult.succeed();

View File

@ -1,54 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.sdk.metrics.internal.export;
import io.opentelemetry.sdk.common.export.MemoryMode;
import io.opentelemetry.sdk.metrics.data.MetricData;
import io.opentelemetry.sdk.metrics.export.CollectionRegistration;
import io.opentelemetry.sdk.metrics.export.MetricReader;
import java.util.Collection;
import java.util.Collections;
import javax.annotation.concurrent.ThreadSafe;
/**
* {@code MetricProducer} is the interface that is used to make metric data available to the {@link
* MetricReader}s. Implementations should be stateful, in that each call to {@link
* #collectAllMetrics()} will return any metric generated since the last call was made.
*
* <p>Implementations must be thread-safe.
*
* <p>This class is internal and is hence not for public use. Its APIs are unstable and can change
* at any time.
*/
@ThreadSafe
public interface MetricProducer extends CollectionRegistration {
/** Cast the registration to a {@link MetricProducer}. */
static MetricProducer asMetricProducer(CollectionRegistration registration) {
if (!(registration instanceof MetricProducer)) {
throw new IllegalArgumentException(
"unrecognized CollectionRegistration, custom MetricReader implementations are not currently supported");
}
return (MetricProducer) registration;
}
/** Return a noop {@link MetricProducer}. */
static MetricProducer noop() {
return Collections::emptyList;
}
/**
* Returns a collection of produced {@link MetricData}s to be exported. This will only be those
* metrics that have been produced since the last time this method was called.
*
* <p>If {@link MetricReader#getMemoryMode()} is configured to {@link MemoryMode#REUSABLE_DATA} do
* not keep the result or any of its contained objects as they are to be reused to return the
* result for the next call of {@code collectAllMetrics}
*
* @return a collection of produced {@link MetricData}s to be exported.
*/
Collection<MetricData> collectAllMetrics();
}

View File

@ -8,6 +8,7 @@ package io.opentelemetry.sdk.metrics.internal.export;
import io.opentelemetry.sdk.metrics.SdkMeterProvider; import io.opentelemetry.sdk.metrics.SdkMeterProvider;
import io.opentelemetry.sdk.metrics.data.AggregationTemporality; import io.opentelemetry.sdk.metrics.data.AggregationTemporality;
import io.opentelemetry.sdk.metrics.data.PointData; import io.opentelemetry.sdk.metrics.data.PointData;
import io.opentelemetry.sdk.metrics.export.MetricProducer;
import io.opentelemetry.sdk.metrics.export.MetricReader; import io.opentelemetry.sdk.metrics.export.MetricReader;
import io.opentelemetry.sdk.metrics.internal.view.ViewRegistry; import io.opentelemetry.sdk.metrics.internal.view.ViewRegistry;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;

View File

@ -26,7 +26,6 @@ import io.opentelemetry.sdk.metrics.data.MetricData;
import io.opentelemetry.sdk.metrics.internal.data.ImmutableLongPointData; import io.opentelemetry.sdk.metrics.internal.data.ImmutableLongPointData;
import io.opentelemetry.sdk.metrics.internal.data.ImmutableMetricData; import io.opentelemetry.sdk.metrics.internal.data.ImmutableMetricData;
import io.opentelemetry.sdk.metrics.internal.data.ImmutableSumData; import io.opentelemetry.sdk.metrics.internal.data.ImmutableSumData;
import io.opentelemetry.sdk.metrics.internal.export.MetricProducer;
import io.opentelemetry.sdk.resources.Resource; import io.opentelemetry.sdk.resources.Resource;
import java.io.IOException; import java.io.IOException;
import java.time.Duration; import java.time.Duration;
@ -67,17 +66,19 @@ class PeriodicMetricReaderTest {
ImmutableSumData.create( ImmutableSumData.create(
/* isMonotonic= */ true, AggregationTemporality.CUMULATIVE, LONG_POINT_LIST)); /* isMonotonic= */ true, AggregationTemporality.CUMULATIVE, LONG_POINT_LIST));
@Mock private MetricProducer metricProducer; @Mock private CollectionRegistration collectionRegistration;
@Mock private MetricExporter metricExporter; @Mock private MetricExporter metricExporter;
@BeforeEach @BeforeEach
void setup() { void setup() {
when(metricProducer.collectAllMetrics()).thenReturn(Collections.singletonList(METRIC_DATA)); when(collectionRegistration.collectAllMetrics())
.thenReturn(Collections.singletonList(METRIC_DATA));
} }
@Test @Test
@SuppressWarnings({"rawtypes", "unchecked"}) @SuppressWarnings({"rawtypes", "unchecked"})
void startOnlyOnce() { void startOnlyOnce() {
ScheduledExecutorService scheduler = mock(ScheduledExecutorService.class); ScheduledExecutorService scheduler = mock(ScheduledExecutorService.class);
ScheduledFuture mock = mock(ScheduledFuture.class); ScheduledFuture mock = mock(ScheduledFuture.class);
@ -89,7 +90,7 @@ class PeriodicMetricReaderTest {
.setExecutor(scheduler) .setExecutor(scheduler)
.build(); .build();
reader.register(metricProducer); reader.register(collectionRegistration);
verify(scheduler, times(1)).scheduleAtFixedRate(any(), anyLong(), anyLong(), any()); verify(scheduler, times(1)).scheduleAtFixedRate(any(), anyLong(), anyLong(), any());
} }
@ -102,7 +103,7 @@ class PeriodicMetricReaderTest {
.setInterval(Duration.ofMillis(100)) .setInterval(Duration.ofMillis(100))
.build(); .build();
reader.register(metricProducer); reader.register(collectionRegistration);
try { try {
assertThat(waitingMetricExporter.waitForNumberOfExports(1)) assertThat(waitingMetricExporter.waitForNumberOfExports(1))
.containsExactly(Collections.singletonList(METRIC_DATA)); .containsExactly(Collections.singletonList(METRIC_DATA));
@ -122,12 +123,12 @@ class PeriodicMetricReaderTest {
PeriodicMetricReader.builder(waitingMetricExporter) PeriodicMetricReader.builder(waitingMetricExporter)
.setInterval(Duration.ofMillis(100)) .setInterval(Duration.ofMillis(100))
.build(); .build();
when(metricProducer.collectAllMetrics()).thenReturn(Collections.emptyList()); when(collectionRegistration.collectAllMetrics()).thenReturn(Collections.emptyList());
reader.register(metricProducer); reader.register(collectionRegistration);
try { try {
assertThat(reader.forceFlush().join(10, TimeUnit.SECONDS).isSuccess()).isTrue(); assertThat(reader.forceFlush().join(10, TimeUnit.SECONDS).isSuccess()).isTrue();
verify(metricProducer).collectAllMetrics(); verify(collectionRegistration).collectAllMetrics();
assertThat(waitingMetricExporter.exportTimes.size()).isEqualTo(0); assertThat(waitingMetricExporter.exportTimes.size()).isEqualTo(0);
} finally { } finally {
reader.shutdown(); reader.shutdown();
@ -142,7 +143,7 @@ class PeriodicMetricReaderTest {
.setInterval(Duration.ofNanos(Long.MAX_VALUE)) .setInterval(Duration.ofNanos(Long.MAX_VALUE))
.build(); .build();
reader.register(metricProducer); reader.register(collectionRegistration);
assertThat(reader.forceFlush().join(10, TimeUnit.SECONDS).isSuccess()).isTrue(); assertThat(reader.forceFlush().join(10, TimeUnit.SECONDS).isSuccess()).isTrue();
try { try {
@ -164,7 +165,7 @@ class PeriodicMetricReaderTest {
.setInterval(Duration.ofMillis(100)) .setInterval(Duration.ofMillis(100))
.build(); .build();
reader.register(metricProducer); reader.register(collectionRegistration);
try { try {
assertThat(waitingMetricExporter.waitForNumberOfExports(2)) assertThat(waitingMetricExporter.waitForNumberOfExports(2))
.containsExactly( .containsExactly(
@ -181,7 +182,7 @@ class PeriodicMetricReaderTest {
PeriodicMetricReader.builder(waitingMetricExporter) PeriodicMetricReader.builder(waitingMetricExporter)
.setInterval(Duration.ofSeconds(Integer.MAX_VALUE)) .setInterval(Duration.ofSeconds(Integer.MAX_VALUE))
.build(); .build();
reader.register(metricProducer); reader.register(collectionRegistration);
reader.shutdown(); reader.shutdown();
// This export was called during shutdown. // This export was called during shutdown.
@ -198,7 +199,7 @@ class PeriodicMetricReaderTest {
PeriodicMetricReader.builder(new WaitingMetricExporter()) PeriodicMetricReader.builder(new WaitingMetricExporter())
.setInterval(Duration.ofSeconds(Integer.MAX_VALUE)) .setInterval(Duration.ofSeconds(Integer.MAX_VALUE))
.build()); .build());
reader.register(metricProducer); reader.register(collectionRegistration);
reader.close(); reader.close();
verify(reader, times(1)).shutdown(); verify(reader, times(1)).shutdown();

View File

@ -17,7 +17,6 @@ import io.opentelemetry.sdk.metrics.export.AggregationTemporalitySelector;
import io.opentelemetry.sdk.metrics.export.CollectionRegistration; import io.opentelemetry.sdk.metrics.export.CollectionRegistration;
import io.opentelemetry.sdk.metrics.export.DefaultAggregationSelector; import io.opentelemetry.sdk.metrics.export.DefaultAggregationSelector;
import io.opentelemetry.sdk.metrics.export.MetricReader; import io.opentelemetry.sdk.metrics.export.MetricReader;
import io.opentelemetry.sdk.metrics.internal.export.MetricProducer;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
@ -54,7 +53,7 @@ public class InMemoryMetricReader implements MetricReader {
private final AggregationTemporalitySelector aggregationTemporalitySelector; private final AggregationTemporalitySelector aggregationTemporalitySelector;
private final DefaultAggregationSelector defaultAggregationSelector; private final DefaultAggregationSelector defaultAggregationSelector;
private final AtomicBoolean isShutdown = new AtomicBoolean(false); private final AtomicBoolean isShutdown = new AtomicBoolean(false);
private volatile MetricProducer metricProducer = MetricProducer.noop(); private volatile CollectionRegistration collectionRegistration = CollectionRegistration.noop();
private final MemoryMode memoryMode; private final MemoryMode memoryMode;
/** /**
@ -111,12 +110,12 @@ public class InMemoryMetricReader implements MetricReader {
if (isShutdown.get()) { if (isShutdown.get()) {
return Collections.emptyList(); return Collections.emptyList();
} }
return metricProducer.collectAllMetrics(); return collectionRegistration.collectAllMetrics();
} }
@Override @Override
public void register(CollectionRegistration registration) { public void register(CollectionRegistration collectionRegistration) {
this.metricProducer = MetricProducer.asMetricProducer(registration); this.collectionRegistration = collectionRegistration;
} }
@Override @Override