Skip to content

Commit e732a32

Browse files
authored
Add Elasticsearch Java client plugin for 7.16.x-9.x (#804)
Add Elasticsearch Java client (co.elastic.clients:elasticsearch-java) plugin for 7.16.x-9.x Instrument RestClientTransport and ElasticsearchTransportBase to create ExitSpans for Elasticsearch operations. Captures db.type, db.instance (index name), and db.statement (request DSL) tags, aligned with existing ES plugin conventions. Tested across 26 versions covering every minor from 7.16 to 9.3.
1 parent e8795e9 commit e732a32

File tree

33 files changed

+1579
-0
lines changed

33 files changed

+1579
-0
lines changed

.github/workflows/plugins-jdk17-test.1.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ jobs:
8181
- spring-scheduled-6.x-scenario
8282
- caffeine-3.x-scenario
8383
- lettuce-webflux-6x-scenario
84+
- elasticsearch-java-9.x-scenario
8485
steps:
8586
- uses: actions/checkout@v2
8687
with:

.github/workflows/plugins-test.2.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ jobs:
9797
- nacos-client-2.x-scenario
9898
- rocketmq-scenario
9999
- rocketmq-5-grpc-scenario
100+
- elasticsearch-java-scenario
100101
steps:
101102
- uses: actions/checkout@v2
102103
with:

CHANGES.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ Release Notes.
2121
* Enhance test/plugin/run.sh to support extra Maven properties per version in support-version.list (format: version,key=value).
2222
* Add MariaDB 3.x plugin (all classes renamed in 3.x).
2323
* Extend Jedis 4.x plugin to support Jedis 5.x (fix witness method for 5.x compatibility).
24+
* Add Elasticsearch Java client (co.elastic.clients:elasticsearch-java) plugin for 7.x-9.x.
2425

2526
All issues and pull requests are [here](https://github.com/apache/skywalking/milestone/249?closed=1)
2627

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!--
3+
~ Licensed to the Apache Software Foundation (ASF) under one or more
4+
~ contributor license agreements. See the NOTICE file distributed with
5+
~ this work for additional information regarding copyright ownership.
6+
~ The ASF licenses this file to You under the Apache License, Version 2.0
7+
~ (the "License"); you may not use this file except in compliance with
8+
~ the License. You may obtain a copy of the License at
9+
~
10+
~ http://www.apache.org/licenses/LICENSE-2.0
11+
~
12+
~ Unless required by applicable law or agreed to in writing, software
13+
~ distributed under the License is distributed on an "AS IS" BASIS,
14+
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
~ See the License for the specific language governing permissions and
16+
~ limitations under the License.
17+
~
18+
-->
19+
20+
<project xmlns="http://maven.apache.org/POM/4.0.0"
21+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
22+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
23+
<modelVersion>4.0.0</modelVersion>
24+
25+
<parent>
26+
<artifactId>apm-sdk-plugin</artifactId>
27+
<groupId>org.apache.skywalking</groupId>
28+
<version>9.7.0-SNAPSHOT</version>
29+
</parent>
30+
31+
<artifactId>apm-elasticsearch-java-plugin</artifactId>
32+
<packaging>jar</packaging>
33+
34+
<name>elasticsearch-java-plugin</name>
35+
36+
<properties>
37+
<elasticsearch-java.version>8.17.0</elasticsearch-java.version>
38+
</properties>
39+
40+
<dependencies>
41+
<dependency>
42+
<groupId>co.elastic.clients</groupId>
43+
<artifactId>elasticsearch-java</artifactId>
44+
<version>${elasticsearch-java.version}</version>
45+
<scope>provided</scope>
46+
</dependency>
47+
</dependencies>
48+
</project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to You under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* the License. You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*
17+
*/
18+
19+
package org.apache.skywalking.apm.plugin.elasticsearch.java;
20+
21+
import org.apache.skywalking.apm.agent.core.boot.PluginConfig;
22+
23+
public class ElasticsearchPluginConfig {
24+
public static class Plugin {
25+
@PluginConfig(root = ElasticsearchPluginConfig.class)
26+
public static class Elasticsearch {
27+
/**
28+
* If true, trace all the DSL(Domain Specific Language) in ElasticSearch access, default is false
29+
*/
30+
public static boolean TRACE_DSL = false;
31+
32+
public static int ELASTICSEARCH_DSL_LENGTH_THRESHOLD = 1024;
33+
}
34+
}
35+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to You under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* the License. You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*
17+
*/
18+
19+
package org.apache.skywalking.apm.plugin.elasticsearch.java.define;
20+
21+
import net.bytebuddy.description.method.MethodDescription;
22+
import net.bytebuddy.matcher.ElementMatcher;
23+
import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
24+
import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
25+
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine;
26+
import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
27+
28+
import static net.bytebuddy.matcher.ElementMatchers.named;
29+
import static org.apache.skywalking.apm.agent.core.plugin.match.NameMatch.byName;
30+
31+
/**
32+
* Enhance {@code co.elastic.clients.transport.ElasticsearchTransportBase}
33+
* which exists in elasticsearch-java 8.x+. The performRequest method
34+
* moved from RestClientTransport to this base class in 8.x.
35+
* <p>
36+
* The peer is propagated from RestClientTransport (subclass) via dynamic field.
37+
*/
38+
public class ElasticsearchTransportBaseInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
39+
40+
private static final String ENHANCE_CLASS = "co.elastic.clients.transport.ElasticsearchTransportBase";
41+
42+
private static final String PERFORM_REQUEST_INTERCEPTOR =
43+
"org.apache.skywalking.apm.plugin.elasticsearch.java.interceptor.TransportPerformRequestInterceptor";
44+
45+
@Override
46+
protected String[] witnessClasses() {
47+
return new String[] {ENHANCE_CLASS};
48+
}
49+
50+
@Override
51+
protected ClassMatch enhanceClass() {
52+
return byName(ENHANCE_CLASS);
53+
}
54+
55+
@Override
56+
public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
57+
return new ConstructorInterceptPoint[0];
58+
}
59+
60+
@Override
61+
public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
62+
return new InstanceMethodsInterceptPoint[] {
63+
new InstanceMethodsInterceptPoint() {
64+
@Override
65+
public ElementMatcher<MethodDescription> getMethodsMatcher() {
66+
return named("performRequest");
67+
}
68+
69+
@Override
70+
public String getMethodsInterceptor() {
71+
return PERFORM_REQUEST_INTERCEPTOR;
72+
}
73+
74+
@Override
75+
public boolean isOverrideArgs() {
76+
return false;
77+
}
78+
}
79+
};
80+
}
81+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to You under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* the License. You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*
17+
*/
18+
19+
package org.apache.skywalking.apm.plugin.elasticsearch.java.define;
20+
21+
import net.bytebuddy.description.method.MethodDescription;
22+
import net.bytebuddy.matcher.ElementMatcher;
23+
import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
24+
import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
25+
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine;
26+
import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
27+
28+
import static net.bytebuddy.matcher.ElementMatchers.named;
29+
import static org.apache.skywalking.apm.agent.core.plugin.bytebuddy.ArgumentTypeNameMatch.takesArgumentWithType;
30+
import static org.apache.skywalking.apm.agent.core.plugin.match.NameMatch.byName;
31+
32+
/**
33+
* Enhance {@code co.elastic.clients.transport.rest_client.RestClientTransport}
34+
* for the Elasticsearch Java client (co.elastic.clients:elasticsearch-java).
35+
* <p>
36+
* Covers both 7.x (performRequest on RestClientTransport) and 8.x+
37+
* (performRequest inherited from ElasticsearchTransportBase, but constructor on RestClientTransport).
38+
*/
39+
public class RestClientTransportInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
40+
41+
private static final String ENHANCE_CLASS = "co.elastic.clients.transport.rest_client.RestClientTransport";
42+
43+
private static final String CONSTRUCTOR_INTERCEPTOR =
44+
"org.apache.skywalking.apm.plugin.elasticsearch.java.interceptor.RestClientTransportConstructorInterceptor";
45+
46+
private static final String PERFORM_REQUEST_INTERCEPTOR =
47+
"org.apache.skywalking.apm.plugin.elasticsearch.java.interceptor.TransportPerformRequestInterceptor";
48+
49+
@Override
50+
protected String[] witnessClasses() {
51+
return new String[] {ENHANCE_CLASS};
52+
}
53+
54+
@Override
55+
protected ClassMatch enhanceClass() {
56+
return byName(ENHANCE_CLASS);
57+
}
58+
59+
@Override
60+
public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
61+
return new ConstructorInterceptPoint[] {
62+
new ConstructorInterceptPoint() {
63+
@Override
64+
public ElementMatcher<MethodDescription> getConstructorMatcher() {
65+
return takesArgumentWithType(0, "org.elasticsearch.client.RestClient");
66+
}
67+
68+
@Override
69+
public String getConstructorInterceptor() {
70+
return CONSTRUCTOR_INTERCEPTOR;
71+
}
72+
}
73+
};
74+
}
75+
76+
@Override
77+
public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
78+
return new InstanceMethodsInterceptPoint[] {
79+
new InstanceMethodsInterceptPoint() {
80+
@Override
81+
public ElementMatcher<MethodDescription> getMethodsMatcher() {
82+
return named("performRequest");
83+
}
84+
85+
@Override
86+
public String getMethodsInterceptor() {
87+
return PERFORM_REQUEST_INTERCEPTOR;
88+
}
89+
90+
@Override
91+
public boolean isOverrideArgs() {
92+
return false;
93+
}
94+
}
95+
};
96+
}
97+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to You under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* the License. You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*
17+
*/
18+
19+
package org.apache.skywalking.apm.plugin.elasticsearch.java.interceptor;
20+
21+
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
22+
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceConstructorInterceptor;
23+
import org.elasticsearch.client.Node;
24+
import org.elasticsearch.client.RestClient;
25+
26+
import java.util.List;
27+
import java.util.stream.Collectors;
28+
29+
/**
30+
* Intercept RestClientTransport constructor to extract peer address from RestClient nodes.
31+
*/
32+
public class RestClientTransportConstructorInterceptor implements InstanceConstructorInterceptor {
33+
34+
@Override
35+
public void onConstruct(EnhancedInstance objInst, Object[] allArguments) {
36+
RestClient restClient = (RestClient) allArguments[0];
37+
List<Node> nodes = restClient.getNodes();
38+
String peers = nodes.stream()
39+
.map(node -> node.getHost().toHostString())
40+
.collect(Collectors.joining(","));
41+
objInst.setSkyWalkingDynamicField(peers);
42+
}
43+
}

0 commit comments

Comments
 (0)