diff --git a/build.gradle b/build.gradle index 4cf6cf2ad9d7..57a1d96fa6e9 100644 --- a/build.gradle +++ b/build.gradle @@ -378,6 +378,7 @@ project(':iceberg-core') { implementation libs.jackson.core implementation libs.jackson.databind implementation libs.caffeine + implementation libs.opentelemetry.httpclient implementation libs.roaringbitmap compileOnly(libs.hadoop3.client) { exclude group: 'org.apache.avro', module: 'avro' 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 86eceba21c95..134b0e6ce717 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); @@ -493,6 +499,7 @@ public static class Builder { private HttpHost proxy; private CredentialsProvider proxyCredentialsProvider; private AuthSession authSession; + private OpenTelemetry telemetry; private Builder(Map properties) { this.properties = properties; @@ -547,6 +554,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()); @@ -590,7 +603,8 @@ public HTTPClient build() { mapper, properties, configureConnectionManager(properties), - authSession); + authSession, + telemetry); } } } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 8395a3d6a26c..612ab5d8e6e2 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -78,6 +78,7 @@ mockserver = "5.15.0" nessie = "0.107.4" netty-buffer = "4.2.10.Final" object-client-bundle = "3.3.2" +opentelemetry-httpclient = "2.23.0-alpha" orc = "1.9.8" parquet = "1.17.0" roaringbitmap = "1.6.13" @@ -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" }