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 9918de27b85..f27a9d26bd1 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
@@ -20,6 +20,7 @@
import io.opentelemetry.sdk.common.export.RetryPolicy;
import io.opentelemetry.sdk.common.internal.StandardComponentId;
import java.time.Duration;
+import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.TimeUnit;
@@ -274,6 +275,22 @@ public OtlpHttpLogRecordExporterBuilder setExecutorService(ExecutorService execu
return this;
}
+ /**
+ * Sets the TLS protocol versions enabled for HTTPS connections. If unset, sender defaults are
+ * used.
+ *
+ *
Protocol names use the JSSE convention, for example {@code TLSv1.2} and {@code TLSv1.3}. The
+ * JVM security policy may prevent use of configured protocols.
+ *
+ * @param enabledProtocols the non-empty list of TLS protocol versions to enable
+ * @return this builder
+ */
+ public OtlpHttpLogRecordExporterBuilder setEnabledProtocols(List enabledProtocols) {
+ requireNonNull(enabledProtocols, "enabledProtocols");
+ delegate.setEnabledProtocols(enabledProtocols);
+ return this;
+ }
+
/**
* Constructs a new instance of the exporter based on the builder's values.
*
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 d408c5543f5..2021210bc0c 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
@@ -26,6 +26,7 @@
import io.opentelemetry.sdk.metrics.export.MetricExporter;
import java.time.Duration;
import java.util.Collection;
+import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.TimeUnit;
@@ -333,6 +334,22 @@ public OtlpHttpMetricExporterBuilder setExecutorService(ExecutorService executor
return this;
}
+ /**
+ * Sets the TLS protocol versions enabled for HTTPS connections. If unset, sender defaults are
+ * used.
+ *
+ * Protocol names use the JSSE convention, for example {@code TLSv1.2} and {@code TLSv1.3}. The
+ * JVM security policy may prevent use of configured protocols.
+ *
+ * @param enabledProtocols the non-empty list of TLS protocol versions to enable
+ * @return this builder
+ */
+ public OtlpHttpMetricExporterBuilder setEnabledProtocols(List enabledProtocols) {
+ requireNonNull(enabledProtocols, "enabledProtocols");
+ delegate.setEnabledProtocols(enabledProtocols);
+ 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 11f3e2d63a9..8f08aa85053 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
@@ -20,6 +20,7 @@
import io.opentelemetry.sdk.common.export.RetryPolicy;
import io.opentelemetry.sdk.common.internal.StandardComponentId;
import java.time.Duration;
+import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.TimeUnit;
@@ -275,6 +276,22 @@ public OtlpHttpSpanExporterBuilder setExecutorService(ExecutorService executorSe
return this;
}
+ /**
+ * Sets the TLS protocol versions enabled for HTTPS connections. If unset, sender defaults are
+ * used.
+ *
+ * Protocol names use the JSSE convention, for example {@code TLSv1.2} and {@code TLSv1.3}. The
+ * JVM security policy may prevent use of configured protocols.
+ *
+ * @param enabledProtocols the non-empty list of TLS protocol versions to enable
+ * @return this builder
+ */
+ public OtlpHttpSpanExporterBuilder setEnabledProtocols(List enabledProtocols) {
+ requireNonNull(enabledProtocols, "enabledProtocols");
+ delegate.setEnabledProtocols(enabledProtocols);
+ return this;
+ }
+
/**
* Constructs a new instance of the exporter based on the builder's values.
*
diff --git a/exporters/otlp/all/src/main/java/io/opentelemetry/exporter/otlp/internal/HttpExporterBuilder.java b/exporters/otlp/all/src/main/java/io/opentelemetry/exporter/otlp/internal/HttpExporterBuilder.java
index 98a5a2e2b85..6ddf1e3d8d1 100644
--- a/exporters/otlp/all/src/main/java/io/opentelemetry/exporter/otlp/internal/HttpExporterBuilder.java
+++ b/exporters/otlp/all/src/main/java/io/opentelemetry/exporter/otlp/internal/HttpExporterBuilder.java
@@ -69,6 +69,7 @@ public final class HttpExporterBuilder {
private ComponentLoader componentLoader =
ComponentLoader.forClassLoader(HttpExporterBuilder.class.getClassLoader());
@Nullable private ExecutorService executorService;
+ @Nullable private List enabledProtocols;
public HttpExporterBuilder(
StandardComponentId.ExporterType exporterType, String defaultEndpoint) {
@@ -167,6 +168,14 @@ public HttpExporterBuilder setExecutorService(ExecutorService executorService) {
return this;
}
+ public HttpExporterBuilder setEnabledProtocols(List enabledProtocols) {
+ if (enabledProtocols.isEmpty()) {
+ throw new IllegalArgumentException("enabledProtocols must not be empty");
+ }
+ this.enabledProtocols = Collections.unmodifiableList(new ArrayList<>(enabledProtocols));
+ return this;
+ }
+
public HttpExporterBuilder exportAsJson() {
this.exportAsJson = true;
exporterType = mapToJsonTypeIfPossible(exporterType);
@@ -204,6 +213,7 @@ public HttpExporterBuilder copy() {
copy.internalTelemetryVersion = internalTelemetryVersion;
copy.proxyOptions = proxyOptions;
copy.componentLoader = componentLoader;
+ copy.enabledProtocols = enabledProtocols;
return copy;
}
@@ -245,6 +255,7 @@ public HttpExporter build() {
isPlainHttp ? null : tlsConfigHelper.getSslContext(),
isPlainHttp ? null : tlsConfigHelper.getTrustManager(),
executorService,
+ enabledProtocols,
// 4mb to align with spec guidance - even though we don't do anything with the
// response today, we will so better to have future-looking memory profile
4 * 1024L * 1024L));
diff --git a/exporters/otlp/all/src/main/java/io/opentelemetry/exporter/otlp/internal/ImmutableHttpSenderConfig.java b/exporters/otlp/all/src/main/java/io/opentelemetry/exporter/otlp/internal/ImmutableHttpSenderConfig.java
index a6d04ae6aa4..bf24415ab28 100644
--- a/exporters/otlp/all/src/main/java/io/opentelemetry/exporter/otlp/internal/ImmutableHttpSenderConfig.java
+++ b/exporters/otlp/all/src/main/java/io/opentelemetry/exporter/otlp/internal/ImmutableHttpSenderConfig.java
@@ -23,6 +23,10 @@
@AutoValue
abstract class ImmutableHttpSenderConfig implements HttpSenderConfig {
+ @Override
+ @Nullable
+ public abstract List getEnabledProtocols();
+
@SuppressWarnings("TooManyParameters")
static HttpSenderConfig create(
URI endpoint,
@@ -36,6 +40,7 @@ static HttpSenderConfig create(
@Nullable SSLContext sslContext,
@Nullable X509TrustManager trustManager,
@Nullable ExecutorService executorService,
+ @Nullable List enabledProtocols,
long maxResponseBodySize) {
return new AutoValue_ImmutableHttpSenderConfig(
endpoint,
@@ -49,6 +54,7 @@ static HttpSenderConfig create(
sslContext,
trustManager,
executorService,
+ enabledProtocols,
maxResponseBodySize);
}
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 6c3610e7345..7f1339c2a0c 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
@@ -45,6 +45,7 @@
import javax.annotation.Nullable;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLException;
+import javax.net.ssl.SSLParameters;
/**
* {@link HttpSender} which is backed by JDK {@link HttpClient}.
@@ -118,9 +119,10 @@ public final class JdkHttpSender implements HttpSender {
@Nullable ProxyOptions proxyOptions,
@Nullable SSLContext sslContext,
@Nullable ExecutorService executorService,
+ @Nullable List enabledProtocols,
long maxResponseBodySize) {
this(
- configureClient(sslContext, connectTimeout, proxyOptions),
+ configureClient(sslContext, connectTimeout, proxyOptions, enabledProtocols),
endpoint,
contentType,
compressor,
@@ -144,7 +146,8 @@ private static ExecutorService newExecutor() {
private static HttpClient configureClient(
@Nullable SSLContext sslContext,
Duration connectTimeout,
- @Nullable ProxyOptions proxyOptions) {
+ @Nullable ProxyOptions proxyOptions,
+ @Nullable List enabledProtocols) {
HttpClient.Builder builder = HttpClient.newBuilder().connectTimeout(connectTimeout);
if (sslContext != null) {
builder.sslContext(sslContext);
@@ -152,6 +155,11 @@ private static HttpClient configureClient(
if (proxyOptions != null) {
builder.proxy(proxyOptions.getProxySelector());
}
+ if (enabledProtocols != null) {
+ SSLParameters sslParameters = new SSLParameters();
+ sslParameters.setProtocols(enabledProtocols.toArray(new String[0]));
+ builder.sslParameters(sslParameters);
+ }
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 fcd9d64e0fe..1f968f62f12 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
@@ -30,6 +30,7 @@ public HttpSender createSender(HttpSenderConfig httpSenderConfig) {
httpSenderConfig.getProxyOptions(),
httpSenderConfig.getSslContext(),
httpSenderConfig.getExecutorService(),
+ httpSenderConfig.getEnabledProtocols(),
httpSenderConfig.getMaxResponseBodySize());
}
}
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 e329266b80d..530dec08e8e 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
@@ -191,6 +191,7 @@ void defaultExecutor_isBounded() {
null,
null,
null,
+ null,
Long.MAX_VALUE);
try {
@@ -223,6 +224,7 @@ void connectTimeout() {
null,
null,
null,
+ null,
Long.MAX_VALUE);
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 266b7080686..df33c1283a4 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
@@ -81,6 +81,7 @@ public OkHttpHttpSender(
@Nullable SSLContext sslContext,
@Nullable X509TrustManager trustManager,
@Nullable ExecutorService executorService,
+ @Nullable List enabledProtocols,
long maxResponseBodySize) {
int callTimeoutMillis = (int) Math.min(timeout.toMillis(), Integer.MAX_VALUE);
int connectTimeoutMillis = (int) Math.min(connectTimeout.toMillis(), Integer.MAX_VALUE);
@@ -111,17 +112,28 @@ public OkHttpHttpSender(
boolean isPlainHttp = endpoint.getScheme().equals("http");
if (isPlainHttp) {
builder.connectionSpecs(Collections.singletonList(ConnectionSpec.CLEARTEXT));
- } else if (sslContext != null) {
- X509TrustManager effectiveTrustManager = trustManager;
-
- if (effectiveTrustManager == null) {
- try {
- effectiveTrustManager = TlsUtil.defaultTrustManager();
- } catch (SSLException e) {
- throw new IllegalStateException("Unable to initialize default trust manager", e);
+ } else {
+ if (enabledProtocols != null) {
+ ConnectionSpec spec =
+ new ConnectionSpec.Builder(ConnectionSpec.COMPATIBLE_TLS)
+ .tlsVersions(enabledProtocols.toArray(new String[0]))
+ .build();
+
+ builder.connectionSpecs(Collections.singletonList(spec));
+ }
+
+ if (sslContext != null) {
+ X509TrustManager effectiveTrustManager = trustManager;
+
+ if (effectiveTrustManager == null) {
+ try {
+ effectiveTrustManager = TlsUtil.defaultTrustManager();
+ } catch (SSLException e) {
+ throw new IllegalStateException("Unable to initialize default trust manager", e);
+ }
}
+ builder.sslSocketFactory(sslContext.getSocketFactory(), effectiveTrustManager);
}
- builder.sslSocketFactory(sslContext.getSocketFactory(), effectiveTrustManager);
}
this.client = builder.build();
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 581cf9bb549..fe644baa95a 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
@@ -31,6 +31,7 @@ public HttpSender createSender(HttpSenderConfig httpSenderConfig) {
httpSenderConfig.getSslContext(),
httpSenderConfig.getTrustManager(),
httpSenderConfig.getExecutorService(),
+ httpSenderConfig.getEnabledProtocols(),
httpSenderConfig.getMaxResponseBodySize());
}
}
diff --git a/exporters/sender/okhttp/src/test/java/io/opentelemetry/exporter/sender/okhttp/internal/OkHttpHttpSenderTest.java b/exporters/sender/okhttp/src/test/java/io/opentelemetry/exporter/sender/okhttp/internal/OkHttpHttpSenderTest.java
index bc62e524762..17b4ce6e024 100644
--- a/exporters/sender/okhttp/src/test/java/io/opentelemetry/exporter/sender/okhttp/internal/OkHttpHttpSenderTest.java
+++ b/exporters/sender/okhttp/src/test/java/io/opentelemetry/exporter/sender/okhttp/internal/OkHttpHttpSenderTest.java
@@ -53,6 +53,7 @@ void send_rejectedExecution_callsOnError() {
null,
null,
executor,
+ null,
Long.MAX_VALUE);
AtomicReference responseRef = new AtomicReference<>();
@@ -216,6 +217,7 @@ private static OkHttpHttpSender newSender(
null,
null,
executorService,
+ null,
Long.MAX_VALUE);
}
@@ -248,6 +250,7 @@ void constructor_usesDefaultTrustManagerWhenTrustManagerIsNull() throws Exceptio
sslContext,
null,
null,
+ null,
Long.MAX_VALUE))
.doesNotThrowAnyException();
}
@@ -276,6 +279,7 @@ void constructor_wrapsDefaultTrustManagerFailure() throws Exception {
sslContext,
null,
null,
+ null,
Long.MAX_VALUE))
.isInstanceOf(IllegalStateException.class)
.hasMessage("Unable to initialize default trust manager")
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 c64247a9b36..be1a0e504ea 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
@@ -47,6 +47,7 @@ OkHttpHttpSender createSender(String endpoint) {
null,
null,
null,
+ null,
Long.MAX_VALUE);
}
}
diff --git a/sdk/common/src/main/java/io/opentelemetry/sdk/common/export/HttpSenderConfig.java b/sdk/common/src/main/java/io/opentelemetry/sdk/common/export/HttpSenderConfig.java
index be40289dd9c..3583b572e73 100644
--- a/sdk/common/src/main/java/io/opentelemetry/sdk/common/export/HttpSenderConfig.java
+++ b/sdk/common/src/main/java/io/opentelemetry/sdk/common/export/HttpSenderConfig.java
@@ -87,6 +87,11 @@ public interface HttpSenderConfig {
@Nullable
ExecutorService getExecutorService();
+ @Nullable
+ default List getEnabledProtocols() {
+ return null;
+ }
+
/**
* The maximum number of bytes to read from a response body. Defaults to 4 MiB.
*