diff --git a/build.gradle b/build.gradle index d917b8d4c528..35051f66b95c 100644 --- a/build.gradle +++ b/build.gradle @@ -373,6 +373,7 @@ project(':iceberg-core') { implementation libs.jackson.core implementation libs.jackson.databind implementation libs.caffeine + implementation libs.opentelemetry.httpclient implementation libs.roaringbitmap implementation libs.failsafe compileOnly(libs.hadoop3.client) { diff --git a/core/src/main/java/org/apache/iceberg/rest/HTTPClient.java b/core/src/main/java/org/apache/iceberg/rest/HTTPClient.java index b30caf1c7db0..7d6171ec045a 100644 --- a/core/src/main/java/org/apache/iceberg/rest/HTTPClient.java +++ b/core/src/main/java/org/apache/iceberg/rest/HTTPClient.java @@ -21,6 +21,8 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectReader; +import io.opentelemetry.api.OpenTelemetry; +import io.opentelemetry.instrumentation.apachehttpclient.v5_2.ApacheHttpClientTelemetry; import java.io.IOException; import java.io.UncheckedIOException; import java.net.URI; @@ -113,13 +115,17 @@ private HTTPClient( ObjectMapper objectMapper, Map properties, HttpClientConnectionManager connectionManager, - AuthSession session) { + AuthSession session, + OpenTelemetry openTelemetry) { this.baseUri = baseUri; this.baseHeaders = baseHeaders; this.mapper = objectMapper; this.authSession = session; - HttpClientBuilder clientBuilder = HttpClients.custom(); + HttpClientBuilder clientBuilder = + openTelemetry != null + ? ApacheHttpClientTelemetry.builder(openTelemetry).build().newHttpClientBuilder() + : HttpClients.custom(); clientBuilder.setConnectionManager(connectionManager); @@ -482,6 +488,7 @@ public static class Builder { private HttpHost proxy; private CredentialsProvider proxyCredentialsProvider; private AuthSession authSession; + private OpenTelemetry telemetry; private Builder(Map properties) { this.properties = properties; @@ -536,6 +543,12 @@ public Builder withAuthSession(AuthSession session) { return this; } + public Builder withOpenTelemetry(OpenTelemetry openTelemetry) { + Preconditions.checkNotNull(openTelemetry, "Invalid openTelemetry for http client: null"); + this.telemetry = openTelemetry; + return this; + } + public HTTPClient build() { withHeader(CLIENT_VERSION_HEADER, IcebergBuild.fullVersion()); withHeader(CLIENT_GIT_COMMIT_SHORT_HEADER, IcebergBuild.gitCommitShortId()); @@ -579,7 +592,8 @@ public HTTPClient build() { mapper, properties, configureConnectionManager(properties), - authSession); + authSession, + telemetry); } } } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index e9e74643d977..e3d74b807226 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -78,6 +78,7 @@ mockserver = "5.15.0" nessie = "0.106.1" netty-buffer = "4.2.9.Final" object-client-bundle = "3.3.2" +opentelemetry-httpclient = "2.23.0-alpha" orc = "1.9.8" parquet = "1.17.0" roaringbitmap = "1.3.0" @@ -166,6 +167,7 @@ microprofile-openapi-api = { module = "org.eclipse.microprofile.openapi:micropro nessie-client = { module = "org.projectnessie.nessie:nessie-client", version.ref = "nessie" } netty-buffer = { module = "io.netty:netty-buffer", version.ref = "netty-buffer" } object-client-bundle = { module = "com.emc.ecs:object-client-bundle", version.ref = "object-client-bundle" } +opentelemetry-httpclient = { module = "io.opentelemetry.instrumentation:opentelemetry-apache-httpclient-5.2", version.ref = "opentelemetry-httpclient" } orc-core = { module = "org.apache.orc:orc-core", version.ref = "orc" } parquet-avro = { module = "org.apache.parquet:parquet-avro", version.ref = "parquet" } parquet-column = { module = "org.apache.parquet:parquet-column", version.ref = "parquet" }