diff --git a/exporters/otlp/src/main/java/io/opentelemetry/exporters/otlp/OtlpGrpcSpanExporter.java b/exporters/otlp/src/main/java/io/opentelemetry/exporters/otlp/OtlpGrpcSpanExporter.java index ab88e1095fc..11a515db34b 100644 --- a/exporters/otlp/src/main/java/io/opentelemetry/exporters/otlp/OtlpGrpcSpanExporter.java +++ b/exporters/otlp/src/main/java/io/opentelemetry/exporters/otlp/OtlpGrpcSpanExporter.java @@ -16,17 +16,26 @@ package io.opentelemetry.exporters.otlp; +import static io.grpc.Metadata.ASCII_STRING_MARSHALLER; + +import com.google.common.base.Splitter; import io.grpc.ManagedChannel; +import io.grpc.ManagedChannelBuilder; +import io.grpc.Metadata; +import io.grpc.Metadata.Key; +import io.grpc.stub.MetadataUtils; import io.opentelemetry.proto.collector.trace.v1.ExportTraceServiceRequest; import io.opentelemetry.proto.collector.trace.v1.TraceServiceGrpc; import io.opentelemetry.sdk.common.export.ConfigBuilder; import io.opentelemetry.sdk.trace.data.SpanData; import io.opentelemetry.sdk.trace.export.SpanExporter; import java.util.Collection; +import java.util.List; import java.util.Map; import java.util.concurrent.TimeUnit; import java.util.logging.Level; import java.util.logging.Logger; +import javax.annotation.Nullable; import javax.annotation.concurrent.ThreadSafe; /** @@ -41,6 +50,10 @@ * * *

For environment variables, {@link OtlpGrpcSpanExporter} will look for the following names: @@ -48,6 +61,10 @@ *

*/ @ThreadSafe @@ -146,11 +163,18 @@ public void shutdown() { /** Builder utility for this exporter. */ public static class Builder extends ConfigBuilder { private static final String KEY_SPAN_TIMEOUT = "otel.otlp.span.timeout"; + private static final String KEY_ENDPOINT = "otel.otlp.endpoint"; + private static final String KEY_USE_TLS = "otel.otlp.use.tls"; + private static final String KEY_METADATA = "otel.otlp.metadata"; private ManagedChannel channel; private long deadlineMs = 1_000; // 1 second + @Nullable private String endpoint; + private boolean useTls; + @Nullable private Metadata metadata; /** - * Sets the managed chanel to use when communicating with the backend. Required. + * Sets the managed chanel to use when communicating with the backend. Required if {@link + * Builder#endpoint} is not set. If {@link Builder#endpoint} is set then build the channel. * * @param channel the channel to use * @return this builder's instance @@ -171,12 +195,67 @@ public Builder setDeadlineMs(long deadlineMs) { return this; } + /** + * Sets the OTLP endpoint to connect to. Optional. + * + * @param endpoint endpoint to connect to + * @return this builder's instance + */ + public Builder setEndpoint(String endpoint) { + this.endpoint = endpoint; + return this; + } + + /** + * Sets use or not TLS, default is false. Optional. Applicable only if {@link Builder#endpoint} + * is set to build channel. + * + * @param useTls use TLS or not + * @return this builder's instance + */ + public Builder setUseTls(boolean useTls) { + this.useTls = useTls; + return this; + } + + /** + * Add header to request. Optional. Applicable only if {@link Builder#endpoint} is set to build + * channel. + * + * @param key header key + * @param value header value + * @return this builder's instance + */ + public Builder addHeader(String key, String value) { + if (metadata == null) { + metadata = new Metadata(); + } + metadata.put(Key.of(key, ASCII_STRING_MARSHALLER), value); + return this; + } + /** * Constructs a new instance of the exporter based on the builder's values. * * @return a new exporter's instance */ public OtlpGrpcSpanExporter build() { + if (endpoint != null) { + final ManagedChannelBuilder managedChannelBuilder = + ManagedChannelBuilder.forTarget(endpoint); + + if (useTls) { + managedChannelBuilder.useTransportSecurity(); + } else { + managedChannelBuilder.usePlaintext(); + } + + if (metadata != null) { + managedChannelBuilder.intercept(MetadataUtils.newAttachHeadersInterceptor(metadata)); + } + + channel = managedChannelBuilder.build(); + } return new OtlpGrpcSpanExporter(channel, deadlineMs); } @@ -196,6 +275,26 @@ protected Builder fromConfigMap( if (value != null) { this.setDeadlineMs(value); } + String endpointValue = getStringProperty(KEY_ENDPOINT, configMap); + if (endpointValue != null) { + this.setEndpoint(endpointValue); + } + + Boolean useTlsValue = getBooleanProperty(KEY_USE_TLS, configMap); + if (useTlsValue != null) { + this.setUseTls(useTlsValue); + } + + String metadataValue = getStringProperty(KEY_METADATA, configMap); + if (metadataValue != null) { + for (String keyValueString : Splitter.on(';').split(metadataValue)) { + final List keyValue = Splitter.on('=').splitToList(keyValueString); + if (keyValue.size() == 2) { + addHeader(keyValue.get(0), keyValue.get(1)); + } + } + } + return this; } } diff --git a/exporters/otlp/src/main/java/io/opentelemetry/exporters/otlp/package-info.java b/exporters/otlp/src/main/java/io/opentelemetry/exporters/otlp/package-info.java index d9111845f7e..a56a0462073 100644 --- a/exporters/otlp/src/main/java/io/opentelemetry/exporters/otlp/package-info.java +++ b/exporters/otlp/src/main/java/io/opentelemetry/exporters/otlp/package-info.java @@ -40,6 +40,10 @@ * * *

For environment variables, {@link io.opentelemetry.exporters.otlp.OtlpGrpcMetricExporter} will @@ -48,6 +52,10 @@ *

* *

{@link io.opentelemetry.exporters.otlp.OtlpGrpcSpanExporter}

diff --git a/exporters/otlp/src/test/java/io/opentelemetry/exporters/otlp/OtlpGrpcSpanExporterTest.java b/exporters/otlp/src/test/java/io/opentelemetry/exporters/otlp/OtlpGrpcSpanExporterTest.java index 4b0f30fa9df..8196f8f063e 100644 --- a/exporters/otlp/src/test/java/io/opentelemetry/exporters/otlp/OtlpGrpcSpanExporterTest.java +++ b/exporters/otlp/src/test/java/io/opentelemetry/exporters/otlp/OtlpGrpcSpanExporterTest.java @@ -66,10 +66,16 @@ public class OtlpGrpcSpanExporterTest { public void configTest() { Map options = new HashMap<>(); options.put("otel.otlp.span.timeout", "12"); + options.put("otel.otlp.endpoint", "http://localhost:6553"); + options.put("otel.otlp.use.tls", "true"); + options.put("otel.otlp.metadata", "key=value"); OtlpGrpcSpanExporter.Builder config = OtlpGrpcSpanExporter.newBuilder(); OtlpGrpcSpanExporter.Builder spy = Mockito.spy(config); spy.fromConfigMap(options, ConfigBuilderTest.getNaming()); Mockito.verify(spy).setDeadlineMs(12); + Mockito.verify(spy).setEndpoint("http://localhost:6553"); + Mockito.verify(spy).setUseTls(true); + Mockito.verify(spy).addHeader("key", "value"); } @Before