Add basic proxy configuration to OtlpHttp{Signal}Exporters (#6270)

Co-authored-by: Marc Schumacher <schumi@zalando.de>
This commit is contained in:
jack-berg 2024-03-07 06:48:36 -06:00 committed by GitHub
parent f24acbdd7f
commit e41470be43
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
25 changed files with 241 additions and 6 deletions

View File

@ -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",
)

View File

@ -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)

View File

@ -1,2 +1,8 @@
Comparing source compatibility of against
No changes.
+++ 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()

View File

@ -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<T extends Marshaler> {
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<String, String> constantHeaders = new HashMap<>();
private Supplier<Map<String, String>> headerSupplier = Collections::emptyMap;
@ -131,6 +133,11 @@ public final class HttpExporterBuilder<T extends Marshaler> {
return this;
}
public HttpExporterBuilder<T> setProxyOptions(ProxyOptions proxyOptions) {
this.proxyOptions = proxyOptions;
return this;
}
public HttpExporterBuilder<T> exportAsJson() {
this.exportAsJson = true;
return this;
@ -152,6 +159,7 @@ public final class HttpExporterBuilder<T extends Marshaler> {
}
copy.meterProviderSupplier = meterProviderSupplier;
copy.authenticator = authenticator;
copy.proxyOptions = proxyOptions;
return copy;
}
@ -187,6 +195,7 @@ public final class HttpExporterBuilder<T extends Marshaler> {
timeoutNanos,
connectTimeoutNanos,
headerSupplier,
proxyOptions,
authenticator,
retryPolicy,
tlsConfigHelper.getSslContext(),
@ -205,6 +214,7 @@ public final class HttpExporterBuilder<T extends Marshaler> {
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));

View File

@ -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<Map<String, List<String>>> headerSupplier,
@Nullable ProxyOptions proxyOptions,
@Nullable Authenticator authenticator,
@Nullable RetryPolicy retryPolicy,
@Nullable SSLContext sslContext,

View File

@ -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()}.

View File

@ -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;

View File

@ -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()}.

View File

@ -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

View File

@ -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<T, U extends Message> {
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<T> 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<T> 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<U> expectedResourceTelemetry = toProto(telemetry);
assertThat(exportedResourceTelemetry).containsExactlyElementsOf(expectedResourceTelemetry);
} finally {
exporter.shutdown();
}
}
}
@Test
@SuppressWarnings("PreferJavaTimeOverload")
void validConfig() {
@ -815,6 +851,7 @@ public abstract class AbstractHttpTelemetryExporterTest<T, U extends Message> {
+ "timeoutNanos="
+ TimeUnit.SECONDS.toNanos(10)
+ ", "
+ "proxyOptions=null, "
+ "compressorEncoding=null, "
+ "connectTimeoutNanos="
+ TimeUnit.SECONDS.toNanos(10)
@ -855,6 +892,7 @@ public abstract class AbstractHttpTelemetryExporterTest<T, U extends Message> {
+ "timeoutNanos="
+ TimeUnit.SECONDS.toNanos(5)
+ ", "
+ "proxyOptions=null, "
+ "compressorEncoding=gzip, "
+ "connectTimeoutNanos="
+ TimeUnit.SECONDS.toNanos(4)

View File

@ -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<LogRecordData> 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<LogRecordData> setProxyOptions(ProxyOptions proxyOptions) {
throw new UnsupportedOperationException("ProxyOptions are not supported for gRPC");
}
@Override
@SuppressWarnings("deprecation") // testing deprecated functionality
public TelemetryExporterBuilder<LogRecordData> setChannel(Object channel) {

View File

@ -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<MetricData> 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<MetricData> setProxyOptions(ProxyOptions proxyOptions) {
throw new UnsupportedOperationException("ProxyOptions are not supported for gRPC");
}
@Override
@SuppressWarnings("deprecation") // testing deprecated functionality
public TelemetryExporterBuilder<MetricData> setChannel(Object channel) {

View File

@ -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<S
@Override
public TelemetryExporterBuilder<SpanData> setConnectTimeout(long timeout, TimeUnit unit) {
throw new UnsupportedOperationException();
builder.setConnectTimeout(timeout, unit);
return this;
}
@Override
@ -104,6 +106,11 @@ final class GrpcSpanExporterBuilderWrapper implements TelemetryExporterBuilder<S
return this;
}
@Override
public TelemetryExporterBuilder<SpanData> setProxyOptions(ProxyOptions proxyOptions) {
throw new UnsupportedOperationException("ProxyOptions are not supported for gRPC");
}
@Override
@SuppressWarnings("deprecation") // testing deprecated functionality
public TelemetryExporterBuilder<SpanData> setChannel(Object channel) {

View File

@ -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<LogRecordData> setProxyOptions(ProxyOptions proxyOptions) {
builder.setProxyOptions(proxyOptions);
return this;
}
@Override
public TelemetryExporterBuilder<LogRecordData> setChannel(Object channel) {
throw new UnsupportedOperationException("Not implemented");

View File

@ -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<MetricData> setProxyOptions(ProxyOptions proxyOptions) {
builder.setProxyOptions(proxyOptions);
return this;
}
@Override
public TelemetryExporterBuilder<MetricData> setChannel(Object channel) {
throw new UnsupportedOperationException("Not implemented");

View File

@ -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<SpanData> setProxyOptions(ProxyOptions proxyOptions) {
builder.setProxy(proxyOptions);
return this;
}
@Override
public TelemetryExporterBuilder<SpanData> setChannel(Object channel) {
throw new UnsupportedOperationException("Not implemented");

View File

@ -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<T>
return this;
}
@Override
public TelemetryExporterBuilder<T> setProxyOptions(ProxyOptions proxyOptions) {
delegate.setProxyOptions(proxyOptions);
return this;
}
@Override
public TelemetryExporterBuilder<T> setChannel(Object channel) {
throw new UnsupportedOperationException();

View File

@ -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<T> {
TelemetryExporterBuilder<T> setRetryPolicy(RetryPolicy retryPolicy);
TelemetryExporterBuilder<T> setProxyOptions(ProxyOptions proxyOptions);
TelemetryExporterBuilder<T> setChannel(Object channel);
TelemetryExporter<T> build();

View File

@ -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<Map<String, List<String>>> 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();
}

View File

@ -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<Map<String, List<String>>> 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);
}
}

View File

@ -108,6 +108,7 @@ class JdkHttpSenderTest {
TimeUnit.SECONDS.toNanos(10),
Collections::emptyMap,
null,
null,
null);
assertThat(sender)

View File

@ -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<Map<String, List<String>>> 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

View File

@ -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<Map<String, List<String>>> 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,

View File

@ -46,6 +46,7 @@ class OkHttpHttpSuppressionTest extends AbstractOkHttpSuppressionTest<OkHttpHttp
null,
null,
null,
null,
null);
}
}

View File

@ -0,0 +1,71 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.sdk.common.export;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.net.ProxySelector;
import java.net.SocketAddress;
import java.net.URI;
import java.util.Collections;
import java.util.List;
/** Configuration for proxy settings. */
public final class ProxyOptions {
private final ProxySelector proxySelector;
private ProxyOptions(ProxySelector proxySelector) {
this.proxySelector = proxySelector;
}
/** Create proxy options with the {@code proxySelector}. */
public static ProxyOptions create(ProxySelector proxySelector) {
return new ProxyOptions(proxySelector);
}
/**
* Create proxy options with a {@link ProxySelector} which always uses an {@link Proxy.Type#HTTP}
* proxy with the {@code socketAddress}.
*/
public static ProxyOptions create(InetSocketAddress socketAddress) {
return new ProxyOptions(new SimpleProxySelector(new Proxy(Proxy.Type.HTTP, socketAddress)));
}
/** Return the {@link ProxySelector}. */
public ProxySelector getProxySelector() {
return proxySelector;
}
@Override
public String toString() {
return "ProxyOptions{proxySelector=" + proxySelector + "}";
}
private static final class SimpleProxySelector extends ProxySelector {
private final List<Proxy> proxyList;
private SimpleProxySelector(Proxy proxy) {
this.proxyList = Collections.singletonList(proxy);
}
@Override
public List<Proxy> 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() + "}";
}
}
}