Selaa lähdekoodia

Add library instrumentation for elasticsearch rest client 7 (#8911)

Co-authored-by: Trask Stalnaker <trask.stalnaker@gmail.com>
Lauri Tulmin 1 vuosi sitten
vanhempi
säilyke
fbae980fc5
31 muutettua tiedostoa jossa 642 lisäystä ja 50 poistoa
  1. 1 0
      instrumentation/elasticsearch/elasticsearch-api-client-7.16/javaagent-unit-tests/src/test/java/io/opentelemetry/javaagent/instrumentation/elasticsearch/rest/ElasticsearchEndpointMapTest.java
  2. 1 1
      instrumentation/elasticsearch/elasticsearch-api-client-7.16/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/elasticsearch/apiclient/ElasticsearchEndpointMap.java
  3. 1 1
      instrumentation/elasticsearch/elasticsearch-api-client-7.16/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/elasticsearch/apiclient/RestClientHttpClientInstrumentation.java
  4. 1 1
      instrumentation/elasticsearch/elasticsearch-api-client-7.16/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/elasticsearch/apiclient/RestClientTransportInstrumentation.java
  5. 2 0
      instrumentation/elasticsearch/elasticsearch-api-client-7.16/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/elasticsearch/apiclient/ElasticsearchClientTest.java
  6. 4 3
      instrumentation/elasticsearch/elasticsearch-rest-5.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/elasticsearch/rest/v5_0/ElasticsearchRest5Singletons.java
  7. 2 2
      instrumentation/elasticsearch/elasticsearch-rest-5.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/elasticsearch/rest/v5_0/RestClientInstrumentation.java
  8. 2 0
      instrumentation/elasticsearch/elasticsearch-rest-5.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/elasticsearch/rest/v5_0/ElasticsearchRest5Test.java
  9. 4 3
      instrumentation/elasticsearch/elasticsearch-rest-6.4/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/elasticsearch/rest/v6_4/ElasticsearchRest6Singletons.java
  10. 2 2
      instrumentation/elasticsearch/elasticsearch-rest-6.4/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/elasticsearch/rest/v6_4/RestClientInstrumentation.java
  11. 2 0
      instrumentation/elasticsearch/elasticsearch-rest-6.4/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/elasticsearch/rest/v6_4/ElasticsearchRest6Test.java
  12. 0 3
      instrumentation/elasticsearch/elasticsearch-rest-7.0/javaagent/build.gradle.kts
  13. 4 3
      instrumentation/elasticsearch/elasticsearch-rest-7.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/elasticsearch/rest/v7_0/ElasticsearchRest7Singletons.java
  14. 5 3
      instrumentation/elasticsearch/elasticsearch-rest-7.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/elasticsearch/rest/v7_0/RestClientInstrumentation.java
  15. 2 0
      instrumentation/elasticsearch/elasticsearch-rest-7.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/elasticsearch/rest/v7_0/ElasticsearchRest7Test.java
  16. 18 0
      instrumentation/elasticsearch/elasticsearch-rest-7.0/library/build.gradle.kts
  17. 46 0
      instrumentation/elasticsearch/elasticsearch-rest-7.0/library/src/main/java/io/opentelemetry/instrumentation/elasticsearch/rest/v7_0/ElasticsearchRest7Telemetry.java
  18. 52 0
      instrumentation/elasticsearch/elasticsearch-rest-7.0/library/src/main/java/io/opentelemetry/instrumentation/elasticsearch/rest/v7_0/ElasticsearchRest7TelemetryBuilder.java
  19. 198 0
      instrumentation/elasticsearch/elasticsearch-rest-7.0/library/src/main/java/io/opentelemetry/instrumentation/elasticsearch/rest/v7_0/RestClientWrapper.java
  20. 179 0
      instrumentation/elasticsearch/elasticsearch-rest-7.0/library/src/test/java/io/opentelemetry/instrumentation/elasticsearch/rest/v7_0/ElasticsearchRest7Test.java
  21. 1 2
      instrumentation/elasticsearch/elasticsearch-rest-common/javaagent/build.gradle.kts
  22. 32 0
      instrumentation/elasticsearch/elasticsearch-rest-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/elasticsearch/rest/ElasticsearchRestJavaagentInstrumenterFactory.java
  23. 10 0
      instrumentation/elasticsearch/elasticsearch-rest-common/library/build.gradle.kts
  24. 5 1
      instrumentation/elasticsearch/elasticsearch-rest-common/library/src/main/java/io/opentelemetry/instrumentation/elasticsearch/rest/internal/ElasticsearchClientAttributeExtractor.java
  25. 12 7
      instrumentation/elasticsearch/elasticsearch-rest-common/library/src/main/java/io/opentelemetry/instrumentation/elasticsearch/rest/internal/ElasticsearchDbAttributesGetter.java
  26. 20 6
      instrumentation/elasticsearch/elasticsearch-rest-common/library/src/main/java/io/opentelemetry/instrumentation/elasticsearch/rest/internal/ElasticsearchEndpointDefinition.java
  27. 15 5
      instrumentation/elasticsearch/elasticsearch-rest-common/library/src/main/java/io/opentelemetry/instrumentation/elasticsearch/rest/internal/ElasticsearchRestInstrumenterFactory.java
  28. 5 1
      instrumentation/elasticsearch/elasticsearch-rest-common/library/src/main/java/io/opentelemetry/instrumentation/elasticsearch/rest/internal/ElasticsearchRestRequest.java
  29. 5 1
      instrumentation/elasticsearch/elasticsearch-rest-common/library/src/main/java/io/opentelemetry/instrumentation/elasticsearch/rest/internal/ElasticsearchSpanNameExtractor.java
  30. 5 1
      instrumentation/elasticsearch/elasticsearch-rest-common/library/src/main/java/io/opentelemetry/instrumentation/elasticsearch/rest/internal/RestResponseListener.java
  31. 6 4
      settings.gradle.kts

+ 1 - 0
instrumentation/elasticsearch/elasticsearch-api-client-7.16/javaagent-unit-tests/src/test/java/io/opentelemetry/javaagent/instrumentation/elasticsearch/rest/ElasticsearchEndpointMapTest.java

@@ -7,6 +7,7 @@ package io.opentelemetry.javaagent.instrumentation.elasticsearch.rest;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
 
+import io.opentelemetry.instrumentation.elasticsearch.rest.internal.ElasticsearchEndpointDefinition;
 import io.opentelemetry.javaagent.instrumentation.elasticsearch.apiclient.ElasticsearchEndpointMap;
 import java.util.ArrayList;
 import java.util.Arrays;

+ 1 - 1
instrumentation/elasticsearch/elasticsearch-api-client-7.16/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/elasticsearch/apiclient/ElasticsearchEndpointMap.java

@@ -5,7 +5,7 @@
 
 package io.opentelemetry.javaagent.instrumentation.elasticsearch.apiclient;
 
-import io.opentelemetry.javaagent.instrumentation.elasticsearch.rest.ElasticsearchEndpointDefinition;
+import io.opentelemetry.instrumentation.elasticsearch.rest.internal.ElasticsearchEndpointDefinition;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;

+ 1 - 1
instrumentation/elasticsearch/elasticsearch-api-client-7.16/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/elasticsearch/apiclient/RestClientHttpClientInstrumentation.java

@@ -14,9 +14,9 @@ import static net.bytebuddy.matcher.ElementMatchers.takesArgument;
 import io.opentelemetry.context.Context;
 import io.opentelemetry.context.Scope;
 import io.opentelemetry.instrumentation.api.util.VirtualField;
+import io.opentelemetry.instrumentation.elasticsearch.rest.internal.ElasticsearchEndpointDefinition;
 import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
 import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
-import io.opentelemetry.javaagent.instrumentation.elasticsearch.rest.ElasticsearchEndpointDefinition;
 import net.bytebuddy.asm.Advice;
 import net.bytebuddy.description.type.TypeDescription;
 import net.bytebuddy.matcher.ElementMatcher;

+ 1 - 1
instrumentation/elasticsearch/elasticsearch-api-client-7.16/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/elasticsearch/apiclient/RestClientTransportInstrumentation.java

@@ -12,9 +12,9 @@ import static net.bytebuddy.matcher.ElementMatchers.takesArgument;
 
 import co.elastic.clients.transport.Endpoint;
 import io.opentelemetry.instrumentation.api.util.VirtualField;
+import io.opentelemetry.instrumentation.elasticsearch.rest.internal.ElasticsearchEndpointDefinition;
 import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
 import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
-import io.opentelemetry.javaagent.instrumentation.elasticsearch.rest.ElasticsearchEndpointDefinition;
 import net.bytebuddy.asm.Advice;
 import net.bytebuddy.description.type.TypeDescription;
 import net.bytebuddy.matcher.ElementMatcher;

+ 2 - 0
instrumentation/elasticsearch/elasticsearch-api-client-7.16/javaagent/src/test/java/ElasticsearchClientTest.java → instrumentation/elasticsearch/elasticsearch-api-client-7.16/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/elasticsearch/apiclient/ElasticsearchClientTest.java

@@ -3,6 +3,8 @@
  * SPDX-License-Identifier: Apache-2.0
  */
 
+package io.opentelemetry.javaagent.instrumentation.elasticsearch.apiclient;
+
 import static io.opentelemetry.instrumentation.testing.GlobalTraceUtil.runWithSpan;
 import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.equalTo;
 import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.satisfies;

+ 4 - 3
instrumentation/elasticsearch/elasticsearch-rest-5.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/elasticsearch/rest/v5_0/ElasticsearchRest5Singletons.java

@@ -6,14 +6,15 @@
 package io.opentelemetry.javaagent.instrumentation.elasticsearch.rest.v5_0;
 
 import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
-import io.opentelemetry.javaagent.instrumentation.elasticsearch.rest.ElasticsearchRestInstrumenterFactory;
-import io.opentelemetry.javaagent.instrumentation.elasticsearch.rest.ElasticsearchRestRequest;
+import io.opentelemetry.instrumentation.elasticsearch.rest.internal.ElasticsearchRestRequest;
+import io.opentelemetry.javaagent.instrumentation.elasticsearch.rest.ElasticsearchRestJavaagentInstrumenterFactory;
 import org.elasticsearch.client.Response;
 
 public final class ElasticsearchRest5Singletons {
 
   private static final Instrumenter<ElasticsearchRestRequest, Response> INSTRUMENTER =
-      ElasticsearchRestInstrumenterFactory.create("io.opentelemetry.elasticsearch-rest-5.0");
+      ElasticsearchRestJavaagentInstrumenterFactory.create(
+          "io.opentelemetry.elasticsearch-rest-5.0");
 
   public static Instrumenter<ElasticsearchRestRequest, Response> instrumenter() {
     return INSTRUMENTER;

+ 2 - 2
instrumentation/elasticsearch/elasticsearch-rest-5.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/elasticsearch/rest/v5_0/RestClientInstrumentation.java

@@ -15,10 +15,10 @@ import static net.bytebuddy.matcher.ElementMatchers.takesArguments;
 
 import io.opentelemetry.context.Context;
 import io.opentelemetry.context.Scope;
+import io.opentelemetry.instrumentation.elasticsearch.rest.internal.ElasticsearchRestRequest;
+import io.opentelemetry.instrumentation.elasticsearch.rest.internal.RestResponseListener;
 import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
 import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
-import io.opentelemetry.javaagent.instrumentation.elasticsearch.rest.ElasticsearchRestRequest;
-import io.opentelemetry.javaagent.instrumentation.elasticsearch.rest.RestResponseListener;
 import net.bytebuddy.asm.Advice;
 import net.bytebuddy.description.type.TypeDescription;
 import net.bytebuddy.matcher.ElementMatcher;

+ 2 - 0
instrumentation/elasticsearch/elasticsearch-rest-5.0/javaagent/src/test/java/ElasticsearchRest5Test.java → instrumentation/elasticsearch/elasticsearch-rest-5.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/elasticsearch/rest/v5_0/ElasticsearchRest5Test.java

@@ -3,6 +3,8 @@
  * SPDX-License-Identifier: Apache-2.0
  */
 
+package io.opentelemetry.javaagent.instrumentation.elasticsearch.rest.v5_0;
+
 import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.equalTo;
 
 import com.fasterxml.jackson.databind.ObjectMapper;

+ 4 - 3
instrumentation/elasticsearch/elasticsearch-rest-6.4/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/elasticsearch/rest/v6_4/ElasticsearchRest6Singletons.java

@@ -6,14 +6,15 @@
 package io.opentelemetry.javaagent.instrumentation.elasticsearch.rest.v6_4;
 
 import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
-import io.opentelemetry.javaagent.instrumentation.elasticsearch.rest.ElasticsearchRestInstrumenterFactory;
-import io.opentelemetry.javaagent.instrumentation.elasticsearch.rest.ElasticsearchRestRequest;
+import io.opentelemetry.instrumentation.elasticsearch.rest.internal.ElasticsearchRestRequest;
+import io.opentelemetry.javaagent.instrumentation.elasticsearch.rest.ElasticsearchRestJavaagentInstrumenterFactory;
 import org.elasticsearch.client.Response;
 
 public final class ElasticsearchRest6Singletons {
 
   private static final Instrumenter<ElasticsearchRestRequest, Response> INSTRUMENTER =
-      ElasticsearchRestInstrumenterFactory.create("io.opentelemetry.elasticsearch-rest-6.4");
+      ElasticsearchRestJavaagentInstrumenterFactory.create(
+          "io.opentelemetry.elasticsearch-rest-6.4");
 
   public static Instrumenter<ElasticsearchRestRequest, Response> instrumenter() {
     return INSTRUMENTER;

+ 2 - 2
instrumentation/elasticsearch/elasticsearch-rest-6.4/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/elasticsearch/rest/v6_4/RestClientInstrumentation.java

@@ -14,10 +14,10 @@ import static net.bytebuddy.matcher.ElementMatchers.takesArguments;
 
 import io.opentelemetry.context.Context;
 import io.opentelemetry.context.Scope;
+import io.opentelemetry.instrumentation.elasticsearch.rest.internal.ElasticsearchRestRequest;
+import io.opentelemetry.instrumentation.elasticsearch.rest.internal.RestResponseListener;
 import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
 import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
-import io.opentelemetry.javaagent.instrumentation.elasticsearch.rest.ElasticsearchRestRequest;
-import io.opentelemetry.javaagent.instrumentation.elasticsearch.rest.RestResponseListener;
 import net.bytebuddy.asm.Advice;
 import net.bytebuddy.description.type.TypeDescription;
 import net.bytebuddy.matcher.ElementMatcher;

+ 2 - 0
instrumentation/elasticsearch/elasticsearch-rest-6.4/javaagent/src/test/java/ElasticsearchRest6Test.java → instrumentation/elasticsearch/elasticsearch-rest-6.4/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/elasticsearch/rest/v6_4/ElasticsearchRest6Test.java

@@ -3,6 +3,8 @@
  * SPDX-License-Identifier: Apache-2.0
  */
 
+package io.opentelemetry.javaagent.instrumentation.elasticsearch.rest.v6_4;
+
 import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.equalTo;
 
 import com.fasterxml.jackson.databind.ObjectMapper;

+ 0 - 3
instrumentation/elasticsearch/elasticsearch-rest-7.0/javaagent/build.gradle.kts

@@ -28,10 +28,7 @@ dependencies {
   // Netty is used, but it adds complexity to the tests since we're using embedded ES.
   // testInstrumentation(project(":instrumentation:netty:netty-4.1:javaagent"))
 
-  testImplementation("org.apache.logging.log4j:log4j-core:2.11.0")
-  testImplementation("org.apache.logging.log4j:log4j-api:2.11.0")
   testImplementation("com.fasterxml.jackson.core:jackson-databind")
-
   testImplementation("org.testcontainers:elasticsearch")
 }
 

+ 4 - 3
instrumentation/elasticsearch/elasticsearch-rest-7.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/elasticsearch/rest/v7_0/ElasticsearchRest7Singletons.java

@@ -6,14 +6,15 @@
 package io.opentelemetry.javaagent.instrumentation.elasticsearch.rest.v7_0;
 
 import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
-import io.opentelemetry.javaagent.instrumentation.elasticsearch.rest.ElasticsearchRestInstrumenterFactory;
-import io.opentelemetry.javaagent.instrumentation.elasticsearch.rest.ElasticsearchRestRequest;
+import io.opentelemetry.instrumentation.elasticsearch.rest.internal.ElasticsearchRestRequest;
+import io.opentelemetry.javaagent.instrumentation.elasticsearch.rest.ElasticsearchRestJavaagentInstrumenterFactory;
 import org.elasticsearch.client.Response;
 
 public final class ElasticsearchRest7Singletons {
 
   private static final Instrumenter<ElasticsearchRestRequest, Response> INSTRUMENTER =
-      ElasticsearchRestInstrumenterFactory.create("io.opentelemetry.elasticsearch-rest-7.0");
+      ElasticsearchRestJavaagentInstrumenterFactory.create(
+          "io.opentelemetry.elasticsearch-rest-7.0");
 
   public static Instrumenter<ElasticsearchRestRequest, Response> instrumenter() {
     return INSTRUMENTER;

+ 5 - 3
instrumentation/elasticsearch/elasticsearch-rest-7.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/elasticsearch/rest/v7_0/RestClientInstrumentation.java

@@ -15,11 +15,11 @@ import static net.bytebuddy.matcher.ElementMatchers.takesArguments;
 import io.opentelemetry.context.Context;
 import io.opentelemetry.context.Scope;
 import io.opentelemetry.instrumentation.api.util.VirtualField;
+import io.opentelemetry.instrumentation.elasticsearch.rest.internal.ElasticsearchEndpointDefinition;
+import io.opentelemetry.instrumentation.elasticsearch.rest.internal.ElasticsearchRestRequest;
+import io.opentelemetry.instrumentation.elasticsearch.rest.internal.RestResponseListener;
 import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
 import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
-import io.opentelemetry.javaagent.instrumentation.elasticsearch.rest.ElasticsearchEndpointDefinition;
-import io.opentelemetry.javaagent.instrumentation.elasticsearch.rest.ElasticsearchRestRequest;
-import io.opentelemetry.javaagent.instrumentation.elasticsearch.rest.RestResponseListener;
 import net.bytebuddy.asm.Advice;
 import net.bytebuddy.description.type.TypeDescription;
 import net.bytebuddy.matcher.ElementMatcher;
@@ -67,6 +67,7 @@ public class RestClientInstrumentation implements TypeInstrumentation {
           ElasticsearchRestRequest.create(
               request.getMethod(),
               request.getEndpoint(),
+              // set by elasticsearch-api-client instrumentation
               virtualField.get(request),
               request.getEntity());
       if (!instrumenter().shouldStart(parentContext, otelRequest)) {
@@ -113,6 +114,7 @@ public class RestClientInstrumentation implements TypeInstrumentation {
           ElasticsearchRestRequest.create(
               request.getMethod(),
               request.getEndpoint(),
+              // set by elasticsearch-api-client instrumentation
               virtualField.get(request),
               request.getEntity());
       if (!instrumenter().shouldStart(parentContext, otelRequest)) {

+ 2 - 0
instrumentation/elasticsearch/elasticsearch-rest-7.0/javaagent/src/test/java/ElasticsearchRest7Test.java → instrumentation/elasticsearch/elasticsearch-rest-7.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/elasticsearch/rest/v7_0/ElasticsearchRest7Test.java

@@ -3,6 +3,8 @@
  * SPDX-License-Identifier: Apache-2.0
  */
 
+package io.opentelemetry.javaagent.instrumentation.elasticsearch.rest.v7_0;
+
 import static io.opentelemetry.instrumentation.testing.GlobalTraceUtil.runWithSpan;
 import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.equalTo;
 import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.satisfies;

+ 18 - 0
instrumentation/elasticsearch/elasticsearch-rest-7.0/library/build.gradle.kts

@@ -0,0 +1,18 @@
+plugins {
+  id("otel.library-instrumentation")
+}
+
+dependencies {
+  library("org.elasticsearch.client:elasticsearch-rest-client:7.0.0")
+  implementation("net.bytebuddy:byte-buddy")
+  implementation(project(":instrumentation:elasticsearch:elasticsearch-rest-common:library"))
+
+  testImplementation("com.fasterxml.jackson.core:jackson-databind")
+  testImplementation("org.testcontainers:elasticsearch")
+}
+
+tasks {
+  test {
+    usesService(gradle.sharedServices.registrations["testcontainersBuildService"].service)
+  }
+}

+ 46 - 0
instrumentation/elasticsearch/elasticsearch-rest-7.0/library/src/main/java/io/opentelemetry/instrumentation/elasticsearch/rest/v7_0/ElasticsearchRest7Telemetry.java

@@ -0,0 +1,46 @@
+/*
+ * Copyright The OpenTelemetry Authors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package io.opentelemetry.instrumentation.elasticsearch.rest.v7_0;
+
+import io.opentelemetry.api.OpenTelemetry;
+import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
+import io.opentelemetry.instrumentation.elasticsearch.rest.internal.ElasticsearchRestRequest;
+import org.elasticsearch.client.Response;
+import org.elasticsearch.client.RestClient;
+
+/** Entrypoint for instrumenting Apache Elasticsearch Rest clients. */
+public final class ElasticsearchRest7Telemetry {
+
+  /**
+   * Returns a new {@link ElasticsearchRest7Telemetry} configured with the given {@link
+   * OpenTelemetry}.
+   */
+  public static ElasticsearchRest7Telemetry create(OpenTelemetry openTelemetry) {
+    return builder(openTelemetry).build();
+  }
+
+  /**
+   * Returns a new {@link ElasticsearchRest7TelemetryBuilder} configured with the given {@link
+   * OpenTelemetry}.
+   */
+  public static ElasticsearchRest7TelemetryBuilder builder(OpenTelemetry openTelemetry) {
+    return new ElasticsearchRest7TelemetryBuilder(openTelemetry);
+  }
+
+  private final Instrumenter<ElasticsearchRestRequest, Response> instrumenter;
+
+  ElasticsearchRest7Telemetry(Instrumenter<ElasticsearchRestRequest, Response> instrumenter) {
+    this.instrumenter = instrumenter;
+  }
+
+  /**
+   * Construct a new tracing-enable {@link RestClient} using the provided {@link RestClient}
+   * instance.
+   */
+  public RestClient wrap(RestClient restClient) {
+    return RestClientWrapper.wrap(restClient, instrumenter);
+  }
+}

+ 52 - 0
instrumentation/elasticsearch/elasticsearch-rest-7.0/library/src/main/java/io/opentelemetry/instrumentation/elasticsearch/rest/v7_0/ElasticsearchRest7TelemetryBuilder.java

@@ -0,0 +1,52 @@
+/*
+ * Copyright The OpenTelemetry Authors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package io.opentelemetry.instrumentation.elasticsearch.rest.v7_0;
+
+import com.google.errorprone.annotations.CanIgnoreReturnValue;
+import io.opentelemetry.api.OpenTelemetry;
+import io.opentelemetry.instrumentation.api.instrumenter.AttributesExtractor;
+import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
+import io.opentelemetry.instrumentation.elasticsearch.rest.internal.ElasticsearchRestInstrumenterFactory;
+import io.opentelemetry.instrumentation.elasticsearch.rest.internal.ElasticsearchRestRequest;
+import java.util.ArrayList;
+import java.util.List;
+import org.elasticsearch.client.Response;
+
+public final class ElasticsearchRest7TelemetryBuilder {
+
+  private static final String INSTRUMENTATION_NAME = "io.opentelemetry.elasticsearch-rest-7.0";
+
+  private final OpenTelemetry openTelemetry;
+  private final List<AttributesExtractor<ElasticsearchRestRequest, Response>> attributesExtractors =
+      new ArrayList<>();
+
+  ElasticsearchRest7TelemetryBuilder(OpenTelemetry openTelemetry) {
+    this.openTelemetry = openTelemetry;
+  }
+
+  /**
+   * Adds an additional {@link AttributesExtractor} to invoke to set attributes to instrumented
+   * items.
+   */
+  @CanIgnoreReturnValue
+  public ElasticsearchRest7TelemetryBuilder addAttributesExtractor(
+      AttributesExtractor<ElasticsearchRestRequest, Response> attributesExtractor) {
+    attributesExtractors.add(attributesExtractor);
+    return this;
+  }
+
+  /**
+   * Returns a new {@link ElasticsearchRest7Telemetry} with the settings of this {@link
+   * ElasticsearchRest7TelemetryBuilder}.
+   */
+  public ElasticsearchRest7Telemetry build() {
+    Instrumenter<ElasticsearchRestRequest, Response> instrumenter =
+        ElasticsearchRestInstrumenterFactory.create(
+            openTelemetry, INSTRUMENTATION_NAME, attributesExtractors, false);
+
+    return new ElasticsearchRest7Telemetry(instrumenter);
+  }
+}

+ 198 - 0
instrumentation/elasticsearch/elasticsearch-rest-7.0/library/src/main/java/io/opentelemetry/instrumentation/elasticsearch/rest/v7_0/RestClientWrapper.java

@@ -0,0 +1,198 @@
+/*
+ * Copyright The OpenTelemetry Authors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package io.opentelemetry.instrumentation.elasticsearch.rest.v7_0;
+
+import io.opentelemetry.context.Context;
+import io.opentelemetry.context.Scope;
+import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
+import io.opentelemetry.instrumentation.elasticsearch.rest.internal.ElasticsearchRestRequest;
+import io.opentelemetry.instrumentation.elasticsearch.rest.internal.RestResponseListener;
+import java.lang.reflect.Array;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.util.List;
+import java.util.function.Function;
+import java.util.function.Supplier;
+import net.bytebuddy.ByteBuddy;
+import net.bytebuddy.description.modifier.Visibility;
+import net.bytebuddy.dynamic.loading.ClassLoadingStrategy;
+import net.bytebuddy.implementation.InvocationHandlerAdapter;
+import net.bytebuddy.matcher.ElementMatchers;
+import org.apache.http.Header;
+import org.elasticsearch.client.Node;
+import org.elasticsearch.client.Request;
+import org.elasticsearch.client.Response;
+import org.elasticsearch.client.ResponseListener;
+import org.elasticsearch.client.RestClient;
+
+class RestClientWrapper {
+  private static final Class<?> proxyClass = createProxyClass();
+  private static final Field targetField = getTargetField(proxyClass);
+  private static final Field instrumenterSupplierField = getInstrumenterSupplierField(proxyClass);
+  private static final Function<RestClient, RestClient> proxyFactory = getProxyFactory(proxyClass);
+
+  private static Class<?> createProxyClass() {
+    return new ByteBuddy()
+        .subclass(RestClient.class)
+        .defineField("target", RestClient.class, Visibility.PUBLIC)
+        // using Supplier instead of Instrumenter in case RestClientWrapper and opentelemetry apis
+        // are in a child class loader of RestClient's class loader and Instrumenter is not visible
+        // for RestClient
+        .defineField("instrumenterSupplier", Supplier.class, Visibility.PUBLIC)
+        .method(ElementMatchers.any())
+        .intercept(
+            InvocationHandlerAdapter.of(
+                (proxy, method, args) -> {
+                  RestClient target = (RestClient) targetField.get(proxy);
+                  Instrumenter<ElasticsearchRestRequest, Response> instrumenter =
+                      getInstrumenter(proxy);
+                  // target is null when running proxy constructor
+                  if (target == null || instrumenter == null) {
+                    return null;
+                  }
+
+                  // instrument performRequest and performRequestAsync methods
+                  if ("performRequest".equals(method.getName())
+                      && args.length == 1
+                      && args[0] instanceof Request
+                      && Response.class == method.getReturnType()) {
+                    Request request = (Request) args[0];
+                    Context parentContext = Context.current();
+                    ElasticsearchRestRequest otelRequest =
+                        ElasticsearchRestRequest.create(request.getMethod(), request.getEndpoint());
+                    if (!instrumenter.shouldStart(parentContext, otelRequest)) {
+                      return method.invoke(target, args);
+                    }
+
+                    Response response = null;
+                    Throwable throwable = null;
+                    Context context = instrumenter.start(parentContext, otelRequest);
+                    try (Scope scope = context.makeCurrent()) {
+                      response = (Response) method.invoke(target, args);
+                    } catch (Throwable exception) {
+                      throwable = exception;
+                    } finally {
+                      instrumenter.end(context, otelRequest, response, throwable);
+                    }
+
+                    return response;
+                  } else if ("performRequestAsync".equals(method.getName())
+                      && args.length == 2
+                      && args[0] instanceof Request
+                      && args[1] instanceof ResponseListener) {
+
+                    Request request = (Request) args[0];
+                    ResponseListener responseListener = (ResponseListener) args[1];
+                    Context parentContext = Context.current();
+                    ElasticsearchRestRequest otelRequest =
+                        ElasticsearchRestRequest.create(request.getMethod(), request.getEndpoint());
+                    if (!instrumenter.shouldStart(parentContext, otelRequest)) {
+                      return method.invoke(target, args);
+                    }
+
+                    Throwable throwable = null;
+                    Context context = instrumenter.start(parentContext, otelRequest);
+                    args[1] =
+                        new RestResponseListener(
+                            responseListener, parentContext, instrumenter, context, otelRequest);
+                    try (Scope scope = context.makeCurrent()) {
+                      return method.invoke(target, args);
+                    } catch (Throwable exception) {
+                      throwable = exception;
+                    } finally {
+                      if (throwable != null) {
+                        instrumenter.end(context, otelRequest, null, throwable);
+                      }
+                      // span ended in RestResponseListener
+                    }
+                  }
+
+                  // delegate to wrapped RestClient
+                  return method.invoke(target, args);
+                }))
+        .make()
+        .load(RestClient.class.getClassLoader(), ClassLoadingStrategy.Default.INJECTION)
+        .getLoaded();
+  }
+
+  private static Field getTargetField(Class<?> clazz) {
+    return getProxyField(clazz, "target");
+  }
+
+  private static Field getInstrumenterSupplierField(Class<?> clazz) {
+    return getProxyField(clazz, "instrumenterSupplier");
+  }
+
+  private static Field getProxyField(Class<?> clazz, String fieldName) {
+    try {
+      return clazz.getDeclaredField(fieldName);
+    } catch (NoSuchFieldException exception) {
+      throw new IllegalStateException("Could not find proxy field", exception);
+    }
+  }
+
+  @SuppressWarnings("unchecked")
+  private static Instrumenter<ElasticsearchRestRequest, Response> getInstrumenter(Object proxy)
+      throws IllegalAccessException {
+    Supplier<Instrumenter<ElasticsearchRestRequest, Response>> supplier =
+        (Supplier<Instrumenter<ElasticsearchRestRequest, Response>>)
+            instrumenterSupplierField.get(proxy);
+    return supplier != null ? supplier.get() : null;
+  }
+
+  private static Function<RestClient, RestClient> getProxyFactory(Class<?> clazz) {
+    for (Constructor<?> constructor : clazz.getDeclaredConstructors()) {
+      Class<?>[] parameterTypes = constructor.getParameterTypes();
+      if (parameterTypes.length >= 3
+          && !parameterTypes[0].isPrimitive()
+          && parameterTypes[1] == Header[].class
+          && parameterTypes[2] == List.class) {
+        return restClient -> {
+          List<Node> nodes = restClient.getNodes();
+          // all the proxy methods will delegate to the wrapped RestClient, we need to fill only the
+          // arguments that are required by the constructor
+          Object[] arguments = new Object[parameterTypes.length];
+          arguments[1] = new Header[0];
+          arguments[2] = nodes;
+          for (int i = 3; i < parameterTypes.length; i++) {
+            if (parameterTypes[i].isPrimitive()) {
+              arguments[i] = getDefaultValue(parameterTypes[i]);
+            }
+          }
+          try {
+            return (RestClient) constructor.newInstance(arguments);
+          } catch (Exception exception) {
+            throw new IllegalStateException("Failed to construct proxy instance", exception);
+          }
+        };
+      }
+    }
+    throw new IllegalStateException("Failed to find suitable constructor");
+  }
+
+  // create a single element array of given type, this method is used to get the default value of
+  // a primitive type
+  @SuppressWarnings("unchecked")
+  private static <T> T getDefaultValue(Class<T> clazz) {
+    return (T) Array.get(Array.newInstance(clazz, 1), 0);
+  }
+
+  static RestClient wrap(
+      RestClient restClient, Instrumenter<ElasticsearchRestRequest, Response> instrumenter) {
+    RestClient wrapped = proxyFactory.apply(restClient);
+    try {
+      // set wrapped RestClient instance and the instrumenter on the proxy
+      targetField.set(wrapped, restClient);
+      instrumenterSupplierField.set(
+          wrapped, (Supplier<Instrumenter<ElasticsearchRestRequest, Response>>) () -> instrumenter);
+      return wrapped;
+    } catch (Exception exception) {
+      throw new IllegalStateException("Failed to construct proxy instance", exception);
+    }
+  }
+
+  private RestClientWrapper() {}
+}

+ 179 - 0
instrumentation/elasticsearch/elasticsearch-rest-7.0/library/src/test/java/io/opentelemetry/instrumentation/elasticsearch/rest/v7_0/ElasticsearchRest7Test.java

@@ -0,0 +1,179 @@
+/*
+ * Copyright The OpenTelemetry Authors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package io.opentelemetry.instrumentation.elasticsearch.rest.v7_0;
+
+import static io.opentelemetry.instrumentation.testing.GlobalTraceUtil.runWithSpan;
+import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.equalTo;
+
+import io.opentelemetry.api.trace.SpanKind;
+import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension;
+import io.opentelemetry.instrumentation.testing.junit.LibraryInstrumentationExtension;
+import io.opentelemetry.semconv.trace.attributes.SemanticAttributes;
+import java.util.Map;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import org.apache.http.HttpHost;
+import org.elasticsearch.client.Request;
+import org.elasticsearch.client.Response;
+import org.elasticsearch.client.ResponseListener;
+import org.elasticsearch.client.RestClient;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
+import org.testcontainers.elasticsearch.ElasticsearchContainer;
+import org.testcontainers.shaded.com.fasterxml.jackson.databind.ObjectMapper;
+
+class ElasticsearchRest7Test {
+  @RegisterExtension
+  static final InstrumentationExtension testing = LibraryInstrumentationExtension.create();
+
+  static ElasticsearchContainer elasticsearch;
+
+  static HttpHost httpHost;
+
+  static RestClient client;
+
+  static ObjectMapper objectMapper;
+
+  @BeforeAll
+  static void setUp() {
+    elasticsearch =
+        new ElasticsearchContainer("docker.elastic.co/elasticsearch/elasticsearch-oss:7.10.2");
+    // limit memory usage
+    elasticsearch.withEnv("ES_JAVA_OPTS", "-Xmx256m -Xms256m");
+    elasticsearch.start();
+
+    httpHost = HttpHost.create(elasticsearch.getHttpHostAddress());
+
+    client =
+        RestClient.builder(httpHost)
+            .setRequestConfigCallback(
+                builder ->
+                    builder
+                        .setConnectTimeout(Integer.MAX_VALUE)
+                        .setSocketTimeout(Integer.MAX_VALUE))
+            .build();
+    client = ElasticsearchRest7Telemetry.create(testing.getOpenTelemetry()).wrap(client);
+
+    objectMapper = new ObjectMapper();
+  }
+
+  @AfterAll
+  static void cleanUp() {
+    elasticsearch.stop();
+  }
+
+  @Test
+  public void elasticsearchStatus() throws Exception {
+    Response response = client.performRequest(new Request("GET", "_cluster/health"));
+    Map<?, ?> result = objectMapper.readValue(response.getEntity().getContent(), Map.class);
+    Assertions.assertEquals(result.get("status"), "green");
+
+    testing.waitAndAssertTraces(
+        trace ->
+            trace.hasSpansSatisfyingExactly(
+                span ->
+                    span.hasName("GET")
+                        .hasKind(SpanKind.CLIENT)
+                        .hasNoParent()
+                        .hasAttributesSatisfyingExactly(
+                            equalTo(SemanticAttributes.DB_SYSTEM, "elasticsearch"),
+                            equalTo(SemanticAttributes.HTTP_METHOD, "GET"),
+                            equalTo(SemanticAttributes.NET_PEER_NAME, httpHost.getHostName()),
+                            equalTo(SemanticAttributes.NET_PEER_PORT, httpHost.getPort()),
+                            equalTo(
+                                SemanticAttributes.HTTP_URL,
+                                httpHost.toURI() + "/_cluster/health"))));
+  }
+
+  @Test
+  public void elasticsearchStatusAsync() throws Exception {
+    AsyncRequest asyncRequest = new AsyncRequest();
+    CountDownLatch countDownLatch = new CountDownLatch(1);
+    ResponseListener responseListener =
+        new ResponseListener() {
+          @Override
+          public void onSuccess(Response response) {
+
+            runWithSpan(
+                "callback",
+                () -> {
+                  asyncRequest.setRequestResponse(response);
+                  countDownLatch.countDown();
+                });
+          }
+
+          @Override
+          public void onFailure(Exception e) {
+            runWithSpan(
+                "callback",
+                () -> {
+                  asyncRequest.setException(e);
+                  countDownLatch.countDown();
+                });
+          }
+        };
+
+    runWithSpan(
+        "parent",
+        () -> client.performRequestAsync(new Request("GET", "_cluster/health"), responseListener));
+    //noinspection ResultOfMethodCallIgnored
+    countDownLatch.await(10, TimeUnit.SECONDS);
+
+    if (asyncRequest.getException() != null) {
+      throw asyncRequest.getException();
+    }
+
+    Map<?, ?> result =
+        objectMapper.readValue(
+            asyncRequest.getRequestResponse().getEntity().getContent(), Map.class);
+    Assertions.assertEquals(result.get("status"), "green");
+
+    testing.waitAndAssertTraces(
+        trace ->
+            trace.hasSpansSatisfyingExactly(
+                span -> span.hasName("parent").hasKind(SpanKind.INTERNAL).hasNoParent(),
+                span ->
+                    span.hasName("GET")
+                        .hasKind(SpanKind.CLIENT)
+                        .hasParent(trace.getSpan(0))
+                        .hasAttributesSatisfyingExactly(
+                            equalTo(SemanticAttributes.DB_SYSTEM, "elasticsearch"),
+                            equalTo(SemanticAttributes.HTTP_METHOD, "GET"),
+                            equalTo(SemanticAttributes.NET_PEER_NAME, httpHost.getHostName()),
+                            equalTo(SemanticAttributes.NET_PEER_PORT, httpHost.getPort()),
+                            equalTo(
+                                SemanticAttributes.HTTP_URL,
+                                httpHost.toURI() + "/_cluster/health")),
+                span ->
+                    span.hasName("callback")
+                        .hasKind(SpanKind.INTERNAL)
+                        .hasParent(trace.getSpan(0))));
+  }
+
+  private static class AsyncRequest {
+    volatile Response requestResponse = null;
+    volatile Exception exception = null;
+
+    public Response getRequestResponse() {
+      return requestResponse;
+    }
+
+    public void setRequestResponse(Response requestResponse) {
+      this.requestResponse = requestResponse;
+    }
+
+    public Exception getException() {
+      return exception;
+    }
+
+    public void setException(Exception exception) {
+      this.exception = exception;
+    }
+  }
+}

+ 1 - 2
instrumentation/elasticsearch/elasticsearch-rest-common/javaagent/build.gradle.kts

@@ -4,7 +4,6 @@ plugins {
 
 dependencies {
   compileOnly("org.elasticsearch.client:rest:5.0.0")
-  compileOnly("com.google.auto.value:auto-value-annotations")
 
-  annotationProcessor("com.google.auto.value:auto-value")
+  api(project(":instrumentation:elasticsearch:elasticsearch-rest-common:library"))
 }

+ 32 - 0
instrumentation/elasticsearch/elasticsearch-rest-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/elasticsearch/rest/ElasticsearchRestJavaagentInstrumenterFactory.java

@@ -0,0 +1,32 @@
+/*
+ * Copyright The OpenTelemetry Authors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package io.opentelemetry.javaagent.instrumentation.elasticsearch.rest;
+
+import io.opentelemetry.api.GlobalOpenTelemetry;
+import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
+import io.opentelemetry.instrumentation.elasticsearch.rest.internal.ElasticsearchRestInstrumenterFactory;
+import io.opentelemetry.instrumentation.elasticsearch.rest.internal.ElasticsearchRestRequest;
+import io.opentelemetry.javaagent.bootstrap.internal.InstrumentationConfig;
+import java.util.Collections;
+import org.elasticsearch.client.Response;
+
+public final class ElasticsearchRestJavaagentInstrumenterFactory {
+
+  private static final boolean CAPTURE_SEARCH_QUERY =
+      InstrumentationConfig.get()
+          .getBoolean("otel.instrumentation.elasticsearch.capture-search-query", false);
+
+  private ElasticsearchRestJavaagentInstrumenterFactory() {}
+
+  public static Instrumenter<ElasticsearchRestRequest, Response> create(
+      String instrumentationName) {
+    return ElasticsearchRestInstrumenterFactory.create(
+        GlobalOpenTelemetry.get(),
+        instrumentationName,
+        Collections.emptyList(),
+        CAPTURE_SEARCH_QUERY);
+  }
+}

+ 10 - 0
instrumentation/elasticsearch/elasticsearch-rest-common/library/build.gradle.kts

@@ -0,0 +1,10 @@
+plugins {
+  id("otel.library-instrumentation")
+}
+
+dependencies {
+  compileOnly("org.elasticsearch.client:rest:5.0.0")
+  compileOnly("com.google.auto.value:auto-value-annotations")
+
+  annotationProcessor("com.google.auto.value:auto-value")
+}

+ 5 - 1
instrumentation/elasticsearch/elasticsearch-rest-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/elasticsearch/rest/ElasticsearchClientAttributeExtractor.java → instrumentation/elasticsearch/elasticsearch-rest-common/library/src/main/java/io/opentelemetry/instrumentation/elasticsearch/rest/internal/ElasticsearchClientAttributeExtractor.java

@@ -3,7 +3,7 @@
  * SPDX-License-Identifier: Apache-2.0
  */
 
-package io.opentelemetry.javaagent.instrumentation.elasticsearch.rest;
+package io.opentelemetry.instrumentation.elasticsearch.rest.internal;
 
 import static io.opentelemetry.instrumentation.api.internal.AttributesExtractorUtil.internalSet;
 
@@ -20,6 +20,10 @@ import javax.annotation.Nullable;
 import org.apache.http.HttpHost;
 import org.elasticsearch.client.Response;
 
+/**
+ * This class is internal and is hence not for public use. Its APIs are unstable and can change at
+ * any time.
+ */
 public class ElasticsearchClientAttributeExtractor
     implements AttributesExtractor<ElasticsearchRestRequest, Response> {
 

+ 12 - 7
instrumentation/elasticsearch/elasticsearch-rest-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/elasticsearch/rest/ElasticsearchDbAttributesGetter.java → instrumentation/elasticsearch/elasticsearch-rest-common/library/src/main/java/io/opentelemetry/instrumentation/elasticsearch/rest/internal/ElasticsearchDbAttributesGetter.java

@@ -3,12 +3,11 @@
  * SPDX-License-Identifier: Apache-2.0
  */
 
-package io.opentelemetry.javaagent.instrumentation.elasticsearch.rest;
+package io.opentelemetry.instrumentation.elasticsearch.rest.internal;
 
 import static java.util.logging.Level.FINE;
 
 import io.opentelemetry.instrumentation.api.instrumenter.db.DbClientAttributesGetter;
-import io.opentelemetry.javaagent.bootstrap.internal.InstrumentationConfig;
 import io.opentelemetry.semconv.trace.attributes.SemanticAttributes;
 import java.io.BufferedReader;
 import java.io.IOException;
@@ -19,16 +18,22 @@ import java.util.stream.Collectors;
 import javax.annotation.Nullable;
 import org.apache.http.HttpEntity;
 
+/**
+ * This class is internal and is hence not for public use. Its APIs are unstable and can change at
+ * any time.
+ */
 final class ElasticsearchDbAttributesGetter
     implements DbClientAttributesGetter<ElasticsearchRestRequest> {
 
-  private static final boolean CAPTURE_SEARCH_QUERY =
-      InstrumentationConfig.get()
-          .getBoolean("otel.instrumentation.elasticsearch.capture-search-query", false);
-
   private static final Logger logger =
       Logger.getLogger(ElasticsearchDbAttributesGetter.class.getName());
 
+  private final boolean captureSearchQuery;
+
+  ElasticsearchDbAttributesGetter(boolean captureSearchQuery) {
+    this.captureSearchQuery = captureSearchQuery;
+  }
+
   @Override
   public String getSystem(ElasticsearchRestRequest request) {
     return SemanticAttributes.DbSystemValues.ELASTICSEARCH;
@@ -57,7 +62,7 @@ final class ElasticsearchDbAttributesGetter
   public String getStatement(ElasticsearchRestRequest request) {
     ElasticsearchEndpointDefinition epDefinition = request.getEndpointDefinition();
     HttpEntity httpEntity = request.getHttpEntity();
-    if (CAPTURE_SEARCH_QUERY
+    if (captureSearchQuery
         && epDefinition != null
         && epDefinition.isSearchEndpoint()
         && httpEntity != null

+ 20 - 6
instrumentation/elasticsearch/elasticsearch-rest-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/elasticsearch/rest/ElasticsearchEndpointDefinition.java → instrumentation/elasticsearch/elasticsearch-rest-common/library/src/main/java/io/opentelemetry/instrumentation/elasticsearch/rest/internal/ElasticsearchEndpointDefinition.java

@@ -3,7 +3,7 @@
  * SPDX-License-Identifier: Apache-2.0
  */
 
-package io.opentelemetry.javaagent.instrumentation.elasticsearch.rest;
+package io.opentelemetry.instrumentation.elasticsearch.rest.internal;
 
 import static java.util.Collections.unmodifiableList;
 
@@ -17,6 +17,10 @@ import java.util.regex.Pattern;
 import java.util.stream.Collectors;
 import javax.annotation.Nullable;
 
+/**
+ * This class is internal and is hence not for public use. Its APIs are unstable and can change at
+ * any time.
+ */
 public final class ElasticsearchEndpointDefinition {
 
   private static final String UNDERSCORE_REPLACEMENT = "0";
@@ -62,11 +66,16 @@ public final class ElasticsearchEndpointDefinition {
     }
   }
 
-  List<Route> getRoutes() {
+  public List<Route> getRoutes() {
     return routes;
   }
 
-  static final class Route {
+  /**
+   * This class is internal and is hence not for public use. Its APIs are unstable and can change at
+   * any time.
+   */
+  // Visible for testing
+  public static final class Route {
     private final String name;
     private final boolean hasParameters;
 
@@ -77,7 +86,7 @@ public final class ElasticsearchEndpointDefinition {
       this.hasParameters = name.contains("{") && name.contains("}");
     }
 
-    String getName() {
+    public String getName() {
       return name;
     }
 
@@ -104,7 +113,12 @@ public final class ElasticsearchEndpointDefinition {
     }
   }
 
-  static final class EndpointPattern {
+  /**
+   * This class is internal and is hence not for public use. Its APIs are unstable and can change at
+   * any time.
+   */
+  // Visible for testing
+  public static final class EndpointPattern {
     private static final Pattern PATH_PART_NAMES_PATTERN = Pattern.compile("\\{([^}]+)}");
     private final Pattern pattern;
     private final List<String> pathPartNames;
@@ -136,7 +150,7 @@ public final class ElasticsearchEndpointDefinition {
     }
 
     /** Builds a regex pattern from the parameterized route pattern. */
-    static Pattern buildRegexPattern(String routeStr) {
+    public static Pattern buildRegexPattern(String routeStr) {
       StringBuilder regexStr = new StringBuilder();
       regexStr.append('^');
       int startIdx = routeStr.indexOf("{");

+ 15 - 5
instrumentation/elasticsearch/elasticsearch-rest-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/elasticsearch/rest/ElasticsearchRestInstrumenterFactory.java → instrumentation/elasticsearch/elasticsearch-rest-common/library/src/main/java/io/opentelemetry/instrumentation/elasticsearch/rest/internal/ElasticsearchRestInstrumenterFactory.java

@@ -3,31 +3,41 @@
  * SPDX-License-Identifier: Apache-2.0
  */
 
-package io.opentelemetry.javaagent.instrumentation.elasticsearch.rest;
+package io.opentelemetry.instrumentation.elasticsearch.rest.internal;
 
-import io.opentelemetry.api.GlobalOpenTelemetry;
+import io.opentelemetry.api.OpenTelemetry;
+import io.opentelemetry.instrumentation.api.instrumenter.AttributesExtractor;
 import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
 import io.opentelemetry.instrumentation.api.instrumenter.SpanKindExtractor;
 import io.opentelemetry.instrumentation.api.instrumenter.db.DbClientAttributesExtractor;
+import java.util.List;
 import org.elasticsearch.client.Response;
 
+/**
+ * This class is internal and is hence not for public use. Its APIs are unstable and can change at
+ * any time.
+ */
 public final class ElasticsearchRestInstrumenterFactory {
 
   private ElasticsearchRestInstrumenterFactory() {}
 
   public static Instrumenter<ElasticsearchRestRequest, Response> create(
-      String instrumentationName) {
+      OpenTelemetry opentelemetry,
+      String instrumentationName,
+      List<AttributesExtractor<ElasticsearchRestRequest, Response>> attributesExtractors,
+      boolean captureSearchQuery) {
     ElasticsearchDbAttributesGetter dbClientAttributesGetter =
-        new ElasticsearchDbAttributesGetter();
+        new ElasticsearchDbAttributesGetter(captureSearchQuery);
     ElasticsearchClientAttributeExtractor esClientAtrributesExtractor =
         new ElasticsearchClientAttributeExtractor();
     ElasticsearchSpanNameExtractor nameExtractor =
         new ElasticsearchSpanNameExtractor(dbClientAttributesGetter);
 
     return Instrumenter.<ElasticsearchRestRequest, Response>builder(
-            GlobalOpenTelemetry.get(), instrumentationName, nameExtractor)
+            opentelemetry, instrumentationName, nameExtractor)
         .addAttributesExtractor(DbClientAttributesExtractor.create(dbClientAttributesGetter))
         .addAttributesExtractor(esClientAtrributesExtractor)
+        .addAttributesExtractors(attributesExtractors)
         .buildInstrumenter(SpanKindExtractor.alwaysClient());
   }
 }

+ 5 - 1
instrumentation/elasticsearch/elasticsearch-rest-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/elasticsearch/rest/ElasticsearchRestRequest.java → instrumentation/elasticsearch/elasticsearch-rest-common/library/src/main/java/io/opentelemetry/instrumentation/elasticsearch/rest/internal/ElasticsearchRestRequest.java

@@ -3,12 +3,16 @@
  * SPDX-License-Identifier: Apache-2.0
  */
 
-package io.opentelemetry.javaagent.instrumentation.elasticsearch.rest;
+package io.opentelemetry.instrumentation.elasticsearch.rest.internal;
 
 import com.google.auto.value.AutoValue;
 import javax.annotation.Nullable;
 import org.apache.http.HttpEntity;
 
+/**
+ * This class is internal and is hence not for public use. Its APIs are unstable and can change at
+ * any time.
+ */
 @AutoValue
 public abstract class ElasticsearchRestRequest {
 

+ 5 - 1
instrumentation/elasticsearch/elasticsearch-rest-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/elasticsearch/rest/ElasticsearchSpanNameExtractor.java → instrumentation/elasticsearch/elasticsearch-rest-common/library/src/main/java/io/opentelemetry/instrumentation/elasticsearch/rest/internal/ElasticsearchSpanNameExtractor.java

@@ -3,10 +3,14 @@
  * SPDX-License-Identifier: Apache-2.0
  */
 
-package io.opentelemetry.javaagent.instrumentation.elasticsearch.rest;
+package io.opentelemetry.instrumentation.elasticsearch.rest.internal;
 
 import io.opentelemetry.instrumentation.api.instrumenter.SpanNameExtractor;
 
+/**
+ * This class is internal and is hence not for public use. Its APIs are unstable and can change at
+ * any time.
+ */
 public class ElasticsearchSpanNameExtractor implements SpanNameExtractor<ElasticsearchRestRequest> {
 
   private final ElasticsearchDbAttributesGetter dbAttributesGetter;

+ 5 - 1
instrumentation/elasticsearch/elasticsearch-rest-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/elasticsearch/rest/RestResponseListener.java → instrumentation/elasticsearch/elasticsearch-rest-common/library/src/main/java/io/opentelemetry/instrumentation/elasticsearch/rest/internal/RestResponseListener.java

@@ -3,7 +3,7 @@
  * SPDX-License-Identifier: Apache-2.0
  */
 
-package io.opentelemetry.javaagent.instrumentation.elasticsearch.rest;
+package io.opentelemetry.instrumentation.elasticsearch.rest.internal;
 
 import io.opentelemetry.context.Context;
 import io.opentelemetry.context.Scope;
@@ -11,6 +11,10 @@ import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
 import org.elasticsearch.client.Response;
 import org.elasticsearch.client.ResponseListener;
 
+/**
+ * This class is internal and is hence not for public use. Its APIs are unstable and can change at
+ * any time.
+ */
 public final class RestResponseListener implements ResponseListener {
 
   private final ResponseListener listener;

+ 6 - 4
settings.gradle.kts

@@ -214,19 +214,19 @@ hideFromDependabot(":instrumentation:couchbase:couchbase-common:testing")
 hideFromDependabot(":instrumentation:dropwizard:dropwizard-metrics-4.0:javaagent")
 hideFromDependabot(":instrumentation:dropwizard:dropwizard-views-0.7:javaagent")
 hideFromDependabot(":instrumentation:dropwizard:dropwizard-testing")
+hideFromDependabot(":instrumentation:elasticsearch:elasticsearch-api-client-7.16:javaagent")
+hideFromDependabot(":instrumentation:elasticsearch:elasticsearch-api-client-7.16:javaagent-unit-tests")
 hideFromDependabot(":instrumentation:elasticsearch:elasticsearch-rest-common:javaagent")
-hideFromDependabot(":instrumentation:opensearch:opensearch-rest-common:javaagent")
+hideFromDependabot(":instrumentation:elasticsearch:elasticsearch-rest-common:library")
 hideFromDependabot(":instrumentation:elasticsearch:elasticsearch-rest-5.0:javaagent")
 hideFromDependabot(":instrumentation:elasticsearch:elasticsearch-rest-6.4:javaagent")
 hideFromDependabot(":instrumentation:elasticsearch:elasticsearch-rest-7.0:javaagent")
-hideFromDependabot(":instrumentation:opensearch:opensearch-rest-1.0:javaagent")
+hideFromDependabot(":instrumentation:elasticsearch:elasticsearch-rest-7.0:library")
 hideFromDependabot(":instrumentation:elasticsearch:elasticsearch-transport-common:javaagent")
 hideFromDependabot(":instrumentation:elasticsearch:elasticsearch-transport-common:testing")
 hideFromDependabot(":instrumentation:elasticsearch:elasticsearch-transport-5.0:javaagent")
 hideFromDependabot(":instrumentation:elasticsearch:elasticsearch-transport-5.3:javaagent")
 hideFromDependabot(":instrumentation:elasticsearch:elasticsearch-transport-6.0:javaagent")
-hideFromDependabot(":instrumentation:elasticsearch:elasticsearch-api-client-7.16:javaagent")
-hideFromDependabot(":instrumentation:elasticsearch:elasticsearch-api-client-7.16:javaagent-unit-tests")
 hideFromDependabot(":instrumentation:executors:bootstrap")
 hideFromDependabot(":instrumentation:executors:javaagent")
 hideFromDependabot(":instrumentation:executors:testing")
@@ -383,6 +383,8 @@ hideFromDependabot(":instrumentation:okhttp:okhttp-3.0:javaagent")
 hideFromDependabot(":instrumentation:okhttp:okhttp-3.0:library")
 hideFromDependabot(":instrumentation:okhttp:okhttp-3.0:testing")
 hideFromDependabot(":instrumentation:opencensus-shim:testing")
+hideFromDependabot(":instrumentation:opensearch:opensearch-rest-common:javaagent")
+hideFromDependabot(":instrumentation:opensearch:opensearch-rest-1.0:javaagent")
 hideFromDependabot(":instrumentation:opentelemetry-api:opentelemetry-api-1.0:javaagent")
 hideFromDependabot(":instrumentation:opentelemetry-api:opentelemetry-api-1.4:javaagent")
 hideFromDependabot(":instrumentation:opentelemetry-api:opentelemetry-api-1.10:javaagent")