Update autoconfigure to append signal path to otlp http endpoint if n… (#3666)
* 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
This commit is contained in:
		
							parent
							
								
									328f4c2a25
								
							
						
					
					
						commit
						5556795623
					
				
							
								
								
									
										10
									
								
								CHANGELOG.md
								
								
								
								
							
							
						
						
									
										10
									
								
								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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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. |
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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 @@ final class MetricExporterConfiguration {
 | 
			
		|||
    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 @@ final class MetricExporterConfiguration {
 | 
			
		|||
          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",
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -8,6 +8,8 @@ package io.opentelemetry.sdk.autoconfigure;
 | 
			
		|||
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.time.Duration;
 | 
			
		|||
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 @@ final class OtlpConfigUtil {
 | 
			
		|||
    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 @@ final class OtlpConfigUtil {
 | 
			
		|||
      Consumer<String> setCompression,
 | 
			
		||||
      Consumer<Duration> setTimeout,
 | 
			
		||||
      Consumer<byte[]> 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<String, String> headers = config.getMap("otel.exporter.otlp." + dataType + ".headers");
 | 
			
		||||
| 
						 | 
				
			
			@ -92,5 +113,55 @@ final class OtlpConfigUtil {
 | 
			
		|||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  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() {}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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 @@ final class SpanExporterConfiguration {
 | 
			
		|||
  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 @@ final class SpanExporterConfiguration {
 | 
			
		|||
          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",
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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 @@ class OtlpConfigUtilTest {
 | 
			
		|||
                        "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<String, String> 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<String, String> properties) {
 | 
			
		||||
    AtomicReference<String> endpoint = new AtomicReference<>("");
 | 
			
		||||
 | 
			
		||||
    OtlpConfigUtil.configureOtlpExporterBuilder(
 | 
			
		||||
        dataType,
 | 
			
		||||
        DefaultConfigProperties.createForTest(properties),
 | 
			
		||||
        endpoint::set,
 | 
			
		||||
        (value1, value2) -> {},
 | 
			
		||||
        value -> {},
 | 
			
		||||
        value -> {},
 | 
			
		||||
        value -> {});
 | 
			
		||||
 | 
			
		||||
    return endpoint.get();
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -161,8 +161,7 @@ class OtlpHttpConfigTest {
 | 
			
		|||
  void configureExportersGeneral() {
 | 
			
		||||
    Map<String, String> 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 @@ class OtlpHttpConfigTest {
 | 
			
		|||
    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 @@ class OtlpHttpConfigTest {
 | 
			
		|||
    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 @@ class OtlpHttpConfigTest {
 | 
			
		|||
  @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 @@ class OtlpHttpConfigTest {
 | 
			
		|||
              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());
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue