Elasticsearch 5.3.0 instrumentation
ADD
dd-java-agent/instrumentation/elasticsearch-transport-5.3/elasticsearch-transport-5.3.gradle
+muzzle {
+ pass {
+ group = "org.elasticsearch.client"
+ module = "transport"
+ versions = "[5.3.0,6.0.0)"
+ assertInverse = true
+ }
+ pass {
+ group = "org.elasticsearch"
+ module = "elasticsearch"
+ versions = "[5.3.0,6.0.0)"
+ assertInverse = true
+ }
+}
+
+apply from: "${rootDir}/gradle/java.gradle"
+
+testJava8Minimum += '**/*Test.class'
+
+dependencies {
+ compileOnly group: 'org.elasticsearch.client', name: 'transport', version: '5.3.0'
+
+ compile project(':dd-java-agent:agent-tooling')
+
+ compile deps.bytebuddy
+ compile deps.opentracing
+ annotationProcessor deps.autoservice
+ implementation deps.autoservice
+
+ testCompile project(':dd-java-agent:testing')
+
+ testCompile group: 'org.apache.logging.log4j', name: 'log4j-core', version: '2.11.0'
+ testCompile group: 'org.apache.logging.log4j', name: 'log4j-api', version: '2.11.0'
+
+ testCompile group: 'org.elasticsearch.plugin', name: 'transport-netty3-client', version: '5.3.0'
+ testCompile group: 'org.elasticsearch.client', name: 'transport', version: '5.3.0'
+}

ADD
dd-java-agent/instrumentation/elasticsearch-transport-5.3/src/main/java/datadog/trace/instrumentation/elasticsearch5_3/Elasticsearch53TransportClientInstrumentation.java
+package datadog.trace.instrumentation.elasticsearch5_3;
+
+import static datadog.trace.agent.tooling.ClassLoaderMatcher.classLoaderHasClasses;
+import static io.opentracing.log.Fields.ERROR_OBJECT;
+import static net.bytebuddy.matcher.ElementMatchers.isInterface;
+import static net.bytebuddy.matcher.ElementMatchers.isMethod;
+import static net.bytebuddy.matcher.ElementMatchers.named;
+import static net.bytebuddy.matcher.ElementMatchers.not;
+import static net.bytebuddy.matcher.ElementMatchers.takesArgument;
+
+import com.google.auto.service.AutoService;
+import datadog.trace.agent.tooling.Instrumenter;
+import datadog.trace.api.DDSpanTypes;
+import datadog.trace.api.DDTags;
+import io.opentracing.Scope;
+import io.opentracing.Span;
+import io.opentracing.tag.Tags;
+import io.opentracing.util.GlobalTracer;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import net.bytebuddy.asm.Advice;
+import net.bytebuddy.description.type.TypeDescription;
+import net.bytebuddy.matcher.ElementMatcher;
+import org.elasticsearch.action.Action;
+import org.elasticsearch.action.ActionListener;
+import org.elasticsearch.action.ActionRequest;
+import org.elasticsearch.action.ActionResponse;
+
+/** Beginning in version 5.3.0, DocumentRequest was renamed to DocWriteRequest. */
+@AutoService(Instrumenter.class)
+public class Elasticsearch53TransportClientInstrumentation extends Instrumenter.Default {
+
+ public Elasticsearch53TransportClientInstrumentation() {
+ super("elasticsearch", "elasticsearch-transport", "elasticsearch-transport-5");
+ }
+
+ @Override
+ public ElementMatcher<TypeDescription> typeMatcher() {
+ // If we want to be more generic, we could instrument the interface instead:
+ // .and(safeHasSuperType(named("org.elasticsearch.client.ElasticsearchClient"))))
+ return not(isInterface()).and(named("org.elasticsearch.client.support.AbstractClient"));
+ }
+
+ @Override
+ public ElementMatcher<ClassLoader> classLoaderMatcher() {
+ return classLoaderHasClasses("org.elasticsearch.percolator.TransportMultiPercolateAction");
+ }
+
+ @Override
+ public String[] helperClassNames() {
+ return new String[] {
+ "com.google.common.base.Preconditions",
+ "com.google.common.base.Joiner",
+ "com.google.common.base.Joiner$1",
+ "com.google.common.base.Joiner$2",
+ "com.google.common.base.Joiner$MapJoiner",
+ "datadog.trace.instrumentation.elasticsearch5_3.TransportActionListener"
+ };
+ }
+
+ @Override
+ public Map<ElementMatcher, String> transformers() {
+ final Map<ElementMatcher, String> transformers = new HashMap<>();
+ transformers.put(
+ isMethod()
+ .and(named("execute"))
+ .and(takesArgument(0, named("org.elasticsearch.action.Action")))
+ .and(takesArgument(1, named("org.elasticsearch.action.ActionRequest")))
+ .and(takesArgument(2, named("org.elasticsearch.action.ActionListener"))),
+ ElasticsearchTransportClientAdvice.class.getName());
+ return transformers;
+ }
+
+ public static class ElasticsearchTransportClientAdvice {
+
+ @Advice.OnMethodEnter(suppress = Throwable.class)
+ public static Scope startSpan(
+ @Advice.Argument(0) final Action action,
+ @Advice.Argument(1) final ActionRequest actionRequest,
+ @Advice.Argument(value = 2, readOnly = false)
+ ActionListener<ActionResponse> actionListener) {
+
+ final Scope scope =
+ GlobalTracer.get()
+ .buildSpan("elasticsearch.query")
+ .withTag(DDTags.SERVICE_NAME, "elasticsearch")
+ .withTag(DDTags.RESOURCE_NAME, action.getClass().getSimpleName())
+ .withTag(DDTags.SPAN_TYPE, DDSpanTypes.ELASTICSEARCH)
+ .withTag(Tags.COMPONENT.getKey(), "elasticsearch-java")
+ .withTag(Tags.SPAN_KIND.getKey(), Tags.SPAN_KIND_CLIENT)
+ .withTag("elasticsearch.action", action.getClass().getSimpleName())
+ .withTag("elasticsearch.request", actionRequest.getClass().getSimpleName())
+ .startActive(false);
+
+ actionListener = new TransportActionListener<>(actionRequest, actionListener, scope.span());
+ return scope;
+ }
+
+ @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
+ public static void stopSpan(
+ @Advice.Enter final Scope scope, @Advice.Thrown final Throwable throwable) {
+ if (throwable != null) {
+ final Span span = scope.span();
+ Tags.ERROR.set(span, true);
+ span.log(Collections.singletonMap(ERROR_OBJECT, throwable));
+ span.finish();
+ }
+ scope.close();
+ }
+ }
+}

ADD
dd-java-agent/instrumentation/elasticsearch-transport-5.3/src/main/java/datadog/trace/instrumentation/elasticsearch5_3/TransportActionListener.java
+package datadog.trace.instrumentation.elasticsearch5_3;
+
+import static io.opentracing.log.Fields.ERROR_OBJECT;
+
+import com.google.common.base.Joiner;
+import io.opentracing.Span;
+import io.opentracing.tag.Tags;
+import java.util.Collections;
+import org.elasticsearch.action.ActionListener;
+import org.elasticsearch.action.ActionRequest;
+import org.elasticsearch.action.ActionResponse;
+import org.elasticsearch.action.DocWriteRequest;
+import org.elasticsearch.action.IndicesRequest;
+import org.elasticsearch.action.bulk.BulkShardResponse;
+import org.elasticsearch.action.get.GetResponse;
+import org.elasticsearch.action.index.IndexResponse;
+import org.elasticsearch.action.search.SearchRequest;
+import org.elasticsearch.action.support.broadcast.BroadcastResponse;
+import org.elasticsearch.action.support.nodes.BaseNodesResponse;
+import org.elasticsearch.action.support.replication.ReplicationResponse;
+
+public class TransportActionListener<T extends ActionResponse> implements ActionListener<T> {
+
+ private final ActionListener<T> listener;
+ private final Span span;
+
+ public TransportActionListener(
+ final ActionRequest actionRequest, final ActionListener<T> listener, final Span span) {
+ this.listener = listener;
+ this.span = span;
+ onRequest(actionRequest);
+ }
+
+ private void onRequest(final ActionRequest request) {
+ if (request != null) {
+ span.setTag("elasticsearch.request.description", request.getDescription());
+ }
+ if (request instanceof IndicesRequest) {
+ final IndicesRequest req = (IndicesRequest) request;
+ if (req.indices() != null) {
+ span.setTag("elasticsearch.request.indices", Joiner.on(",").join(req.indices()));
+ }
+ }
+ if (request instanceof SearchRequest) {
+ final SearchRequest req = (SearchRequest) request;
+ span.setTag("elasticsearch.request.search.types", Joiner.on(",").join(req.types()));
+ }
+ if (request instanceof DocWriteRequest) {
+ final DocWriteRequest req = (DocWriteRequest) request;
+ span.setTag("elasticsearch.request.write.type", req.type());
+ span.setTag("elasticsearch.request.write.routing", req.routing());
+ span.setTag("elasticsearch.request.write.version", req.version());
+ }
+ }
+
+ @Override
+ public void onResponse(final T response) {
+ if (response.remoteAddress() != null) {
+ Tags.PEER_HOSTNAME.set(span, response.remoteAddress().getHost());
+ Tags.PEER_HOST_IPV4.set(span, response.remoteAddress().getAddress());
+ Tags.PEER_PORT.set(span, response.remoteAddress().getPort());
+ }
+
+ if (response instanceof GetResponse) {
+ final GetResponse resp = (GetResponse) response;
+ span.setTag("elasticsearch.type", resp.getType());
+ span.setTag("elasticsearch.id", resp.getId());
+ span.setTag("elasticsearch.version", resp.getVersion());
+ }
+
+ if (response instanceof BroadcastResponse) {
+ final BroadcastResponse resp = (BroadcastResponse) response;
+ span.setTag("elasticsearch.shard.broadcast.total", resp.getTotalShards());
+ span.setTag("elasticsearch.shard.broadcast.successful", resp.getSuccessfulShards());
+ span.setTag("elasticsearch.shard.broadcast.failed", resp.getFailedShards());
+ }
+
+ if (response instanceof ReplicationResponse) {
+ final ReplicationResponse resp = (ReplicationResponse) response;
+ span.setTag("elasticsearch.shard.replication.total", resp.getShardInfo().getTotal());
+ span.setTag(
+ "elasticsearch.shard.replication.successful", resp.getShardInfo().getSuccessful());
+ span.setTag("elasticsearch.shard.replication.failed", resp.getShardInfo().getFailed());
+ }
+
+ if (response instanceof IndexResponse) {
+ span.setTag("elasticsearch.response.status", ((IndexResponse) response).status().getStatus());
+ }
+
+ if (response instanceof BulkShardResponse) {
+ final BulkShardResponse resp = (BulkShardResponse) response;
+ span.setTag("elasticsearch.shard.bulk.id", resp.getShardId().getId());
+ span.setTag("elasticsearch.shard.bulk.index", resp.getShardId().getIndexName());
+ }
+
+ if (response instanceof BaseNodesResponse) {
+ final BaseNodesResponse resp = (BaseNodesResponse) response;
+ if (resp.hasFailures()) {
+ span.setTag("elasticsearch.node.failures", resp.failures().size());
+ }
+ span.setTag("elasticsearch.node.cluster.name", resp.getClusterName().value());
+ }
+
+ try {
+ listener.onResponse(response);
+ } finally {
+ span.finish();
+ }
+ }
+
+ @Override
+ public void onFailure(final Exception e) {
+ Tags.ERROR.set(span, true);
+ span.log(Collections.singletonMap(ERROR_OBJECT, e));
+
+ try {
+ listener.onFailure(e);
+ } finally {
+ span.finish();
+ }
+ }
+}

ADD
dd-java-agent/instrumentation/elasticsearch-transport-5.3/src/test/groovy/Elasticsearch53NodeClientTest.groovy
+import com.anotherchrisberry.spock.extensions.retry.RetryOnFailure
+import datadog.trace.agent.test.AgentTestRunner
+import datadog.trace.agent.test.TestUtils
+import datadog.trace.api.DDSpanTypes
+import datadog.trace.api.DDTags
+import io.opentracing.tag.Tags
+import org.elasticsearch.action.admin.cluster.health.ClusterHealthRequest
+import org.elasticsearch.common.io.FileSystemUtils
+import org.elasticsearch.common.settings.Settings
+import org.elasticsearch.env.Environment
+import org.elasticsearch.index.IndexNotFoundException
+import org.elasticsearch.node.Node
+import org.elasticsearch.node.InternalSettingsPreparer
+import org.elasticsearch.transport.Netty3Plugin
+import spock.lang.Shared
+
+import static datadog.trace.agent.test.TestUtils.runUnderTrace
+import static datadog.trace.agent.test.asserts.ListWriterAssert.assertTraces
+import static org.elasticsearch.cluster.ClusterName.CLUSTER_NAME_SETTING
+
+@RetryOnFailure
+class Elasticsearch53NodeClientTest extends AgentTestRunner {
+ public static final long TIMEOUT = 10000; // 10 seconds
+
+ @Shared
+ int httpPort
+ @Shared
+ int tcpPort
+ @Shared
+ Node testNode
+ @Shared
+ File esWorkingDir
+
+ def client = testNode.client()
+
+ def setupSpec() {
+ httpPort = TestUtils.randomOpenPort()
+ tcpPort = TestUtils.randomOpenPort()
+
+ esWorkingDir = File.createTempDir("test-es-working-dir-", "")
+ esWorkingDir.deleteOnExit()
+ println "ES work dir: $esWorkingDir"
+
+ def settings = Settings.builder()
+ .put("path.home", esWorkingDir.path)
+ // Since we use listeners to close spans this should make our span closing deterministic which is good for tests
+ .put("thread_pool.listener.size", 1)
+ .put("http.port", httpPort)
+ .put("transport.tcp.port", tcpPort)
+ .put("transport.type", "netty3")
+ .put("http.type", "netty3")
+ .put(CLUSTER_NAME_SETTING.getKey(), "test-cluster")
+ .build()
+ testNode = new Node(new Environment(InternalSettingsPreparer.prepareSettings(settings)), [Netty3Plugin])
+ testNode.start()
+ runUnderTrace("setup") {
+ // this may potentially create multiple requests and therefore multiple spans, so we wrap this call
+ // into a top level trace to get exactly one trace in the result.
+ testNode.client().admin().cluster().prepareHealth().setWaitForYellowStatus().execute().actionGet(TIMEOUT)
+ }
+ TEST_WRITER.waitForTraces(1)
+ }
+
+ def cleanupSpec() {
+ testNode?.close()
+ if (esWorkingDir != null) {
+ FileSystemUtils.deleteSubDirectories(esWorkingDir.toPath())
+ esWorkingDir.delete()
+ }
+ }
+
+ def "test elasticsearch status"() {
+ setup:
+ def result = client.admin().cluster().health(new ClusterHealthRequest())
+
+ def status = result.get().status
+
+ expect:
+ status.name() == "GREEN"
+
+ assertTraces(TEST_WRITER, 1) {
+ trace(0, 1) {
+ span(0) {
+ serviceName "elasticsearch"
+ resourceName "ClusterHealthAction"
+ operationName "elasticsearch.query"
+ spanType DDSpanTypes.ELASTICSEARCH
+ tags {
+ "$Tags.COMPONENT.key" "elasticsearch-java"
+ "$Tags.SPAN_KIND.key" Tags.SPAN_KIND_CLIENT
+ "$DDTags.SPAN_TYPE" DDSpanTypes.ELASTICSEARCH
+ "elasticsearch.action" "ClusterHealthAction"
+ "elasticsearch.request" "ClusterHealthRequest"
+ defaultTags()
+ }
+ }
+ }
+ }
+ }
+
+ def "test elasticsearch error"() {
+ when:
+ client.prepareGet(indexName, indexType, id).get()
+
+ then:
+ thrown IndexNotFoundException
+
+ and:
+ assertTraces(TEST_WRITER, 1) {
+ trace(0, 1) {
+ span(0) {
+ serviceName "elasticsearch"
+ resourceName "GetAction"
+ operationName "elasticsearch.query"
+ spanType DDSpanTypes.ELASTICSEARCH
+ errored true
+ tags {
+ "$Tags.COMPONENT.key" "elasticsearch-java"
+ "$Tags.SPAN_KIND.key" Tags.SPAN_KIND_CLIENT
+ "$DDTags.SPAN_TYPE" DDSpanTypes.ELASTICSEARCH
+ "elasticsearch.action" "GetAction"
+ "elasticsearch.request" "GetRequest"
+ "elasticsearch.request.indices" indexName
+ errorTags IndexNotFoundException, "no such index"
+ defaultTags()
+ }
+ }
+ }
+ }
+
+ where:
+ indexName = "invalid-index"
+ indexType = "test-type"
+ id = "1"
+ }
+}

ADD
dd-java-agent/instrumentation/elasticsearch-transport-5.3/src/test/groovy/Elasticsearch53TransportClientTest.groovy
+import com.anotherchrisberry.spock.extensions.retry.RetryOnFailure
+import datadog.trace.agent.test.AgentTestRunner
+import datadog.trace.agent.test.TestUtils
+import datadog.trace.api.DDSpanTypes
+import datadog.trace.api.DDTags
+import io.opentracing.tag.Tags
+import org.elasticsearch.action.admin.cluster.health.ClusterHealthRequest
+import org.elasticsearch.client.transport.TransportClient
+import org.elasticsearch.common.io.FileSystemUtils
+import org.elasticsearch.common.settings.Settings
+import org.elasticsearch.common.transport.InetSocketTransportAddress
+import org.elasticsearch.env.Environment
+import org.elasticsearch.index.IndexNotFoundException
+import org.elasticsearch.node.Node
+import org.elasticsearch.node.InternalSettingsPreparer
+import org.elasticsearch.transport.Netty3Plugin
+import org.elasticsearch.transport.RemoteTransportException
+import org.elasticsearch.transport.client.PreBuiltTransportClient
+import spock.lang.Shared
+
+import static datadog.trace.agent.test.TestUtils.runUnderTrace
+import static datadog.trace.agent.test.asserts.ListWriterAssert.assertTraces
+import static org.elasticsearch.cluster.ClusterName.CLUSTER_NAME_SETTING
+
+@RetryOnFailure
+class Elasticsearch53TransportClientTest extends AgentTestRunner {
+ public static final long TIMEOUT = 10000; // 10 seconds
+
+ @Shared
+ int httpPort
+ @Shared
+ int tcpPort
+ @Shared
+ Node testNode
+ @Shared
+ File esWorkingDir
+
+ @Shared
+ TransportClient client
+
+ def setupSpec() {
+ httpPort = TestUtils.randomOpenPort()
+ tcpPort = TestUtils.randomOpenPort()
+
+ esWorkingDir = File.createTempDir("test-es-working-dir-", "")
+ esWorkingDir.deleteOnExit()
+ println "ES work dir: $esWorkingDir"
+
+ def settings = Settings.builder()
+ .put("path.home", esWorkingDir.path)
+ .put("http.port", httpPort)
+ .put("transport.tcp.port", tcpPort)
+ .put("transport.type", "netty3")
+ .put("http.type", "netty3")
+ .put(CLUSTER_NAME_SETTING.getKey(), "test-cluster")
+ .build()
+ testNode = new Node(new Environment(InternalSettingsPreparer.prepareSettings(settings)), [Netty3Plugin])
+ testNode.start()
+
+ client = new PreBuiltTransportClient(
+ Settings.builder()
+ // Since we use listeners to close spans this should make our span closing deterministic which is good for tests
+ .put("thread_pool.listener.size", 1)
+ .put(CLUSTER_NAME_SETTING.getKey(), "test-cluster")
+ .build()
+ )
+ client.addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName("localhost"), tcpPort))
+ runUnderTrace("setup") {
+ // this may potentially create multiple requests and therefore multiple spans, so we wrap this call
+ // into a top level trace to get exactly one trace in the result.
+ client.admin().cluster().prepareHealth().setWaitForYellowStatus().execute().actionGet(TIMEOUT)
+ }
+ TEST_WRITER.waitForTraces(1)
+ }
+
+ def cleanupSpec() {
+ testNode?.close()
+ if (esWorkingDir != null) {
+ FileSystemUtils.deleteSubDirectories(esWorkingDir.toPath())
+ esWorkingDir.delete()
+ }
+ }
+
+ def "test elasticsearch status"() {
+ setup:
+ def result = client.admin().cluster().health(new ClusterHealthRequest())
+
+ def status = result.get().status
+
+ expect:
+ status.name() == "GREEN"
+
+ assertTraces(TEST_WRITER, 1) {
+ trace(0, 1) {
+ span(0) {
+ serviceName "elasticsearch"
+ resourceName "ClusterHealthAction"
+ operationName "elasticsearch.query"
+ spanType DDSpanTypes.ELASTICSEARCH
+ tags {
+ "$Tags.COMPONENT.key" "elasticsearch-java"
+ "$Tags.SPAN_KIND.key" Tags.SPAN_KIND_CLIENT
+ "$DDTags.SPAN_TYPE" DDSpanTypes.ELASTICSEARCH
+ "$Tags.PEER_HOSTNAME.key" "localhost"
+ "$Tags.PEER_HOST_IPV4.key" "127.0.0.1"
+ "$Tags.PEER_PORT.key" tcpPort
+ "elasticsearch.action" "ClusterHealthAction"
+ "elasticsearch.request" "ClusterHealthRequest"
+ defaultTags()
+ }
+ }
+ }
+ }
+ }
+
+ def "test elasticsearch error"() {
+ when:
+ client.prepareGet(indexName, indexType, id).get()
+
+ then:
+ thrown IndexNotFoundException
+
+ and:
+ assertTraces(TEST_WRITER, 1) {
+ trace(0, 1) {
+ span(0) {
+ serviceName "elasticsearch"
+ resourceName "GetAction"
+ operationName "elasticsearch.query"
+ spanType DDSpanTypes.ELASTICSEARCH
+ errored true
+ tags {
+ "$Tags.COMPONENT.key" "elasticsearch-java"
+ "$Tags.SPAN_KIND.key" Tags.SPAN_KIND_CLIENT
+ "$DDTags.SPAN_TYPE" DDSpanTypes.ELASTICSEARCH
+ "elasticsearch.action" "GetAction"
+ "elasticsearch.request" "GetRequest"
+ "elasticsearch.request.indices" indexName
+ errorTags RemoteTransportException, String
+ defaultTags()
+ }
+ }
+ }
+ }
+
+ where:
+ indexName = "invalid-index"
+ indexType = "test-type"
+ id = "1"
+ }
+
+ def "test elasticsearch get"() {
+ setup:
+ assert TEST_WRITER == []
+ def indexResult = client.admin().indices().prepareCreate(indexName).get()
+ TEST_WRITER.waitForTraces(1)
+
+ expect:
+ indexResult.acknowledged
+ TEST_WRITER.size() == 1
+
+ when:
+ def emptyResult = client.prepareGet(indexName, indexType, id).get()
+
+ then:
+ !emptyResult.isExists()
+ emptyResult.id == id
+ emptyResult.type == indexType
+ emptyResult.index == indexName
+
+ when:
+ def createResult = client.prepareIndex(indexName, indexType, id).setSource([:]).get()
+
+ then:
+ createResult.id == id
+ createResult.type == indexType
+ createResult.index == indexName
+ createResult.status().status == 201
+
+ when:
+ def result = client.prepareGet(indexName, indexType, id).get()
+
+ then:
+ result.isExists()
+ result.id == id
+ result.type == indexType
+ result.index == indexName
+
+ and:
+ // IndexAction and PutMappingAction run in separate threads and order in which
+ // these spans are closed is not defined. So we force the order if it is wrong.
+ if (TEST_WRITER[2][0].resourceName == "IndexAction") {
+ def tmp = TEST_WRITER[2]
+ TEST_WRITER[2] = TEST_WRITER[3]
+ TEST_WRITER[3] = tmp
+ }
+ assertTraces(TEST_WRITER, 5) {
+ trace(0, 1) {
+ span(0) {
+ serviceName "elasticsearch"
+ resourceName "CreateIndexAction"
+ operationName "elasticsearch.query"
+ spanType DDSpanTypes.ELASTICSEARCH
+ tags {
+ "$Tags.COMPONENT.key" "elasticsearch-java"
+ "$Tags.SPAN_KIND.key" Tags.SPAN_KIND_CLIENT
+ "$DDTags.SPAN_TYPE" DDSpanTypes.ELASTICSEARCH
+ "$Tags.PEER_HOSTNAME.key" "localhost"
+ "$Tags.PEER_HOST_IPV4.key" "127.0.0.1"
+ "$Tags.PEER_PORT.key" tcpPort
+ "elasticsearch.action" "CreateIndexAction"
+ "elasticsearch.request" "CreateIndexRequest"
+ "elasticsearch.request.indices" indexName
+ defaultTags()
+ }
+ }
+ }
+ trace(1, 1) {
+ span(0) {
+ serviceName "elasticsearch"
+ resourceName "GetAction"
+ operationName "elasticsearch.query"
+ spanType DDSpanTypes.ELASTICSEARCH
+ tags {
+ "$Tags.COMPONENT.key" "elasticsearch-java"
+ "$Tags.SPAN_KIND.key" Tags.SPAN_KIND_CLIENT
+ "$DDTags.SPAN_TYPE" DDSpanTypes.ELASTICSEARCH
+ "$Tags.PEER_HOSTNAME.key" "localhost"
+ "$Tags.PEER_HOST_IPV4.key" "127.0.0.1"
+ "$Tags.PEER_PORT.key" tcpPort
+ "elasticsearch.action" "GetAction"
+ "elasticsearch.request" "GetRequest"
+ "elasticsearch.request.indices" indexName
+ "elasticsearch.type" indexType
+ "elasticsearch.id" "1"
+ "elasticsearch.version"(-1)
+ defaultTags()
+ }
+ }
+ }
+ trace(2, 1) {
+ span(0) {
+ serviceName "elasticsearch"
+ resourceName "PutMappingAction"
+ operationName "elasticsearch.query"
+ spanType DDSpanTypes.ELASTICSEARCH
+ tags {
+ "$Tags.COMPONENT.key" "elasticsearch-java"
+ "$Tags.SPAN_KIND.key" Tags.SPAN_KIND_CLIENT
+ "$DDTags.SPAN_TYPE" DDSpanTypes.ELASTICSEARCH
+ "elasticsearch.action" "PutMappingAction"
+ "elasticsearch.request" "PutMappingRequest"
+ defaultTags()
+ }
+ }
+ }
+ trace(3, 1) {
+ span(0) {
+ serviceName "elasticsearch"
+ resourceName "IndexAction"
+ operationName "elasticsearch.query"
+ spanType DDSpanTypes.ELASTICSEARCH
+ tags {
+ "$Tags.COMPONENT.key" "elasticsearch-java"
+ "$Tags.SPAN_KIND.key" Tags.SPAN_KIND_CLIENT
+ "$DDTags.SPAN_TYPE" DDSpanTypes.ELASTICSEARCH
+ "$Tags.PEER_HOSTNAME.key" "localhost"
+ "$Tags.PEER_HOST_IPV4.key" "127.0.0.1"
+ "$Tags.PEER_PORT.key" tcpPort
+ "elasticsearch.action" "IndexAction"
+ "elasticsearch.request" "IndexRequest"
+ "elasticsearch.request.indices" indexName
+ "elasticsearch.request.write.type" indexType
+ "elasticsearch.request.write.version"(-3)
+ "elasticsearch.response.status" 201
+ "elasticsearch.shard.replication.total" 2
+ "elasticsearch.shard.replication.successful" 1
+ "elasticsearch.shard.replication.failed" 0
+ "elasticsearch.request.description" "index {[$indexName][$indexType][1], source[{}]}"
+ defaultTags()
+ }
+ }
+ }
+ trace(4, 1) {
+ span(0) {
+ serviceName "elasticsearch"
+ resourceName "GetAction"
+ operationName "elasticsearch.query"
+ spanType DDSpanTypes.ELASTICSEARCH
+ tags {
+ "$Tags.COMPONENT.key" "elasticsearch-java"
+ "$Tags.SPAN_KIND.key" Tags.SPAN_KIND_CLIENT
+ "$DDTags.SPAN_TYPE" DDSpanTypes.ELASTICSEARCH
+ "$Tags.PEER_HOSTNAME.key" "localhost"
+ "$Tags.PEER_HOST_IPV4.key" "127.0.0.1"
+ "$Tags.PEER_PORT.key" tcpPort
+ "elasticsearch.action" "GetAction"
+ "elasticsearch.request" "GetRequest"
+ "elasticsearch.request.indices" indexName
+ "elasticsearch.type" indexType
+ "elasticsearch.id" "1"
+ "elasticsearch.version" 1
+ defaultTags()
+ }
+ }
+ }
+ }
+
+ where:
+ indexName = "test-index"
+ indexType = "test-type"
+ id = "1"
+ }
+}

MODIFY
settings.gradle
settings.gradle
@@ -18,6 +18,7 @@ include ':dd-java-agent:instrumentation:datastax-cassandra-3.2'
include ':dd-java-agent:instrumentation:elasticsearch-rest-5'
include ':dd-java-agent:instrumentation:elasticsearch-transport-2'
include ':dd-java-agent:instrumentation:elasticsearch-transport-5'
+include ':dd-java-agent:instrumentation:elasticsearch-transport-5.3'
include ':dd-java-agent:instrumentation:elasticsearch-transport-6'
include ':dd-java-agent:instrumentation:grpc-1.5'
include ':dd-java-agent:instrumentation:http-url-connection'

Elasticsearch 5.3.0 instrumentation