Browse Source

Convert elasticsearch-rest to Instrumenter API (#4153)

* Convert elasticsearch-rest to Instrumenter API

* Add net.transport attribute
Mateusz Rzeszutek 3 years ago
parent
commit
1c3ea2ec56
22 changed files with 293 additions and 114 deletions
  1. 1 1
      instrumentation/elasticsearch/elasticsearch-rest-5.0/javaagent/build.gradle.kts
  2. 2 2
      instrumentation/elasticsearch/elasticsearch-rest-5.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/elasticsearch/rest/v5_0/ElasticsearchRest5InstrumentationModule.java
  3. 22 0
      instrumentation/elasticsearch/elasticsearch-rest-5.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/elasticsearch/rest/v5_0/ElasticsearchRest5Singletons.java
  4. 18 4
      instrumentation/elasticsearch/elasticsearch-rest-5.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/elasticsearch/rest/v5_0/RestClientInstrumentation.java
  5. 3 1
      instrumentation/elasticsearch/elasticsearch-rest-5.0/javaagent/src/test/groovy/ElasticsearchRest5Test.groovy
  6. 1 1
      instrumentation/elasticsearch/elasticsearch-rest-6.4/javaagent/build.gradle.kts
  7. 2 2
      instrumentation/elasticsearch/elasticsearch-rest-6.4/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/elasticsearch/rest/v6_4/ElasticsearchRest6InstrumentationModule.java
  8. 22 0
      instrumentation/elasticsearch/elasticsearch-rest-6.4/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/elasticsearch/rest/v6_4/ElasticsearchRest6Singletons.java
  9. 18 6
      instrumentation/elasticsearch/elasticsearch-rest-6.4/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/elasticsearch/rest/v6_4/RestClientInstrumentation.java
  10. 3 1
      instrumentation/elasticsearch/elasticsearch-rest-6.4/javaagent/src/test/groovy/ElasticsearchRest6Test.groovy
  11. 1 1
      instrumentation/elasticsearch/elasticsearch-rest-7.0/javaagent/build.gradle.kts
  12. 2 2
      instrumentation/elasticsearch/elasticsearch-rest-7.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/elasticsearch/rest/v7_0/ElasticsearchRest7InstrumentationModule.java
  13. 22 0
      instrumentation/elasticsearch/elasticsearch-rest-7.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/elasticsearch/rest/v7_0/ElasticsearchRest7Singletons.java
  14. 34 18
      instrumentation/elasticsearch/elasticsearch-rest-7.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/elasticsearch/rest/v7_0/RestClientInstrumentation.java
  15. 3 1
      instrumentation/elasticsearch/elasticsearch-rest-7.0/javaagent/src/test/groovy/ElasticsearchRest7Test.groovy
  16. 1 1
      instrumentation/elasticsearch/elasticsearch-rest-common/javaagent/build.gradle.kts
  17. 43 0
      instrumentation/elasticsearch/elasticsearch-rest-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/elasticsearch/rest/ElasticsearchRestAttributesExtractor.java
  18. 34 0
      instrumentation/elasticsearch/elasticsearch-rest-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/elasticsearch/rest/ElasticsearchRestInstrumenterFactory.java
  19. 43 0
      instrumentation/elasticsearch/elasticsearch-rest-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/elasticsearch/rest/ElasticsearchRestNetAttributesExtractor.java
  20. 17 13
      instrumentation/elasticsearch/elasticsearch-rest-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/elasticsearch/rest/RestResponseListener.java
  21. 0 59
      instrumentation/elasticsearch/elasticsearch-rest-common/library/src/main/java/io/opentelemetry/javaagent/instrumentation/elasticsearch/rest/ElasticsearchRestClientTracer.java
  22. 1 1
      settings.gradle.kts

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

@@ -23,7 +23,7 @@ val versions: Map<String, String> by project
 dependencies {
   compileOnly("org.elasticsearch.client:rest:5.0.0")
 
-  implementation(project(":instrumentation:elasticsearch:elasticsearch-rest-common:library"))
+  implementation(project(":instrumentation:elasticsearch:elasticsearch-rest-common:javaagent"))
 
   testInstrumentation(project(":instrumentation:apache-httpclient:apache-httpclient-4.0:javaagent"))
   testInstrumentation(project(":instrumentation:apache-httpasyncclient-4.1:javaagent"))

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

@@ -13,8 +13,8 @@ import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
 import java.util.List;
 
 @AutoService(InstrumentationModule.class)
-public class Elasticsearch5RestClientInstrumentationModule extends InstrumentationModule {
-  public Elasticsearch5RestClientInstrumentationModule() {
+public class ElasticsearchRest5InstrumentationModule extends InstrumentationModule {
+  public ElasticsearchRest5InstrumentationModule() {
     super("elasticsearch-rest", "elasticsearch-rest-5.0", "elasticsearch");
   }
 

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

@@ -0,0 +1,22 @@
+/*
+ * Copyright The OpenTelemetry Authors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+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 org.elasticsearch.client.Response;
+
+public final class ElasticsearchRest5Singletons {
+
+  private static final Instrumenter<String, Response> INSTRUMENTER =
+      ElasticsearchRestInstrumenterFactory.create("io.opentelemetry.elasticsearch-rest-5.0");
+
+  public static Instrumenter<String, Response> instrumenter() {
+    return INSTRUMENTER;
+  }
+
+  private ElasticsearchRest5Singletons() {}
+}

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

@@ -6,7 +6,7 @@
 package io.opentelemetry.javaagent.instrumentation.elasticsearch.rest.v5_0;
 
 import static io.opentelemetry.javaagent.instrumentation.api.Java8BytecodeBridge.currentContext;
-import static io.opentelemetry.javaagent.instrumentation.elasticsearch.rest.ElasticsearchRestClientTracer.tracer;
+import static io.opentelemetry.javaagent.instrumentation.elasticsearch.rest.v5_0.ElasticsearchRest5Singletons.instrumenter;
 import static net.bytebuddy.matcher.ElementMatchers.isMethod;
 import static net.bytebuddy.matcher.ElementMatchers.named;
 import static net.bytebuddy.matcher.ElementMatchers.namedOneOf;
@@ -48,25 +48,39 @@ public class RestClientInstrumentation implements TypeInstrumentation {
     public static void onEnter(
         @Advice.Argument(0) String method,
         @Advice.Argument(1) String endpoint,
+        @Advice.Local("otelRequest") String request,
         @Advice.Local("otelContext") Context context,
         @Advice.Local("otelScope") Scope scope,
         @Advice.Argument(value = 5, readOnly = false) ResponseListener responseListener) {
 
       Context parentContext = currentContext();
-      context = tracer().startSpan(parentContext, null, method + " " + endpoint);
+      request = method + " " + endpoint;
+      if (!instrumenter().shouldStart(parentContext, request)) {
+        return;
+      }
+
+      context = instrumenter().start(parentContext, request);
       scope = context.makeCurrent();
 
-      responseListener = new RestResponseListener(responseListener, context, parentContext);
+      responseListener =
+          new RestResponseListener(
+              responseListener, parentContext, instrumenter(), context, request);
     }
 
     @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
     public static void stopSpan(
         @Advice.Thrown Throwable throwable,
+        @Advice.Local("otelRequest") String request,
         @Advice.Local("otelContext") Context context,
         @Advice.Local("otelScope") Scope scope) {
+
+      if (scope == null) {
+        return;
+      }
       scope.close();
+
       if (throwable != null) {
-        tracer().endExceptionally(context, throwable);
+        instrumenter().end(context, request, null, throwable);
       }
       // span ended in RestResponseListener
     }

+ 3 - 1
instrumentation/elasticsearch/elasticsearch-rest-5.0/javaagent/src/test/groovy/Elasticsearch5RestClientTest.groovy → instrumentation/elasticsearch/elasticsearch-rest-5.0/javaagent/src/test/groovy/ElasticsearchRest5Test.groovy

@@ -21,7 +21,7 @@ import java.util.concurrent.CountDownLatch
 import static io.opentelemetry.api.trace.SpanKind.CLIENT
 import static io.opentelemetry.api.trace.SpanKind.INTERNAL
 
-class Elasticsearch5RestClientTest extends AgentInstrumentationSpecification {
+class ElasticsearchRest5Test extends AgentInstrumentationSpecification {
   @Shared
   ElasticsearchContainer elasticsearch
 
@@ -75,6 +75,7 @@ class Elasticsearch5RestClientTest extends AgentInstrumentationSpecification {
           attributes {
             "${SemanticAttributes.DB_SYSTEM.key}" "elasticsearch"
             "${SemanticAttributes.DB_OPERATION.key}" "GET _cluster/health"
+            "${SemanticAttributes.NET_TRANSPORT.key}" SemanticAttributes.NetTransportValues.IP_TCP
             "${SemanticAttributes.NET_PEER_NAME.key}" httpHost.hostName
             "${SemanticAttributes.NET_PEER_PORT.key}" httpHost.port
           }
@@ -132,6 +133,7 @@ class Elasticsearch5RestClientTest extends AgentInstrumentationSpecification {
           attributes {
             "${SemanticAttributes.DB_SYSTEM.key}" "elasticsearch"
             "${SemanticAttributes.DB_OPERATION.key}" "GET _cluster/health"
+            "${SemanticAttributes.NET_TRANSPORT.key}" SemanticAttributes.NetTransportValues.IP_TCP
             "${SemanticAttributes.NET_PEER_NAME.key}" httpHost.hostName
             "${SemanticAttributes.NET_PEER_PORT.key}" httpHost.port
           }

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

@@ -22,7 +22,7 @@ val versions: Map<String, String> by project
 dependencies {
   library("org.elasticsearch.client:elasticsearch-rest-client:6.4.0")
 
-  implementation(project(":instrumentation:elasticsearch:elasticsearch-rest-common:library"))
+  implementation(project(":instrumentation:elasticsearch:elasticsearch-rest-common:javaagent"))
 
   testInstrumentation(project(":instrumentation:apache-httpclient:apache-httpclient-4.0:javaagent"))
   testInstrumentation(project(":instrumentation:apache-httpasyncclient-4.1:javaagent"))

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

@@ -16,8 +16,8 @@ import java.util.List;
 import net.bytebuddy.matcher.ElementMatcher;
 
 @AutoService(InstrumentationModule.class)
-public class Elasticsearch6RestClientInstrumentationModule extends InstrumentationModule {
-  public Elasticsearch6RestClientInstrumentationModule() {
+public class ElasticsearchRest6InstrumentationModule extends InstrumentationModule {
+  public ElasticsearchRest6InstrumentationModule() {
     super("elasticsearch-rest", "elasticsearch-rest-6.0", "elasticsearch");
   }
 

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

@@ -0,0 +1,22 @@
+/*
+ * Copyright The OpenTelemetry Authors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+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 org.elasticsearch.client.Response;
+
+public final class ElasticsearchRest6Singletons {
+
+  private static final Instrumenter<String, Response> INSTRUMENTER =
+      ElasticsearchRestInstrumenterFactory.create("io.opentelemetry.elasticsearch-rest-6.4");
+
+  public static Instrumenter<String, Response> instrumenter() {
+    return INSTRUMENTER;
+  }
+
+  private ElasticsearchRest6Singletons() {}
+}

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

@@ -6,7 +6,7 @@
 package io.opentelemetry.javaagent.instrumentation.elasticsearch.rest.v6_4;
 
 import static io.opentelemetry.javaagent.instrumentation.api.Java8BytecodeBridge.currentContext;
-import static io.opentelemetry.javaagent.instrumentation.elasticsearch.rest.ElasticsearchRestClientTracer.tracer;
+import static io.opentelemetry.javaagent.instrumentation.elasticsearch.rest.v6_4.ElasticsearchRest6Singletons.instrumenter;
 import static net.bytebuddy.matcher.ElementMatchers.isMethod;
 import static net.bytebuddy.matcher.ElementMatchers.named;
 import static net.bytebuddy.matcher.ElementMatchers.takesArgument;
@@ -47,26 +47,38 @@ public class RestClientInstrumentation implements TypeInstrumentation {
     public static void onEnter(
         @Advice.Argument(0) Request request,
         @Advice.Argument(value = 1, readOnly = false) ResponseListener responseListener,
+        @Advice.Local("otelRequest") String otelRequest,
         @Advice.Local("otelContext") Context context,
         @Advice.Local("otelScope") Scope scope) {
 
       Context parentContext = currentContext();
-      context =
-          tracer()
-              .startSpan(parentContext, null, request.getMethod() + " " + request.getEndpoint());
+      otelRequest = request.getMethod() + " " + request.getEndpoint();
+      if (!instrumenter().shouldStart(parentContext, otelRequest)) {
+        return;
+      }
+
+      context = instrumenter().start(parentContext, otelRequest);
       scope = context.makeCurrent();
 
-      responseListener = new RestResponseListener(responseListener, context, parentContext);
+      responseListener =
+          new RestResponseListener(
+              responseListener, parentContext, instrumenter(), context, otelRequest);
     }
 
     @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
     public static void stopSpan(
         @Advice.Thrown Throwable throwable,
+        @Advice.Local("otelRequest") String otelRequest,
         @Advice.Local("otelContext") Context context,
         @Advice.Local("otelScope") Scope scope) {
+
+      if (scope == null) {
+        return;
+      }
       scope.close();
+
       if (throwable != null) {
-        tracer().endExceptionally(context, throwable);
+        instrumenter().end(context, otelRequest, null, throwable);
       }
       // span ended in RestResponseListener
     }

+ 3 - 1
instrumentation/elasticsearch/elasticsearch-rest-6.4/javaagent/src/test/groovy/Elasticsearch6RestClientTest.groovy → instrumentation/elasticsearch/elasticsearch-rest-6.4/javaagent/src/test/groovy/ElasticsearchRest6Test.groovy

@@ -21,7 +21,7 @@ import java.util.concurrent.CountDownLatch
 import static io.opentelemetry.api.trace.SpanKind.CLIENT
 import static io.opentelemetry.api.trace.SpanKind.INTERNAL
 
-class Elasticsearch6RestClientTest extends AgentInstrumentationSpecification {
+class ElasticsearchRest6Test extends AgentInstrumentationSpecification {
   @Shared
   ElasticsearchContainer elasticsearch
 
@@ -70,6 +70,7 @@ class Elasticsearch6RestClientTest extends AgentInstrumentationSpecification {
           attributes {
             "${SemanticAttributes.DB_SYSTEM.key}" "elasticsearch"
             "${SemanticAttributes.DB_OPERATION.key}" "GET _cluster/health"
+            "${SemanticAttributes.NET_TRANSPORT.key}" SemanticAttributes.NetTransportValues.IP_TCP
             "${SemanticAttributes.NET_PEER_NAME.key}" httpHost.hostName
             "${SemanticAttributes.NET_PEER_PORT.key}" httpHost.port
           }
@@ -127,6 +128,7 @@ class Elasticsearch6RestClientTest extends AgentInstrumentationSpecification {
           attributes {
             "${SemanticAttributes.DB_SYSTEM.key}" "elasticsearch"
             "${SemanticAttributes.DB_OPERATION.key}" "GET _cluster/health"
+            "${SemanticAttributes.NET_TRANSPORT.key}" SemanticAttributes.NetTransportValues.IP_TCP
             "${SemanticAttributes.NET_PEER_NAME.key}" httpHost.hostName
             "${SemanticAttributes.NET_PEER_PORT.key}" httpHost.port
           }

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

@@ -22,7 +22,7 @@ val versions: Map<String, String> by project
 dependencies {
   library("org.elasticsearch.client:elasticsearch-rest-client:7.0.0")
 
-  implementation(project(":instrumentation:elasticsearch:elasticsearch-rest-common:library"))
+  implementation(project(":instrumentation:elasticsearch:elasticsearch-rest-common:javaagent"))
 
   testInstrumentation(project(":instrumentation:apache-httpclient:apache-httpclient-4.0:javaagent"))
   testInstrumentation(project(":instrumentation:apache-httpasyncclient-4.1:javaagent"))

+ 2 - 2
instrumentation/elasticsearch/elasticsearch-rest-7.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/elasticsearch/rest/v7_0/Elasticsearch7RestClientInstrumentationModule.java → instrumentation/elasticsearch/elasticsearch-rest-7.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/elasticsearch/rest/v7_0/ElasticsearchRest7InstrumentationModule.java

@@ -15,8 +15,8 @@ import java.util.List;
 import net.bytebuddy.matcher.ElementMatcher;
 
 @AutoService(InstrumentationModule.class)
-public class Elasticsearch7RestClientInstrumentationModule extends InstrumentationModule {
-  public Elasticsearch7RestClientInstrumentationModule() {
+public class ElasticsearchRest7InstrumentationModule extends InstrumentationModule {
+  public ElasticsearchRest7InstrumentationModule() {
     super("elasticsearch-rest", "elasticsearch-rest-7.0", "elasticsearch");
   }
 

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

@@ -0,0 +1,22 @@
+/*
+ * Copyright The OpenTelemetry Authors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+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 org.elasticsearch.client.Response;
+
+public final class ElasticsearchRest7Singletons {
+
+  private static final Instrumenter<String, Response> INSTRUMENTER =
+      ElasticsearchRestInstrumenterFactory.create("io.opentelemetry.elasticsearch-rest-7.0");
+
+  public static Instrumenter<String, Response> instrumenter() {
+    return INSTRUMENTER;
+  }
+
+  private ElasticsearchRest7Singletons() {}
+}

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

@@ -6,7 +6,7 @@
 package io.opentelemetry.javaagent.instrumentation.elasticsearch.rest.v7_0;
 
 import static io.opentelemetry.javaagent.instrumentation.api.Java8BytecodeBridge.currentContext;
-import static io.opentelemetry.javaagent.instrumentation.elasticsearch.rest.ElasticsearchRestClientTracer.tracer;
+import static io.opentelemetry.javaagent.instrumentation.elasticsearch.rest.v7_0.ElasticsearchRest7Singletons.instrumenter;
 import static net.bytebuddy.matcher.ElementMatchers.isMethod;
 import static net.bytebuddy.matcher.ElementMatchers.named;
 import static net.bytebuddy.matcher.ElementMatchers.takesArgument;
@@ -53,30 +53,34 @@ public class RestClientInstrumentation implements TypeInstrumentation {
     @Advice.OnMethodEnter(suppress = Throwable.class)
     public static void onEnter(
         @Advice.Argument(0) Request request,
+        @Advice.Local("otelRequest") String otelRequest,
         @Advice.Local("otelContext") Context context,
         @Advice.Local("otelScope") Scope scope) {
 
-      context =
-          tracer()
-              .startSpan(currentContext(), null, request.getMethod() + " " + request.getEndpoint());
+      Context parentContext = currentContext();
+      otelRequest = request.getMethod() + " " + request.getEndpoint();
+      if (!instrumenter().shouldStart(parentContext, otelRequest)) {
+        return;
+      }
+
+      context = instrumenter().start(parentContext, otelRequest);
       scope = context.makeCurrent();
     }
 
     @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
     public static void stopSpan(
-        @Advice.Thrown Throwable throwable,
         @Advice.Return(readOnly = false) Response response,
+        @Advice.Thrown Throwable throwable,
+        @Advice.Local("otelRequest") String otelRequest,
         @Advice.Local("otelContext") Context context,
         @Advice.Local("otelScope") Scope scope) {
-      scope.close();
-      if (throwable != null) {
-        tracer().endExceptionally(context, throwable);
-      } else {
-        if (response != null) {
-          tracer().onResponse(context, response);
-        }
-        tracer().end(context);
+
+      if (scope == null) {
+        return;
       }
+      scope.close();
+
+      instrumenter().end(context, otelRequest, response, throwable);
     }
   }
 
@@ -87,26 +91,38 @@ public class RestClientInstrumentation implements TypeInstrumentation {
     public static void onEnter(
         @Advice.Argument(0) Request request,
         @Advice.Argument(value = 1, readOnly = false) ResponseListener responseListener,
+        @Advice.Local("otelRequest") String otelRequest,
         @Advice.Local("otelContext") Context context,
         @Advice.Local("otelScope") Scope scope) {
 
       Context parentContext = currentContext();
-      context =
-          tracer()
-              .startSpan(parentContext, null, request.getMethod() + " " + request.getEndpoint());
+      otelRequest = request.getMethod() + " " + request.getEndpoint();
+      if (!instrumenter().shouldStart(parentContext, otelRequest)) {
+        return;
+      }
+
+      context = instrumenter().start(parentContext, otelRequest);
       scope = context.makeCurrent();
 
-      responseListener = new RestResponseListener(responseListener, context, parentContext);
+      responseListener =
+          new RestResponseListener(
+              responseListener, parentContext, instrumenter(), context, otelRequest);
     }
 
     @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
     public static void stopSpan(
         @Advice.Thrown Throwable throwable,
+        @Advice.Local("otelRequest") String otelRequest,
         @Advice.Local("otelContext") Context context,
         @Advice.Local("otelScope") Scope scope) {
+
+      if (scope == null) {
+        return;
+      }
       scope.close();
+
       if (throwable != null) {
-        tracer().endExceptionally(context, throwable);
+        instrumenter().end(context, otelRequest, null, throwable);
       }
       // span ended in RestResponseListener
     }

+ 3 - 1
instrumentation/elasticsearch/elasticsearch-rest-7.0/javaagent/src/test/groovy/Elasticsearch7RestClientTest.groovy → instrumentation/elasticsearch/elasticsearch-rest-7.0/javaagent/src/test/groovy/ElasticsearchRest7Test.groovy

@@ -22,7 +22,7 @@ import java.util.concurrent.CountDownLatch
 import static io.opentelemetry.api.trace.SpanKind.CLIENT
 import static io.opentelemetry.api.trace.SpanKind.INTERNAL
 
-class Elasticsearch7RestClientTest extends AgentInstrumentationSpecification {
+class ElasticsearchRest7Test extends AgentInstrumentationSpecification {
   @Shared
   ElasticsearchContainer elasticsearch
 
@@ -69,6 +69,7 @@ class Elasticsearch7RestClientTest extends AgentInstrumentationSpecification {
           attributes {
             "${SemanticAttributes.DB_SYSTEM.key}" "elasticsearch"
             "${SemanticAttributes.DB_OPERATION.key}" "GET _cluster/health"
+            "${SemanticAttributes.NET_TRANSPORT.key}" SemanticAttributes.NetTransportValues.IP_TCP
             "${SemanticAttributes.NET_PEER_NAME.key}" httpHost.hostName
             "${SemanticAttributes.NET_PEER_PORT.key}" httpHost.port
           }
@@ -126,6 +127,7 @@ class Elasticsearch7RestClientTest extends AgentInstrumentationSpecification {
           attributes {
             "${SemanticAttributes.DB_SYSTEM.key}" "elasticsearch"
             "${SemanticAttributes.DB_OPERATION.key}" "GET _cluster/health"
+            "${SemanticAttributes.NET_TRANSPORT.key}" SemanticAttributes.NetTransportValues.IP_TCP
             "${SemanticAttributes.NET_PEER_NAME.key}" httpHost.hostName
             "${SemanticAttributes.NET_PEER_PORT.key}" httpHost.port
           }

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

@@ -1,5 +1,5 @@
 plugins {
-  id("otel.library-instrumentation")
+  id("otel.javaagent-instrumentation")
 }
 
 dependencies {

+ 43 - 0
instrumentation/elasticsearch/elasticsearch-rest-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/elasticsearch/rest/ElasticsearchRestAttributesExtractor.java

@@ -0,0 +1,43 @@
+/*
+ * Copyright The OpenTelemetry Authors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package io.opentelemetry.javaagent.instrumentation.elasticsearch.rest;
+
+import io.opentelemetry.instrumentation.api.instrumenter.db.DbAttributesExtractor;
+import io.opentelemetry.semconv.trace.attributes.SemanticAttributes;
+import org.checkerframework.checker.nullness.qual.Nullable;
+import org.elasticsearch.client.Response;
+
+final class ElasticsearchRestAttributesExtractor extends DbAttributesExtractor<String, Response> {
+  @Override
+  protected String system(String s) {
+    return SemanticAttributes.DbSystemValues.ELASTICSEARCH;
+  }
+
+  @Override
+  protected @Nullable String user(String s) {
+    return null;
+  }
+
+  @Override
+  protected @Nullable String name(String s) {
+    return null;
+  }
+
+  @Override
+  protected @Nullable String connectionString(String s) {
+    return null;
+  }
+
+  @Override
+  protected @Nullable String statement(String s) {
+    return null;
+  }
+
+  @Override
+  protected @Nullable String operation(String operation) {
+    return operation;
+  }
+}

+ 34 - 0
instrumentation/elasticsearch/elasticsearch-rest-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/elasticsearch/rest/ElasticsearchRestInstrumenterFactory.java

@@ -0,0 +1,34 @@
+/*
+ * 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.api.instrumenter.SpanKindExtractor;
+import io.opentelemetry.instrumentation.api.instrumenter.SpanNameExtractor;
+import io.opentelemetry.instrumentation.api.instrumenter.db.DbSpanNameExtractor;
+import io.opentelemetry.javaagent.instrumentation.api.instrumenter.PeerServiceAttributesExtractor;
+import org.elasticsearch.client.Response;
+
+public final class ElasticsearchRestInstrumenterFactory {
+
+  public static Instrumenter<String, Response> create(String instrumentationName) {
+    ElasticsearchRestAttributesExtractor attributesExtractor =
+        new ElasticsearchRestAttributesExtractor();
+    SpanNameExtractor<String> spanNameExtractor = DbSpanNameExtractor.create(attributesExtractor);
+    ElasticsearchRestNetAttributesExtractor netAttributesExtractor =
+        new ElasticsearchRestNetAttributesExtractor();
+
+    return Instrumenter.<String, Response>newBuilder(
+            GlobalOpenTelemetry.get(), instrumentationName, spanNameExtractor)
+        .addAttributesExtractor(attributesExtractor)
+        .addAttributesExtractor(netAttributesExtractor)
+        .addAttributesExtractor(PeerServiceAttributesExtractor.create(netAttributesExtractor))
+        .newInstrumenter(SpanKindExtractor.alwaysClient());
+  }
+
+  private ElasticsearchRestInstrumenterFactory() {}
+}

+ 43 - 0
instrumentation/elasticsearch/elasticsearch-rest-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/elasticsearch/rest/ElasticsearchRestNetAttributesExtractor.java

@@ -0,0 +1,43 @@
+/*
+ * Copyright The OpenTelemetry Authors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package io.opentelemetry.javaagent.instrumentation.elasticsearch.rest;
+
+import io.opentelemetry.instrumentation.api.instrumenter.net.NetAttributesExtractor;
+import io.opentelemetry.semconv.trace.attributes.SemanticAttributes;
+import org.checkerframework.checker.nullness.qual.Nullable;
+import org.elasticsearch.client.Response;
+
+final class ElasticsearchRestNetAttributesExtractor
+    extends NetAttributesExtractor<String, Response> {
+  @Override
+  public String transport(String s) {
+    return SemanticAttributes.NetTransportValues.IP_TCP;
+  }
+
+  @Override
+  public @Nullable String peerName(String s, @Nullable Response response) {
+    if (response != null) {
+      return response.getHost().getHostName();
+    }
+    return null;
+  }
+
+  @Override
+  public @Nullable Integer peerPort(String s, @Nullable Response response) {
+    if (response != null) {
+      return response.getHost().getPort();
+    }
+    return null;
+  }
+
+  @Override
+  public @Nullable String peerIp(String s, @Nullable Response response) {
+    if (response != null && response.getHost().getAddress() != null) {
+      return response.getHost().getAddress().getHostAddress();
+    }
+    return null;
+  }
+}

+ 17 - 13
instrumentation/elasticsearch/elasticsearch-rest-common/library/src/main/java/io/opentelemetry/javaagent/instrumentation/elasticsearch/rest/RestResponseListener.java → instrumentation/elasticsearch/elasticsearch-rest-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/elasticsearch/rest/RestResponseListener.java

@@ -5,32 +5,36 @@
 
 package io.opentelemetry.javaagent.instrumentation.elasticsearch.rest;
 
-import static io.opentelemetry.javaagent.instrumentation.elasticsearch.rest.ElasticsearchRestClientTracer.tracer;
-
 import io.opentelemetry.context.Context;
 import io.opentelemetry.context.Scope;
+import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
 import org.elasticsearch.client.Response;
 import org.elasticsearch.client.ResponseListener;
 
-public class RestResponseListener implements ResponseListener {
+public final class RestResponseListener implements ResponseListener {
 
   private final ResponseListener listener;
-  private final Context context;
   private final Context parentContext;
-
-  public RestResponseListener(ResponseListener listener, Context context, Context parentContext) {
+  private final Instrumenter<String, Response> instrumenter;
+  private final Context context;
+  private final String request;
+
+  public RestResponseListener(
+      ResponseListener listener,
+      Context parentContext,
+      Instrumenter<String, Response> instrumenter,
+      Context context,
+      String request) {
     this.listener = listener;
-    this.context = context;
     this.parentContext = parentContext;
+    this.instrumenter = instrumenter;
+    this.context = context;
+    this.request = request;
   }
 
   @Override
   public void onSuccess(Response response) {
-    if (response.getHost() != null) {
-      tracer().onResponse(context, response);
-    }
-    tracer().end(context);
-
+    instrumenter.end(context, request, response, null);
     try (Scope ignored = parentContext.makeCurrent()) {
       listener.onSuccess(response);
     }
@@ -38,7 +42,7 @@ public class RestResponseListener implements ResponseListener {
 
   @Override
   public void onFailure(Exception e) {
-    tracer().endExceptionally(context, e);
+    instrumenter.end(context, request, null, e);
     try (Scope ignored = parentContext.makeCurrent()) {
       listener.onFailure(e);
     }

+ 0 - 59
instrumentation/elasticsearch/elasticsearch-rest-common/library/src/main/java/io/opentelemetry/javaagent/instrumentation/elasticsearch/rest/ElasticsearchRestClientTracer.java

@@ -1,59 +0,0 @@
-/*
- * Copyright The OpenTelemetry Authors
- * SPDX-License-Identifier: Apache-2.0
- */
-
-package io.opentelemetry.javaagent.instrumentation.elasticsearch.rest;
-
-import io.opentelemetry.api.trace.Span;
-import io.opentelemetry.context.Context;
-import io.opentelemetry.instrumentation.api.tracer.DatabaseClientTracer;
-import io.opentelemetry.instrumentation.api.tracer.net.NetPeerAttributes;
-import io.opentelemetry.semconv.trace.attributes.SemanticAttributes;
-import java.net.InetSocketAddress;
-import org.elasticsearch.client.Response;
-
-public class ElasticsearchRestClientTracer extends DatabaseClientTracer<Void, String, String> {
-  private static final ElasticsearchRestClientTracer TRACER = new ElasticsearchRestClientTracer();
-
-  private ElasticsearchRestClientTracer() {
-    super(NetPeerAttributes.INSTANCE);
-  }
-
-  public static ElasticsearchRestClientTracer tracer() {
-    return TRACER;
-  }
-
-  public void onResponse(Context context, Response response) {
-    if (response != null && response.getHost() != null) {
-      Span span = Span.fromContext(context);
-      netPeerAttributes.setNetPeer(span, response.getHost().getHostName(), null);
-      span.setAttribute(SemanticAttributes.NET_PEER_PORT, (long) response.getHost().getPort());
-    }
-  }
-
-  @Override
-  protected String sanitizeStatement(String operation) {
-    return operation;
-  }
-
-  @Override
-  protected String dbSystem(Void connection) {
-    return "elasticsearch";
-  }
-
-  @Override
-  protected InetSocketAddress peerAddress(Void connection) {
-    return null;
-  }
-
-  @Override
-  protected String dbOperation(Void connection, String operation, String ignored) {
-    return operation;
-  }
-
-  @Override
-  protected String getInstrumentationName() {
-    return "io.opentelemetry.elasticsearch-rest-common";
-  }
-}

+ 1 - 1
settings.gradle.kts

@@ -132,7 +132,7 @@ include(":instrumentation:couchbase:couchbase-3.2:tracing-opentelemetry-shaded")
 include(":instrumentation:couchbase:couchbase-testing")
 include(":instrumentation:dropwizard-views-0.7:javaagent")
 include(":instrumentation:dropwizard-testing")
-include(":instrumentation:elasticsearch:elasticsearch-rest-common:library")
+include(":instrumentation:elasticsearch:elasticsearch-rest-common:javaagent")
 include(":instrumentation:elasticsearch:elasticsearch-rest-5.0:javaagent")
 include(":instrumentation:elasticsearch:elasticsearch-rest-6.4:javaagent")
 include(":instrumentation:elasticsearch:elasticsearch-rest-7.0:javaagent")