From 55567956237dd0209767cf886dd478403afcb4d3 Mon Sep 17 00:00:00 2001 From: jack-berg <34418638+jack-berg@users.noreply.github.com> Date: Tue, 5 Oct 2021 14:48:21 -0500 Subject: [PATCH] =?UTF-8?q?Update=20autoconfigure=20to=20append=20signal?= =?UTF-8?q?=20path=20to=20otlp=20http=20endpoint=20if=20n=E2=80=A6=20(#366?= =?UTF-8?q?6)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Update autoconfigure to append signal path to otlp http endpoint if not present * Use URI.resolve() instead of string concatenation * revert to string concatenation * Add URL validation to OTLP endpoint * Always append signal path to otlp http/protobuf endpoint * Add changelog entry, clarify tests, append root path if not included on generic http endpoint --- CHANGELOG.md | 10 + sdk-extensions/autoconfigure/README.md | 6 +- .../MetricExporterConfiguration.java | 6 +- .../sdk/autoconfigure/OtlpConfigUtil.java | 81 +++++- .../SpanExporterConfiguration.java | 6 +- .../sdk/autoconfigure/OtlpConfigUtilTest.java | 230 +++++++++++++++++- .../sdk/autoconfigure/OtlpHttpConfigTest.java | 23 +- 7 files changed, 335 insertions(+), 27 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 84d286f8ba2..e0fdeac4b08 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,16 @@ you must update your build configuration to also include the new `jaeger-proto` artifact will not be included in a future 2.0 release of the SDK so it is recommended to instead generated the protobuf classes in your own build. +### Auto-configuration (alpha) + +- BREAKING CHANGE: The behavior of `otel.exporter.otlp.endpoint` has changed when the protocol + is `http/protobuf`. The new behavior is in line + with [recent changes](https://github.com/open-telemetry/opentelemetry-specification/pull/1975) to + the specification, which states that the signal path (e.g. `v1/traces` or `v1/metrics`) is + appended to the configured endpoint. Values for signal specific endpoint configuration ( + e.g. `otel.exporter.otlp.traces.endpoint` and `otel.exporter.otlp.metrics.endpoint`) override the + generic endpoint configuration and are used as-is without modification. + ## Version 1.6.0 (2021-09-13): ### API diff --git a/sdk-extensions/autoconfigure/README.md b/sdk-extensions/autoconfigure/README.md index d736112c01a..4c9afa508ef 100644 --- a/sdk-extensions/autoconfigure/README.md +++ b/sdk-extensions/autoconfigure/README.md @@ -50,9 +50,9 @@ The [OpenTelemetry Protocol (OTLP)](https://github.com/open-telemetry/openteleme |------------------------------|-----------------------------|---------------------------------------------------------------------------| | otel.traces.exporter=otlp (default) | OTEL_TRACES_EXPORTER=otlp | Select the OpenTelemetry exporter for tracing (default) | | otel.metrics.exporter=otlp | OTEL_METRICS_EXPORTER=otlp | Select the OpenTelemetry exporter for metrics | -| otel.exporter.otlp.endpoint | OTEL_EXPORTER_OTLP_ENDPOINT | The OTLP traces and metrics endpoint to connect to. Must be a URL with a scheme of either `http` or `https` based on the use of TLS. Default is `http://localhost:4317`. | -| otel.exporter.otlp.traces.endpoint | OTEL_EXPORTER_OTLP_TRACES_ENDPOINT | The OTLP traces endpoint to connect to. Must be a URL with a scheme of either `http` or `https` based on the use of TLS. Default is `http://localhost:4317`. | -| otel.exporter.otlp.metrics.endpoint | OTEL_EXPORTER_OTLP_METRICS_ENDPOINT | The OTLP metrics endpoint to connect to. Must be a URL with a scheme of either `http` or `https` based on the use of TLS. Default is `http://localhost:4317`. | +| otel.exporter.otlp.endpoint | OTEL_EXPORTER_OTLP_ENDPOINT | The OTLP traces and metrics endpoint to connect to. Must be a URL with a scheme of either `http` or `https` based on the use of TLS. If protocol is `http/protobuf` the version and signal will be appended to the path (e.g. `v1/traces` or `v1/metrics`). Default is `http://localhost:4317` when protocol is `grpc`, and `http://localhost:4317/v1/{signal}` when protocol is `http/protobuf`. | +| otel.exporter.otlp.traces.endpoint | OTEL_EXPORTER_OTLP_TRACES_ENDPOINT | The OTLP traces endpoint to connect to. Must be a URL with a scheme of either `http` or `https` based on the use of TLS. Default is `http://localhost:4317` when protocol is `grpc`, and `http://localhost:4317/v1/traces` when protocol is `http/protobuf`. | +| otel.exporter.otlp.metrics.endpoint | OTEL_EXPORTER_OTLP_METRICS_ENDPOINT | The OTLP metrics endpoint to connect to. Must be a URL with a scheme of either `http` or `https` based on the use of TLS. Default is `http://localhost:4317` when protocol is `grpc`, and `http://localhost:4317/v1/metrics` when protocol is `http/protobuf`. | | otel.exporter.otlp.certificate | OTEL_EXPORTER_OTLP_CERTIFICATE | The path to the file containing trusted certificates to use when verifying an OTLP trace or metric server's TLS credentials. The file should contain one or more X.509 certificates in PEM format. By default the host platform's trusted root certificates are used. | | otel.exporter.otlp.traces.certificate | OTEL_EXPORTER_OTLP_TRACES_CERTIFICATE | The path to the file containing trusted certificates to use when verifying an OTLP trace server's TLS credentials. The file should contain one or more X.509 certificates in PEM format. By default the host platform's trusted root certificates are used. | | otel.exporter.otlp.metrics.certificate | OTEL_EXPORTER_OTLP_METRICS_CERTIFICATE | The path to the file containing trusted certificates to use when verifying an OTLP metric server's TLS credentials. The file should contain one or more X.509 certificates in PEM format. By default the host platform's trusted root certificates are used. | diff --git a/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/autoconfigure/MetricExporterConfiguration.java b/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/autoconfigure/MetricExporterConfiguration.java index b958d3afcd1..880cf8d36b6 100644 --- a/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/autoconfigure/MetricExporterConfiguration.java +++ b/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/autoconfigure/MetricExporterConfiguration.java @@ -6,6 +6,8 @@ package io.opentelemetry.sdk.autoconfigure; import static io.opentelemetry.sdk.autoconfigure.OtlpConfigUtil.DATA_TYPE_METRICS; +import static io.opentelemetry.sdk.autoconfigure.OtlpConfigUtil.PROTOCOL_GRPC; +import static io.opentelemetry.sdk.autoconfigure.OtlpConfigUtil.PROTOCOL_HTTP_PROTOBUF; import io.opentelemetry.exporter.logging.LoggingMetricExporter; import io.opentelemetry.exporter.otlp.http.metrics.OtlpHttpMetricExporter; @@ -80,7 +82,7 @@ static MetricExporter configureOtlpMetrics( String protocol = OtlpConfigUtil.getOtlpProtocol(DATA_TYPE_METRICS, config); MetricExporter exporter; - if (protocol.equals("http/protobuf")) { + if (protocol.equals(PROTOCOL_HTTP_PROTOBUF)) { try { ClasspathUtil.checkClassExists( "io.opentelemetry.exporter.otlp.http.metrics.OtlpHttpMetricExporter", @@ -102,7 +104,7 @@ static MetricExporter configureOtlpMetrics( builder::setTrustedCertificates); exporter = builder.build(); - } else if (protocol.equals("grpc")) { + } else if (protocol.equals(PROTOCOL_GRPC)) { try { ClasspathUtil.checkClassExists( "io.opentelemetry.exporter.otlp.metrics.OtlpGrpcMetricExporter", diff --git a/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/autoconfigure/OtlpConfigUtil.java b/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/autoconfigure/OtlpConfigUtil.java index 859619da740..250178d283c 100644 --- a/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/autoconfigure/OtlpConfigUtil.java +++ b/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/autoconfigure/OtlpConfigUtil.java @@ -8,6 +8,8 @@ import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; import io.opentelemetry.sdk.autoconfigure.spi.ConfigurationException; import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URL; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; @@ -15,11 +17,14 @@ import java.util.Map; import java.util.function.BiConsumer; import java.util.function.Consumer; +import javax.annotation.Nullable; final class OtlpConfigUtil { static final String DATA_TYPE_TRACES = "traces"; static final String DATA_TYPE_METRICS = "metrics"; + static final String PROTOCOL_GRPC = "grpc"; + static final String PROTOCOL_HTTP_PROTOBUF = "http/protobuf"; static String getOtlpProtocol(String dataType, ConfigProperties config) { String protocol = config.getString("otel.exporter.otlp." + dataType + ".protocol"); @@ -32,7 +37,7 @@ static String getOtlpProtocol(String dataType, ConfigProperties config) { if (protocol == null) { protocol = config.getString("otel.experimental.exporter.otlp.protocol"); } - return (protocol == null) ? "grpc" : protocol; + return (protocol == null) ? PROTOCOL_GRPC : protocol; } static void configureOtlpExporterBuilder( @@ -43,12 +48,28 @@ static void configureOtlpExporterBuilder( Consumer setCompression, Consumer setTimeout, Consumer setTrustedCertificates) { - String endpoint = config.getString("otel.exporter.otlp." + dataType + ".endpoint"); - if (endpoint == null) { - endpoint = config.getString("otel.exporter.otlp.endpoint"); + String protocol = getOtlpProtocol(dataType, config); + boolean isHttpProtobuf = protocol.equals(PROTOCOL_HTTP_PROTOBUF); + URL endpoint = + validateEndpoint( + config.getString("otel.exporter.otlp." + dataType + ".endpoint"), isHttpProtobuf); + if (endpoint != null) { + if (endpoint.getPath().isEmpty()) { + endpoint = createUrl(endpoint, "/"); + } + } else { + endpoint = validateEndpoint(config.getString("otel.exporter.otlp.endpoint"), isHttpProtobuf); + if (endpoint != null && isHttpProtobuf) { + String path = endpoint.getPath(); + if (!path.endsWith("/")) { + path += "/"; + } + path += signalPath(dataType); + endpoint = createUrl(endpoint, path); + } } if (endpoint != null) { - setEndpoint.accept(endpoint); + setEndpoint.accept(endpoint.toString()); } Map headers = config.getMap("otel.exporter.otlp." + dataType + ".headers"); @@ -92,5 +113,55 @@ static void configureOtlpExporterBuilder( } } + private static URL createUrl(URL context, String spec) { + try { + return new URL(context, spec); + } catch (MalformedURLException e) { + throw new ConfigurationException("Unexpected exception creating URL.", e); + } + } + + @Nullable + private static URL validateEndpoint(@Nullable String endpoint, boolean allowPath) { + if (endpoint == null) { + return null; + } + URL endpointUrl; + try { + endpointUrl = new URL(endpoint); + } catch (MalformedURLException e) { + throw new ConfigurationException("OTLP endpoint must be a valid URL: " + endpoint, e); + } + if (!endpointUrl.getProtocol().equals("http") && !endpointUrl.getProtocol().equals("https")) { + throw new ConfigurationException( + "OTLP endpoint scheme must be http or https: " + endpointUrl.getProtocol()); + } + if (endpointUrl.getQuery() != null) { + throw new ConfigurationException( + "OTLP endpoint must not have a query string: " + endpointUrl.getQuery()); + } + if (endpointUrl.getRef() != null) { + throw new ConfigurationException( + "OTLP endpoint must not have a fragment: " + endpointUrl.getRef()); + } + if (!allowPath && (!endpointUrl.getPath().isEmpty() && !endpointUrl.getPath().equals("/"))) { + throw new ConfigurationException( + "OTLP endpoint must not have a path: " + endpointUrl.getPath()); + } + return endpointUrl; + } + + private static String signalPath(String dataType) { + switch (dataType) { + case DATA_TYPE_METRICS: + return "v1/metrics"; + case DATA_TYPE_TRACES: + return "v1/traces"; + default: + throw new IllegalArgumentException( + "Cannot determine signal path for unrecognized data type: " + dataType); + } + } + private OtlpConfigUtil() {} } diff --git a/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/autoconfigure/SpanExporterConfiguration.java b/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/autoconfigure/SpanExporterConfiguration.java index 10bce58cdfc..26af736aa68 100644 --- a/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/autoconfigure/SpanExporterConfiguration.java +++ b/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/autoconfigure/SpanExporterConfiguration.java @@ -6,6 +6,8 @@ package io.opentelemetry.sdk.autoconfigure; import static io.opentelemetry.sdk.autoconfigure.OtlpConfigUtil.DATA_TYPE_TRACES; +import static io.opentelemetry.sdk.autoconfigure.OtlpConfigUtil.PROTOCOL_GRPC; +import static io.opentelemetry.sdk.autoconfigure.OtlpConfigUtil.PROTOCOL_HTTP_PROTOBUF; import static java.util.stream.Collectors.counting; import static java.util.stream.Collectors.groupingBy; import static java.util.stream.Collectors.joining; @@ -107,7 +109,7 @@ static SpanExporter configureExporter( static SpanExporter configureOtlp(ConfigProperties config) { String protocol = OtlpConfigUtil.getOtlpProtocol(DATA_TYPE_TRACES, config); - if (protocol.equals("http/protobuf")) { + if (protocol.equals(PROTOCOL_HTTP_PROTOBUF)) { ClasspathUtil.checkClassExists( "io.opentelemetry.exporter.otlp.http.trace.OtlpHttpSpanExporter", "OTLP HTTP Trace Exporter", @@ -124,7 +126,7 @@ static SpanExporter configureOtlp(ConfigProperties config) { builder::setTrustedCertificates); return builder.build(); - } else if (protocol.equals("grpc")) { + } else if (protocol.equals(PROTOCOL_GRPC)) { ClasspathUtil.checkClassExists( "io.opentelemetry.exporter.otlp.trace.OtlpGrpcSpanExporter", "OTLP gRPC Trace Exporter", diff --git a/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/autoconfigure/OtlpConfigUtilTest.java b/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/autoconfigure/OtlpConfigUtilTest.java index b3f7618f31e..26f7ab9c572 100644 --- a/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/autoconfigure/OtlpConfigUtilTest.java +++ b/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/autoconfigure/OtlpConfigUtilTest.java @@ -5,21 +5,34 @@ package io.opentelemetry.sdk.autoconfigure; +import static io.opentelemetry.sdk.autoconfigure.OtlpConfigUtil.DATA_TYPE_METRICS; import static io.opentelemetry.sdk.autoconfigure.OtlpConfigUtil.DATA_TYPE_TRACES; +import static io.opentelemetry.sdk.autoconfigure.OtlpConfigUtil.PROTOCOL_GRPC; +import static io.opentelemetry.sdk.autoconfigure.OtlpConfigUtil.PROTOCOL_HTTP_PROTOBUF; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatCode; +import static org.assertj.core.api.Assertions.assertThatThrownBy; import com.google.common.collect.ImmutableMap; +import io.opentelemetry.sdk.autoconfigure.spi.ConfigurationException; import java.util.Collections; +import java.util.Map; +import java.util.concurrent.atomic.AtomicReference; +import org.assertj.core.api.ThrowableAssert.ThrowingCallable; import org.junit.jupiter.api.Test; class OtlpConfigUtilTest { + private static final String GENERIC_ENDPOINT_KEY = "otel.exporter.otlp.endpoint"; + private static final String TRACES_ENDPOINT_KEY = "otel.exporter.otlp.traces.endpoint"; + private static final String METRICS_ENDPOINT_KEY = "otel.exporter.otlp.metrics.endpoint"; + @Test void getOtlpProtocolDefault() { assertThat( OtlpConfigUtil.getOtlpProtocol( DATA_TYPE_TRACES, DefaultConfigProperties.createForTest(Collections.emptyMap()))) - .isEqualTo("grpc"); + .isEqualTo(PROTOCOL_GRPC); assertThat( OtlpConfigUtil.getOtlpProtocol( @@ -58,4 +71,219 @@ void getOtlpProtocolDefault() { "otel.exporter.otlp.traces.protocol", "qux")))) .isEqualTo("qux"); } + + @Test + void configureOtlpExporterBuilder_ValidEndpoints() { + assertThatCode( + configureEndpointCallable( + ImmutableMap.of(GENERIC_ENDPOINT_KEY, "http://localhost:4317"))) + .doesNotThrowAnyException(); + assertThatCode( + configureEndpointCallable( + ImmutableMap.of(GENERIC_ENDPOINT_KEY, "http://localhost:4317/"))) + .doesNotThrowAnyException(); + assertThatCode( + configureEndpointCallable(ImmutableMap.of(GENERIC_ENDPOINT_KEY, "http://localhost"))) + .doesNotThrowAnyException(); + assertThatCode( + configureEndpointCallable(ImmutableMap.of(GENERIC_ENDPOINT_KEY, "https://localhost"))) + .doesNotThrowAnyException(); + assertThatCode( + configureEndpointCallable( + ImmutableMap.of(GENERIC_ENDPOINT_KEY, "http://foo:bar@localhost"))) + .doesNotThrowAnyException(); + assertThatCode( + configureEndpointCallable( + ImmutableMap.of( + GENERIC_ENDPOINT_KEY, + "http://localhost:4317/path", + "otel.exporter.otlp.protocol", + "http/protobuf"))) + .doesNotThrowAnyException(); + } + + @Test + void configureOtlpExporterBuilder_InvalidEndpoints() { + assertThatThrownBy(configureEndpointCallable(ImmutableMap.of(GENERIC_ENDPOINT_KEY, "/foo/bar"))) + .isInstanceOf(ConfigurationException.class) + .hasMessageContaining("OTLP endpoint must be a valid URL:"); + assertThatThrownBy( + configureEndpointCallable( + ImmutableMap.of(GENERIC_ENDPOINT_KEY, "file://localhost:4317"))) + .isInstanceOf(ConfigurationException.class) + .hasMessageContaining("OTLP endpoint scheme must be http or https:"); + assertThatThrownBy( + configureEndpointCallable( + ImmutableMap.of(GENERIC_ENDPOINT_KEY, "http://localhost:4317?foo=bar"))) + .isInstanceOf(ConfigurationException.class) + .hasMessageContaining("OTLP endpoint must not have a query string:"); + assertThatThrownBy( + configureEndpointCallable( + ImmutableMap.of(GENERIC_ENDPOINT_KEY, "http://localhost:4317#fragment"))) + .isInstanceOf(ConfigurationException.class) + .hasMessageContaining("OTLP endpoint must not have a fragment:"); + assertThatThrownBy( + configureEndpointCallable( + ImmutableMap.of( + GENERIC_ENDPOINT_KEY, + "http://localhost:4317/path", + "otel.exporter.otlp.protocol", + "grpc"))) + .isInstanceOf(ConfigurationException.class) + .hasMessageContaining("OTLP endpoint must not have a path:"); + } + + private static ThrowingCallable configureEndpointCallable(Map properties) { + return () -> configureEndpoint(DATA_TYPE_TRACES, properties); + } + + @Test + void configureOtlpExporterBuilder_HttpGenericEndpointKey() { + assertThat( + configureEndpointForHttp( + DATA_TYPE_TRACES, GENERIC_ENDPOINT_KEY, "http://localhost:4317")) + .isEqualTo("http://localhost:4317/v1/traces"); + assertThat( + configureEndpointForHttp( + DATA_TYPE_TRACES, GENERIC_ENDPOINT_KEY, "http://localhost:4317/")) + .isEqualTo("http://localhost:4317/v1/traces"); + assertThat( + configureEndpointForHttp( + DATA_TYPE_TRACES, GENERIC_ENDPOINT_KEY, "http://localhost:4317/foo")) + .isEqualTo("http://localhost:4317/foo/v1/traces"); + assertThat( + configureEndpointForHttp( + DATA_TYPE_TRACES, GENERIC_ENDPOINT_KEY, "http://localhost:4317/foo/")) + .isEqualTo("http://localhost:4317/foo/v1/traces"); + assertThat( + configureEndpointForHttp( + DATA_TYPE_TRACES, GENERIC_ENDPOINT_KEY, "http://localhost:4317/v1/traces")) + .isEqualTo("http://localhost:4317/v1/traces/v1/traces"); + assertThat( + configureEndpointForHttp( + DATA_TYPE_TRACES, GENERIC_ENDPOINT_KEY, "http://localhost:4317/v1/metrics")) + .isEqualTo("http://localhost:4317/v1/metrics/v1/traces"); + + assertThat( + configureEndpointForHttp( + DATA_TYPE_METRICS, GENERIC_ENDPOINT_KEY, "http://localhost:4317")) + .isEqualTo("http://localhost:4317/v1/metrics"); + assertThat( + configureEndpointForHttp( + DATA_TYPE_METRICS, GENERIC_ENDPOINT_KEY, "http://localhost:4317/")) + .isEqualTo("http://localhost:4317/v1/metrics"); + assertThat( + configureEndpointForHttp( + DATA_TYPE_METRICS, GENERIC_ENDPOINT_KEY, "http://localhost:4317/foo")) + .isEqualTo("http://localhost:4317/foo/v1/metrics"); + assertThat( + configureEndpointForHttp( + DATA_TYPE_METRICS, GENERIC_ENDPOINT_KEY, "http://localhost:4317/foo/")) + .isEqualTo("http://localhost:4317/foo/v1/metrics"); + assertThat( + configureEndpointForHttp( + DATA_TYPE_METRICS, GENERIC_ENDPOINT_KEY, "http://localhost:4317/v1/metrics")) + .isEqualTo("http://localhost:4317/v1/metrics/v1/metrics"); + assertThat( + configureEndpointForHttp( + DATA_TYPE_METRICS, GENERIC_ENDPOINT_KEY, "http://localhost:4317/v1/traces")) + .isEqualTo("http://localhost:4317/v1/traces/v1/metrics"); + } + + @Test + void configureOtlpExporterBuilder_HttpTracesEndpointKey() { + assertThat( + configureEndpointForHttp( + DATA_TYPE_TRACES, TRACES_ENDPOINT_KEY, "http://localhost:4317")) + .isEqualTo("http://localhost:4317/"); + assertThat( + configureEndpointForHttp( + DATA_TYPE_TRACES, TRACES_ENDPOINT_KEY, "http://localhost:4317")) + .isEqualTo("http://localhost:4317/"); + assertThat( + configureEndpointForHttp( + DATA_TYPE_TRACES, TRACES_ENDPOINT_KEY, "http://localhost:4317/")) + .isEqualTo("http://localhost:4317/"); + assertThat( + configureEndpointForHttp( + DATA_TYPE_TRACES, TRACES_ENDPOINT_KEY, "http://localhost:4317/v1/traces")) + .isEqualTo("http://localhost:4317/v1/traces"); + assertThat( + configureEndpointForHttp( + DATA_TYPE_TRACES, TRACES_ENDPOINT_KEY, "http://localhost:4317/foo/bar")) + .isEqualTo("http://localhost:4317/foo/bar"); + assertThat( + configureEndpoint( + DATA_TYPE_TRACES, + ImmutableMap.of( + "otel.exporter.otlp.protocol", + PROTOCOL_HTTP_PROTOBUF, + GENERIC_ENDPOINT_KEY, + "http://localhost:4317/foo/bar", + TRACES_ENDPOINT_KEY, + "http://localhost:4317/baz/qux"))) + .isEqualTo("http://localhost:4317/baz/qux"); + } + + @Test + void configureOtlpExporterBuilder_HttpMetricsEndpointKey() { + assertThat( + configureEndpointForHttp( + DATA_TYPE_METRICS, METRICS_ENDPOINT_KEY, "http://localhost:4317")) + .isEqualTo("http://localhost:4317/"); + assertThat( + configureEndpointForHttp( + DATA_TYPE_METRICS, METRICS_ENDPOINT_KEY, "http://localhost:4317")) + .isEqualTo("http://localhost:4317/"); + assertThat( + configureEndpointForHttp( + DATA_TYPE_METRICS, METRICS_ENDPOINT_KEY, "http://localhost:4317/")) + .isEqualTo("http://localhost:4317/"); + assertThat( + configureEndpointForHttp( + DATA_TYPE_METRICS, METRICS_ENDPOINT_KEY, "http://localhost:4317/v1/traces")) + .isEqualTo("http://localhost:4317/v1/traces"); + assertThat( + configureEndpointForHttp( + DATA_TYPE_METRICS, METRICS_ENDPOINT_KEY, "http://localhost:4317/foo/bar")) + .isEqualTo("http://localhost:4317/foo/bar"); + assertThat( + configureEndpoint( + DATA_TYPE_METRICS, + ImmutableMap.of( + "otel.exporter.otlp.protocol", + PROTOCOL_HTTP_PROTOBUF, + GENERIC_ENDPOINT_KEY, + "http://localhost:4317/foo/bar", + METRICS_ENDPOINT_KEY, + "http://localhost:4317/baz/qux"))) + .isEqualTo("http://localhost:4317/baz/qux"); + } + + private static String configureEndpointForHttp( + String dataType, String endpointPropertyKey, String endpointPropertyValue) { + return configureEndpoint( + dataType, + ImmutableMap.of( + "otel.exporter.otlp.protocol", + PROTOCOL_HTTP_PROTOBUF, + endpointPropertyKey, + endpointPropertyValue)); + } + + /** Configure and return the endpoint for the data type using the given properties. */ + private static String configureEndpoint(String dataType, Map properties) { + AtomicReference endpoint = new AtomicReference<>(""); + + OtlpConfigUtil.configureOtlpExporterBuilder( + dataType, + DefaultConfigProperties.createForTest(properties), + endpoint::set, + (value1, value2) -> {}, + value -> {}, + value -> {}, + value -> {}); + + return endpoint.get(); + } } diff --git a/sdk-extensions/autoconfigure/src/testOtlpHttp/java/io/opentelemetry/sdk/autoconfigure/OtlpHttpConfigTest.java b/sdk-extensions/autoconfigure/src/testOtlpHttp/java/io/opentelemetry/sdk/autoconfigure/OtlpHttpConfigTest.java index 97e6c5ee2d3..953d3811af9 100644 --- a/sdk-extensions/autoconfigure/src/testOtlpHttp/java/io/opentelemetry/sdk/autoconfigure/OtlpHttpConfigTest.java +++ b/sdk-extensions/autoconfigure/src/testOtlpHttp/java/io/opentelemetry/sdk/autoconfigure/OtlpHttpConfigTest.java @@ -161,8 +161,7 @@ public void tearDown() { void configureExportersGeneral() { Map props = new HashMap<>(); props.put("otel.exporter.otlp.protocol", "http/protobuf"); - props.put("otel.exporter.otlp.traces.endpoint", traceEndpoint()); - props.put("otel.exporter.otlp.metrics.endpoint", metricEndpoint()); + props.put("otel.exporter.otlp.endpoint", "https://localhost:" + server.httpsPort()); props.put("otel.exporter.otlp.certificate", certificateExtension.filePath); props.put("otel.exporter.otlp.headers", "header-key=header-value"); props.put("otel.exporter.otlp.compression", "gzip"); @@ -222,7 +221,9 @@ void configureSpanExporter() { props.put("otel.exporter.otlp.headers", "header-key=dummy-value"); props.put("otel.exporter.otlp.compression", "foo"); props.put("otel.exporter.otlp.timeout", "10s"); - props.put("otel.exporter.otlp.traces.endpoint", traceEndpoint()); + props.put( + "otel.exporter.otlp.traces.endpoint", + "https://localhost:" + server.httpsPort() + "/v1/traces"); props.put("otel.exporter.otlp.traces.certificate", certificateExtension.filePath); props.put("otel.exporter.otlp.traces.headers", "header-key=header-value"); props.put("otel.exporter.otlp.traces.compression", "gzip"); @@ -262,7 +263,9 @@ public void configureMetricExporter() { props.put("otel.exporter.otlp.headers", "header-key=dummy-value"); props.put("otel.exporter.otlp.compression", "foo"); props.put("otel.exporter.otlp.timeout", "10s"); - props.put("otel.exporter.otlp.metrics.endpoint", metricEndpoint()); + props.put( + "otel.exporter.otlp.metrics.endpoint", + "https://localhost:" + server.httpsPort() + "/v1/metrics"); props.put("otel.exporter.otlp.metrics.certificate", certificateExtension.filePath); props.put("otel.exporter.otlp.metrics.headers", "header-key=header-value"); props.put("otel.exporter.otlp.metrics.compression", "gzip"); @@ -345,8 +348,8 @@ private static MetricData generateFakeMetric() { @Test void configuresGlobal() { System.setProperty("otel.exporter.otlp.protocol", "http/protobuf"); - System.setProperty("otel.exporter.otlp.traces.endpoint", traceEndpoint()); - System.setProperty("otel.exporter.otlp.metrics.endpoint", metricEndpoint()); + System.setProperty( + "otel.exporter.otlp.endpoint", "https://localhost:" + server.httpsPort() + "/"); System.setProperty("otel.exporter.otlp.certificate", certificateExtension.filePath); System.setProperty("otel.imr.export.interval", "1s"); @@ -363,12 +366,4 @@ void configuresGlobal() { assertThat(metricRequests).isNotEmpty(); }); } - - private static String traceEndpoint() { - return String.format("https://localhost:%s/v1/traces", server.httpsPort()); - } - - private static String metricEndpoint() { - return String.format("https://localhost:%s/v1/metrics", server.httpsPort()); - } }