From e41470be4366d4fadb2cf0f810441dda21ce6c5e Mon Sep 17 00:00:00 2001 From: jack-berg <34418638+jack-berg@users.noreply.github.com> Date: Thu, 7 Mar 2024 06:48:36 -0600 Subject: [PATCH] Add basic proxy configuration to OtlpHttp{Signal}Exporters (#6270) Co-authored-by: Marc Schumacher --- dependencyManagement/build.gradle.kts | 1 + .../opentelemetry-exporter-otlp.txt | 9 +++ .../opentelemetry-sdk-common.txt | 8 ++- .../internal/http/HttpExporterBuilder.java | 10 +++ .../internal/http/HttpSenderProvider.java | 2 + .../OtlpHttpLogRecordExporterBuilder.java | 8 +++ .../OtlpHttpMetricExporterBuilder.java | 8 +++ .../trace/OtlpHttpSpanExporterBuilder.java | 8 +++ .../otlp/testing-internal/build.gradle.kts | 1 + .../AbstractHttpTelemetryExporterTest.java | 38 ++++++++++ .../GrpcLogRecordExporterBuilderWrapper.java | 9 ++- .../GrpcMetricExporterBuilderWrapper.java | 9 ++- .../GrpcSpanExporterBuilderWrapper.java | 9 ++- .../HttpLogRecordExporterBuilderWrapper.java | 7 ++ .../HttpMetricExporterBuilderWrapper.java | 7 ++ .../HttpSpanExporterBuilderWrapper.java | 7 ++ ...anagedChannelTelemetryExporterBuilder.java | 7 ++ .../internal/TelemetryExporterBuilder.java | 3 + .../sender/jdk/internal/JdkHttpSender.java | 11 ++- .../jdk/internal/JdkHttpSenderProvider.java | 3 + .../jdk/internal/JdkHttpSenderTest.java | 1 + .../okhttp/internal/OkHttpHttpSender.java | 6 ++ .../internal/OkHttpHttpSenderProvider.java | 3 + .../internal/OkHttpHttpSuppressionTest.java | 1 + .../sdk/common/export/ProxyOptions.java | 71 +++++++++++++++++++ 25 files changed, 241 insertions(+), 6 deletions(-) create mode 100644 sdk/common/src/main/java/io/opentelemetry/sdk/common/export/ProxyOptions.java diff --git a/dependencyManagement/build.gradle.kts b/dependencyManagement/build.gradle.kts index 69c01f9d35..f136adcdc3 100644 --- a/dependencyManagement/build.gradle.kts +++ b/dependencyManagement/build.gradle.kts @@ -77,6 +77,7 @@ val DEPENDENCIES = listOf( "org.codehaus.mojo:animal-sniffer-annotations:1.23", "org.jctools:jctools-core:4.0.3", "org.junit-pioneer:junit-pioneer:1.9.1", + "org.mock-server:mockserver-netty:5.15.0:shaded", "org.skyscreamer:jsonassert:1.5.1", "com.android.tools:desugar_jdk_libs:2.0.4", ) diff --git a/docs/apidiffs/current_vs_latest/opentelemetry-exporter-otlp.txt b/docs/apidiffs/current_vs_latest/opentelemetry-exporter-otlp.txt index f5f51eb6e2..36d0f38ffc 100644 --- a/docs/apidiffs/current_vs_latest/opentelemetry-exporter-otlp.txt +++ b/docs/apidiffs/current_vs_latest/opentelemetry-exporter-otlp.txt @@ -1,4 +1,13 @@ Comparing source compatibility of against +*** MODIFIED CLASS: PUBLIC FINAL io.opentelemetry.exporter.otlp.http.logs.OtlpHttpLogRecordExporterBuilder (not serializable) + === CLASS FILE FORMAT VERSION: 52.0 <- 52.0 + +++ NEW METHOD: PUBLIC(+) io.opentelemetry.exporter.otlp.http.logs.OtlpHttpLogRecordExporterBuilder setProxyOptions(io.opentelemetry.sdk.common.export.ProxyOptions) +*** MODIFIED CLASS: PUBLIC FINAL io.opentelemetry.exporter.otlp.http.metrics.OtlpHttpMetricExporterBuilder (not serializable) + === CLASS FILE FORMAT VERSION: 52.0 <- 52.0 + +++ NEW METHOD: PUBLIC(+) io.opentelemetry.exporter.otlp.http.metrics.OtlpHttpMetricExporterBuilder setProxyOptions(io.opentelemetry.sdk.common.export.ProxyOptions) +*** 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 setProxy(io.opentelemetry.sdk.common.export.ProxyOptions) *** MODIFIED CLASS: PUBLIC FINAL io.opentelemetry.exporter.otlp.logs.OtlpGrpcLogRecordExporterBuilder (not serializable) === CLASS FILE FORMAT VERSION: 52.0 <- 52.0 +++ NEW METHOD: PUBLIC(+) io.opentelemetry.exporter.otlp.logs.OtlpGrpcLogRecordExporterBuilder setConnectTimeout(long, java.util.concurrent.TimeUnit) diff --git a/docs/apidiffs/current_vs_latest/opentelemetry-sdk-common.txt b/docs/apidiffs/current_vs_latest/opentelemetry-sdk-common.txt index df26146497..80cfb0c667 100644 --- a/docs/apidiffs/current_vs_latest/opentelemetry-sdk-common.txt +++ b/docs/apidiffs/current_vs_latest/opentelemetry-sdk-common.txt @@ -1,2 +1,8 @@ Comparing source compatibility of against -No changes. \ No newline at end of file ++++ NEW CLASS: PUBLIC(+) FINAL(+) io.opentelemetry.sdk.common.export.ProxyOptions (not serializable) + +++ CLASS FILE FORMAT VERSION: 52.0 <- n.a. + +++ NEW SUPERCLASS: java.lang.Object + +++ NEW METHOD: PUBLIC(+) STATIC(+) io.opentelemetry.sdk.common.export.ProxyOptions create(java.net.ProxySelector) + +++ NEW METHOD: PUBLIC(+) STATIC(+) io.opentelemetry.sdk.common.export.ProxyOptions create(java.net.InetSocketAddress) + +++ NEW METHOD: PUBLIC(+) java.net.ProxySelector getProxySelector() + +++ NEW METHOD: PUBLIC(+) java.lang.String toString() diff --git a/exporters/common/src/main/java/io/opentelemetry/exporter/internal/http/HttpExporterBuilder.java b/exporters/common/src/main/java/io/opentelemetry/exporter/internal/http/HttpExporterBuilder.java index 3b8275e252..c9087185ec 100644 --- a/exporters/common/src/main/java/io/opentelemetry/exporter/internal/http/HttpExporterBuilder.java +++ b/exporters/common/src/main/java/io/opentelemetry/exporter/internal/http/HttpExporterBuilder.java @@ -13,6 +13,7 @@ import io.opentelemetry.exporter.internal.TlsConfigHelper; import io.opentelemetry.exporter.internal.auth.Authenticator; import io.opentelemetry.exporter.internal.compression.Compressor; import io.opentelemetry.exporter.internal.marshal.Marshaler; +import io.opentelemetry.sdk.common.export.ProxyOptions; import io.opentelemetry.sdk.common.export.RetryPolicy; import java.net.URI; import java.util.ArrayList; @@ -52,6 +53,7 @@ public final class HttpExporterBuilder { private long timeoutNanos = TimeUnit.SECONDS.toNanos(DEFAULT_TIMEOUT_SECS); @Nullable private Compressor compressor; private long connectTimeoutNanos = TimeUnit.SECONDS.toNanos(DEFAULT_CONNECT_TIMEOUT_SECS); + @Nullable private ProxyOptions proxyOptions; private boolean exportAsJson = false; private final Map constantHeaders = new HashMap<>(); private Supplier> headerSupplier = Collections::emptyMap; @@ -131,6 +133,11 @@ public final class HttpExporterBuilder { return this; } + public HttpExporterBuilder setProxyOptions(ProxyOptions proxyOptions) { + this.proxyOptions = proxyOptions; + return this; + } + public HttpExporterBuilder exportAsJson() { this.exportAsJson = true; return this; @@ -152,6 +159,7 @@ public final class HttpExporterBuilder { } copy.meterProviderSupplier = meterProviderSupplier; copy.authenticator = authenticator; + copy.proxyOptions = proxyOptions; return copy; } @@ -187,6 +195,7 @@ public final class HttpExporterBuilder { timeoutNanos, connectTimeoutNanos, headerSupplier, + proxyOptions, authenticator, retryPolicy, tlsConfigHelper.getSslContext(), @@ -205,6 +214,7 @@ public final class HttpExporterBuilder { joiner.add("type=" + type); joiner.add("endpoint=" + endpoint); joiner.add("timeoutNanos=" + timeoutNanos); + joiner.add("proxyOptions=" + proxyOptions); joiner.add( "compressorEncoding=" + Optional.ofNullable(compressor).map(Compressor::getEncoding).orElse(null)); diff --git a/exporters/common/src/main/java/io/opentelemetry/exporter/internal/http/HttpSenderProvider.java b/exporters/common/src/main/java/io/opentelemetry/exporter/internal/http/HttpSenderProvider.java index 90259734d1..b308511eba 100644 --- a/exporters/common/src/main/java/io/opentelemetry/exporter/internal/http/HttpSenderProvider.java +++ b/exporters/common/src/main/java/io/opentelemetry/exporter/internal/http/HttpSenderProvider.java @@ -7,6 +7,7 @@ package io.opentelemetry.exporter.internal.http; import io.opentelemetry.exporter.internal.auth.Authenticator; import io.opentelemetry.exporter.internal.compression.Compressor; +import io.opentelemetry.sdk.common.export.ProxyOptions; import io.opentelemetry.sdk.common.export.RetryPolicy; import java.util.List; import java.util.Map; @@ -34,6 +35,7 @@ public interface HttpSenderProvider { long timeoutNanos, long connectTimeout, Supplier>> headerSupplier, + @Nullable ProxyOptions proxyOptions, @Nullable Authenticator authenticator, @Nullable RetryPolicy retryPolicy, @Nullable SSLContext sslContext, diff --git a/exporters/otlp/all/src/main/java/io/opentelemetry/exporter/otlp/http/logs/OtlpHttpLogRecordExporterBuilder.java b/exporters/otlp/all/src/main/java/io/opentelemetry/exporter/otlp/http/logs/OtlpHttpLogRecordExporterBuilder.java index 0b6253336b..e81f290bc7 100644 --- a/exporters/otlp/all/src/main/java/io/opentelemetry/exporter/otlp/http/logs/OtlpHttpLogRecordExporterBuilder.java +++ b/exporters/otlp/all/src/main/java/io/opentelemetry/exporter/otlp/http/logs/OtlpHttpLogRecordExporterBuilder.java @@ -16,6 +16,7 @@ import io.opentelemetry.exporter.internal.compression.CompressorUtil; import io.opentelemetry.exporter.internal.http.HttpExporterBuilder; import io.opentelemetry.exporter.internal.otlp.logs.LogsRequestMarshaler; import io.opentelemetry.exporter.otlp.internal.OtlpUserAgent; +import io.opentelemetry.sdk.common.export.ProxyOptions; import io.opentelemetry.sdk.common.export.RetryPolicy; import java.time.Duration; import java.util.Map; @@ -171,6 +172,13 @@ public final class OtlpHttpLogRecordExporterBuilder { return this; } + /** Sets the proxy options. Proxying is disabled by default. */ + public OtlpHttpLogRecordExporterBuilder setProxyOptions(ProxyOptions proxyOptions) { + requireNonNull(proxyOptions, "proxyOptions"); + delegate.setProxyOptions(proxyOptions); + return this; + } + /** * Sets the {@link MeterProvider} to use to collect metrics related to export. If not set, uses * {@link GlobalOpenTelemetry#getMeterProvider()}. diff --git a/exporters/otlp/all/src/main/java/io/opentelemetry/exporter/otlp/http/metrics/OtlpHttpMetricExporterBuilder.java b/exporters/otlp/all/src/main/java/io/opentelemetry/exporter/otlp/http/metrics/OtlpHttpMetricExporterBuilder.java index d4b2e57df8..0ccbbef035 100644 --- a/exporters/otlp/all/src/main/java/io/opentelemetry/exporter/otlp/http/metrics/OtlpHttpMetricExporterBuilder.java +++ b/exporters/otlp/all/src/main/java/io/opentelemetry/exporter/otlp/http/metrics/OtlpHttpMetricExporterBuilder.java @@ -15,6 +15,7 @@ import io.opentelemetry.exporter.internal.compression.CompressorUtil; import io.opentelemetry.exporter.internal.http.HttpExporterBuilder; import io.opentelemetry.exporter.internal.otlp.metrics.MetricsRequestMarshaler; import io.opentelemetry.exporter.otlp.internal.OtlpUserAgent; +import io.opentelemetry.sdk.common.export.ProxyOptions; import io.opentelemetry.sdk.common.export.RetryPolicy; import io.opentelemetry.sdk.metrics.InstrumentType; import io.opentelemetry.sdk.metrics.export.AggregationTemporalitySelector; @@ -215,6 +216,13 @@ public final class OtlpHttpMetricExporterBuilder { return this; } + /** Sets the proxy options. Proxying is disabled by default. */ + public OtlpHttpMetricExporterBuilder setProxyOptions(ProxyOptions proxyOptions) { + requireNonNull(proxyOptions, "proxyOptions"); + delegate.setProxyOptions(proxyOptions); + return this; + } + OtlpHttpMetricExporterBuilder exportAsJson() { delegate.exportAsJson(); return this; diff --git a/exporters/otlp/all/src/main/java/io/opentelemetry/exporter/otlp/http/trace/OtlpHttpSpanExporterBuilder.java b/exporters/otlp/all/src/main/java/io/opentelemetry/exporter/otlp/http/trace/OtlpHttpSpanExporterBuilder.java index c7e3549428..a9b148739a 100644 --- a/exporters/otlp/all/src/main/java/io/opentelemetry/exporter/otlp/http/trace/OtlpHttpSpanExporterBuilder.java +++ b/exporters/otlp/all/src/main/java/io/opentelemetry/exporter/otlp/http/trace/OtlpHttpSpanExporterBuilder.java @@ -16,6 +16,7 @@ import io.opentelemetry.exporter.internal.compression.CompressorUtil; import io.opentelemetry.exporter.internal.http.HttpExporterBuilder; import io.opentelemetry.exporter.internal.otlp.traces.TraceRequestMarshaler; import io.opentelemetry.exporter.otlp.internal.OtlpUserAgent; +import io.opentelemetry.sdk.common.export.ProxyOptions; import io.opentelemetry.sdk.common.export.RetryPolicy; import java.time.Duration; import java.util.Map; @@ -172,6 +173,13 @@ public final class OtlpHttpSpanExporterBuilder { return this; } + /** Sets the proxy options. Proxying is disabled by default. */ + public OtlpHttpSpanExporterBuilder setProxy(ProxyOptions proxyOptions) { + requireNonNull(proxyOptions, "proxyOptions"); + delegate.setProxyOptions(proxyOptions); + return this; + } + /** * Sets the {@link MeterProvider} to use to collect metrics related to export. If not set, uses * {@link GlobalOpenTelemetry#getMeterProvider()}. diff --git a/exporters/otlp/testing-internal/build.gradle.kts b/exporters/otlp/testing-internal/build.gradle.kts index 2e491e84c1..2c7c3cc9bd 100644 --- a/exporters/otlp/testing-internal/build.gradle.kts +++ b/exporters/otlp/testing-internal/build.gradle.kts @@ -31,6 +31,7 @@ dependencies { implementation("com.linecorp.armeria:armeria-junit5") implementation("io.github.netmikey.logunit:logunit-jul") implementation("org.assertj:assertj-core") + implementation("org.mock-server:mockserver-netty") } // Skip OWASP dependencyCheck task on test module diff --git a/exporters/otlp/testing-internal/src/main/java/io/opentelemetry/exporter/otlp/testing/internal/AbstractHttpTelemetryExporterTest.java b/exporters/otlp/testing-internal/src/main/java/io/opentelemetry/exporter/otlp/testing/internal/AbstractHttpTelemetryExporterTest.java index 3b903ba0c3..27d9e5f2f2 100644 --- a/exporters/otlp/testing-internal/src/main/java/io/opentelemetry/exporter/otlp/testing/internal/AbstractHttpTelemetryExporterTest.java +++ b/exporters/otlp/testing-internal/src/main/java/io/opentelemetry/exporter/otlp/testing/internal/AbstractHttpTelemetryExporterTest.java @@ -39,12 +39,14 @@ import io.opentelemetry.proto.collector.metrics.v1.ExportMetricsServiceResponse; import io.opentelemetry.proto.collector.trace.v1.ExportTraceServiceRequest; import io.opentelemetry.proto.collector.trace.v1.ExportTraceServiceResponse; import io.opentelemetry.sdk.common.CompletableResultCode; +import io.opentelemetry.sdk.common.export.ProxyOptions; import io.opentelemetry.sdk.common.export.RetryPolicy; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.UncheckedIOException; import java.lang.reflect.Field; +import java.net.InetSocketAddress; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.security.cert.CertificateEncodingException; @@ -84,6 +86,7 @@ import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.ArgumentsProvider; import org.junit.jupiter.params.provider.ArgumentsSource; import org.junit.jupiter.params.provider.ValueSource; +import org.mockserver.integration.ClientAndServer; import org.slf4j.event.Level; import org.slf4j.event.LoggingEvent; @@ -655,6 +658,39 @@ public abstract class AbstractHttpTelemetryExporterTest { assertThat(attempts).hasValue(1); } + @Test + void proxy() { + // configure mockserver to proxy to the local OTLP server + InetSocketAddress serverSocketAddress = server.httpSocketAddress(); + try (ClientAndServer clientAndServer = + ClientAndServer.startClientAndServer( + serverSocketAddress.getHostName(), serverSocketAddress.getPort())) { + TelemetryExporter exporter = + exporterBuilder() + // Configure exporter with server endpoint, and proxy options to route through + // mockserver proxy + .setEndpoint(server.httpUri() + path) + .setProxyOptions( + ProxyOptions.create( + InetSocketAddress.createUnresolved("localhost", clientAndServer.getPort()))) + .build(); + + try { + List telemetry = Collections.singletonList(generateFakeTelemetry()); + + assertThat(exporter.export(telemetry).join(10, TimeUnit.SECONDS).isSuccess()).isTrue(); + // assert that mock server received request + assertThat(clientAndServer.retrieveRecordedRequests(new org.mockserver.model.HttpRequest())) + .hasSize(1); + // assert that server received telemetry from proxy, and is as expected + List expectedResourceTelemetry = toProto(telemetry); + assertThat(exportedResourceTelemetry).containsExactlyElementsOf(expectedResourceTelemetry); + } finally { + exporter.shutdown(); + } + } + } + @Test @SuppressWarnings("PreferJavaTimeOverload") void validConfig() { @@ -815,6 +851,7 @@ public abstract class AbstractHttpTelemetryExporterTest { + "timeoutNanos=" + TimeUnit.SECONDS.toNanos(10) + ", " + + "proxyOptions=null, " + "compressorEncoding=null, " + "connectTimeoutNanos=" + TimeUnit.SECONDS.toNanos(10) @@ -855,6 +892,7 @@ public abstract class AbstractHttpTelemetryExporterTest { + "timeoutNanos=" + TimeUnit.SECONDS.toNanos(5) + ", " + + "proxyOptions=null, " + "compressorEncoding=gzip, " + "connectTimeoutNanos=" + TimeUnit.SECONDS.toNanos(4) diff --git a/exporters/otlp/testing-internal/src/main/java/io/opentelemetry/exporter/otlp/testing/internal/GrpcLogRecordExporterBuilderWrapper.java b/exporters/otlp/testing-internal/src/main/java/io/opentelemetry/exporter/otlp/testing/internal/GrpcLogRecordExporterBuilderWrapper.java index 60e616e783..5753d4c20f 100644 --- a/exporters/otlp/testing-internal/src/main/java/io/opentelemetry/exporter/otlp/testing/internal/GrpcLogRecordExporterBuilderWrapper.java +++ b/exporters/otlp/testing-internal/src/main/java/io/opentelemetry/exporter/otlp/testing/internal/GrpcLogRecordExporterBuilderWrapper.java @@ -8,6 +8,7 @@ package io.opentelemetry.exporter.otlp.testing.internal; import io.grpc.ManagedChannel; import io.opentelemetry.exporter.internal.auth.Authenticator; import io.opentelemetry.exporter.otlp.logs.OtlpGrpcLogRecordExporterBuilder; +import io.opentelemetry.sdk.common.export.ProxyOptions; import io.opentelemetry.sdk.common.export.RetryPolicy; import io.opentelemetry.sdk.logs.data.LogRecordData; import java.time.Duration; @@ -44,7 +45,8 @@ final class GrpcLogRecordExporterBuilderWrapper implements TelemetryExporterBuil @Override public TelemetryExporterBuilder setConnectTimeout(long timeout, TimeUnit unit) { - throw new UnsupportedOperationException(); + builder.setConnectTimeout(timeout, unit); + return this; } @Override @@ -103,6 +105,11 @@ final class GrpcLogRecordExporterBuilderWrapper implements TelemetryExporterBuil return this; } + @Override + public TelemetryExporterBuilder setProxyOptions(ProxyOptions proxyOptions) { + throw new UnsupportedOperationException("ProxyOptions are not supported for gRPC"); + } + @Override @SuppressWarnings("deprecation") // testing deprecated functionality public TelemetryExporterBuilder setChannel(Object channel) { diff --git a/exporters/otlp/testing-internal/src/main/java/io/opentelemetry/exporter/otlp/testing/internal/GrpcMetricExporterBuilderWrapper.java b/exporters/otlp/testing-internal/src/main/java/io/opentelemetry/exporter/otlp/testing/internal/GrpcMetricExporterBuilderWrapper.java index 6d1f236551..e6e44fab1c 100644 --- a/exporters/otlp/testing-internal/src/main/java/io/opentelemetry/exporter/otlp/testing/internal/GrpcMetricExporterBuilderWrapper.java +++ b/exporters/otlp/testing-internal/src/main/java/io/opentelemetry/exporter/otlp/testing/internal/GrpcMetricExporterBuilderWrapper.java @@ -8,6 +8,7 @@ package io.opentelemetry.exporter.otlp.testing.internal; import io.grpc.ManagedChannel; import io.opentelemetry.exporter.internal.auth.Authenticator; import io.opentelemetry.exporter.otlp.metrics.OtlpGrpcMetricExporterBuilder; +import io.opentelemetry.sdk.common.export.ProxyOptions; import io.opentelemetry.sdk.common.export.RetryPolicy; import io.opentelemetry.sdk.metrics.data.MetricData; import java.time.Duration; @@ -44,7 +45,8 @@ final class GrpcMetricExporterBuilderWrapper implements TelemetryExporterBuilder @Override public TelemetryExporterBuilder setConnectTimeout(long timeout, TimeUnit unit) { - throw new UnsupportedOperationException(); + builder.setConnectTimeout(timeout, unit); + return this; } @Override @@ -103,6 +105,11 @@ final class GrpcMetricExporterBuilderWrapper implements TelemetryExporterBuilder return this; } + @Override + public TelemetryExporterBuilder setProxyOptions(ProxyOptions proxyOptions) { + throw new UnsupportedOperationException("ProxyOptions are not supported for gRPC"); + } + @Override @SuppressWarnings("deprecation") // testing deprecated functionality public TelemetryExporterBuilder setChannel(Object channel) { diff --git a/exporters/otlp/testing-internal/src/main/java/io/opentelemetry/exporter/otlp/testing/internal/GrpcSpanExporterBuilderWrapper.java b/exporters/otlp/testing-internal/src/main/java/io/opentelemetry/exporter/otlp/testing/internal/GrpcSpanExporterBuilderWrapper.java index 871eb559de..caf82b92ec 100644 --- a/exporters/otlp/testing-internal/src/main/java/io/opentelemetry/exporter/otlp/testing/internal/GrpcSpanExporterBuilderWrapper.java +++ b/exporters/otlp/testing-internal/src/main/java/io/opentelemetry/exporter/otlp/testing/internal/GrpcSpanExporterBuilderWrapper.java @@ -8,6 +8,7 @@ package io.opentelemetry.exporter.otlp.testing.internal; import io.grpc.ManagedChannel; import io.opentelemetry.exporter.internal.auth.Authenticator; import io.opentelemetry.exporter.otlp.trace.OtlpGrpcSpanExporterBuilder; +import io.opentelemetry.sdk.common.export.ProxyOptions; import io.opentelemetry.sdk.common.export.RetryPolicy; import io.opentelemetry.sdk.trace.data.SpanData; import java.time.Duration; @@ -45,7 +46,8 @@ final class GrpcSpanExporterBuilderWrapper implements TelemetryExporterBuilder setConnectTimeout(long timeout, TimeUnit unit) { - throw new UnsupportedOperationException(); + builder.setConnectTimeout(timeout, unit); + return this; } @Override @@ -104,6 +106,11 @@ final class GrpcSpanExporterBuilderWrapper implements TelemetryExporterBuilder setProxyOptions(ProxyOptions proxyOptions) { + throw new UnsupportedOperationException("ProxyOptions are not supported for gRPC"); + } + @Override @SuppressWarnings("deprecation") // testing deprecated functionality public TelemetryExporterBuilder setChannel(Object channel) { diff --git a/exporters/otlp/testing-internal/src/main/java/io/opentelemetry/exporter/otlp/testing/internal/HttpLogRecordExporterBuilderWrapper.java b/exporters/otlp/testing-internal/src/main/java/io/opentelemetry/exporter/otlp/testing/internal/HttpLogRecordExporterBuilderWrapper.java index a849395cbc..c08fc4ae23 100644 --- a/exporters/otlp/testing-internal/src/main/java/io/opentelemetry/exporter/otlp/testing/internal/HttpLogRecordExporterBuilderWrapper.java +++ b/exporters/otlp/testing-internal/src/main/java/io/opentelemetry/exporter/otlp/testing/internal/HttpLogRecordExporterBuilderWrapper.java @@ -7,6 +7,7 @@ package io.opentelemetry.exporter.otlp.testing.internal; import io.opentelemetry.exporter.internal.auth.Authenticator; import io.opentelemetry.exporter.otlp.http.logs.OtlpHttpLogRecordExporterBuilder; +import io.opentelemetry.sdk.common.export.ProxyOptions; import io.opentelemetry.sdk.common.export.RetryPolicy; import io.opentelemetry.sdk.logs.data.LogRecordData; import java.time.Duration; @@ -106,6 +107,12 @@ public class HttpLogRecordExporterBuilderWrapper return this; } + @Override + public TelemetryExporterBuilder setProxyOptions(ProxyOptions proxyOptions) { + builder.setProxyOptions(proxyOptions); + return this; + } + @Override public TelemetryExporterBuilder setChannel(Object channel) { throw new UnsupportedOperationException("Not implemented"); diff --git a/exporters/otlp/testing-internal/src/main/java/io/opentelemetry/exporter/otlp/testing/internal/HttpMetricExporterBuilderWrapper.java b/exporters/otlp/testing-internal/src/main/java/io/opentelemetry/exporter/otlp/testing/internal/HttpMetricExporterBuilderWrapper.java index 51f5eff0b3..9382ee247d 100644 --- a/exporters/otlp/testing-internal/src/main/java/io/opentelemetry/exporter/otlp/testing/internal/HttpMetricExporterBuilderWrapper.java +++ b/exporters/otlp/testing-internal/src/main/java/io/opentelemetry/exporter/otlp/testing/internal/HttpMetricExporterBuilderWrapper.java @@ -7,6 +7,7 @@ package io.opentelemetry.exporter.otlp.testing.internal; import io.opentelemetry.exporter.internal.auth.Authenticator; import io.opentelemetry.exporter.otlp.http.metrics.OtlpHttpMetricExporterBuilder; +import io.opentelemetry.sdk.common.export.ProxyOptions; import io.opentelemetry.sdk.common.export.RetryPolicy; import io.opentelemetry.sdk.metrics.data.MetricData; import java.time.Duration; @@ -105,6 +106,12 @@ public class HttpMetricExporterBuilderWrapper implements TelemetryExporterBuilde return this; } + @Override + public TelemetryExporterBuilder setProxyOptions(ProxyOptions proxyOptions) { + builder.setProxyOptions(proxyOptions); + return this; + } + @Override public TelemetryExporterBuilder setChannel(Object channel) { throw new UnsupportedOperationException("Not implemented"); diff --git a/exporters/otlp/testing-internal/src/main/java/io/opentelemetry/exporter/otlp/testing/internal/HttpSpanExporterBuilderWrapper.java b/exporters/otlp/testing-internal/src/main/java/io/opentelemetry/exporter/otlp/testing/internal/HttpSpanExporterBuilderWrapper.java index 90bc3ab00e..8652d8a38c 100644 --- a/exporters/otlp/testing-internal/src/main/java/io/opentelemetry/exporter/otlp/testing/internal/HttpSpanExporterBuilderWrapper.java +++ b/exporters/otlp/testing-internal/src/main/java/io/opentelemetry/exporter/otlp/testing/internal/HttpSpanExporterBuilderWrapper.java @@ -7,6 +7,7 @@ package io.opentelemetry.exporter.otlp.testing.internal; import io.opentelemetry.exporter.internal.auth.Authenticator; import io.opentelemetry.exporter.otlp.http.trace.OtlpHttpSpanExporterBuilder; +import io.opentelemetry.sdk.common.export.ProxyOptions; import io.opentelemetry.sdk.common.export.RetryPolicy; import io.opentelemetry.sdk.trace.data.SpanData; import java.time.Duration; @@ -105,6 +106,12 @@ public class HttpSpanExporterBuilderWrapper implements TelemetryExporterBuilder< return this; } + @Override + public TelemetryExporterBuilder setProxyOptions(ProxyOptions proxyOptions) { + builder.setProxy(proxyOptions); + return this; + } + @Override public TelemetryExporterBuilder setChannel(Object channel) { throw new UnsupportedOperationException("Not implemented"); diff --git a/exporters/otlp/testing-internal/src/main/java/io/opentelemetry/exporter/otlp/testing/internal/ManagedChannelTelemetryExporterBuilder.java b/exporters/otlp/testing-internal/src/main/java/io/opentelemetry/exporter/otlp/testing/internal/ManagedChannelTelemetryExporterBuilder.java index e5545aa41b..4a5a8b885b 100644 --- a/exporters/otlp/testing-internal/src/main/java/io/opentelemetry/exporter/otlp/testing/internal/ManagedChannelTelemetryExporterBuilder.java +++ b/exporters/otlp/testing-internal/src/main/java/io/opentelemetry/exporter/otlp/testing/internal/ManagedChannelTelemetryExporterBuilder.java @@ -17,6 +17,7 @@ import io.opentelemetry.exporter.internal.auth.Authenticator; import io.opentelemetry.exporter.internal.grpc.ManagedChannelUtil; import io.opentelemetry.exporter.otlp.internal.OtlpUserAgent; import io.opentelemetry.sdk.common.CompletableResultCode; +import io.opentelemetry.sdk.common.export.ProxyOptions; import io.opentelemetry.sdk.common.export.RetryPolicy; import java.net.URI; import java.time.Duration; @@ -151,6 +152,12 @@ public final class ManagedChannelTelemetryExporterBuilder return this; } + @Override + public TelemetryExporterBuilder setProxyOptions(ProxyOptions proxyOptions) { + delegate.setProxyOptions(proxyOptions); + return this; + } + @Override public TelemetryExporterBuilder setChannel(Object channel) { throw new UnsupportedOperationException(); diff --git a/exporters/otlp/testing-internal/src/main/java/io/opentelemetry/exporter/otlp/testing/internal/TelemetryExporterBuilder.java b/exporters/otlp/testing-internal/src/main/java/io/opentelemetry/exporter/otlp/testing/internal/TelemetryExporterBuilder.java index 3f0b03b2e5..4cbcc9f5c5 100644 --- a/exporters/otlp/testing-internal/src/main/java/io/opentelemetry/exporter/otlp/testing/internal/TelemetryExporterBuilder.java +++ b/exporters/otlp/testing-internal/src/main/java/io/opentelemetry/exporter/otlp/testing/internal/TelemetryExporterBuilder.java @@ -9,6 +9,7 @@ import io.opentelemetry.exporter.internal.auth.Authenticator; import io.opentelemetry.exporter.otlp.logs.OtlpGrpcLogRecordExporterBuilder; import io.opentelemetry.exporter.otlp.metrics.OtlpGrpcMetricExporterBuilder; import io.opentelemetry.exporter.otlp.trace.OtlpGrpcSpanExporterBuilder; +import io.opentelemetry.sdk.common.export.ProxyOptions; import io.opentelemetry.sdk.common.export.RetryPolicy; import io.opentelemetry.sdk.logs.data.LogRecordData; import io.opentelemetry.sdk.metrics.data.MetricData; @@ -60,6 +61,8 @@ public interface TelemetryExporterBuilder { TelemetryExporterBuilder setRetryPolicy(RetryPolicy retryPolicy); + TelemetryExporterBuilder setProxyOptions(ProxyOptions proxyOptions); + TelemetryExporterBuilder setChannel(Object channel); TelemetryExporter build(); diff --git a/exporters/sender/jdk/src/main/java/io/opentelemetry/exporter/sender/jdk/internal/JdkHttpSender.java b/exporters/sender/jdk/src/main/java/io/opentelemetry/exporter/sender/jdk/internal/JdkHttpSender.java index 838e1d5e20..22c0609e53 100644 --- a/exporters/sender/jdk/src/main/java/io/opentelemetry/exporter/sender/jdk/internal/JdkHttpSender.java +++ b/exporters/sender/jdk/src/main/java/io/opentelemetry/exporter/sender/jdk/internal/JdkHttpSender.java @@ -9,6 +9,7 @@ import io.opentelemetry.exporter.internal.compression.Compressor; import io.opentelemetry.exporter.internal.http.HttpSender; import io.opentelemetry.exporter.internal.marshal.Marshaler; import io.opentelemetry.sdk.common.CompletableResultCode; +import io.opentelemetry.sdk.common.export.ProxyOptions; import io.opentelemetry.sdk.common.export.RetryPolicy; import java.io.ByteArrayOutputStream; import java.io.IOException; @@ -94,9 +95,10 @@ public final class JdkHttpSender implements HttpSender { long connectTimeoutNanos, Supplier>> headerSupplier, @Nullable RetryPolicy retryPolicy, + @Nullable ProxyOptions proxyOptions, @Nullable SSLContext sslContext) { this( - configureClient(sslContext, connectTimeoutNanos), + configureClient(sslContext, connectTimeoutNanos, proxyOptions), endpoint, compressor, exportAsJson, @@ -107,12 +109,17 @@ public final class JdkHttpSender implements HttpSender { } private static HttpClient configureClient( - @Nullable SSLContext sslContext, long connectionTimeoutNanos) { + @Nullable SSLContext sslContext, + long connectionTimeoutNanos, + @Nullable ProxyOptions proxyOptions) { HttpClient.Builder builder = HttpClient.newBuilder().connectTimeout(Duration.ofNanos(connectionTimeoutNanos)); if (sslContext != null) { builder.sslContext(sslContext); } + if (proxyOptions != null) { + builder.proxy(proxyOptions.getProxySelector()); + } return builder.build(); } diff --git a/exporters/sender/jdk/src/main/java/io/opentelemetry/exporter/sender/jdk/internal/JdkHttpSenderProvider.java b/exporters/sender/jdk/src/main/java/io/opentelemetry/exporter/sender/jdk/internal/JdkHttpSenderProvider.java index c4c6bf071c..8c2b44cddc 100644 --- a/exporters/sender/jdk/src/main/java/io/opentelemetry/exporter/sender/jdk/internal/JdkHttpSenderProvider.java +++ b/exporters/sender/jdk/src/main/java/io/opentelemetry/exporter/sender/jdk/internal/JdkHttpSenderProvider.java @@ -9,6 +9,7 @@ import io.opentelemetry.exporter.internal.auth.Authenticator; import io.opentelemetry.exporter.internal.compression.Compressor; import io.opentelemetry.exporter.internal.http.HttpSender; import io.opentelemetry.exporter.internal.http.HttpSenderProvider; +import io.opentelemetry.sdk.common.export.ProxyOptions; import io.opentelemetry.sdk.common.export.RetryPolicy; import java.util.List; import java.util.Map; @@ -34,6 +35,7 @@ public final class JdkHttpSenderProvider implements HttpSenderProvider { long timeoutNanos, long connectTimeout, Supplier>> headerSupplier, + @Nullable ProxyOptions proxyOptions, @Nullable Authenticator authenticator, @Nullable RetryPolicy retryPolicy, @Nullable SSLContext sslContext, @@ -47,6 +49,7 @@ public final class JdkHttpSenderProvider implements HttpSenderProvider { connectTimeout, headerSupplier, retryPolicy, + proxyOptions, sslContext); } } diff --git a/exporters/sender/jdk/src/test/java/io/opentelemetry/exporter/sender/jdk/internal/JdkHttpSenderTest.java b/exporters/sender/jdk/src/test/java/io/opentelemetry/exporter/sender/jdk/internal/JdkHttpSenderTest.java index e4ce06f466..79a06521c5 100644 --- a/exporters/sender/jdk/src/test/java/io/opentelemetry/exporter/sender/jdk/internal/JdkHttpSenderTest.java +++ b/exporters/sender/jdk/src/test/java/io/opentelemetry/exporter/sender/jdk/internal/JdkHttpSenderTest.java @@ -108,6 +108,7 @@ class JdkHttpSenderTest { TimeUnit.SECONDS.toNanos(10), Collections::emptyMap, null, + null, null); assertThat(sender) diff --git a/exporters/sender/okhttp/src/main/java/io/opentelemetry/exporter/sender/okhttp/internal/OkHttpHttpSender.java b/exporters/sender/okhttp/src/main/java/io/opentelemetry/exporter/sender/okhttp/internal/OkHttpHttpSender.java index 656b9258c2..5d0c839046 100644 --- a/exporters/sender/okhttp/src/main/java/io/opentelemetry/exporter/sender/okhttp/internal/OkHttpHttpSender.java +++ b/exporters/sender/okhttp/src/main/java/io/opentelemetry/exporter/sender/okhttp/internal/OkHttpHttpSender.java @@ -12,6 +12,7 @@ import io.opentelemetry.exporter.internal.compression.Compressor; import io.opentelemetry.exporter.internal.http.HttpSender; import io.opentelemetry.exporter.internal.marshal.Marshaler; import io.opentelemetry.sdk.common.CompletableResultCode; +import io.opentelemetry.sdk.common.export.ProxyOptions; import io.opentelemetry.sdk.common.export.RetryPolicy; import java.io.IOException; import java.time.Duration; @@ -58,6 +59,7 @@ public final class OkHttpHttpSender implements HttpSender { long timeoutNanos, long connectionTimeoutNanos, Supplier>> headerSupplier, + @Nullable ProxyOptions proxyOptions, @Nullable Authenticator authenticator, @Nullable RetryPolicy retryPolicy, @Nullable SSLContext sslContext, @@ -68,6 +70,10 @@ public final class OkHttpHttpSender implements HttpSender { .connectTimeout(Duration.ofNanos(connectionTimeoutNanos)) .callTimeout(Duration.ofNanos(timeoutNanos)); + if (proxyOptions != null) { + builder.proxySelector(proxyOptions.getProxySelector()); + } + if (authenticator != null) { Authenticator finalAuthenticator = authenticator; // Generate and attach OkHttp Authenticator implementation diff --git a/exporters/sender/okhttp/src/main/java/io/opentelemetry/exporter/sender/okhttp/internal/OkHttpHttpSenderProvider.java b/exporters/sender/okhttp/src/main/java/io/opentelemetry/exporter/sender/okhttp/internal/OkHttpHttpSenderProvider.java index 3acad86d03..fc91030fb5 100644 --- a/exporters/sender/okhttp/src/main/java/io/opentelemetry/exporter/sender/okhttp/internal/OkHttpHttpSenderProvider.java +++ b/exporters/sender/okhttp/src/main/java/io/opentelemetry/exporter/sender/okhttp/internal/OkHttpHttpSenderProvider.java @@ -9,6 +9,7 @@ import io.opentelemetry.exporter.internal.auth.Authenticator; import io.opentelemetry.exporter.internal.compression.Compressor; import io.opentelemetry.exporter.internal.http.HttpSender; import io.opentelemetry.exporter.internal.http.HttpSenderProvider; +import io.opentelemetry.sdk.common.export.ProxyOptions; import io.opentelemetry.sdk.common.export.RetryPolicy; import java.util.List; import java.util.Map; @@ -34,6 +35,7 @@ public final class OkHttpHttpSenderProvider implements HttpSenderProvider { long timeoutNanos, long connectTimeout, Supplier>> headerSupplier, + @Nullable ProxyOptions proxyOptions, @Nullable Authenticator authenticator, @Nullable RetryPolicy retryPolicy, @Nullable SSLContext sslContext, @@ -46,6 +48,7 @@ public final class OkHttpHttpSenderProvider implements HttpSenderProvider { timeoutNanos, connectTimeout, headerSupplier, + proxyOptions, authenticator, retryPolicy, sslContext, diff --git a/exporters/sender/okhttp/src/test/java/io/opentelemetry/exporter/sender/okhttp/internal/OkHttpHttpSuppressionTest.java b/exporters/sender/okhttp/src/test/java/io/opentelemetry/exporter/sender/okhttp/internal/OkHttpHttpSuppressionTest.java index 046dbee521..38686c3652 100644 --- a/exporters/sender/okhttp/src/test/java/io/opentelemetry/exporter/sender/okhttp/internal/OkHttpHttpSuppressionTest.java +++ b/exporters/sender/okhttp/src/test/java/io/opentelemetry/exporter/sender/okhttp/internal/OkHttpHttpSuppressionTest.java @@ -46,6 +46,7 @@ class OkHttpHttpSuppressionTest extends AbstractOkHttpSuppressionTest proxyList; + + private SimpleProxySelector(Proxy proxy) { + this.proxyList = Collections.singletonList(proxy); + } + + @Override + public List select(URI uri) { + return proxyList; + } + + @Override + public void connectFailed(URI uri, SocketAddress sa, IOException e) { + // ignore + } + + @Override + public String toString() { + return "SimpleProxySelector{proxy=" + proxyList.get(0).toString() + "}"; + } + } +}