Don't use global meter provider for trace export (#3901)

This commit is contained in:
Anuraag Agrawal 2021-11-19 15:06:22 +09:00 committed by GitHub
parent b9b8105da7
commit 6933de18e5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
25 changed files with 187 additions and 50 deletions

View File

@ -1,2 +1,4 @@
Comparing source compatibility of against
No changes.
*** MODIFIED CLASS: PUBLIC FINAL io.opentelemetry.exporter.otlp.http.trace.OtlpHttpSpanExporterBuilder (not serializable)
=== CLASS FILE FORMAT VERSION: 52.0 <- 52.0
+++ NEW METHOD: PUBLIC(+) io.opentelemetry.exporter.otlp.http.trace.OtlpHttpSpanExporterBuilder setMeterProvider(io.opentelemetry.api.metrics.MeterProvider)

View File

@ -1,2 +1,4 @@
Comparing source compatibility of against
No changes.
*** MODIFIED CLASS: PUBLIC FINAL io.opentelemetry.exporter.otlp.trace.OtlpGrpcSpanExporterBuilder (not serializable)
=== CLASS FILE FORMAT VERSION: 52.0 <- 52.0
+++ NEW METHOD: PUBLIC(+) io.opentelemetry.exporter.otlp.trace.OtlpGrpcSpanExporterBuilder setMeterProvider(io.opentelemetry.api.metrics.MeterProvider)

View File

@ -1,2 +1,4 @@
Comparing source compatibility of against
No changes.
*** MODIFIED CLASS: PUBLIC FINAL io.opentelemetry.sdk.trace.export.BatchSpanProcessorBuilder (not serializable)
=== CLASS FILE FORMAT VERSION: 52.0 <- 52.0
+++ NEW METHOD: PUBLIC(+) io.opentelemetry.sdk.trace.export.BatchSpanProcessorBuilder setMeterProvider(io.opentelemetry.api.metrics.MeterProvider)

View File

@ -8,6 +8,7 @@ package io.opentelemetry.exporter.otlp.http.trace;
import static io.opentelemetry.api.internal.Utils.checkArgument;
import static java.util.Objects.requireNonNull;
import io.opentelemetry.api.metrics.MeterProvider;
import io.opentelemetry.exporter.otlp.internal.okhttp.OkHttpExporterBuilder;
import io.opentelemetry.exporter.otlp.internal.traces.TraceRequestMarshaler;
import java.time.Duration;
@ -83,6 +84,16 @@ public final class OtlpHttpSpanExporterBuilder {
return this;
}
/**
* Sets the {@link MeterProvider} to use to collect metrics related to export. If not set, metrics
* will not be collected.
*/
public OtlpHttpSpanExporterBuilder setMeterProvider(MeterProvider meterProvider) {
requireNonNull(meterProvider, "meterProvider");
delegate.setMeterProvider(meterProvider);
return this;
}
/**
* Constructs a new instance of the exporter based on the builder's values.
*

View File

@ -11,9 +11,9 @@ import static io.opentelemetry.api.common.AttributeKey.stringKey;
import io.opentelemetry.api.common.AttributeKey;
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.api.metrics.BoundLongCounter;
import io.opentelemetry.api.metrics.GlobalMeterProvider;
import io.opentelemetry.api.metrics.LongCounter;
import io.opentelemetry.api.metrics.Meter;
import io.opentelemetry.api.metrics.MeterProvider;
/**
* Helper for recording metrics from OTLP exporters.
@ -61,14 +61,12 @@ public class ExporterMetrics {
}
/** Create an instance for recording OTLP gRPC exporter metrics. */
public static ExporterMetrics createGrpc(String type) {
return new ExporterMetrics(
GlobalMeterProvider.get().get("io.opentelemetry.exporters.otlp-grpc"), type);
public static ExporterMetrics createGrpc(String type, MeterProvider meterProvider) {
return new ExporterMetrics(meterProvider.get("io.opentelemetry.exporters.otlp-grpc"), type);
}
/** Create an instance for recording OTLP http/protobuf exporter metrics. */
public static ExporterMetrics createHttpProtobuf(String type) {
return new ExporterMetrics(
GlobalMeterProvider.get().get("io.opentelemetry.exporters.otlp-http"), type);
public static ExporterMetrics createHttpProtobuf(String type, MeterProvider meterProvider) {
return new ExporterMetrics(meterProvider.get("io.opentelemetry.exporters.otlp-http"), type);
}
}

View File

@ -11,6 +11,7 @@ import com.google.common.util.concurrent.MoreExecutors;
import io.grpc.Codec;
import io.grpc.ManagedChannel;
import io.grpc.Status;
import io.opentelemetry.api.metrics.MeterProvider;
import io.opentelemetry.exporter.otlp.internal.ExporterMetrics;
import io.opentelemetry.exporter.otlp.internal.Marshaler;
import io.opentelemetry.sdk.common.CompletableResultCode;
@ -44,10 +45,11 @@ public final class DefaultGrpcExporter<T extends Marshaler> implements GrpcExpor
String type,
ManagedChannel channel,
MarshalerServiceStub<T, ?, ?> stub,
MeterProvider meterProvider,
long timeoutNanos,
boolean compressionEnabled) {
this.type = type;
this.exporterMetrics = ExporterMetrics.createGrpc(type);
this.exporterMetrics = ExporterMetrics.createGrpc(type, meterProvider);
this.managedChannel = channel;
this.timeoutNanos = timeoutNanos;
Codec codec = compressionEnabled ? new Codec.Gzip() : Codec.Identity.NONE;

View File

@ -13,6 +13,7 @@ import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder;
import io.grpc.Metadata;
import io.grpc.stub.MetadataUtils;
import io.opentelemetry.api.metrics.MeterProvider;
import io.opentelemetry.exporter.otlp.internal.Marshaler;
import io.opentelemetry.exporter.otlp.internal.RetryPolicy;
import java.lang.reflect.Field;
@ -44,6 +45,7 @@ public final class DefaultGrpcExporterBuilder<T extends Marshaler>
@Nullable private Metadata metadata;
@Nullable private byte[] trustedCertificatesPem;
@Nullable private RetryPolicy retryPolicy;
private MeterProvider meterProvider = MeterProvider.noop();
/** Creates a new {@link DefaultGrpcExporterBuilder}. */
// Visible for testing
@ -123,6 +125,12 @@ public final class DefaultGrpcExporterBuilder<T extends Marshaler>
return this;
}
@Override
public GrpcExporterBuilder<T> setMeterProvider(MeterProvider meterProvider) {
this.meterProvider = meterProvider;
return this;
}
@Override
public GrpcExporter<T> build() {
ManagedChannel channel = this.channel;
@ -162,7 +170,8 @@ public final class DefaultGrpcExporterBuilder<T extends Marshaler>
Codec codec = compressionEnabled ? new Codec.Gzip() : Codec.Identity.NONE;
MarshalerServiceStub<T, ?, ?> stub =
stubFactory.apply(channel).withCompression(codec.getMessageEncoding());
return new DefaultGrpcExporter<>(type, channel, stub, timeoutNanos, compressionEnabled);
return new DefaultGrpcExporter<>(
type, channel, stub, meterProvider, timeoutNanos, compressionEnabled);
}
/**

View File

@ -6,6 +6,7 @@
package io.opentelemetry.exporter.otlp.internal.grpc;
import io.grpc.ManagedChannel;
import io.opentelemetry.api.metrics.MeterProvider;
import io.opentelemetry.exporter.otlp.internal.Marshaler;
import io.opentelemetry.exporter.otlp.internal.RetryPolicy;
import java.time.Duration;
@ -29,5 +30,7 @@ public interface GrpcExporterBuilder<T extends Marshaler> {
GrpcExporterBuilder<T> addRetryPolicy(RetryPolicy retryPolicy);
GrpcExporterBuilder<T> setMeterProvider(MeterProvider meterProvider);
GrpcExporter<T> build();
}

View File

@ -25,9 +25,9 @@ package io.opentelemetry.exporter.otlp.internal.grpc;
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.api.metrics.BoundLongCounter;
import io.opentelemetry.api.metrics.GlobalMeterProvider;
import io.opentelemetry.api.metrics.LongCounter;
import io.opentelemetry.api.metrics.Meter;
import io.opentelemetry.api.metrics.MeterProvider;
import io.opentelemetry.exporter.otlp.internal.Marshaler;
import io.opentelemetry.sdk.common.CompletableResultCode;
import io.opentelemetry.sdk.internal.ThrottlingLogger;
@ -76,6 +76,7 @@ public final class OkHttpGrpcExporter<T extends Marshaler> implements GrpcExport
OkHttpGrpcExporter(
String type,
OkHttpClient client,
MeterProvider meterProvider,
String endpoint,
Headers headers,
boolean compressionEnabled) {
@ -85,7 +86,7 @@ public final class OkHttpGrpcExporter<T extends Marshaler> implements GrpcExport
this.headers = headers;
this.compressionEnabled = compressionEnabled;
Meter meter = GlobalMeterProvider.get().get("io.opentelemetry.exporters.otlp-grpc-okhttp");
Meter meter = meterProvider.get("io.opentelemetry.exporters.otlp-grpc-okhttp");
Attributes attributes = Attributes.builder().put("type", type).build();
seen = meter.counterBuilder("otlp.exporter.seen").build().bind(attributes);
LongCounter exported = meter.counterBuilder("otlp.exported.exported").build();

View File

@ -6,6 +6,7 @@
package io.opentelemetry.exporter.otlp.internal.grpc;
import io.grpc.ManagedChannel;
import io.opentelemetry.api.metrics.MeterProvider;
import io.opentelemetry.exporter.otlp.internal.Marshaler;
import io.opentelemetry.exporter.otlp.internal.RetryPolicy;
import io.opentelemetry.exporter.otlp.internal.TlsUtil;
@ -39,6 +40,7 @@ public final class OkHttpGrpcExporterBuilder<T extends Marshaler>
private boolean compressionEnabled = false;
private final Headers.Builder headers = new Headers.Builder();
@Nullable private byte[] trustedCertificatesPem;
private MeterProvider meterProvider = MeterProvider.noop();
/** Creates a new {@link OkHttpGrpcExporterBuilder}. */
// Visible for testing
@ -108,6 +110,12 @@ public final class OkHttpGrpcExporterBuilder<T extends Marshaler>
throw new UnsupportedOperationException("Only available on DefaultGrpcExporter");
}
@Override
public GrpcExporterBuilder<T> setMeterProvider(MeterProvider meterProvider) {
this.meterProvider = meterProvider;
return this;
}
@Override
public GrpcExporter<T> build() {
OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder();
@ -139,6 +147,6 @@ public final class OkHttpGrpcExporterBuilder<T extends Marshaler>
}
return new OkHttpGrpcExporter<>(
type, clientBuilder.build(), endpoint, headers.build(), compressionEnabled);
type, clientBuilder.build(), meterProvider, endpoint, headers.build(), compressionEnabled);
}
}

View File

@ -5,6 +5,7 @@
package io.opentelemetry.exporter.otlp.internal.okhttp;
import io.opentelemetry.api.metrics.MeterProvider;
import io.opentelemetry.exporter.otlp.internal.ExporterMetrics;
import io.opentelemetry.exporter.otlp.internal.Marshaler;
import io.opentelemetry.exporter.otlp.internal.grpc.GrpcStatusUtil;
@ -46,6 +47,7 @@ public final class OkHttpExporter<T extends Marshaler> {
OkHttpExporter(
String type,
OkHttpClient client,
MeterProvider meterProvider,
String endpoint,
@Nullable Headers headers,
boolean compressionEnabled) {
@ -55,7 +57,7 @@ public final class OkHttpExporter<T extends Marshaler> {
this.headers = headers;
this.compressionEnabled = compressionEnabled;
this.exporterMetrics = ExporterMetrics.createHttpProtobuf(type);
this.exporterMetrics = ExporterMetrics.createHttpProtobuf(type, meterProvider);
}
public CompletableResultCode export(T exportRequest, int numItems) {

View File

@ -5,6 +5,7 @@
package io.opentelemetry.exporter.otlp.internal.okhttp;
import io.opentelemetry.api.metrics.MeterProvider;
import io.opentelemetry.exporter.otlp.internal.Marshaler;
import io.opentelemetry.exporter.otlp.internal.TlsUtil;
import java.net.URI;
@ -30,6 +31,7 @@ public final class OkHttpExporterBuilder<T extends Marshaler> {
private boolean compressionEnabled = false;
@Nullable private Headers.Builder headersBuilder;
@Nullable private byte[] trustedCertificatesPem;
private MeterProvider meterProvider = MeterProvider.noop();
public OkHttpExporterBuilder(String type, String defaultEndpoint) {
this.type = type;
@ -84,6 +86,11 @@ public final class OkHttpExporterBuilder<T extends Marshaler> {
return this;
}
public OkHttpExporterBuilder<T> setMeterProvider(MeterProvider meterProvider) {
this.meterProvider = meterProvider;
return this;
}
public OkHttpExporter<T> build() {
OkHttpClient.Builder clientBuilder =
new OkHttpClient.Builder().callTimeout(Duration.ofNanos(timeoutNanos));
@ -101,6 +108,7 @@ public final class OkHttpExporterBuilder<T extends Marshaler> {
Headers headers = headersBuilder == null ? null : headersBuilder.build();
return new OkHttpExporter<>(type, clientBuilder.build(), endpoint, headers, compressionEnabled);
return new OkHttpExporter<>(
type, clientBuilder.build(), meterProvider, endpoint, headers, compressionEnabled);
}
}

View File

@ -9,6 +9,7 @@ import static io.opentelemetry.api.internal.Utils.checkArgument;
import static java.util.Objects.requireNonNull;
import io.grpc.ManagedChannel;
import io.opentelemetry.api.metrics.MeterProvider;
import io.opentelemetry.exporter.otlp.internal.grpc.GrpcExporter;
import io.opentelemetry.exporter.otlp.internal.grpc.GrpcExporterBuilder;
import io.opentelemetry.exporter.otlp.internal.traces.TraceRequestMarshaler;
@ -121,6 +122,16 @@ public final class OtlpGrpcSpanExporterBuilder {
return this;
}
/**
* Sets the {@link MeterProvider} to use to collect metrics related to export. If not set, metrics
* will not be collected.
*/
public OtlpGrpcSpanExporterBuilder setMeterProvider(MeterProvider meterProvider) {
requireNonNull(meterProvider, "meterProvider");
delegate.setMeterProvider(meterProvider);
return this;
}
/**
* Constructs a new instance of the exporter based on the builder's values.
*

View File

@ -98,11 +98,16 @@ public final class OpenTelemetrySdkAutoConfiguration {
PropagatorConfiguration.configurePropagators(
config, serviceClassLoader, propagatorCustomizer);
configureMeterProvider(resource, config, serviceClassLoader);
MeterProvider meterProvider = configureMeterProvider(resource, config, serviceClassLoader);
SdkTracerProvider tracerProvider =
TracerProviderConfiguration.configureTracerProvider(
resource, config, serviceClassLoader, spanExporterCustomizer, samplerCustomizer);
resource,
config,
serviceClassLoader,
meterProvider,
spanExporterCustomizer,
samplerCustomizer);
OpenTelemetrySdk openTelemetrySdk =
OpenTelemetrySdk.builder()
@ -115,7 +120,7 @@ public final class OpenTelemetrySdkAutoConfiguration {
return openTelemetrySdk;
}
private static void configureMeterProvider(
private static MeterProvider configureMeterProvider(
Resource resource, ConfigProperties config, ClassLoader serviceClassLoader) {
SdkMeterProviderBuilder meterProviderBuilder = SdkMeterProvider.builder().setResource(resource);
@ -146,7 +151,7 @@ public final class OpenTelemetrySdkAutoConfiguration {
if (exporterName == null || exporterName.equals("none")) {
// In the event no exporters are configured set a noop exporter
GlobalMeterProvider.set(MeterProvider.noop());
return;
return MeterProvider.noop();
}
MetricExporterConfiguration.configureExporter(
exporterName, config, serviceClassLoader, meterProviderBuilder);
@ -155,6 +160,8 @@ public final class OpenTelemetrySdkAutoConfiguration {
// Make sure metrics shut down when JVM shuts down.
Runtime.getRuntime().addShutdownHook(new Thread(meterProvider::close));
return meterProvider;
}
private OpenTelemetrySdkAutoConfiguration() {}

View File

@ -13,6 +13,7 @@ import static java.util.stream.Collectors.groupingBy;
import static java.util.stream.Collectors.joining;
import static java.util.stream.Collectors.toMap;
import io.opentelemetry.api.metrics.MeterProvider;
import io.opentelemetry.exporter.jaeger.JaegerGrpcSpanExporter;
import io.opentelemetry.exporter.jaeger.JaegerGrpcSpanExporterBuilder;
import io.opentelemetry.exporter.logging.LoggingSpanExporter;
@ -44,6 +45,7 @@ final class SpanExporterConfiguration {
static Map<String, SpanExporter> configureSpanExporters(
ConfigProperties config,
ClassLoader serviceClassLoader,
MeterProvider meterProvider,
BiFunction<? super SpanExporter, ConfigProperties, ? extends SpanExporter>
spanExporterCustomizer) {
List<String> exporterNamesList = config.getList("otel.traces.exporter");
@ -91,15 +93,19 @@ final class SpanExporterConfiguration {
Function.identity(),
exporterName ->
spanExporterCustomizer.apply(
configureExporter(exporterName, config, spiExporters), config)));
configureExporter(exporterName, config, spiExporters, meterProvider),
config)));
}
// Visible for testing
static SpanExporter configureExporter(
String name, ConfigProperties config, Map<String, SpanExporter> spiExporters) {
String name,
ConfigProperties config,
Map<String, SpanExporter> spiExporters,
MeterProvider meterProvider) {
switch (name) {
case "otlp":
return configureOtlp(config);
return configureOtlp(config, meterProvider);
case "jaeger":
return configureJaeger(config);
case "zipkin":
@ -120,7 +126,7 @@ final class SpanExporterConfiguration {
}
// Visible for testing
static SpanExporter configureOtlp(ConfigProperties config) {
static SpanExporter configureOtlp(ConfigProperties config, MeterProvider meterProvider) {
String protocol = OtlpConfigUtil.getOtlpProtocol(DATA_TYPE_TRACES, config);
if (protocol.equals(PROTOCOL_HTTP_PROTOBUF)) {
@ -140,6 +146,8 @@ final class SpanExporterConfiguration {
builder::setTrustedCertificates,
unused -> {});
builder.setMeterProvider(meterProvider);
return builder.build();
} else if (protocol.equals(PROTOCOL_GRPC)) {
ClasspathUtil.checkClassExists(
@ -160,6 +168,9 @@ final class SpanExporterConfiguration {
DefaultGrpcExporterBuilder.getDelegateBuilder(
OtlpGrpcSpanExporterBuilder.class, builder)
.addRetryPolicy(retryPolicy));
builder.setMeterProvider(meterProvider);
return builder.build();
} else {
throw new ConfigurationException("Unsupported OTLP traces protocol: " + protocol);

View File

@ -5,6 +5,7 @@
package io.opentelemetry.sdk.autoconfigure;
import io.opentelemetry.api.metrics.MeterProvider;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigurationException;
import io.opentelemetry.sdk.autoconfigure.spi.traces.ConfigurableSamplerProvider;
@ -35,6 +36,7 @@ final class TracerProviderConfiguration {
Resource resource,
ConfigProperties config,
ClassLoader serviceClassLoader,
MeterProvider meterProvider,
BiFunction<? super SpanExporter, ConfigProperties, ? extends SpanExporter>
spanExporterCustomizer,
BiFunction<? super Sampler, ConfigProperties, ? extends Sampler> samplerCustomizer) {
@ -59,7 +61,7 @@ final class TracerProviderConfiguration {
Map<String, SpanExporter> exportersByName =
SpanExporterConfiguration.configureSpanExporters(
config, serviceClassLoader, spanExporterCustomizer);
config, serviceClassLoader, meterProvider, spanExporterCustomizer);
configureSpanProcessors(config, exportersByName)
.forEach(tracerProviderBuilder::addSpanProcessor);

View File

@ -8,6 +8,7 @@ package io.opentelemetry.sdk.autoconfigure;
import static org.assertj.core.api.Assertions.assertThatCode;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import io.opentelemetry.api.metrics.MeterProvider;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigurationException;
import io.opentelemetry.sdk.metrics.SdkMeterProvider;
@ -23,7 +24,8 @@ class NotOnClasspathTest {
void otlpGrpcSpans() {
assertThatThrownBy(
() ->
SpanExporterConfiguration.configureExporter("otlp", EMPTY, Collections.emptyMap()))
SpanExporterConfiguration.configureExporter(
"otlp", EMPTY, Collections.emptyMap(), MeterProvider.noop()))
.isInstanceOf(ConfigurationException.class)
.hasMessageContaining(
"OTLP gRPC Trace Exporter enabled but opentelemetry-exporter-otlp not found on "
@ -37,7 +39,8 @@ class NotOnClasspathTest {
Collections.singletonMap("otel.exporter.otlp.protocol", "http/protobuf"));
assertThatThrownBy(
() ->
SpanExporterConfiguration.configureExporter("otlp", config, Collections.emptyMap()))
SpanExporterConfiguration.configureExporter(
"otlp", config, Collections.emptyMap(), MeterProvider.noop()))
.isInstanceOf(ConfigurationException.class)
.hasMessageContaining(
"OTLP HTTP Trace Exporter enabled but opentelemetry-exporter-otlp-http-trace not found on "
@ -49,7 +52,7 @@ class NotOnClasspathTest {
assertThatThrownBy(
() ->
SpanExporterConfiguration.configureExporter(
"jaeger", EMPTY, Collections.emptyMap()))
"jaeger", EMPTY, Collections.emptyMap(), MeterProvider.noop()))
.isInstanceOf(ConfigurationException.class)
.hasMessageContaining(
"Jaeger gRPC Exporter enabled but opentelemetry-exporter-jaeger not found on "
@ -61,7 +64,7 @@ class NotOnClasspathTest {
assertThatThrownBy(
() ->
SpanExporterConfiguration.configureExporter(
"zipkin", EMPTY, Collections.emptyMap()))
"zipkin", EMPTY, Collections.emptyMap(), MeterProvider.noop()))
.isInstanceOf(ConfigurationException.class)
.hasMessageContaining(
"Zipkin Exporter enabled but opentelemetry-exporter-zipkin not found on classpath");
@ -72,7 +75,7 @@ class NotOnClasspathTest {
assertThatThrownBy(
() ->
SpanExporterConfiguration.configureExporter(
"logging", EMPTY, Collections.emptyMap()))
"logging", EMPTY, Collections.emptyMap(), MeterProvider.noop()))
.isInstanceOf(ConfigurationException.class)
.hasMessageContaining(
"Logging Trace Exporter enabled but opentelemetry-exporter-logging not found on "

View File

@ -10,6 +10,7 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.mockito.Mockito.when;
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.api.metrics.MeterProvider;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigurationException;
import io.opentelemetry.sdk.common.CompletableResultCode;
@ -65,6 +66,7 @@ class TracerProviderConfigurationTest {
resource,
DefaultConfigProperties.createForTest(properties),
TracerProviderConfiguration.class.getClassLoader(),
MeterProvider.noop(),
(a, unused) -> a,
(a, unused) -> a);
try {

View File

@ -9,6 +9,7 @@ import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import com.google.common.collect.ImmutableMap;
import io.opentelemetry.api.metrics.MeterProvider;
import io.opentelemetry.exporter.logging.LoggingSpanExporter;
import io.opentelemetry.exporter.otlp.trace.OtlpGrpcSpanExporter;
import io.opentelemetry.exporter.zipkin.ZipkinSpanExporter;
@ -33,7 +34,10 @@ public class ConfigurableSpanExporterTest {
ImmutableMap.of("test.option", "true", "otel.traces.exporter", "testExporter"));
Map<String, SpanExporter> exportersByName =
SpanExporterConfiguration.configureSpanExporters(
config, SpanExporterConfiguration.class.getClassLoader(), (a, unused) -> a);
config,
SpanExporterConfiguration.class.getClassLoader(),
MeterProvider.noop(),
(a, unused) -> a);
assertThat(exportersByName)
.hasSize(1)
@ -52,7 +56,10 @@ public class ConfigurableSpanExporterTest {
assertThatThrownBy(
() ->
SpanExporterConfiguration.configureSpanExporters(
config, new URLClassLoader(new URL[0], null), (a, unused) -> a))
config,
new URLClassLoader(new URL[0], null),
MeterProvider.noop(),
(a, unused) -> a))
.isInstanceOf(ConfigurationException.class)
.hasMessageContaining("testExporter");
}
@ -66,7 +73,10 @@ public class ConfigurableSpanExporterTest {
assertThatThrownBy(
() ->
SpanExporterConfiguration.configureSpanExporters(
config, SpanExporterConfiguration.class.getClassLoader(), (a, unused) -> a))
config,
SpanExporterConfiguration.class.getClassLoader(),
MeterProvider.noop(),
(a, unused) -> a))
.isInstanceOf(ConfigurationException.class)
.hasMessageContaining("otel.traces.exporter contains duplicates: [otlp]");
}
@ -79,7 +89,10 @@ public class ConfigurableSpanExporterTest {
assertThatThrownBy(
() ->
SpanExporterConfiguration.configureSpanExporters(
config, SpanExporterConfiguration.class.getClassLoader(), (a, unused) -> a))
config,
SpanExporterConfiguration.class.getClassLoader(),
MeterProvider.noop(),
(a, unused) -> a))
.isInstanceOf(ConfigurationException.class)
.hasMessageContaining("otel.traces.exporter contains none along with other exporters");
}
@ -91,7 +104,8 @@ public class ConfigurableSpanExporterTest {
SpanExporterConfiguration.configureExporter(
"catExporter",
DefaultConfigProperties.createForTest(Collections.emptyMap()),
Collections.emptyMap()))
Collections.emptyMap(),
MeterProvider.noop()))
.isInstanceOf(ConfigurationException.class)
.hasMessageContaining("catExporter");
}

View File

@ -9,6 +9,7 @@ import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import com.google.common.collect.ImmutableMap;
import io.opentelemetry.api.metrics.MeterProvider;
import io.opentelemetry.exporter.jaeger.JaegerGrpcSpanExporter;
import io.opentelemetry.exporter.otlp.trace.OtlpGrpcSpanExporter;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigurationException;
@ -25,7 +26,8 @@ class SpanExporterConfigurationTest {
() ->
SpanExporterConfiguration.configureOtlp(
DefaultConfigProperties.createForTest(
ImmutableMap.of("otel.exporter.otlp.protocol", "foo"))))
ImmutableMap.of("otel.exporter.otlp.protocol", "foo")),
MeterProvider.noop()))
.isInstanceOf(ConfigurationException.class)
.hasMessageContaining("Unsupported OTLP traces protocol: foo");
}
@ -38,7 +40,8 @@ class SpanExporterConfigurationTest {
"otlp",
DefaultConfigProperties.createForTest(
Collections.singletonMap("otel.exporter.otlp.timeout", "10")),
Collections.emptyMap());
Collections.emptyMap(),
MeterProvider.noop());
try {
assertThat(exporter)
.isInstanceOfSatisfying(
@ -60,7 +63,8 @@ class SpanExporterConfigurationTest {
"jaeger",
DefaultConfigProperties.createForTest(
Collections.singletonMap("otel.exporter.jaeger.timeout", "10")),
Collections.emptyMap());
Collections.emptyMap(),
MeterProvider.noop());
try {
assertThat(exporter)
.isInstanceOfSatisfying(
@ -82,7 +86,8 @@ class SpanExporterConfigurationTest {
"zipkin",
DefaultConfigProperties.createForTest(
Collections.singletonMap("otel.exporter.zipkin.timeout", "5s")),
Collections.emptyMap());
Collections.emptyMap(),
MeterProvider.noop());
try {
assertThat(exporter).isNotNull();
} finally {

View File

@ -15,6 +15,7 @@ import com.google.common.collect.Lists;
import com.linecorp.armeria.testing.junit5.server.SelfSignedCertificateExtension;
import io.opentelemetry.api.GlobalOpenTelemetry;
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.api.metrics.MeterProvider;
import io.opentelemetry.api.trace.SpanKind;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigurationException;
@ -104,7 +105,8 @@ class OtlpGrpcConfigTest {
props.put("otel.exporter.otlp.timeout", "15s");
ConfigProperties properties = DefaultConfigProperties.createForTest(props);
SpanExporter spanExporter =
SpanExporterConfiguration.configureExporter("otlp", properties, Collections.emptyMap());
SpanExporterConfiguration.configureExporter(
"otlp", properties, Collections.emptyMap(), MeterProvider.noop());
MetricExporter metricExporter =
MetricExporterConfiguration.configureOtlpMetrics(properties, SdkMeterProvider.builder());
@ -153,7 +155,10 @@ class OtlpGrpcConfigTest {
props.put("otel.exporter.otlp.traces.timeout", "15s");
SpanExporter spanExporter =
SpanExporterConfiguration.configureExporter(
"otlp", DefaultConfigProperties.createForTest(props), Collections.emptyMap());
"otlp",
DefaultConfigProperties.createForTest(props),
Collections.emptyMap(),
MeterProvider.noop());
assertThat(spanExporter)
.extracting("delegate.timeoutNanos")
@ -213,7 +218,7 @@ class OtlpGrpcConfigTest {
assertThatThrownBy(
() ->
SpanExporterConfiguration.configureExporter(
"otlp", properties, Collections.emptyMap()))
"otlp", properties, Collections.emptyMap(), MeterProvider.noop()))
.isInstanceOf(ConfigurationException.class)
.hasMessageContaining("Invalid OTLP certificate path:");

View File

@ -14,6 +14,7 @@ import com.google.common.collect.Lists;
import com.linecorp.armeria.testing.junit5.server.SelfSignedCertificateExtension;
import io.grpc.Status;
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.api.metrics.MeterProvider;
import io.opentelemetry.api.trace.SpanKind;
import io.opentelemetry.exporter.otlp.internal.RetryPolicy;
import io.opentelemetry.sdk.common.CompletableResultCode;
@ -90,7 +91,10 @@ class OtlpGrpcRetryTest {
props.put("otel.experimental.exporter.otlp.retry.enabled", "true");
SpanExporter spanExporter =
SpanExporterConfiguration.configureExporter(
"otlp", DefaultConfigProperties.createForTest(props), Collections.emptyMap());
"otlp",
DefaultConfigProperties.createForTest(props),
Collections.emptyMap(),
MeterProvider.noop());
testRetryableStatusCodes(() -> SPAN_DATA, spanExporter::export, server.traceRequests::size);
testDefaultRetryPolicy(() -> SPAN_DATA, spanExporter::export, server.traceRequests::size);

View File

@ -22,6 +22,7 @@ import com.linecorp.armeria.server.ServerBuilder;
import com.linecorp.armeria.testing.junit5.server.ServerExtension;
import io.opentelemetry.api.GlobalOpenTelemetry;
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.api.metrics.MeterProvider;
import io.opentelemetry.api.trace.SpanKind;
import io.opentelemetry.proto.collector.metrics.v1.ExportMetricsServiceRequest;
import io.opentelemetry.proto.collector.trace.v1.ExportTraceServiceRequest;
@ -179,7 +180,8 @@ class OtlpHttpConfigTest {
props.put("otel.exporter.otlp.timeout", "15s");
ConfigProperties properties = DefaultConfigProperties.createForTest(props);
SpanExporter spanExporter =
SpanExporterConfiguration.configureExporter("otlp", properties, Collections.emptyMap());
SpanExporterConfiguration.configureExporter(
"otlp", properties, Collections.emptyMap(), MeterProvider.noop());
MetricExporter metricExporter =
MetricExporterConfiguration.configureOtlpMetrics(properties, SdkMeterProvider.builder());
@ -241,7 +243,10 @@ class OtlpHttpConfigTest {
props.put("otel.exporter.otlp.traces.timeout", "15s");
SpanExporter spanExporter =
SpanExporterConfiguration.configureExporter(
"otlp", DefaultConfigProperties.createForTest(props), Collections.emptyMap());
"otlp",
DefaultConfigProperties.createForTest(props),
Collections.emptyMap(),
MeterProvider.noop());
assertThat(spanExporter)
.extracting("delegate.client", as(InstanceOfAssertFactories.type(OkHttpClient.class)))
@ -315,7 +320,7 @@ class OtlpHttpConfigTest {
assertThatThrownBy(
() ->
SpanExporterConfiguration.configureExporter(
"otlp", properties, Collections.emptyMap()))
"otlp", properties, Collections.emptyMap(), MeterProvider.noop()))
.isInstanceOf(ConfigurationException.class)
.hasMessageContaining("Invalid OTLP certificate path:");

View File

@ -8,9 +8,9 @@ package io.opentelemetry.sdk.trace.export;
import io.opentelemetry.api.common.AttributeKey;
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.api.metrics.BoundLongCounter;
import io.opentelemetry.api.metrics.GlobalMeterProvider;
import io.opentelemetry.api.metrics.LongCounter;
import io.opentelemetry.api.metrics.Meter;
import io.opentelemetry.api.metrics.MeterProvider;
import io.opentelemetry.context.Context;
import io.opentelemetry.sdk.common.CompletableResultCode;
import io.opentelemetry.sdk.internal.DaemonThreadFactory;
@ -66,6 +66,7 @@ public final class BatchSpanProcessor implements SpanProcessor {
BatchSpanProcessor(
SpanExporter spanExporter,
MeterProvider meterProvider,
long scheduleDelayNanos,
int maxQueueSize,
int maxExportBatchSize,
@ -73,6 +74,7 @@ public final class BatchSpanProcessor implements SpanProcessor {
this.worker =
new Worker(
spanExporter,
meterProvider,
scheduleDelayNanos,
maxExportBatchSize,
exporterTimeoutNanos,
@ -150,6 +152,7 @@ public final class BatchSpanProcessor implements SpanProcessor {
private Worker(
SpanExporter spanExporter,
MeterProvider meterProvider,
long scheduleDelayNanos,
int maxExportBatchSize,
long exporterTimeoutNanos,
@ -160,7 +163,7 @@ public final class BatchSpanProcessor implements SpanProcessor {
this.exporterTimeoutNanos = exporterTimeoutNanos;
this.queue = queue;
this.signal = new ArrayBlockingQueue<>(1);
Meter meter = GlobalMeterProvider.get().meterBuilder("io.opentelemetry.sdk.trace").build();
Meter meter = meterProvider.meterBuilder("io.opentelemetry.sdk.trace").build();
meter
.gaugeBuilder("queueSize")
.ofLongs()

View File

@ -8,6 +8,7 @@ package io.opentelemetry.sdk.trace.export;
import static io.opentelemetry.api.internal.Utils.checkArgument;
import static java.util.Objects.requireNonNull;
import io.opentelemetry.api.metrics.MeterProvider;
import java.time.Duration;
import java.util.concurrent.TimeUnit;
@ -28,6 +29,7 @@ public final class BatchSpanProcessorBuilder {
private int maxQueueSize = DEFAULT_MAX_QUEUE_SIZE;
private int maxExportBatchSize = DEFAULT_MAX_EXPORT_BATCH_SIZE;
private long exporterTimeoutNanos = TimeUnit.MILLISECONDS.toNanos(DEFAULT_EXPORT_TIMEOUT_MILLIS);
private MeterProvider meterProvider = MeterProvider.noop();
BatchSpanProcessorBuilder(SpanExporter spanExporter) {
this.spanExporter = requireNonNull(spanExporter, "spanExporter");
@ -125,6 +127,16 @@ public final class BatchSpanProcessorBuilder {
return this;
}
/**
* Sets the {@link MeterProvider} to use to collect metrics related to batch export. If not set,
* metrics will not be collected.
*/
public BatchSpanProcessorBuilder setMeterProvider(MeterProvider meterProvider) {
requireNonNull(meterProvider, "meterProvider");
this.meterProvider = meterProvider;
return this;
}
// Visible for testing
int getMaxExportBatchSize() {
return maxExportBatchSize;
@ -139,6 +151,11 @@ public final class BatchSpanProcessorBuilder {
*/
public BatchSpanProcessor build() {
return new BatchSpanProcessor(
spanExporter, scheduleDelayNanos, maxQueueSize, maxExportBatchSize, exporterTimeoutNanos);
spanExporter,
meterProvider,
scheduleDelayNanos,
maxQueueSize,
maxExportBatchSize,
exporterTimeoutNanos);
}
}