excludePortsCache;
@Override
public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes,
MethodInterceptResult result) throws Throwable {
- if (allArguments[0] == null || allArguments[1] == null) {
- // illegal args, can't trace. ignore.
+ if (skipIntercept(allArguments)) {
return;
}
final HttpHost httpHost = (HttpHost) allArguments[0];
@@ -82,7 +95,7 @@ public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allAr
@Override
public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes,
Object ret) throws Throwable {
- if (allArguments[0] == null || allArguments[1] == null) {
+ if (skipIntercept(allArguments)) {
return ret;
}
@@ -111,10 +124,62 @@ public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allA
@Override
public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments,
Class>[] argumentsTypes, Throwable t) {
+ if (skipIntercept(allArguments)) {
+ return;
+ }
AbstractSpan activeSpan = ContextManager.activeSpan();
activeSpan.log(t);
}
+ private boolean skipIntercept(Object[] allArguments) {
+ if (allArguments[0] == null || allArguments[1] == null) {
+ return true;
+ }
+ HttpHost httpHost = (HttpHost) allArguments[0];
+ return isExcludedPort(port(httpHost));
+ }
+
+ /**
+ * Returns {@code true} when {@code port} is listed in
+ * {@link HttpClientPluginConfig.Plugin.HttpClient#PROPAGATION_EXCLUDE_PORTS}.
+ *
+ * The config value is parsed lazily and cached so that it is read after
+ * the agent has fully initialised its configuration subsystem.
+ */
+ private boolean isExcludedPort(int port) {
+ if (port <= 0) {
+ return false;
+ }
+ if (excludePortsCache == null) {
+ synchronized (this) {
+ if (excludePortsCache == null) {
+ excludePortsCache = parseExcludePorts(
+ HttpClientPluginConfig.Plugin.HttpClient.PROPAGATION_EXCLUDE_PORTS);
+ }
+ }
+ }
+ return excludePortsCache.contains(port);
+ }
+
+ private static Set parseExcludePorts(String raw) {
+ if (raw == null || raw.trim().isEmpty()) {
+ return Collections.emptySet();
+ }
+ return Arrays.stream(raw.split(","))
+ .map(String::trim)
+ .filter(s -> !s.isEmpty())
+ .map(s -> {
+ try {
+ return Integer.parseInt(s);
+ } catch (NumberFormatException e) {
+ LOGGER.warn("Ignoring invalid port in PROPAGATION_EXCLUDE_PORTS: {}", s);
+ return -1;
+ }
+ })
+ .filter(p -> p > 0)
+ .collect(Collectors.toSet());
+ }
+
private String getRequestURI(String uri) {
if (isUrl(uri)) {
String requestPath;
diff --git a/apm-sniffer/apm-sdk-plugin/httpClient-4.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/httpClient/v4/HttpClientPropagationExcludePortTest.java b/apm-sniffer/apm-sdk-plugin/httpClient-4.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/httpClient/v4/HttpClientPropagationExcludePortTest.java
new file mode 100644
index 0000000000..9975bd92fc
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/httpClient-4.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/httpClient/v4/HttpClientPropagationExcludePortTest.java
@@ -0,0 +1,203 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.httpClient.v4;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import static org.mockito.Mockito.mock;
+
+import java.util.List;
+
+import org.apache.http.HttpHost;
+import org.apache.http.HttpResponse;
+import org.apache.http.ProtocolVersion;
+import org.apache.http.RequestLine;
+import org.apache.http.StatusLine;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.skywalking.apm.agent.core.boot.ServiceManager;
+import org.apache.skywalking.apm.agent.core.context.trace.TraceSegment;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
+import org.apache.skywalking.apm.agent.test.tools.AgentServiceRule;
+import org.apache.skywalking.apm.agent.test.tools.SegmentStorage;
+import org.apache.skywalking.apm.agent.test.tools.SegmentStoragePoint;
+import org.apache.skywalking.apm.agent.test.tools.TracingSegmentRunner;
+import org.apache.skywalking.apm.plugin.httpclient.HttpClientPluginConfig;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+
+/**
+ * Verifies that requests to ports listed in
+ * {@link HttpClientPluginConfig.Plugin.HttpClient#PROPAGATION_EXCLUDE_PORTS}
+ * are silently skipped (no span created, no sw8 header injected).
+ */
+@RunWith(TracingSegmentRunner.class)
+public class HttpClientPropagationExcludePortTest {
+
+ @SegmentStoragePoint
+ private SegmentStorage segmentStorage;
+
+ @Rule
+ public AgentServiceRule agentServiceRule = new AgentServiceRule();
+ @Rule
+ public MockitoRule rule = MockitoJUnit.rule();
+
+ @Mock
+ private HttpHost clickHouseHost;
+ @Mock
+ private HttpHost regularHost;
+ @Mock
+ private HttpGet request;
+ @Mock
+ private HttpResponse httpResponse;
+ @Mock
+ private StatusLine statusLine;
+ @Mock
+ private EnhancedInstance enhancedInstance;
+
+ private HttpClientExecuteInterceptor interceptor;
+
+ private Object[] clickHouseArgs;
+ private Object[] regularArgs;
+ private Class>[] argumentsType;
+
+ @Before
+ public void setUp() throws Exception {
+ ServiceManager.INSTANCE.boot();
+
+ HttpClientPluginConfig.Plugin.HttpClient.PROPAGATION_EXCLUDE_PORTS = "8123";
+ interceptor = new HttpClientExecuteInterceptor();
+
+ when(statusLine.getStatusCode()).thenReturn(200);
+ when(httpResponse.getStatusLine()).thenReturn(statusLine);
+
+ RequestLine requestLine = new RequestLine() {
+ @Override
+ public String getMethod() {
+ return "GET";
+ }
+
+ @Override
+ public ProtocolVersion getProtocolVersion() {
+ return new ProtocolVersion("http", 1, 1);
+ }
+
+ @Override
+ public String getUri() {
+ return "http://my-service:8080/api/ping";
+ }
+ };
+ when(request.getRequestLine()).thenReturn(requestLine);
+
+ when(clickHouseHost.getHostName()).thenReturn("clickhouse-server");
+ when(clickHouseHost.getSchemeName()).thenReturn("http");
+ when(clickHouseHost.getPort()).thenReturn(8123);
+
+ when(regularHost.getHostName()).thenReturn("my-service");
+ when(regularHost.getSchemeName()).thenReturn("http");
+ when(regularHost.getPort()).thenReturn(8080);
+
+ clickHouseArgs = new Object[]{clickHouseHost, request};
+ regularArgs = new Object[]{regularHost, request};
+ argumentsType = new Class[]{HttpHost.class, HttpGet.class};
+ }
+
+ @Test
+ public void requestToExcludedPort_noSpanAndNoHeaderInjected() throws Throwable {
+ interceptor.beforeMethod(enhancedInstance, null, clickHouseArgs, argumentsType, null);
+ interceptor.afterMethod(enhancedInstance, null, clickHouseArgs, argumentsType, httpResponse);
+
+ List segments = segmentStorage.getTraceSegments();
+ assertThat(segments.size(), is(0));
+ verify(request, never()).setHeader(anyString(), anyString());
+ }
+
+ @Test
+ public void requestToRegularPort_spanCreatedAndHeadersInjected() throws Throwable {
+ interceptor.beforeMethod(enhancedInstance, null, regularArgs, argumentsType, null);
+ interceptor.afterMethod(enhancedInstance, null, regularArgs, argumentsType, httpResponse);
+
+ List segments = segmentStorage.getTraceSegments();
+ assertThat(segments.size(), is(1));
+ verify(request, times(3)).setHeader(anyString(), anyString());
+ }
+
+ @Test
+ public void whenExcludePortsEmpty_allPortsAreTraced() throws Throwable {
+ HttpClientPluginConfig.Plugin.HttpClient.PROPAGATION_EXCLUDE_PORTS = "";
+
+ HttpClientExecuteInterceptor freshInterceptor = new HttpClientExecuteInterceptor();
+ freshInterceptor.beforeMethod(enhancedInstance, null, clickHouseArgs, argumentsType, null);
+ freshInterceptor.afterMethod(enhancedInstance, null, clickHouseArgs, argumentsType, httpResponse);
+
+ List segments = segmentStorage.getTraceSegments();
+ assertThat(segments.size(), is(1));
+ }
+
+ @Test
+ public void multipleExcludedPorts_allSkippedAndNonExcludedStillTraced() throws Throwable {
+ HttpClientPluginConfig.Plugin.HttpClient.PROPAGATION_EXCLUDE_PORTS = "8123,9200";
+
+ HttpClientExecuteInterceptor freshInterceptor = new HttpClientExecuteInterceptor();
+
+ // 8123 should be excluded
+ freshInterceptor.beforeMethod(enhancedInstance, null, clickHouseArgs, argumentsType, null);
+ freshInterceptor.afterMethod(enhancedInstance, null, clickHouseArgs, argumentsType, httpResponse);
+ assertThat(segmentStorage.getTraceSegments().size(), is(0));
+
+ // 9200 should also be excluded
+ HttpHost esHost = mock(HttpHost.class);
+ when(esHost.getHostName()).thenReturn("es-server");
+ when(esHost.getSchemeName()).thenReturn("http");
+ when(esHost.getPort()).thenReturn(9200);
+ Object[] esArgs = new Object[]{esHost, request};
+
+ freshInterceptor = new HttpClientExecuteInterceptor();
+ HttpClientPluginConfig.Plugin.HttpClient.PROPAGATION_EXCLUDE_PORTS = "8123,9200";
+ freshInterceptor.beforeMethod(enhancedInstance, null, esArgs, argumentsType, null);
+ freshInterceptor.afterMethod(enhancedInstance, null, esArgs, argumentsType, httpResponse);
+ assertThat(segmentStorage.getTraceSegments().size(), is(0));
+
+ // 8080 should still be traced
+ freshInterceptor = new HttpClientExecuteInterceptor();
+ HttpClientPluginConfig.Plugin.HttpClient.PROPAGATION_EXCLUDE_PORTS = "8123,9200";
+ freshInterceptor.beforeMethod(enhancedInstance, null, regularArgs, argumentsType, null);
+ freshInterceptor.afterMethod(enhancedInstance, null, regularArgs, argumentsType, httpResponse);
+ assertThat(segmentStorage.getTraceSegments().size(), is(1));
+ }
+
+ @Test
+ public void excludedPort_handleMethodExceptionSkipped() throws Throwable {
+ interceptor.beforeMethod(enhancedInstance, null, clickHouseArgs, argumentsType, null);
+ interceptor.handleMethodException(enhancedInstance, null, clickHouseArgs, argumentsType, new RuntimeException("test"));
+ interceptor.afterMethod(enhancedInstance, null, clickHouseArgs, argumentsType, httpResponse);
+
+ List segments = segmentStorage.getTraceSegments();
+ assertThat(segments.size(), is(0));
+ }
+}
diff --git a/apm-sniffer/apm-sdk-plugin/httpasyncclient-4.x-plugin/pom.xml b/apm-sniffer/apm-sdk-plugin/httpasyncclient-4.x-plugin/pom.xml
index 87656a9dbc..2cd5025cd6 100644
--- a/apm-sniffer/apm-sdk-plugin/httpasyncclient-4.x-plugin/pom.xml
+++ b/apm-sniffer/apm-sdk-plugin/httpasyncclient-4.x-plugin/pom.xml
@@ -22,7 +22,7 @@
org.apache.skywalking
apm-sdk-plugin
- 9.3.0-SNAPSHOT
+ 9.7.0-SNAPSHOT
apm-httpasyncclient-4.x-plugin
diff --git a/apm-sniffer/apm-sdk-plugin/httpclient-3.x-plugin/pom.xml b/apm-sniffer/apm-sdk-plugin/httpclient-3.x-plugin/pom.xml
index e03fcef53c..2127da9e0d 100644
--- a/apm-sniffer/apm-sdk-plugin/httpclient-3.x-plugin/pom.xml
+++ b/apm-sniffer/apm-sdk-plugin/httpclient-3.x-plugin/pom.xml
@@ -23,7 +23,7 @@
org.apache.skywalking
apm-sdk-plugin
- 9.3.0-SNAPSHOT
+ 9.7.0-SNAPSHOT
apm-httpclient-3.x-plugin
diff --git a/apm-sniffer/apm-sdk-plugin/httpclient-5.x-plugin/pom.xml b/apm-sniffer/apm-sdk-plugin/httpclient-5.x-plugin/pom.xml
index d205761cee..ba159639a4 100644
--- a/apm-sniffer/apm-sdk-plugin/httpclient-5.x-plugin/pom.xml
+++ b/apm-sniffer/apm-sdk-plugin/httpclient-5.x-plugin/pom.xml
@@ -22,7 +22,7 @@
org.apache.skywalking
apm-sdk-plugin
- 9.3.0-SNAPSHOT
+ 9.7.0-SNAPSHOT
apm-httpclient-5.x-plugin
@@ -46,7 +46,6 @@
junit
junit
- ${junit.version}
test
diff --git a/apm-sniffer/apm-sdk-plugin/httpclient-5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/httpclient/v5/HttpClient5PluginConfig.java b/apm-sniffer/apm-sdk-plugin/httpclient-5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/httpclient/v5/HttpClient5PluginConfig.java
new file mode 100644
index 0000000000..3b6aaf6aa9
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/httpclient-5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/httpclient/v5/HttpClient5PluginConfig.java
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.httpclient.v5;
+
+import org.apache.skywalking.apm.agent.core.boot.PluginConfig;
+
+public class HttpClient5PluginConfig {
+ public static class Plugin {
+ @PluginConfig(root = HttpClient5PluginConfig.class)
+ public static class HttpClient5 {
+ /**
+ * Comma-separated list of destination ports whose outbound HTTP requests
+ * will be completely skipped by the classic client interceptor: no exit
+ * span is created and no SkyWalking propagation headers are injected.
+ *
+ * Some HTTP-based database protocols (e.g. ClickHouse on port 8123)
+ * reject requests that contain unknown HTTP headers, returning HTTP 400.
+ * Adding such ports here prevents the agent from creating exit spans
+ * and from injecting the {@code sw8} tracing headers into those outbound
+ * requests, meaning these requests are completely untraced by SkyWalking,
+ * while leaving all other HTTP calls fully traced.
+ *
+ *
Default: {@code "8123"} (ClickHouse HTTP interface).
+ *
+ *
Example – also exclude port 9200 (Elasticsearch):
+ * {@code plugin.httpclient5.PROPAGATION_EXCLUDE_PORTS=8123,9200}
+ */
+ public static String PROPAGATION_EXCLUDE_PORTS = "8123";
+ }
+ }
+}
diff --git a/apm-sniffer/apm-sdk-plugin/httpclient-5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/httpclient/v5/HttpClientDoExecuteInterceptor.java b/apm-sniffer/apm-sdk-plugin/httpclient-5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/httpclient/v5/HttpClientDoExecuteInterceptor.java
index d53eb7a246..238a745b69 100644
--- a/apm-sniffer/apm-sdk-plugin/httpclient-5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/httpclient/v5/HttpClientDoExecuteInterceptor.java
+++ b/apm-sniffer/apm-sdk-plugin/httpclient-5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/httpclient/v5/HttpClientDoExecuteInterceptor.java
@@ -37,12 +37,23 @@
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Set;
+import java.util.stream.Collectors;
public abstract class HttpClientDoExecuteInterceptor implements InstanceMethodsAroundInterceptor {
private static final String ERROR_URI = "/_blank";
private static final ILog LOGGER = LogManager.getLogger(HttpClientDoExecuteInterceptor.class);
+ /**
+ * Lazily-resolved set of ports that must not receive SkyWalking
+ * propagation headers. Built once from
+ * {@link HttpClient5PluginConfig.Plugin.HttpClient5#PROPAGATION_EXCLUDE_PORTS}.
+ */
+ private volatile Set excludePortsCache;
+
@Override
public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes,
MethodInterceptResult result) throws Throwable {
@@ -77,7 +88,55 @@ public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allAr
protected boolean skipIntercept(EnhancedInstance objInst, Method method, Object[] allArguments,
Class>[] argumentsTypes) {
- return allArguments[1] == null || getHttpHost(objInst, method, allArguments, argumentsTypes) == null;
+ if (allArguments[1] == null) {
+ return true;
+ }
+ HttpHost host = getHttpHost(objInst, method, allArguments, argumentsTypes);
+ if (host == null) {
+ return true;
+ }
+ return isExcludedPort(port(host));
+ }
+
+ /**
+ * Returns {@code true} when {@code port} is listed in
+ * {@link HttpClient5PluginConfig.Plugin.HttpClient5#PROPAGATION_EXCLUDE_PORTS}.
+ *
+ * The config value is parsed lazily and cached so that it is read after
+ * the agent has fully initialised its configuration subsystem.
+ */
+ private boolean isExcludedPort(int port) {
+ if (port <= 0) {
+ return false;
+ }
+ if (excludePortsCache == null) {
+ synchronized (this) {
+ if (excludePortsCache == null) {
+ excludePortsCache = parseExcludePorts(
+ HttpClient5PluginConfig.Plugin.HttpClient5.PROPAGATION_EXCLUDE_PORTS);
+ }
+ }
+ }
+ return excludePortsCache.contains(port);
+ }
+
+ private static Set parseExcludePorts(String raw) {
+ if (raw == null || raw.trim().isEmpty()) {
+ return Collections.emptySet();
+ }
+ return Arrays.stream(raw.split(","))
+ .map(String::trim)
+ .filter(s -> !s.isEmpty())
+ .map(s -> {
+ try {
+ return Integer.parseInt(s);
+ } catch (NumberFormatException e) {
+ LOGGER.warn("Ignoring invalid port in PROPAGATION_EXCLUDE_PORTS: {}", s);
+ return -1;
+ }
+ })
+ .filter(p -> p > 0)
+ .collect(Collectors.toSet());
}
protected abstract HttpHost getHttpHost(EnhancedInstance objInst, Method method, Object[] allArguments,
diff --git a/apm-sniffer/apm-sdk-plugin/httpclient-5.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/httpclient/v5/HttpClientPropagationExcludePortTest.java b/apm-sniffer/apm-sdk-plugin/httpclient-5.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/httpclient/v5/HttpClientPropagationExcludePortTest.java
new file mode 100644
index 0000000000..717eb61a3e
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/httpclient-5.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/httpclient/v5/HttpClientPropagationExcludePortTest.java
@@ -0,0 +1,244 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.httpclient.v5;
+
+import org.apache.hc.core5.http.ClassicHttpRequest;
+import org.apache.hc.core5.http.ClassicHttpResponse;
+import org.apache.hc.core5.http.HttpHost;
+import org.apache.skywalking.apm.agent.core.boot.ServiceManager;
+import org.apache.skywalking.apm.agent.core.context.trace.TraceSegment;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
+import org.apache.skywalking.apm.agent.test.tools.AgentServiceRule;
+import org.apache.skywalking.apm.agent.test.tools.SegmentStorage;
+import org.apache.skywalking.apm.agent.test.tools.SegmentStoragePoint;
+import org.apache.skywalking.apm.agent.test.tools.TracingSegmentRunner;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+
+import java.net.URI;
+import java.util.List;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+/**
+ * Verifies that requests to ports listed in
+ * {@link HttpClient5PluginConfig.Plugin.HttpClient5#PROPAGATION_EXCLUDE_PORTS}
+ * are silently skipped (no span created, no {@code sw8} header injected).
+ *
+ * This regression-covers the ClickHouse HTTP-interface issue: ClickHouse
+ * listens on port 8123 and rejects HTTP requests that carry unknown headers
+ * (such as the SkyWalking {@code sw8} propagation header), responding with
+ * HTTP 400 Bad Request. By excluding port 8123 the agent leaves those
+ * requests untouched while continuing to trace all other HTTP calls.
+ */
+@RunWith(TracingSegmentRunner.class)
+public class HttpClientPropagationExcludePortTest {
+
+ @SegmentStoragePoint
+ private SegmentStorage segmentStorage;
+
+ @Rule
+ public AgentServiceRule agentServiceRule = new AgentServiceRule();
+ @Rule
+ public MockitoRule rule = MockitoJUnit.rule();
+
+ @Mock
+ private HttpHost clickHouseHost; // port 8123 – should be excluded
+ @Mock
+ private HttpHost regularHost; // port 8080 – should be traced
+ @Mock
+ private ClassicHttpRequest request;
+ @Mock
+ private ClassicHttpResponse httpResponse;
+ @Mock
+ private EnhancedInstance enhancedInstance;
+
+ private HttpClientDoExecuteInterceptor internalInterceptor;
+ private HttpClientDoExecuteInterceptor minimalInterceptor;
+
+ private Object[] clickHouseArgs;
+ private Object[] regularArgs;
+ private Class>[] argumentsType;
+
+ @Before
+ public void setUp() throws Exception {
+ ServiceManager.INSTANCE.boot();
+
+ // Set the exclusion list to the default (includes 8123)
+ HttpClient5PluginConfig.Plugin.HttpClient5.PROPAGATION_EXCLUDE_PORTS = "8123";
+
+ internalInterceptor = new InternalClientDoExecuteInterceptor();
+ minimalInterceptor = new MinimalClientDoExecuteInterceptor();
+
+ when(httpResponse.getCode()).thenReturn(200);
+
+ // ClickHouse-like host on port 8123
+ when(clickHouseHost.getHostName()).thenReturn("clickhouse-server");
+ when(clickHouseHost.getSchemeName()).thenReturn("http");
+ when(clickHouseHost.getPort()).thenReturn(8123);
+
+ // Regular application host on port 8080
+ when(regularHost.getHostName()).thenReturn("my-service");
+ when(regularHost.getSchemeName()).thenReturn("http");
+ when(regularHost.getPort()).thenReturn(8080);
+
+ when(request.getUri()).thenReturn(new URI("http://my-service:8080/api/ping"));
+ when(request.getMethod()).thenReturn("GET");
+
+ clickHouseArgs = new Object[]{clickHouseHost, request};
+ regularArgs = new Object[]{regularHost, request};
+ argumentsType = new Class[]{HttpHost.class, ClassicHttpRequest.class};
+ }
+
+ // -----------------------------------------------------------------------
+ // InternalHttpClient path
+ // -----------------------------------------------------------------------
+
+ /**
+ * Requests to port 8123 via {@code InternalHttpClient} must not produce a
+ * trace segment and must NOT set any propagation header on the request.
+ *
+ *
Before this fix the agent injected {@code sw8} (and two companion
+ * headers) into every outbound request regardless of the destination port.
+ * ClickHouse interprets unknown headers as malformed requests and returns
+ * HTTP 400, making all JDBC queries fail while the SkyWalking agent is
+ * attached.
+ */
+ @Test
+ public void internalClient_requestToExcludedPort_noSpanAndNoHeaderInjected() throws Throwable {
+ internalInterceptor.beforeMethod(enhancedInstance, null, clickHouseArgs, argumentsType, null);
+ internalInterceptor.afterMethod(enhancedInstance, null, clickHouseArgs, argumentsType, httpResponse);
+
+ List segments = segmentStorage.getTraceSegments();
+ assertThat("No trace segment should be created for excluded port", segments.size(), is(0));
+ verify(request, never()).setHeader(anyString(), anyString());
+ }
+
+ /**
+ * Requests to a non-excluded port via {@code InternalHttpClient} must still
+ * be traced and have propagation headers injected.
+ */
+ @Test
+ public void internalClient_requestToRegularPort_spanCreatedAndHeadersInjected() throws Throwable {
+ internalInterceptor.beforeMethod(enhancedInstance, null, regularArgs, argumentsType, null);
+ internalInterceptor.afterMethod(enhancedInstance, null, regularArgs, argumentsType, httpResponse);
+
+ List segments = segmentStorage.getTraceSegments();
+ assertThat("A trace segment must be created for a non-excluded port", segments.size(), is(1));
+ // sw8, sw8-correlation, sw8-x – exactly 3 propagation headers, consistent with existing tests
+ verify(request, org.mockito.Mockito.times(3)).setHeader(anyString(), anyString());
+ }
+
+ // -----------------------------------------------------------------------
+ // MinimalHttpClient path
+ // -----------------------------------------------------------------------
+
+ /**
+ * Same assertion for the {@code MinimalHttpClient} code path.
+ */
+ @Test
+ public void minimalClient_requestToExcludedPort_noSpanAndNoHeaderInjected() throws Throwable {
+ minimalInterceptor.beforeMethod(enhancedInstance, null, clickHouseArgs, argumentsType, null);
+ minimalInterceptor.afterMethod(enhancedInstance, null, clickHouseArgs, argumentsType, httpResponse);
+
+ List segments = segmentStorage.getTraceSegments();
+ assertThat("No trace segment should be created for excluded port", segments.size(), is(0));
+ verify(request, never()).setHeader(anyString(), anyString());
+ }
+
+ /**
+ * Normal (non-excluded) port via {@code MinimalHttpClient} must still be
+ * traced.
+ */
+ @Test
+ public void minimalClient_requestToRegularPort_spanCreatedAndHeadersInjected() throws Throwable {
+ minimalInterceptor.beforeMethod(enhancedInstance, null, regularArgs, argumentsType, null);
+ minimalInterceptor.afterMethod(enhancedInstance, null, regularArgs, argumentsType, httpResponse);
+
+ List segments = segmentStorage.getTraceSegments();
+ assertThat("A trace segment must be created for a non-excluded port", segments.size(), is(1));
+ verify(request, org.mockito.Mockito.times(3)).setHeader(anyString(), anyString());
+ }
+
+ // -----------------------------------------------------------------------
+ // Configuration edge cases
+ // -----------------------------------------------------------------------
+
+ /**
+ * When {@code PROPAGATION_EXCLUDE_PORTS} is cleared (empty string), every
+ * port – including 8123 – must be traced normally.
+ */
+ @Test
+ public void whenExcludePortsEmpty_allPortsAreTraced() throws Throwable {
+ HttpClient5PluginConfig.Plugin.HttpClient5.PROPAGATION_EXCLUDE_PORTS = "";
+
+ // Use a fresh interceptor so the cache is not pre-populated
+ HttpClientDoExecuteInterceptor freshInterceptor = new MinimalClientDoExecuteInterceptor();
+ freshInterceptor.beforeMethod(enhancedInstance, null, clickHouseArgs, argumentsType, null);
+ freshInterceptor.afterMethod(enhancedInstance, null, clickHouseArgs, argumentsType, httpResponse);
+
+ List segments = segmentStorage.getTraceSegments();
+ assertThat("Port 8123 should be traced when exclusion list is empty", segments.size(), is(1));
+ }
+
+ /**
+ * Multiple ports can be listed: verify that both excluded ports are silently
+ * skipped while a non-excluded port is still traced under the same config.
+ */
+ @Test
+ public void multipleExcludedPorts_allSkippedAndNonExcludedStillTraced() throws Throwable {
+ HttpClient5PluginConfig.Plugin.HttpClient5.PROPAGATION_EXCLUDE_PORTS = "8123,9200";
+
+ HttpClientDoExecuteInterceptor freshInterceptor = new MinimalClientDoExecuteInterceptor();
+
+ // 8123 – must be excluded
+ freshInterceptor.beforeMethod(enhancedInstance, null, clickHouseArgs, argumentsType, null);
+ freshInterceptor.afterMethod(enhancedInstance, null, clickHouseArgs, argumentsType, httpResponse);
+ assertThat("Port 8123 should be excluded", segmentStorage.getTraceSegments().size(), is(0));
+
+ // 9200 (Elasticsearch) – must also be excluded
+ HttpHost esHost = org.mockito.Mockito.mock(HttpHost.class);
+ when(esHost.getHostName()).thenReturn("es-server");
+ when(esHost.getSchemeName()).thenReturn("http");
+ when(esHost.getPort()).thenReturn(9200);
+ Object[] esArgs = new Object[]{esHost, request};
+
+ freshInterceptor = new MinimalClientDoExecuteInterceptor();
+ freshInterceptor.beforeMethod(enhancedInstance, null, esArgs, argumentsType, null);
+ freshInterceptor.afterMethod(enhancedInstance, null, esArgs, argumentsType, httpResponse);
+ assertThat("Port 9200 should also be excluded", segmentStorage.getTraceSegments().size(), is(0));
+
+ // 8080 (regular service) – must still be traced under the same multi-port config
+ freshInterceptor = new MinimalClientDoExecuteInterceptor();
+ freshInterceptor.beforeMethod(enhancedInstance, null, regularArgs, argumentsType, null);
+ freshInterceptor.afterMethod(enhancedInstance, null, regularArgs, argumentsType, httpResponse);
+ assertThat("Non-excluded port 8080 must still produce a trace segment",
+ segmentStorage.getTraceSegments().size(), is(1));
+ }
+}
diff --git a/apm-sniffer/apm-sdk-plugin/httpclient-commons/pom.xml b/apm-sniffer/apm-sdk-plugin/httpclient-commons/pom.xml
index e0cdc80bbe..c9976aadf2 100644
--- a/apm-sniffer/apm-sdk-plugin/httpclient-commons/pom.xml
+++ b/apm-sniffer/apm-sdk-plugin/httpclient-commons/pom.xml
@@ -22,7 +22,7 @@
apm-sdk-plugin
org.apache.skywalking
- 9.3.0-SNAPSHOT
+ 9.7.0-SNAPSHOT
apm-httpclient-commons
diff --git a/apm-sniffer/apm-sdk-plugin/httpclient-commons/src/main/java/org/apache/skywalking/apm/plugin/httpclient/HttpClientPluginConfig.java b/apm-sniffer/apm-sdk-plugin/httpclient-commons/src/main/java/org/apache/skywalking/apm/plugin/httpclient/HttpClientPluginConfig.java
index 9a4a94cdb1..2c54e1b220 100644
--- a/apm-sniffer/apm-sdk-plugin/httpclient-commons/src/main/java/org/apache/skywalking/apm/plugin/httpclient/HttpClientPluginConfig.java
+++ b/apm-sniffer/apm-sdk-plugin/httpclient-commons/src/main/java/org/apache/skywalking/apm/plugin/httpclient/HttpClientPluginConfig.java
@@ -28,6 +28,22 @@ public static class HttpClient {
* This config item controls that whether the HttpClient plugin should collect the parameters of the request.
*/
public static boolean COLLECT_HTTP_PARAMS = false;
+
+ /**
+ * Comma-separated list of destination ports whose outbound HTTP requests
+ * will be completely skipped by the httpclient-4.x interceptor: no exit
+ * span is created and no SkyWalking propagation headers are injected.
+ *
+ * Some HTTP-based database protocols (e.g. ClickHouse on port 8123)
+ * reject requests that contain unknown HTTP headers, returning HTTP 400.
+ * Adding such ports here prevents the agent from creating exit spans
+ * and from injecting the {@code sw8} tracing headers into those outbound
+ * requests.
+ *
+ *
Example – exclude ClickHouse and Elasticsearch ports:
+ * {@code plugin.httpclient.propagation_exclude_ports=8123,9200}
+ */
+ public static String PROPAGATION_EXCLUDE_PORTS = "";
}
@PluginConfig(root = HttpClientPluginConfig.class)
diff --git a/apm-sniffer/apm-sdk-plugin/hutool-plugins/hutool-http-5.x-plugin/pom.xml b/apm-sniffer/apm-sdk-plugin/hutool-plugins/hutool-http-5.x-plugin/pom.xml
index f2d0495cc8..b31ba12cf4 100644
--- a/apm-sniffer/apm-sdk-plugin/hutool-plugins/hutool-http-5.x-plugin/pom.xml
+++ b/apm-sniffer/apm-sdk-plugin/hutool-plugins/hutool-http-5.x-plugin/pom.xml
@@ -20,7 +20,7 @@
hutool-plugins
org.apache.skywalking
- 9.3.0-SNAPSHOT
+ 9.7.0-SNAPSHOT
4.0.0
diff --git a/apm-sniffer/apm-sdk-plugin/hutool-plugins/pom.xml b/apm-sniffer/apm-sdk-plugin/hutool-plugins/pom.xml
index 3394b0092c..6c41996fb0 100644
--- a/apm-sniffer/apm-sdk-plugin/hutool-plugins/pom.xml
+++ b/apm-sniffer/apm-sdk-plugin/hutool-plugins/pom.xml
@@ -20,7 +20,7 @@
apm-sdk-plugin
org.apache.skywalking
- 9.3.0-SNAPSHOT
+ 9.7.0-SNAPSHOT
4.0.0
@@ -32,7 +32,6 @@
UTF-8
- /..
diff --git a/apm-sniffer/apm-sdk-plugin/hystrix-1.x-plugin/pom.xml b/apm-sniffer/apm-sdk-plugin/hystrix-1.x-plugin/pom.xml
index b4ed0b93b3..83f8023afe 100644
--- a/apm-sniffer/apm-sdk-plugin/hystrix-1.x-plugin/pom.xml
+++ b/apm-sniffer/apm-sdk-plugin/hystrix-1.x-plugin/pom.xml
@@ -21,7 +21,7 @@
apm-sdk-plugin
org.apache.skywalking
- 9.3.0-SNAPSHOT
+ 9.7.0-SNAPSHOT
4.0.0
diff --git a/apm-sniffer/apm-sdk-plugin/influxdb-2.x-plugin/pom.xml b/apm-sniffer/apm-sdk-plugin/influxdb-2.x-plugin/pom.xml
index ab281eaeb1..e360c9ac4b 100644
--- a/apm-sniffer/apm-sdk-plugin/influxdb-2.x-plugin/pom.xml
+++ b/apm-sniffer/apm-sdk-plugin/influxdb-2.x-plugin/pom.xml
@@ -21,7 +21,7 @@
apm-sdk-plugin
org.apache.skywalking
- 9.3.0-SNAPSHOT
+ 9.7.0-SNAPSHOT
4.0.0
diff --git a/apm-sniffer/apm-sdk-plugin/jdbc-commons/pom.xml b/apm-sniffer/apm-sdk-plugin/jdbc-commons/pom.xml
index a6485b4582..1eecc0d35c 100755
--- a/apm-sniffer/apm-sdk-plugin/jdbc-commons/pom.xml
+++ b/apm-sniffer/apm-sdk-plugin/jdbc-commons/pom.xml
@@ -20,7 +20,7 @@
apm-sdk-plugin
org.apache.skywalking
- 9.3.0-SNAPSHOT
+ 9.7.0-SNAPSHOT
4.0.0
diff --git a/apm-sniffer/apm-sdk-plugin/jdbc-commons/src/main/java/org/apache/skywalking/apm/plugin/jdbc/connectionurl/parser/DMURLParser.java b/apm-sniffer/apm-sdk-plugin/jdbc-commons/src/main/java/org/apache/skywalking/apm/plugin/jdbc/connectionurl/parser/DMURLParser.java
new file mode 100644
index 0000000000..2cb4c1c4c0
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/jdbc-commons/src/main/java/org/apache/skywalking/apm/plugin/jdbc/connectionurl/parser/DMURLParser.java
@@ -0,0 +1,112 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.jdbc.connectionurl.parser;
+
+import org.apache.skywalking.apm.network.trace.component.ComponentsDefine;
+import org.apache.skywalking.apm.plugin.jdbc.trace.ConnectionInfo;
+
+public class DMURLParser extends AbstractURLParser {
+ private static final int DEFAULT_PORT = 5236;
+ private static final String DB_TYPE = "DM";
+ private static final String URL_PARAMS_HOST_KEY = "host";
+ private static final String URL_PARAMS_PORT_KEY = "port";
+ private static final String URL_PARAMS_SCHEMA_KEY = "schema";
+
+ public DMURLParser(String url) {
+ super(url);
+ }
+
+ @Override
+ protected URLLocation fetchDatabaseHostsIndexRange() {
+ int hostLabelStartIndex = url.indexOf("//");
+ if (hostLabelStartIndex == -1) {
+ return new URLLocation(0, 0);
+ }
+ int hostLabelEndIndex = url.indexOf("?", hostLabelStartIndex + 2);
+ if (hostLabelEndIndex == -1) {
+ hostLabelEndIndex = url.length();
+ }
+ return new URLLocation(hostLabelStartIndex + 2, hostLabelEndIndex);
+ }
+
+ @Override
+ protected URLLocation fetchDatabaseNameIndexRange() {
+ return new URLLocation(0, 0);
+ }
+
+ @Override
+ public ConnectionInfo parse() {
+ URLLocation location = fetchDatabaseHostsIndexRange();
+ String hostPortSegment = "";
+ if (location.endIndex() > location.startIndex()) {
+ hostPortSegment = url.substring(location.startIndex(), location.endIndex());
+ }
+
+ String host = "";
+ String port = "";
+
+ if (!hostPortSegment.isEmpty()) {
+ String[] parts = hostPortSegment.split(":");
+ if (parts.length >= 1) {
+ host = parts[0];
+ }
+ if (parts.length == 2) {
+ port = parts[1];
+ }
+ }
+
+ if (host.isEmpty()) {
+ host = fetchFromUrlParams(URL_PARAMS_HOST_KEY);
+ }
+ if (port == null || port.isEmpty()) {
+ port = fetchFromUrlParams(URL_PARAMS_PORT_KEY);
+ }
+
+ if (port == null || port.isEmpty()) {
+ port = String.valueOf(DEFAULT_PORT);
+ }
+
+ String schema = fetchFromUrlParams(URL_PARAMS_SCHEMA_KEY);
+
+ return new ConnectionInfo(
+ ComponentsDefine.DMDB_JDBC_DRIVER,
+ DB_TYPE,
+ host,
+ Integer.parseInt(port),
+ schema == null ? "" : schema
+ );
+ }
+
+ private String fetchFromUrlParams(String key) {
+ int paramIndex = url.indexOf("?");
+ if (paramIndex == -1) {
+ return null;
+ }
+ String[] params = url.substring(paramIndex + 1).split("&");
+ for (String pair : params) {
+ if (pair.startsWith(key + "=")) {
+ String[] segments = pair.split("=", 2);
+ if (segments.length == 2) {
+ return segments[1];
+ }
+ }
+ }
+ return null;
+ }
+}
diff --git a/apm-sniffer/apm-sdk-plugin/jdbc-commons/src/main/java/org/apache/skywalking/apm/plugin/jdbc/connectionurl/parser/Db2URLParser.java b/apm-sniffer/apm-sdk-plugin/jdbc-commons/src/main/java/org/apache/skywalking/apm/plugin/jdbc/connectionurl/parser/Db2URLParser.java
new file mode 100644
index 0000000000..8fe2b36515
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/jdbc-commons/src/main/java/org/apache/skywalking/apm/plugin/jdbc/connectionurl/parser/Db2URLParser.java
@@ -0,0 +1,129 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.jdbc.connectionurl.parser;
+
+import org.apache.skywalking.apm.network.trace.component.ComponentsDefine;
+import org.apache.skywalking.apm.plugin.jdbc.trace.ConnectionInfo;
+
+public class Db2URLParser extends AbstractURLParser {
+ private static final String DEFAULT_HOST = "localhost";
+ private static final int DEFAULT_PORT = 50000;
+ private static final String DB_TYPE = "DB2";
+ private static final String JDBC_PREFIX = "jdbc:db2:";
+
+ public Db2URLParser(String url) {
+ super(url);
+ }
+
+ @Override
+ protected URLLocation fetchDatabaseHostsIndexRange() {
+ int hostLabelStartIndex = url.indexOf("//");
+ if (hostLabelStartIndex == -1) {
+ return null;
+ }
+ int hostLabelEndIndex = url.indexOf("/", hostLabelStartIndex + 2);
+ int hostLabelEndIndexWithParameter = url.indexOf(":", hostLabelEndIndex + 1);
+ if (hostLabelEndIndex == -1) {
+ hostLabelEndIndex = hostLabelEndIndexWithParameter;
+ }
+ if (hostLabelEndIndexWithParameter < hostLabelEndIndex && hostLabelEndIndexWithParameter != -1) {
+ hostLabelEndIndex = hostLabelEndIndexWithParameter;
+ }
+ if (hostLabelEndIndex == -1) {
+ hostLabelEndIndex = url.length();
+ }
+ return new URLLocation(hostLabelStartIndex + 2, hostLabelEndIndex);
+ }
+
+ protected String fetchDatabaseNameFromURL(int startSize) {
+ URLLocation hostsLocation = fetchDatabaseNameIndexRange(startSize);
+ if (hostsLocation == null) {
+ return "";
+ }
+ return url.substring(hostsLocation.startIndex(), hostsLocation.endIndex());
+ }
+
+ protected URLLocation fetchDatabaseNameIndexRange(int startSize) {
+ int databaseStartTag = url.indexOf("/", startSize);
+ int parameterStartTag = url.indexOf(":", startSize);
+ if (parameterStartTag < databaseStartTag && parameterStartTag != -1) {
+ return null;
+ }
+ if (databaseStartTag == -1) {
+ databaseStartTag = startSize - 1;
+ }
+ int databaseEndTag = url.indexOf(":", startSize);
+ if (databaseEndTag == -1) {
+ databaseEndTag = url.length();
+ }
+ return new URLLocation(databaseStartTag + 1, databaseEndTag);
+ }
+
+ @Override
+ protected URLLocation fetchDatabaseNameIndexRange() {
+ int databaseStartTag = url.lastIndexOf("/");
+ int databaseEndTag = url.indexOf(":", databaseStartTag);
+ if (databaseEndTag == -1) {
+ databaseEndTag = url.length();
+ }
+ return new URLLocation(databaseStartTag + 1, databaseEndTag);
+ }
+
+ @Override
+ public ConnectionInfo parse() {
+ URLLocation location = fetchDatabaseHostsIndexRange();
+ if (location == null) {
+ return new ConnectionInfo(
+ ComponentsDefine.DB2_JDBC_DRIVER, DB_TYPE, DEFAULT_HOST, DEFAULT_PORT,
+ fetchDatabaseNameFromURL(JDBC_PREFIX.length())
+ );
+ }
+ String hosts = url.substring(location.startIndex(), location.endIndex());
+ String[] hostSegment = hosts.split(",");
+ if (hostSegment.length > 1) {
+ StringBuilder sb = new StringBuilder();
+ for (String host : hostSegment) {
+ if (host.split(":").length == 1) {
+ sb.append(host).append(":").append(DEFAULT_PORT).append(",");
+ } else {
+ sb.append(host).append(",");
+ }
+ }
+ return new ConnectionInfo(
+ ComponentsDefine.DB2_JDBC_DRIVER, DB_TYPE, sb.substring(0, sb.length() - 1),
+ fetchDatabaseNameFromURL()
+ );
+ } else {
+ String[] hostAndPort = hostSegment[0].split(":");
+ if (hostAndPort.length != 1) {
+ return new ConnectionInfo(
+ ComponentsDefine.DB2_JDBC_DRIVER, DB_TYPE, hostAndPort[0], Integer.valueOf(hostAndPort[1]),
+ fetchDatabaseNameFromURL(location
+ .endIndex())
+ );
+ } else {
+ return new ConnectionInfo(
+ ComponentsDefine.DB2_JDBC_DRIVER, DB_TYPE, hostAndPort[0], DEFAULT_PORT,
+ fetchDatabaseNameFromURL(location
+ .endIndex())
+ );
+ }
+ }
+ }
+}
diff --git a/apm-sniffer/apm-sdk-plugin/jdbc-commons/src/main/java/org/apache/skywalking/apm/plugin/jdbc/connectionurl/parser/DerbyURLParser.java b/apm-sniffer/apm-sdk-plugin/jdbc-commons/src/main/java/org/apache/skywalking/apm/plugin/jdbc/connectionurl/parser/DerbyURLParser.java
new file mode 100644
index 0000000000..dd96b8e06a
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/jdbc-commons/src/main/java/org/apache/skywalking/apm/plugin/jdbc/connectionurl/parser/DerbyURLParser.java
@@ -0,0 +1,197 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.jdbc.connectionurl.parser;
+
+import org.apache.skywalking.apm.network.trace.component.ComponentsDefine;
+import org.apache.skywalking.apm.plugin.jdbc.trace.ConnectionInfo;
+
+public class DerbyURLParser extends AbstractURLParser {
+
+ private static final String DEFAULT_HOST = "localhost";
+ private static final int DEFAULT_PORT = 1527;
+ private static final String DB_TYPE = "Derby";
+ private static final String DERBY_JDBC_URL_PREFIX = "jdbc:derby";
+ /**
+ * Flag that running with directory mode.
+ */
+ private static final String DIRECTORY_MODE_FLAG = "derby:directory";
+ /**
+ * Flag that running with memory mode.
+ */
+ private static final String MEMORY_MODE_FLAG = "derby:memory";
+ /**
+ * Flag that running with classpath mode.
+ */
+ private static final String CLASSPATH_MODE_FLAG = "derby:classpath";
+ /**
+ * Flag that running with jar mode.
+ */
+ private static final String JAR_MODE_FLAG = "derby:jar";
+
+ public DerbyURLParser(String url) {
+ super(url);
+ }
+
+ /**
+ * Fetch range index that the database name from connection url if Derby database running in client/server
+ * environment. eg: jdbc:derby://host[:port]/[databaseName][;attribute=value]*
+ *
+ * @return range index that the database name.
+ */
+ @Override
+ protected URLLocation fetchDatabaseHostsIndexRange() {
+ int hostLabelStartIndex = url.indexOf("//");
+ int hostLabelEndIndex = url.indexOf("/", hostLabelStartIndex + 2);
+ return new URLLocation(hostLabelStartIndex + 2, hostLabelEndIndex);
+ }
+
+ @Override
+ protected URLLocation fetchDatabaseNameIndexRange() {
+ int databaseEndTag = url.indexOf(";");
+ if (databaseEndTag == -1) {
+ databaseEndTag = url.length();
+ }
+ int databaseStartTag = url.lastIndexOf("\\");
+ if (databaseStartTag == -1) {
+ databaseStartTag = url.lastIndexOf("/");
+ }
+ if (url.indexOf(":", databaseStartTag) != -1) {
+ databaseStartTag = url.indexOf(":", databaseStartTag);
+ }
+ return new URLLocation(databaseStartTag + 1, databaseEndTag);
+ }
+
+ @Override
+ public ConnectionInfo parse() {
+ int[] databaseNameRangeIndex = fetchDatabaseNameRangeIndexForSubProtocol(DIRECTORY_MODE_FLAG);
+ if (databaseNameRangeIndex != null) {
+ return defaultConnection(databaseNameRangeIndex);
+ }
+ databaseNameRangeIndex = fetchDatabaseNameRangeIndexForSubProtocol(MEMORY_MODE_FLAG);
+ if (databaseNameRangeIndex != null) {
+ return defaultConnection(databaseNameRangeIndex);
+ }
+ databaseNameRangeIndex = fetchDatabaseNameRangeIndexForSubProtocol(CLASSPATH_MODE_FLAG);
+ if (databaseNameRangeIndex != null) {
+ return defaultConnection(databaseNameRangeIndex);
+ }
+ databaseNameRangeIndex = fetchDatabaseNameRangeIndexForSubProtocol(JAR_MODE_FLAG);
+ if (databaseNameRangeIndex != null) {
+ return defaultConnection(databaseNameRangeIndex);
+ }
+ databaseNameRangeIndex = fetchDatabaseNameRangeIndexWithoutHosts();
+ if (databaseNameRangeIndex != null) {
+ return defaultConnection(databaseNameRangeIndex);
+ }
+ String[] hostAndPort = fetchDatabaseHostsFromURL().split(":");
+ if (hostAndPort.length == 1) {
+ return new ConnectionInfo(
+ ComponentsDefine.DERBY_JDBC_DRIVER, DB_TYPE, hostAndPort[0], DEFAULT_PORT, fetchDatabaseNameFromURL());
+ } else {
+ return new ConnectionInfo(
+ ComponentsDefine.DERBY_JDBC_DRIVER, DB_TYPE, hostAndPort[0], Integer.valueOf(hostAndPort[1]),
+ fetchDatabaseNameFromURL()
+ );
+ }
+ }
+
+ /**
+ * Fetch range index that the database name from connection url if Derby database running in embedded environment.
+ * eg: jdbc:derby:[databaseName][;attribute=value]*
+ *
+ * @return range index that the database name.
+ */
+ private int[] fetchDatabaseNameRangeIndexWithoutHosts() {
+ if (url.contains("//")) {
+ return null;
+ }
+ int fileLabelIndex = url.indexOf(DERBY_JDBC_URL_PREFIX);
+ int parameterLabelIndex = url.indexOf(";");
+ if (parameterLabelIndex == -1) {
+ parameterLabelIndex = url.length();
+ }
+
+ if (fileLabelIndex != -1) {
+ int pathLabelIndexForLinux = url.lastIndexOf("/");
+ if (pathLabelIndexForLinux != -1 && pathLabelIndexForLinux > fileLabelIndex) {
+ return new int[] {
+ pathLabelIndexForLinux + 1,
+ parameterLabelIndex
+ };
+ }
+ int pathLabelIndexForWin = url.lastIndexOf("\\");
+ if (pathLabelIndexForWin != -1 && pathLabelIndexForWin > fileLabelIndex) {
+ return new int[] {
+ pathLabelIndexForWin + 1,
+ parameterLabelIndex
+ };
+ }
+ return new int[] {
+ fileLabelIndex + DERBY_JDBC_URL_PREFIX.length() + 1,
+ parameterLabelIndex
+ };
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Fetch range index that the database name from connection url if Derby database running with subprotocol. eg:
+ * jdbc:derby:subprotocol:[databaseName][;attribute=value]*
+ *
+ * @return range index that the database name.
+ */
+ private int[] fetchDatabaseNameRangeIndexForSubProtocol(String mode) {
+ int fileLabelIndex = url.indexOf(mode);
+ int parameterLabelIndex = url.indexOf(";", fileLabelIndex);
+ if (parameterLabelIndex == -1) {
+ parameterLabelIndex = url.length();
+ }
+
+ if (fileLabelIndex != -1) {
+ int pathLabelIndexForLinux = url.lastIndexOf("/");
+ if (pathLabelIndexForLinux != -1 && pathLabelIndexForLinux > fileLabelIndex) {
+ return new int[] {
+ pathLabelIndexForLinux + 1,
+ parameterLabelIndex
+ };
+ }
+ int pathLabelIndexForWin = url.lastIndexOf("\\");
+ if (pathLabelIndexForWin != -1 && pathLabelIndexForWin > fileLabelIndex) {
+ return new int[] {
+ pathLabelIndexForWin + 1,
+ parameterLabelIndex
+ };
+ }
+ return new int[] {
+ fileLabelIndex + mode.length() + 1,
+ parameterLabelIndex
+ };
+ } else {
+ return null;
+ }
+ }
+
+ private ConnectionInfo defaultConnection(int[] databaseNameRangeIndex) {
+ return new ConnectionInfo(
+ ComponentsDefine.DERBY_JDBC_DRIVER, DB_TYPE, DEFAULT_HOST, -1,
+ fetchDatabaseNameFromURL(databaseNameRangeIndex)
+ );
+ }
+}
diff --git a/apm-sniffer/apm-sdk-plugin/jdbc-commons/src/main/java/org/apache/skywalking/apm/plugin/jdbc/connectionurl/parser/OceanBaseURLParser.java b/apm-sniffer/apm-sdk-plugin/jdbc-commons/src/main/java/org/apache/skywalking/apm/plugin/jdbc/connectionurl/parser/OceanBaseURLParser.java
new file mode 100644
index 0000000000..f459c268e8
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/jdbc-commons/src/main/java/org/apache/skywalking/apm/plugin/jdbc/connectionurl/parser/OceanBaseURLParser.java
@@ -0,0 +1,27 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.jdbc.connectionurl.parser;
+
+import org.apache.skywalking.apm.network.trace.component.ComponentsDefine;
+
+public class OceanBaseURLParser extends MysqlURLParser {
+ public OceanBaseURLParser(String url) {
+ super(url, "OceanBase", ComponentsDefine.OCEANBASE_JDBC_DRIVER, 2881);
+ }
+}
diff --git a/apm-sniffer/apm-sdk-plugin/jdbc-commons/src/main/java/org/apache/skywalking/apm/plugin/jdbc/connectionurl/parser/SqliteURLParser.java b/apm-sniffer/apm-sdk-plugin/jdbc-commons/src/main/java/org/apache/skywalking/apm/plugin/jdbc/connectionurl/parser/SqliteURLParser.java
new file mode 100644
index 0000000000..21f44492b3
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/jdbc-commons/src/main/java/org/apache/skywalking/apm/plugin/jdbc/connectionurl/parser/SqliteURLParser.java
@@ -0,0 +1,57 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.jdbc.connectionurl.parser;
+
+import org.apache.skywalking.apm.network.trace.component.ComponentsDefine;
+import org.apache.skywalking.apm.plugin.jdbc.trace.ConnectionInfo;
+
+public class SqliteURLParser extends AbstractURLParser {
+ private static final String DEFAULT_HOST = "localhost";
+ private static final int DEFAULT_PORT = -1;
+ private static final String DB_TYPE = "Sqlite";
+
+ public SqliteURLParser(String url) {
+ super(url);
+ }
+
+ @Override
+ protected URLLocation fetchDatabaseHostsIndexRange() {
+ return null;
+ }
+
+ @Override
+ protected URLLocation fetchDatabaseNameIndexRange() {
+ int databaseStartTag = url.lastIndexOf("/");
+ if (databaseStartTag == -1) {
+ databaseStartTag = url.lastIndexOf(":");
+ }
+ int databaseEndTag = url.indexOf("?");
+ if (databaseEndTag == -1) {
+ databaseEndTag = url.length();
+ }
+
+ return new URLLocation(databaseStartTag + 1, databaseEndTag);
+ }
+
+ @Override
+ public ConnectionInfo parse() {
+ return new ConnectionInfo(
+ ComponentsDefine.SQLITE_JDBC_DRIVER, DB_TYPE, DEFAULT_HOST, DEFAULT_PORT, fetchDatabaseNameFromURL());
+ }
+}
diff --git a/apm-sniffer/apm-sdk-plugin/jdbc-commons/src/main/java/org/apache/skywalking/apm/plugin/jdbc/connectionurl/parser/SybaseURLParser.java b/apm-sniffer/apm-sdk-plugin/jdbc-commons/src/main/java/org/apache/skywalking/apm/plugin/jdbc/connectionurl/parser/SybaseURLParser.java
new file mode 100644
index 0000000000..dfc8a57519
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/jdbc-commons/src/main/java/org/apache/skywalking/apm/plugin/jdbc/connectionurl/parser/SybaseURLParser.java
@@ -0,0 +1,114 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.jdbc.connectionurl.parser;
+
+import org.apache.skywalking.apm.network.trace.component.ComponentsDefine;
+import org.apache.skywalking.apm.plugin.jdbc.trace.ConnectionInfo;
+
+public class SybaseURLParser extends AbstractURLParser {
+ private static final int DEFAULT_PORT = 5000;
+ private static final String DB_TYPE = "Sybase";
+ private static final String JDBC_PREFIX = "jdbc:sybase:Tds:";
+
+ public SybaseURLParser(String url) {
+ super(url);
+ }
+
+ @Override
+ protected URLLocation fetchDatabaseHostsIndexRange() {
+ int hostLabelStartIndex = JDBC_PREFIX.length();
+ int hostLabelEndIndex = url.indexOf("/", hostLabelStartIndex);
+ int hostLabelEndIndexWithParameter = url.indexOf("?", hostLabelStartIndex);
+ if (hostLabelEndIndex == -1) {
+ hostLabelEndIndex = hostLabelEndIndexWithParameter;
+ }
+ if (hostLabelEndIndexWithParameter < hostLabelEndIndex && hostLabelEndIndexWithParameter != -1) {
+ hostLabelEndIndex = hostLabelEndIndexWithParameter;
+ }
+ if (hostLabelEndIndex == -1) {
+ hostLabelEndIndex = url.length();
+ }
+ return new URLLocation(hostLabelStartIndex, hostLabelEndIndex);
+ }
+
+ protected String fetchDatabaseNameFromURL(int startSize) {
+ URLLocation hostsLocation = fetchDatabaseNameIndexRange(startSize);
+ if (hostsLocation == null) {
+ return "";
+ }
+ return url.substring(hostsLocation.startIndex(), hostsLocation.endIndex());
+ }
+
+ protected URLLocation fetchDatabaseNameIndexRange(int startSize) {
+ int databaseStartTag = url.indexOf("/", startSize);
+ int parameterStartTag = url.indexOf("?", startSize);
+ if (parameterStartTag < databaseStartTag && parameterStartTag != -1) {
+ return null;
+ }
+ if (databaseStartTag == -1) {
+ return null;
+ }
+ int databaseEndTag = url.indexOf("?", databaseStartTag);
+ if (databaseEndTag == -1) {
+ databaseEndTag = url.length();
+ }
+ return new URLLocation(databaseStartTag + 1, databaseEndTag);
+ }
+
+ @Override
+ protected URLLocation fetchDatabaseNameIndexRange() {
+ int databaseStartTag = url.lastIndexOf("/");
+ int databaseEndTag = url.indexOf("?", databaseStartTag);
+ if (databaseEndTag == -1) {
+ databaseEndTag = url.length();
+ }
+ return new URLLocation(databaseStartTag + 1, databaseEndTag);
+ }
+
+ @Override
+ public ConnectionInfo parse() {
+ URLLocation location = fetchDatabaseHostsIndexRange();
+ String hosts = url.substring(location.startIndex(), location.endIndex());
+ String[] hostSegment = hosts.split(",");
+ if (hostSegment.length > 1) {
+ StringBuilder sb = new StringBuilder();
+ for (String host : hostSegment) {
+ if (host.split(":").length == 1) {
+ sb.append(host).append(":").append(DEFAULT_PORT).append(",");
+ } else {
+ sb.append(host).append(",");
+ }
+ }
+ return new ConnectionInfo(ComponentsDefine.SYBASE_JDBC_DRIVER, DB_TYPE, sb.substring(0, sb.length() - 1), fetchDatabaseNameFromURL());
+ } else {
+ String[] hostAndPort = hostSegment[0].split(":");
+ if (hostAndPort.length != 1) {
+ return new ConnectionInfo(
+ ComponentsDefine.SYBASE_JDBC_DRIVER, DB_TYPE, hostAndPort[0], Integer.valueOf(hostAndPort[1]),
+ fetchDatabaseNameFromURL(location
+ .endIndex())
+ );
+ } else {
+ return new ConnectionInfo(
+ ComponentsDefine.SYBASE_JDBC_DRIVER, DB_TYPE, hostAndPort[0], DEFAULT_PORT, fetchDatabaseNameFromURL(location
+ .endIndex()));
+ }
+ }
+ }
+}
diff --git a/apm-sniffer/apm-sdk-plugin/jdbc-commons/src/main/java/org/apache/skywalking/apm/plugin/jdbc/connectionurl/parser/URLParser.java b/apm-sniffer/apm-sdk-plugin/jdbc-commons/src/main/java/org/apache/skywalking/apm/plugin/jdbc/connectionurl/parser/URLParser.java
index ddf2f20fc7..83afcf9efa 100644
--- a/apm-sniffer/apm-sdk-plugin/jdbc-commons/src/main/java/org/apache/skywalking/apm/plugin/jdbc/connectionurl/parser/URLParser.java
+++ b/apm-sniffer/apm-sdk-plugin/jdbc-commons/src/main/java/org/apache/skywalking/apm/plugin/jdbc/connectionurl/parser/URLParser.java
@@ -33,9 +33,15 @@ public class URLParser {
private static final String MARIADB_JDBC_URL_PREFIX = "jdbc:mariadb";
private static final String MSSQL_JTDS_URL_PREFIX = "jdbc:jtds:sqlserver:";
private static final String MSSQL_JDBC_URL_PREFIX = "jdbc:sqlserver:";
- private static final String KYLIN_JDBC_URK_PREFIX = "jdbc:kylin";
- private static final String IMPALA_JDBC_URK_PREFIX = "jdbc:impala";
- private static final String CLICKHOUSE_JDBC_URK_PREFIX = "jdbc:clickhouse";
+ private static final String KYLIN_JDBC_URL_PREFIX = "jdbc:kylin";
+ private static final String IMPALA_JDBC_URL_PREFIX = "jdbc:impala";
+ private static final String CLICKHOUSE_JDBC_URL_PREFIX = "jdbc:clickhouse";
+ private static final String DERBY_JDBC_URL_PREFIX = "jdbc:derby:";
+ private static final String SQLITE_JDBC_URL_PREFIX = "jdbc:sqlite:";
+ private static final String DB2_JDBC_URL_PREFIIX = "jdbc:db2:";
+ private static final String SYBASE_JDBC_URL_PREFIX = "jdbc:sybase:tds:";
+ private static final String OCEANBASE_JDBC_URL_PREFIX = "jdbc:oceanbase:";
+ private static final String DM_JDBC_URL_PREFIX = "jdbc:dm:";
public static ConnectionInfo parser(String url) {
ConnectionURLParser parser = null;
@@ -54,13 +60,26 @@ public static ConnectionInfo parser(String url) {
parser = new MssqlJtdsURLParser(url);
} else if (lowerCaseUrl.startsWith(MSSQL_JDBC_URL_PREFIX)) {
parser = new MssqlJdbcURLParser(url);
- } else if (lowerCaseUrl.startsWith(KYLIN_JDBC_URK_PREFIX)) {
+ } else if (lowerCaseUrl.startsWith(KYLIN_JDBC_URL_PREFIX)) {
parser = new KylinJdbcURLParser(url);
- } else if (lowerCaseUrl.startsWith(IMPALA_JDBC_URK_PREFIX)) {
+ } else if (lowerCaseUrl.startsWith(IMPALA_JDBC_URL_PREFIX)) {
parser = new ImpalaJdbcURLParser(url);
- } else if (lowerCaseUrl.startsWith(CLICKHOUSE_JDBC_URK_PREFIX)) {
+ } else if (lowerCaseUrl.startsWith(CLICKHOUSE_JDBC_URL_PREFIX)) {
parser = new ClickHouseURLParser(url);
+ } else if (lowerCaseUrl.startsWith(DERBY_JDBC_URL_PREFIX)) {
+ parser = new DerbyURLParser(url);
+ } else if (lowerCaseUrl.startsWith(SQLITE_JDBC_URL_PREFIX)) {
+ parser = new SqliteURLParser(url);
+ } else if (lowerCaseUrl.startsWith(DB2_JDBC_URL_PREFIIX)) {
+ parser = new Db2URLParser(url);
+ } else if (lowerCaseUrl.startsWith(SYBASE_JDBC_URL_PREFIX)) {
+ parser = new SybaseURLParser(url);
+ } else if (lowerCaseUrl.startsWith(OCEANBASE_JDBC_URL_PREFIX)) {
+ parser = new OceanBaseURLParser(url);
+ } else if (lowerCaseUrl.startsWith(DM_JDBC_URL_PREFIX)) {
+ parser = new DMURLParser(url);
}
+
return parser.parse();
}
}
diff --git a/apm-sniffer/apm-sdk-plugin/jdbc-commons/src/main/java/org/apache/skywalking/apm/plugin/jdbc/trace/CallableStatementTracing.java b/apm-sniffer/apm-sdk-plugin/jdbc-commons/src/main/java/org/apache/skywalking/apm/plugin/jdbc/trace/CallableStatementTracing.java
index 58bea0fd22..2a3a1f33b0 100644
--- a/apm-sniffer/apm-sdk-plugin/jdbc-commons/src/main/java/org/apache/skywalking/apm/plugin/jdbc/trace/CallableStatementTracing.java
+++ b/apm-sniffer/apm-sdk-plugin/jdbc-commons/src/main/java/org/apache/skywalking/apm/plugin/jdbc/trace/CallableStatementTracing.java
@@ -23,6 +23,7 @@
import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan;
import org.apache.skywalking.apm.agent.core.context.trace.SpanLayer;
import org.apache.skywalking.apm.agent.core.context.ContextManager;
+import org.apache.skywalking.apm.plugin.jdbc.SqlBodyUtil;
/**
* {@link CallableStatementTracing} create an exit span when the client call the method in the class that extend {@link
@@ -38,7 +39,7 @@ public static R execute(java.sql.CallableStatement realStatement, Connection
Tags.DB_TYPE.set(span, connectInfo.getDBType());
SpanLayer.asDB(span);
Tags.DB_INSTANCE.set(span, connectInfo.getDatabaseName());
- Tags.DB_STATEMENT.set(span, sql);
+ Tags.DB_STATEMENT.set(span, SqlBodyUtil.limitSqlBodySize(sql));
span.setComponent(connectInfo.getComponent());
return exec.exe(realStatement, sql);
} catch (SQLException e) {
diff --git a/apm-sniffer/apm-sdk-plugin/jdbc-commons/src/main/java/org/apache/skywalking/apm/plugin/jdbc/trace/PreparedStatementTracing.java b/apm-sniffer/apm-sdk-plugin/jdbc-commons/src/main/java/org/apache/skywalking/apm/plugin/jdbc/trace/PreparedStatementTracing.java
index 86989b7b3d..7c70cb65b0 100644
--- a/apm-sniffer/apm-sdk-plugin/jdbc-commons/src/main/java/org/apache/skywalking/apm/plugin/jdbc/trace/PreparedStatementTracing.java
+++ b/apm-sniffer/apm-sdk-plugin/jdbc-commons/src/main/java/org/apache/skywalking/apm/plugin/jdbc/trace/PreparedStatementTracing.java
@@ -26,6 +26,7 @@
import org.apache.skywalking.apm.agent.core.context.trace.SpanLayer;
import org.apache.skywalking.apm.plugin.jdbc.JDBCPluginConfig;
import org.apache.skywalking.apm.plugin.jdbc.PreparedStatementParameterBuilder;
+import org.apache.skywalking.apm.plugin.jdbc.SqlBodyUtil;
import org.apache.skywalking.apm.plugin.jdbc.define.StatementEnhanceInfos;
/**
@@ -42,7 +43,7 @@ public static R execute(java.sql.PreparedStatement realStatement, Connection
try {
Tags.DB_TYPE.set(span, connectInfo.getDBType());
Tags.DB_INSTANCE.set(span, connectInfo.getDatabaseName());
- Tags.DB_STATEMENT.set(span, sql);
+ Tags.DB_STATEMENT.set(span, SqlBodyUtil.limitSqlBodySize(sql));
span.setComponent(connectInfo.getComponent());
SpanLayer.asDB(span);
if (JDBCPluginConfig.Plugin.JDBC.TRACE_SQL_PARAMETERS && Objects.nonNull(statementEnhanceInfos)) {
diff --git a/apm-sniffer/apm-sdk-plugin/jdbc-commons/src/main/java/org/apache/skywalking/apm/plugin/jdbc/trace/StatementTracing.java b/apm-sniffer/apm-sdk-plugin/jdbc-commons/src/main/java/org/apache/skywalking/apm/plugin/jdbc/trace/StatementTracing.java
index c94b777441..cbac44a6fd 100644
--- a/apm-sniffer/apm-sdk-plugin/jdbc-commons/src/main/java/org/apache/skywalking/apm/plugin/jdbc/trace/StatementTracing.java
+++ b/apm-sniffer/apm-sdk-plugin/jdbc-commons/src/main/java/org/apache/skywalking/apm/plugin/jdbc/trace/StatementTracing.java
@@ -23,6 +23,7 @@
import org.apache.skywalking.apm.agent.core.context.tag.Tags;
import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan;
import org.apache.skywalking.apm.agent.core.context.trace.SpanLayer;
+import org.apache.skywalking.apm.plugin.jdbc.SqlBodyUtil;
/**
* {@link PreparedStatementTracing} create an exit span when the client call the method in the class that extend {@link
@@ -36,7 +37,7 @@ public static R execute(java.sql.Statement realStatement, ConnectionInfo con
.getDatabasePeer());
Tags.DB_TYPE.set(span, connectInfo.getDBType());
Tags.DB_INSTANCE.set(span, connectInfo.getDatabaseName());
- Tags.DB_STATEMENT.set(span, sql);
+ Tags.DB_STATEMENT.set(span, SqlBodyUtil.limitSqlBodySize(sql));
span.setComponent(connectInfo.getComponent());
SpanLayer.asDB(span);
return exec.exe(realStatement, sql);
diff --git a/apm-sniffer/apm-sdk-plugin/jdbc-commons/src/test/java/org/apache/skywalking/apm/plugin/jdbc/connectionurl/parser/URLParserTest.java b/apm-sniffer/apm-sdk-plugin/jdbc-commons/src/test/java/org/apache/skywalking/apm/plugin/jdbc/connectionurl/parser/URLParserTest.java
index f679f05cdf..a9a38450e0 100644
--- a/apm-sniffer/apm-sdk-plugin/jdbc-commons/src/test/java/org/apache/skywalking/apm/plugin/jdbc/connectionurl/parser/URLParserTest.java
+++ b/apm-sniffer/apm-sdk-plugin/jdbc-commons/src/test/java/org/apache/skywalking/apm/plugin/jdbc/connectionurl/parser/URLParserTest.java
@@ -27,7 +27,7 @@
public class URLParserTest {
@Test
public void testParseMysqlJDBCURLWithHost() {
- ConnectionInfo connectionInfo = new URLParser().parser("jdbc:mysql//primaryhost/test");
+ ConnectionInfo connectionInfo = URLParser.parser("jdbc:mysql//primaryhost/test");
assertThat(connectionInfo.getDBType(), is("Mysql"));
assertThat(connectionInfo.getDatabaseName(), is("test"));
assertThat(connectionInfo.getDatabasePeer(), is("primaryhost:3306"));
@@ -35,7 +35,7 @@ public void testParseMysqlJDBCURLWithHost() {
@Test
public void testParseMysqlJDBCURLWithoutDB() {
- ConnectionInfo connectionInfo = new URLParser().parser("jdbc:mysql//primaryhost?profileSQL=true");
+ ConnectionInfo connectionInfo = URLParser.parser("jdbc:mysql//primaryhost?profileSQL=true");
assertThat(connectionInfo.getDBType(), is("Mysql"));
assertThat(connectionInfo.getDatabaseName(), is(""));
assertThat(connectionInfo.getDatabasePeer(), is("primaryhost:3306"));
@@ -43,7 +43,7 @@ public void testParseMysqlJDBCURLWithoutDB() {
@Test
public void testParseMysqlJDBCURLWithHostAndPort() {
- ConnectionInfo connectionInfo = new URLParser().parser("jdbc:mysql//primaryhost:3307/test?profileSQL=true");
+ ConnectionInfo connectionInfo = URLParser.parser("jdbc:mysql//primaryhost:3307/test?profileSQL=true");
assertThat(connectionInfo.getDBType(), is("Mysql"));
assertThat(connectionInfo.getDatabaseName(), is("test"));
assertThat(connectionInfo.getDatabasePeer(), is("primaryhost:3307"));
@@ -51,7 +51,7 @@ public void testParseMysqlJDBCURLWithHostAndPort() {
@Test
public void testParseMysqlJDBCURLWithMultiHost() {
- ConnectionInfo connectionInfo = new URLParser().parser("jdbc:mysql//primaryhost:3307,secondaryhost1,secondaryhost2/test?profileSQL=true");
+ ConnectionInfo connectionInfo = URLParser.parser("jdbc:mysql//primaryhost:3307,secondaryhost1,secondaryhost2/test?profileSQL=true");
assertThat(connectionInfo.getDBType(), is("Mysql"));
assertThat(connectionInfo.getDatabaseName(), is("test"));
assertThat(connectionInfo.getDatabasePeer(), is("primaryhost:3307,secondaryhost1:3306,secondaryhost2:3306"));
@@ -59,7 +59,7 @@ public void testParseMysqlJDBCURLWithMultiHost() {
@Test
public void testParseMysqlJDBCURLWitOutDatabase() {
- ConnectionInfo connectionInfo = new URLParser().parser("jdbc:mysql//primaryhost:3307?profileSQL=true");
+ ConnectionInfo connectionInfo = URLParser.parser("jdbc:mysql//primaryhost:3307?profileSQL=true");
assertThat(connectionInfo.getDBType(), is("Mysql"));
assertThat(connectionInfo.getDatabaseName(), is(""));
assertThat(connectionInfo.getDatabasePeer(), is("primaryhost:3307"));
@@ -67,7 +67,7 @@ public void testParseMysqlJDBCURLWitOutDatabase() {
@Test
public void testParseMysqlJDBCURLWithConnectorJs() {
- ConnectionInfo connectionInfo = new URLParser().parser("jdbc:mysql:replication://master,slave1,slave2,slave3/test");
+ ConnectionInfo connectionInfo = URLParser.parser("jdbc:mysql:replication://master,slave1,slave2,slave3/test");
assertThat(connectionInfo.getDBType(), is("Mysql"));
assertThat(connectionInfo.getDatabaseName(), is("test"));
assertThat(connectionInfo.getDatabasePeer(), is("master:3306,slave1:3306,slave2:3306,slave3:3306"));
@@ -75,7 +75,7 @@ public void testParseMysqlJDBCURLWithConnectorJs() {
@Test
public void testParseOracleJDBCURLWithHost() {
- ConnectionInfo connectionInfo = new URLParser().parser("jdbc:oracle:thin:@localhost:orcl");
+ ConnectionInfo connectionInfo = URLParser.parser("jdbc:oracle:thin:@localhost:orcl");
assertThat(connectionInfo.getDBType(), is("Oracle"));
assertThat(connectionInfo.getDatabaseName(), is("orcl"));
assertThat(connectionInfo.getDatabasePeer(), is("localhost:1521"));
@@ -83,7 +83,7 @@ public void testParseOracleJDBCURLWithHost() {
@Test
public void testParseOracleJDBCURLWithHostAndPort() {
- ConnectionInfo connectionInfo = new URLParser().parser("jdbc:oracle:thin:@localhost:1522:orcl");
+ ConnectionInfo connectionInfo = URLParser.parser("jdbc:oracle:thin:@localhost:1522:orcl");
assertThat(connectionInfo.getDBType(), is("Oracle"));
assertThat(connectionInfo.getDatabaseName(), is("orcl"));
assertThat(connectionInfo.getDatabasePeer(), is("localhost:1522"));
@@ -91,7 +91,7 @@ public void testParseOracleJDBCURLWithHostAndPort() {
@Test
public void testParseOracleSID() {
- ConnectionInfo connectionInfo = new URLParser().parser("jdbc:oracle:thin:@localhost:1522/orcl");
+ ConnectionInfo connectionInfo = URLParser.parser("jdbc:oracle:thin:@localhost:1522/orcl");
assertThat(connectionInfo.getDBType(), is("Oracle"));
assertThat(connectionInfo.getDatabaseName(), is("orcl"));
assertThat(connectionInfo.getDatabasePeer(), is("localhost:1522"));
@@ -99,7 +99,7 @@ public void testParseOracleSID() {
@Test
public void testParseOracleServiceName() {
- ConnectionInfo connectionInfo = new URLParser().parser("jdbc:oracle:thin:@//localhost:1531/orcl");
+ ConnectionInfo connectionInfo = URLParser.parser("jdbc:oracle:thin:@//localhost:1531/orcl");
assertThat(connectionInfo.getDBType(), is("Oracle"));
assertThat(connectionInfo.getDatabaseName(), is("orcl"));
assertThat(connectionInfo.getDatabasePeer(), is("localhost:1531"));
@@ -107,7 +107,7 @@ public void testParseOracleServiceName() {
@Test
public void testParseOracleTNSName() {
- ConnectionInfo connectionInfo = new URLParser().parser("jdbc:oracle:thin:@(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST= localhost )(PORT= 1521))(CONNECT_DATA=(SERVER=DEDICATED)(SERVICE_NAME=orcl)))");
+ ConnectionInfo connectionInfo = URLParser.parser("jdbc:oracle:thin:@(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST= localhost )(PORT= 1521))(CONNECT_DATA=(SERVER=DEDICATED)(SERVICE_NAME=orcl)))");
assertThat(connectionInfo.getDBType(), is("Oracle"));
assertThat(connectionInfo.getDatabaseName(), is("orcl"));
assertThat(connectionInfo.getDatabasePeer(), is("localhost:1521"));
@@ -115,7 +115,7 @@ public void testParseOracleTNSName() {
@Test
public void testParseOracleLowerTNSName() {
- ConnectionInfo connectionInfo = new URLParser().parser("jdbc:oracle:thin:@(description=(address=(protocol=tcp)(host= localhost )(port= 1521))(connect_data=(server=dedicated)(service_name=orcl)))");
+ ConnectionInfo connectionInfo = URLParser.parser("jdbc:oracle:thin:@(description=(address=(protocol=tcp)(host= localhost )(port= 1521))(connect_data=(server=dedicated)(service_name=orcl)))");
assertThat(connectionInfo.getDBType(), is("Oracle"));
assertThat(connectionInfo.getDatabaseName(), is("orcl"));
assertThat(connectionInfo.getDatabasePeer(), is("localhost:1521"));
@@ -123,7 +123,7 @@ public void testParseOracleLowerTNSName() {
@Test
public void testParseOracleTNSNameWithMultiAddress() {
- ConnectionInfo connectionInfo = new URLParser().parser("jdbc:oracle:thin:@(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL= TCP)(HOST=hostA)(PORT= 1523 ))(ADDRESS=(PROTOCOL=TCP)(HOST=hostB)(PORT= 1521 )))(SOURCE_ROUTE=yes)(CONNECT_DATA=(SERVICE_NAME=orcl)))");
+ ConnectionInfo connectionInfo = URLParser.parser("jdbc:oracle:thin:@(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL= TCP)(HOST=hostA)(PORT= 1523 ))(ADDRESS=(PROTOCOL=TCP)(HOST=hostB)(PORT= 1521 )))(SOURCE_ROUTE=yes)(CONNECT_DATA=(SERVICE_NAME=orcl)))");
assertThat(connectionInfo.getDBType(), is("Oracle"));
assertThat(connectionInfo.getDatabaseName(), is("orcl"));
assertThat(connectionInfo.getDatabasePeer(), is("hostA:1523,hostB:1521"));
@@ -131,7 +131,7 @@ public void testParseOracleTNSNameWithMultiAddress() {
@Test
public void testParseOracleJDBCURLWithUserNameAndPassword() {
- ConnectionInfo connectionInfo = new URLParser().parser("jdbc:oracle:thin:scott/tiger@myhost:1521:orcl");
+ ConnectionInfo connectionInfo = URLParser.parser("jdbc:oracle:thin:scott/tiger@myhost:1521:orcl");
assertThat(connectionInfo.getDBType(), is("Oracle"));
assertThat(connectionInfo.getDatabaseName(), is("orcl"));
assertThat(connectionInfo.getDatabasePeer(), is("myhost:1521"));
@@ -139,7 +139,7 @@ public void testParseOracleJDBCURLWithUserNameAndPassword() {
@Test
public void testParseH2JDBCURLWithEmbedded() {
- ConnectionInfo connectionInfo = new URLParser().parser("jdbc:h2:file:/data/sample");
+ ConnectionInfo connectionInfo = URLParser.parser("jdbc:h2:file:/data/sample");
assertThat(connectionInfo.getDBType(), is("H2"));
assertThat(connectionInfo.getDatabaseName(), is("/data/sample"));
assertThat(connectionInfo.getDatabasePeer(), is("localhost:-1"));
@@ -147,7 +147,7 @@ public void testParseH2JDBCURLWithEmbedded() {
@Test
public void testParseH2JDBCURLWithEmbeddedRunningInWindows() {
- ConnectionInfo connectionInfo = new URLParser().parser("jdbc:h2:file:C:/data/sample");
+ ConnectionInfo connectionInfo = URLParser.parser("jdbc:h2:file:C:/data/sample");
assertThat(connectionInfo.getDBType(), is("H2"));
assertThat(connectionInfo.getDatabaseName(), is("C:/data/sample"));
assertThat(connectionInfo.getDatabasePeer(), is("localhost:-1"));
@@ -155,7 +155,7 @@ public void testParseH2JDBCURLWithEmbeddedRunningInWindows() {
@Test
public void testParseH2JDBCURLWithMemoryMode() {
- ConnectionInfo connectionInfo = new URLParser().parser("jdbc:h2:mem:test_mem");
+ ConnectionInfo connectionInfo = URLParser.parser("jdbc:h2:mem:test_mem");
assertThat(connectionInfo.getDBType(), is("H2"));
assertThat(connectionInfo.getDatabaseName(), is("test_mem"));
assertThat(connectionInfo.getDatabasePeer(), is("localhost:-1"));
@@ -163,7 +163,7 @@ public void testParseH2JDBCURLWithMemoryMode() {
@Test
public void testParseH2JDBCURL() {
- ConnectionInfo connectionInfo = new URLParser().parser("jdbc:h2:tcp://localhost:8084/~/sample");
+ ConnectionInfo connectionInfo = URLParser.parser("jdbc:h2:tcp://localhost:8084/~/sample");
assertThat(connectionInfo.getDBType(), is("H2"));
assertThat(connectionInfo.getDatabaseName(), is("sample"));
assertThat(connectionInfo.getDatabasePeer(), is("localhost:8084"));
@@ -171,7 +171,7 @@ public void testParseH2JDBCURL() {
@Test
public void testParseMariadbJDBCURLWithHost() {
- ConnectionInfo connectionInfo = new URLParser().parser("jdbc:mariadb//primaryhost/test");
+ ConnectionInfo connectionInfo = URLParser.parser("jdbc:mariadb//primaryhost/test");
assertThat(connectionInfo.getDBType(), is("Mariadb"));
assertThat(connectionInfo.getDatabaseName(), is("test"));
assertThat(connectionInfo.getDatabasePeer(), is("primaryhost:3306"));
@@ -179,7 +179,7 @@ public void testParseMariadbJDBCURLWithHost() {
@Test
public void testParseClickhouseJDBCURL() {
- ConnectionInfo connectionInfo = new URLParser().parser("jdbc:clickhouse://localhost:8123/test");
+ ConnectionInfo connectionInfo = URLParser.parser("jdbc:clickhouse://localhost:8123/test");
assertThat(connectionInfo.getDBType(), is("ClickHouse"));
assertThat(connectionInfo.getDatabaseName(), is("test"));
assertThat(connectionInfo.getDatabasePeer(), is("localhost:8123"));
@@ -187,7 +187,7 @@ public void testParseClickhouseJDBCURL() {
@Test
public void testParseImpalaJDBCURL() {
- ConnectionInfo connectionInfo = new URLParser().parser("jdbc:impala://localhost:21050/test;AuthMech=3;UID=UserName;PWD=Password");
+ ConnectionInfo connectionInfo = URLParser.parser("jdbc:impala://localhost:21050/test;AuthMech=3;UID=UserName;PWD=Password");
assertThat(connectionInfo.getDBType(), is("Impala"));
assertThat(connectionInfo.getDatabaseName(), is("test"));
assertThat(connectionInfo.getDatabasePeer(), is("localhost:21050"));
@@ -195,7 +195,7 @@ public void testParseImpalaJDBCURL() {
@Test
public void testParseImpalaJDBCURLWithSchema() {
- ConnectionInfo connectionInfo = new URLParser().parser("jdbc:impala://localhost:21050/test");
+ ConnectionInfo connectionInfo = URLParser.parser("jdbc:impala://localhost:21050/test");
assertThat(connectionInfo.getDBType(), is("Impala"));
assertThat(connectionInfo.getDatabaseName(), is("test"));
assertThat(connectionInfo.getDatabasePeer(), is("localhost:21050"));
@@ -203,14 +203,14 @@ public void testParseImpalaJDBCURLWithSchema() {
@Test
public void testParseImpalaJDBCURLWithoutSchema() {
- ConnectionInfo connectionInfo = new URLParser().parser("jdbc:impala://localhost:21050");
+ ConnectionInfo connectionInfo = URLParser.parser("jdbc:impala://localhost:21050");
assertThat(connectionInfo.getDBType(), is("Impala"));
assertThat(connectionInfo.getDatabasePeer(), is("localhost:21050"));
}
@Test
public void testParsePostgresqlJDBCURLWithHostAndParams() {
- ConnectionInfo connectionInfo = new URLParser().parser("jdbc:postgresql://localhost:5432/testdb?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf8&characterSetResults=utf8&useSSL=false&allowMultiQueries=true");
+ ConnectionInfo connectionInfo = URLParser.parser("jdbc:postgresql://localhost:5432/testdb?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf8&characterSetResults=utf8&useSSL=false&allowMultiQueries=true");
assertThat(connectionInfo.getDBType(), is("PostgreSQL"));
assertThat(connectionInfo.getDatabaseName(), is("testdb"));
assertThat(connectionInfo.getDatabasePeer(), is("localhost:5432"));
@@ -218,7 +218,7 @@ public void testParsePostgresqlJDBCURLWithHostAndParams() {
@Test
public void testParsePostgresqlJDBCURLWithMultiHost() {
- ConnectionInfo connectionInfo = new URLParser().parser("jdbc:postgresql://localhost1:5432,localhost2:5433/testdb?target_session_attrs=any&application_name=myapp");
+ ConnectionInfo connectionInfo = URLParser.parser("jdbc:postgresql://localhost1:5432,localhost2:5433/testdb?target_session_attrs=any&application_name=myapp");
assertThat(connectionInfo.getDBType(), is("PostgreSQL"));
assertThat(connectionInfo.getDatabaseName(), is("testdb"));
assertThat(connectionInfo.getDatabasePeer(), is("localhost1:5432,localhost2:5433"));
@@ -226,7 +226,7 @@ public void testParsePostgresqlJDBCURLWithMultiHost() {
@Test
public void testParsePostgresqlJDBCURLWithHostNoPort() {
- ConnectionInfo connectionInfo = new URLParser().parser("jdbc:postgresql://localhost/testdb");
+ ConnectionInfo connectionInfo = URLParser.parser("jdbc:postgresql://localhost/testdb");
assertThat(connectionInfo.getDBType(), is("PostgreSQL"));
assertThat(connectionInfo.getDatabaseName(), is("testdb"));
assertThat(connectionInfo.getDatabasePeer(), is("localhost:5432"));
@@ -234,7 +234,7 @@ public void testParsePostgresqlJDBCURLWithHostNoPort() {
@Test
public void testParsePostgresqlJDBCURLWithHostNoDb() {
- ConnectionInfo connectionInfo = new URLParser().parser("jdbc:postgresql://localhost:5432");
+ ConnectionInfo connectionInfo = URLParser.parser("jdbc:postgresql://localhost:5432");
assertThat(connectionInfo.getDBType(), is("PostgreSQL"));
assertThat(connectionInfo.getDatabaseName(), is(""));
assertThat(connectionInfo.getDatabasePeer(), is("localhost:5432"));
@@ -242,7 +242,7 @@ public void testParsePostgresqlJDBCURLWithHostNoDb() {
@Test
public void testParsePostgresqlJDBCURLWithHostNoPortAndDb() {
- ConnectionInfo connectionInfo = new URLParser().parser("jdbc:postgresql://localhost");
+ ConnectionInfo connectionInfo = URLParser.parser("jdbc:postgresql://localhost");
assertThat(connectionInfo.getDBType(), is("PostgreSQL"));
assertThat(connectionInfo.getDatabaseName(), is(""));
assertThat(connectionInfo.getDatabasePeer(), is("localhost:5432"));
@@ -250,7 +250,7 @@ public void testParsePostgresqlJDBCURLWithHostNoPortAndDb() {
@Test
public void testParsePostgresqlJDBCURLEmpty() {
- ConnectionInfo connectionInfo = new URLParser().parser("jdbc:postgresql://");
+ ConnectionInfo connectionInfo = URLParser.parser("jdbc:postgresql://");
assertThat(connectionInfo.getDBType(), is("PostgreSQL"));
assertThat(connectionInfo.getDatabaseName(), is(""));
assertThat(connectionInfo.getDatabasePeer(), is(":5432"));
@@ -258,7 +258,7 @@ public void testParsePostgresqlJDBCURLEmpty() {
@Test
public void testParsePostgresqlJDBCURLWithNamedParams() {
- ConnectionInfo connectionInfo = new URLParser().parser("jdbc:postgresql:///testdb?host=localhost&port=5433");
+ ConnectionInfo connectionInfo = URLParser.parser("jdbc:postgresql:///testdb?host=localhost&port=5433");
assertThat(connectionInfo.getDBType(), is("PostgreSQL"));
assertThat(connectionInfo.getDatabaseName(), is("testdb"));
assertThat(connectionInfo.getDatabasePeer(), is("localhost:5433"));
@@ -266,7 +266,7 @@ public void testParsePostgresqlJDBCURLWithNamedParams() {
@Test
public void testParsePostgresqlJDBCURLWithSingleIpv6() {
- ConnectionInfo connectionInfo = new URLParser().parser("jdbc:postgresql://[2001:db8::1234]/testdb");
+ ConnectionInfo connectionInfo = URLParser.parser("jdbc:postgresql://[2001:db8::1234]/testdb");
assertThat(connectionInfo.getDBType(), is("PostgreSQL"));
assertThat(connectionInfo.getDatabaseName(), is("testdb"));
assertThat(connectionInfo.getDatabasePeer(), is("[2001:db8::1234]:5432"));
@@ -274,10 +274,190 @@ public void testParsePostgresqlJDBCURLWithSingleIpv6() {
@Test
public void testParsePostgresqlJDBCURLWithMultiIpv6() {
- ConnectionInfo connectionInfo = new URLParser().parser(
+ ConnectionInfo connectionInfo = URLParser.parser(
"jdbc:postgresql://[2001:db8::1234],[2001:db8::1235]/testdb");
assertThat(connectionInfo.getDBType(), is("PostgreSQL"));
assertThat(connectionInfo.getDatabaseName(), is("testdb"));
assertThat(connectionInfo.getDatabasePeer(), is("[2001:db8::1234]:5432,[2001:db8::1235]:5432"));
}
+
+ @Test
+ public void testParseOceanBaseJDBCURL() {
+ ConnectionInfo connectionInfo = URLParser.parser(
+ "jdbc:oceanbase://localhost:2881/mydb?user=root@sys&password=pass&pool=false&useBulkStmts=true&rewriteBatchedStatements=false&useServerPrepStmts=true");
+ assertThat(connectionInfo.getDBType(), is("OceanBase"));
+ assertThat(connectionInfo.getDatabaseName(), is("mydb"));
+ assertThat(connectionInfo.getDatabasePeer(), is("localhost:2881"));
+ }
+
+ @Test
+ public void testParseOceanBaseJDBCURLWithMultiHosts() {
+ ConnectionInfo connectionInfo = URLParser.parser(
+ "jdbc:oceanbase://primaryhost:2888,secondaryhost1,secondaryhost2/mydb?user=root@sys&password=pass&pool=false&useBulkStmts=true&rewriteBatchedStatements=false&useServerPrepStmts=true");
+ assertThat(connectionInfo.getDBType(), is("OceanBase"));
+ assertThat(connectionInfo.getDatabaseName(), is("mydb"));
+ assertThat(connectionInfo.getDatabasePeer(), is("primaryhost:2888,secondaryhost1:2881,secondaryhost2:2881"));
+ }
+
+ @Test
+ public void testParseDerbyJDBCURLWithDirMode() {
+ ConnectionInfo connectionInfo = URLParser.parser(
+ "jdbc:derby:directory:mydb");
+ assertThat(connectionInfo.getDBType(), is("Derby"));
+ assertThat(connectionInfo.getDatabaseName(), is("mydb"));
+ assertThat(connectionInfo.getDatabasePeer(), is("localhost:-1"));
+ }
+
+ @Test
+ public void testParseDerbyJDBCURLWithMemMode() {
+ ConnectionInfo connectionInfo = URLParser.parser(
+ "jdbc:derby:memory:mydb;create=true");
+ assertThat(connectionInfo.getDBType(), is("Derby"));
+ assertThat(connectionInfo.getDatabaseName(), is("mydb"));
+ assertThat(connectionInfo.getDatabasePeer(), is("localhost:-1"));
+ }
+
+ @Test
+ public void testParseDerbyJDBCURLWithClassPathMode() {
+ ConnectionInfo connectionInfo = URLParser.parser(
+ "jdbc:derby:classpath:/test/mydb");
+ assertThat(connectionInfo.getDBType(), is("Derby"));
+ assertThat(connectionInfo.getDatabaseName(), is("mydb"));
+ assertThat(connectionInfo.getDatabasePeer(), is("localhost:-1"));
+ }
+
+ @Test
+ public void testParseDerbyJDBCURLWithJarMode() {
+ ConnectionInfo connectionInfo = URLParser.parser(
+ "jdbc:derby:jar:(C:/dbs.jar)test/mydb");
+ assertThat(connectionInfo.getDBType(), is("Derby"));
+ assertThat(connectionInfo.getDatabaseName(), is("mydb"));
+ assertThat(connectionInfo.getDatabasePeer(), is("localhost:-1"));
+ }
+
+ @Test
+ public void testParseDerbyJDBCURLWithEmbeddedMode() {
+ ConnectionInfo connectionInfo = URLParser.parser(
+ "jdbc:derby:test/mydb;create=true");
+ assertThat(connectionInfo.getDBType(), is("Derby"));
+ assertThat(connectionInfo.getDatabaseName(), is("mydb"));
+ assertThat(connectionInfo.getDatabasePeer(), is("localhost:-1"));
+ }
+
+ @Test
+ public void testParseDerbyJDBCURLWithMemModeAndClientServerMode() {
+ ConnectionInfo connectionInfo = URLParser.parser(
+ "jdbc:derby://localhost:1527/memory:/test/mydb;create=true");
+ assertThat(connectionInfo.getDBType(), is("Derby"));
+ assertThat(connectionInfo.getDatabaseName(), is("mydb"));
+ assertThat(connectionInfo.getDatabasePeer(), is("localhost:1527"));
+ }
+
+ @Test
+ public void testParseDerbyJDBCURLWithClientServerMode() {
+ ConnectionInfo connectionInfo = URLParser.parser(
+ "jdbc:derby://localhost:1527/mydb;create=true;user=root;password=pass");
+ assertThat(connectionInfo.getDBType(), is("Derby"));
+ assertThat(connectionInfo.getDatabaseName(), is("mydb"));
+ assertThat(connectionInfo.getDatabasePeer(), is("localhost:1527"));
+ }
+
+ @Test
+ public void testParseDB2JDBCURL() {
+ ConnectionInfo connectionInfo = URLParser.parser(
+ "jdbc:db2://localhost:50000/mydb:user=root;password=pass");
+ assertThat(connectionInfo.getDBType(), is("DB2"));
+ assertThat(connectionInfo.getDatabaseName(), is("mydb"));
+ assertThat(connectionInfo.getDatabasePeer(), is("localhost:50000"));
+ }
+
+ @Test
+ public void testParseDB2JDBCURLWithoutHost() {
+ ConnectionInfo connectionInfo = URLParser.parser(
+ "jdbc:db2:mydb:user=root;password=pass");
+ assertThat(connectionInfo.getDBType(), is("DB2"));
+ assertThat(connectionInfo.getDatabaseName(), is("mydb"));
+ assertThat(connectionInfo.getDatabasePeer(), is("localhost:50000"));
+ }
+
+ @Test
+ public void testParseSqliteJDBCURL() {
+ ConnectionInfo connectionInfo = URLParser.parser(
+ "jdbc:sqlite:C/test/mydb.db");
+ assertThat(connectionInfo.getDBType(), is("Sqlite"));
+ assertThat(connectionInfo.getDatabaseName(), is("mydb.db"));
+ assertThat(connectionInfo.getDatabasePeer(), is("localhost:-1"));
+ }
+
+ @Test
+ public void testParseSqliteJDBCURLWithMem() {
+ ConnectionInfo connectionInfo = URLParser.parser(
+ "jdbc:sqlite::memory:?jdbc.explicit_readonly=true");
+ assertThat(connectionInfo.getDBType(), is("Sqlite"));
+ assertThat(connectionInfo.getDatabaseName(), is(""));
+ assertThat(connectionInfo.getDatabasePeer(), is("localhost:-1"));
+ }
+
+ @Test
+ public void testParseSqliteJDBCURLWithResource() {
+ ConnectionInfo connectionInfo = URLParser.parser(
+ "jdbc:sqlite::resource:org/test/mydb.db");
+ assertThat(connectionInfo.getDBType(), is("Sqlite"));
+ assertThat(connectionInfo.getDatabaseName(), is("mydb.db"));
+ assertThat(connectionInfo.getDatabasePeer(), is("localhost:-1"));
+ }
+
+ @Test
+ public void testParseSybaseJDBCURL() {
+ ConnectionInfo connectionInfo = URLParser.parser(
+ "jdbc:sybase:Tds:localhost:5000/mydb?charset=utf-8");
+ assertThat(connectionInfo.getDBType(), is("Sybase"));
+ assertThat(connectionInfo.getDatabaseName(), is("mydb"));
+ assertThat(connectionInfo.getDatabasePeer(), is("localhost:5000"));
+ }
+
+ @Test
+ public void testParseDMJDBCURLWithNamedParams()
+ {
+ ConnectionInfo connectionInfo = URLParser.parser("jdbc:dm://?host=localhost&port=5236");
+ assertThat(connectionInfo.getDBType(), is("DM"));
+ assertThat(connectionInfo.getDatabaseName(), is(""));
+ assertThat(connectionInfo.getDatabasePeer(), is("localhost:5236"));
+ }
+
+ @Test
+ public void testParseDMJDBCURLWithNamedParamsAndScheme()
+ {
+ ConnectionInfo connectionInfo = URLParser.parser("jdbc:dm://?host=localhost&port=5236&schema=dm");
+ assertThat(connectionInfo.getDBType(), is("DM"));
+ assertThat(connectionInfo.getDatabaseName(), is("dm"));
+ assertThat(connectionInfo.getDatabasePeer(), is("localhost:5236"));
+ }
+
+ @Test
+ public void testParseDMJDBCURLWithoutHost()
+ {
+ ConnectionInfo connectionInfo = URLParser.parser("jdbc:dm://localhost");
+ assertThat(connectionInfo.getDBType(), is("DM"));
+ assertThat(connectionInfo.getDatabaseName(), is(""));
+ assertThat(connectionInfo.getDatabasePeer(), is("localhost:5236"));
+ }
+
+ @Test
+ public void testParseDMJDBCURLWithoutHostAndScheme()
+ {
+ ConnectionInfo connectionInfo = URLParser.parser("jdbc:dm://localhost?schema=dm");
+ assertThat(connectionInfo.getDBType(), is("DM"));
+ assertThat(connectionInfo.getDatabaseName(), is("dm"));
+ assertThat(connectionInfo.getDatabasePeer(), is("localhost:5236"));
+ }
+
+ @Test
+ public void testParseDMJDBCURLWithoutHostPort()
+ {
+ ConnectionInfo connectionInfo = URLParser.parser("jdbc:dm://localhost:5237?schema=dm");
+ assertThat(connectionInfo.getDBType(), is("DM"));
+ assertThat(connectionInfo.getDatabaseName(), is("dm"));
+ assertThat(connectionInfo.getDatabasePeer(), is("localhost:5237"));
+ }
}
diff --git a/apm-sniffer/apm-sdk-plugin/jedis-plugins/jedis-2.x-3.x-plugin/pom.xml b/apm-sniffer/apm-sdk-plugin/jedis-plugins/jedis-2.x-3.x-plugin/pom.xml
index 310e07a400..53f72f82af 100644
--- a/apm-sniffer/apm-sdk-plugin/jedis-plugins/jedis-2.x-3.x-plugin/pom.xml
+++ b/apm-sniffer/apm-sdk-plugin/jedis-plugins/jedis-2.x-3.x-plugin/pom.xml
@@ -21,7 +21,7 @@
org.apache.skywalking
jedis-plugins
- 9.3.0-SNAPSHOT
+ 9.7.0-SNAPSHOT
4.0.0
diff --git a/apm-sniffer/apm-sdk-plugin/jedis-plugins/jedis-4.x-plugin/pom.xml b/apm-sniffer/apm-sdk-plugin/jedis-plugins/jedis-4.x-plugin/pom.xml
index 1f6cc9db71..4593b1c654 100644
--- a/apm-sniffer/apm-sdk-plugin/jedis-plugins/jedis-4.x-plugin/pom.xml
+++ b/apm-sniffer/apm-sdk-plugin/jedis-plugins/jedis-4.x-plugin/pom.xml
@@ -21,7 +21,7 @@
jedis-plugins
org.apache.skywalking
- 9.3.0-SNAPSHOT
+ 9.7.0-SNAPSHOT
4.0.0
diff --git a/apm-sniffer/apm-sdk-plugin/jedis-plugins/jedis-4.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jedis/v4/define/AbstractWitnessInstrumentation.java b/apm-sniffer/apm-sdk-plugin/jedis-plugins/jedis-4.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jedis/v4/define/AbstractWitnessInstrumentation.java
index 8c736751a3..03e5dc6792 100644
--- a/apm-sniffer/apm-sdk-plugin/jedis-plugins/jedis-4.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jedis/v4/define/AbstractWitnessInstrumentation.java
+++ b/apm-sniffer/apm-sdk-plugin/jedis-plugins/jedis-4.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jedis/v4/define/AbstractWitnessInstrumentation.java
@@ -35,8 +35,11 @@ protected String[] witnessClasses() {
@Override
protected List witnessMethods() {
+ // Connection.executeCommand(CommandObject) exists in Jedis 4.x+ and 5.x,
+ // but not in 3.x. Previous witness Pipeline.persist(1) broke in 5.x
+ // because persist moved from Pipeline to PipeliningBase parent class.
return Collections.singletonList(new WitnessMethod(
- "redis.clients.jedis.Pipeline",
- named("persist").and(takesArguments(1))));
+ "redis.clients.jedis.Connection",
+ named("executeCommand").and(takesArguments(1))));
}
}
diff --git a/apm-sniffer/apm-sdk-plugin/jedis-plugins/pom.xml b/apm-sniffer/apm-sdk-plugin/jedis-plugins/pom.xml
index 56bf312da3..440d8a3232 100644
--- a/apm-sniffer/apm-sdk-plugin/jedis-plugins/pom.xml
+++ b/apm-sniffer/apm-sdk-plugin/jedis-plugins/pom.xml
@@ -20,14 +20,11 @@
org.apache.skywalking
apm-sdk-plugin
- 9.3.0-SNAPSHOT
+ 9.7.0-SNAPSHOT
- 8
- 8
UTF-8
- /..
4.0.0
diff --git a/apm-sniffer/apm-sdk-plugin/jersey-2.x-plugin/pom.xml b/apm-sniffer/apm-sdk-plugin/jersey-2.x-plugin/pom.xml
index 0f56f34dbf..f3a8001daf 100644
--- a/apm-sniffer/apm-sdk-plugin/jersey-2.x-plugin/pom.xml
+++ b/apm-sniffer/apm-sdk-plugin/jersey-2.x-plugin/pom.xml
@@ -21,7 +21,7 @@
apm-sdk-plugin
org.apache.skywalking
- 9.3.0-SNAPSHOT
+ 9.7.0-SNAPSHOT
4.0.0
diff --git a/apm-sniffer/apm-sdk-plugin/jersey-3.x-plugin/pom.xml b/apm-sniffer/apm-sdk-plugin/jersey-3.x-plugin/pom.xml
index 36070531c2..94fd991b19 100644
--- a/apm-sniffer/apm-sdk-plugin/jersey-3.x-plugin/pom.xml
+++ b/apm-sniffer/apm-sdk-plugin/jersey-3.x-plugin/pom.xml
@@ -21,7 +21,7 @@
apm-sdk-plugin
org.apache.skywalking
- 9.3.0-SNAPSHOT
+ 9.7.0-SNAPSHOT
4.0.0
diff --git a/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-client-11.x-plugin/pom.xml b/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-client-11.x-plugin/pom.xml
index cde6fd5449..d800a09ddd 100644
--- a/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-client-11.x-plugin/pom.xml
+++ b/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-client-11.x-plugin/pom.xml
@@ -20,7 +20,7 @@
jetty-plugins
org.apache.skywalking
- 9.3.0-SNAPSHOT
+ 9.7.0-SNAPSHOT
4.0.0
diff --git a/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-client-9.0-plugin/pom.xml b/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-client-9.0-plugin/pom.xml
index 199bc45aac..be26052758 100644
--- a/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-client-9.0-plugin/pom.xml
+++ b/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-client-9.0-plugin/pom.xml
@@ -20,7 +20,7 @@
jetty-plugins
org.apache.skywalking
- 9.3.0-SNAPSHOT
+ 9.7.0-SNAPSHOT
4.0.0
diff --git a/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-client-9.0-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/v90/client/AsyncHttpRequestSendInterceptor.java b/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-client-9.0-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/v90/client/AsyncHttpRequestSendInterceptor.java
index 669b43ffda..2858afce44 100644
--- a/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-client-9.0-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/v90/client/AsyncHttpRequestSendInterceptor.java
+++ b/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-client-9.0-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/v90/client/AsyncHttpRequestSendInterceptor.java
@@ -58,8 +58,13 @@ public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allAr
span.prepareForAsync();
request.attribute(Constants.SW_JETTY_EXIT_SPAN_KEY, span);
- Response.CompleteListener callback = (Response.CompleteListener) allArguments[0];
- allArguments[0] = new CompleteListenerWrapper(callback, ContextManager.capture());
+ if (allArguments[0] instanceof Response.Listener) {
+ Response.Listener listener = (Response.Listener) allArguments[0];
+ allArguments[0] = new ResponseListenerWrapper(listener, ContextManager.capture());
+ } else {
+ Response.CompleteListener listener = (Response.CompleteListener) allArguments[0];
+ allArguments[0] = new CompleteListenerWrapper(listener, ContextManager.capture());
+ }
}
@Override
diff --git a/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-client-9.0-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/v90/client/CompleteListenerWrapper.java b/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-client-9.0-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/v90/client/CompleteListenerWrapper.java
index 0318bd4c00..294b32fe7d 100644
--- a/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-client-9.0-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/v90/client/CompleteListenerWrapper.java
+++ b/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-client-9.0-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/v90/client/CompleteListenerWrapper.java
@@ -27,11 +27,11 @@
import org.eclipse.jetty.client.api.Result;
public class CompleteListenerWrapper implements Response.CompleteListener {
- private Response.CompleteListener callback;
+ private Response.CompleteListener listener;
private ContextSnapshot context;
- public CompleteListenerWrapper(Response.CompleteListener callback, ContextSnapshot context) {
- this.callback = callback;
+ public CompleteListenerWrapper(Response.CompleteListener listener, ContextSnapshot context) {
+ this.listener = listener;
this.context = context;
}
@@ -43,9 +43,9 @@ public void onComplete(Result result) {
if (context != null) {
ContextManager.continued(context);
}
- if (callback != null) {
- callback.onComplete(result);
+ if (listener != null) {
+ listener.onComplete(result);
}
ContextManager.stopSpan();
}
-}
+}
\ No newline at end of file
diff --git a/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-client-9.0-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/v90/client/ResponseListenerWrapper.java b/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-client-9.0-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/v90/client/ResponseListenerWrapper.java
new file mode 100644
index 0000000000..cf3e097dda
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-client-9.0-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/v90/client/ResponseListenerWrapper.java
@@ -0,0 +1,85 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.jetty.v90.client;
+
+import org.apache.skywalking.apm.agent.core.context.ContextManager;
+import org.apache.skywalking.apm.agent.core.context.ContextSnapshot;
+import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan;
+import org.apache.skywalking.apm.agent.core.context.trace.SpanLayer;
+import org.apache.skywalking.apm.network.trace.component.ComponentsDefine;
+import org.eclipse.jetty.client.api.Response;
+import org.eclipse.jetty.client.api.Result;
+import org.eclipse.jetty.http.HttpField;
+import java.nio.ByteBuffer;
+
+public class ResponseListenerWrapper implements Response.Listener {
+
+ private final Response.Listener listener;
+
+ private final ContextSnapshot context;
+
+ public ResponseListenerWrapper(Response.Listener listener, ContextSnapshot context) {
+ this.listener = listener;
+ this.context = context;
+ }
+
+ @Override
+ public void onComplete(Result result) {
+ AbstractSpan span = ContextManager.createLocalSpan(Constants.PLUGIN_NAME + "/CompleteListener/onComplete");
+ span.setComponent(ComponentsDefine.JETTY_CLIENT);
+ SpanLayer.asHttp(span);
+ if (context != null) {
+ ContextManager.continued(context);
+ }
+ if (listener != null) {
+ listener.onComplete(result);
+ }
+ ContextManager.stopSpan();
+ }
+
+ @Override
+ public void onHeaders(Response response) {
+ listener.onHeaders(response);
+ }
+
+ @Override
+ public void onContent(Response response, ByteBuffer content) {
+ listener.onContent(response, content);
+ }
+
+ @Override
+ public void onBegin(Response response) {
+ listener.onBegin(response);
+ }
+
+ @Override
+ public boolean onHeader(Response response, HttpField field) {
+ return listener.onHeader(response, field);
+ }
+
+ @Override
+ public void onSuccess(Response response) {
+ listener.onSuccess(response);
+ }
+
+ @Override
+ public void onFailure(Response response, Throwable failure) {
+ listener.onFailure(response, failure);
+ }
+}
\ No newline at end of file
diff --git a/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-client-9.0-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/v90/client/define/HttpRequestInstrumentation.java b/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-client-9.0-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/v90/client/define/HttpRequestInstrumentation.java
index ef8daf105a..2bee7ecdc1 100644
--- a/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-client-9.0-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/v90/client/define/HttpRequestInstrumentation.java
+++ b/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-client-9.0-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/v90/client/define/HttpRequestInstrumentation.java
@@ -41,7 +41,7 @@ public class HttpRequestInstrumentation extends ClassInstanceMethodsEnhancePlugi
private static final String ENHANCE_CLASS = "org.eclipse.jetty.client.HttpRequest";
private static final String ENHANCE_CLASS_NAME = "send";
public static final String SYNC_SEND_INTERCEPTOR =
- "org.apache.skywalking.apm.plugin.jetty.v90.client.SyncHttpRequestSendV90Interceptor";
+ "org.apache.skywalking.apm.plugin.jetty.v90.client.SyncHttpRequestSendInterceptor";
public static final String ASYNC_SEND_INTERCEPTOR =
"org.apache.skywalking.apm.plugin.jetty.v90.client.AsyncHttpRequestSendInterceptor";
@@ -85,7 +85,7 @@ public String getMethodsInterceptor() {
@Override
public boolean isOverrideArgs() {
- return false;
+ return true;
}
}
};
diff --git a/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-client-9.0-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/v90/client/define/ResponseNotifierInstrumentation.java b/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-client-9.0-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/v90/client/define/ResponseNotifierInstrumentation.java
index c4f39c4147..5502c8dc78 100644
--- a/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-client-9.0-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/v90/client/define/ResponseNotifierInstrumentation.java
+++ b/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-client-9.0-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/v90/client/define/ResponseNotifierInstrumentation.java
@@ -41,10 +41,10 @@
*/
public class ResponseNotifierInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
- private static final String ENHANCE_CLASS = "org.eclipse.jetty.client.tar";
+ private static final String ENHANCE_CLASS = "org.eclipse.jetty.client.ResponseNotifier";
private static final String ENHANCE_CLASS_NAME = "notifyComplete";
public static final String SYNC_SEND_INTERCEPTOR =
- "org.apache.skywalking.apm.plugin.jetty.v9.client.ResponseNotifierInterceptor";
+ "org.apache.skywalking.apm.plugin.jetty.v90.client.ResponseNotifierInterceptor";
@Override
public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
diff --git a/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-client-9.x-plugin/pom.xml b/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-client-9.x-plugin/pom.xml
index 8e091d09b2..a7f7168743 100644
--- a/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-client-9.x-plugin/pom.xml
+++ b/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-client-9.x-plugin/pom.xml
@@ -20,7 +20,7 @@
jetty-plugins
org.apache.skywalking
- 9.3.0-SNAPSHOT
+ 9.7.0-SNAPSHOT
4.0.0
@@ -31,7 +31,7 @@
http://maven.apache.org
- 9.1.0.v20131115
+ 9.2.23.v20171218
diff --git a/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-client-9.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/v9/client/AsyncHttpRequestSendInterceptor.java b/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-client-9.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/v9/client/AsyncHttpRequestSendInterceptor.java
index 6f8870af49..6f39452e0c 100644
--- a/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-client-9.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/v9/client/AsyncHttpRequestSendInterceptor.java
+++ b/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-client-9.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/v9/client/AsyncHttpRequestSendInterceptor.java
@@ -57,8 +57,13 @@ public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allAr
span.prepareForAsync();
request.attribute(Constants.SW_JETTY_EXIT_SPAN_KEY, span);
- Response.CompleteListener callback = (Response.CompleteListener) allArguments[0];
- allArguments[0] = new CompleteListenerWrapper(callback, ContextManager.capture());
+ if (allArguments[0] instanceof Response.Listener) {
+ Response.Listener listener = (Response.Listener) allArguments[0];
+ allArguments[0] = new ResponseListenerWrapper(listener, ContextManager.capture());
+ } else {
+ Response.CompleteListener listener = (Response.CompleteListener) allArguments[0];
+ allArguments[0] = new CompleteListenerWrapper(listener, ContextManager.capture());
+ }
}
@Override
diff --git a/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-client-9.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/v9/client/CompleteListenerWrapper.java b/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-client-9.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/v9/client/CompleteListenerWrapper.java
index 50697bf3e4..156e636884 100644
--- a/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-client-9.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/v9/client/CompleteListenerWrapper.java
+++ b/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-client-9.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/v9/client/CompleteListenerWrapper.java
@@ -27,11 +27,11 @@
import org.eclipse.jetty.client.api.Result;
public class CompleteListenerWrapper implements Response.CompleteListener {
- private Response.CompleteListener callback;
+ private Response.CompleteListener listener;
private ContextSnapshot context;
- public CompleteListenerWrapper(Response.CompleteListener callback, ContextSnapshot context) {
- this.callback = callback;
+ public CompleteListenerWrapper(Response.CompleteListener listener, ContextSnapshot context) {
+ this.listener = listener;
this.context = context;
}
@@ -43,9 +43,9 @@ public void onComplete(Result result) {
if (context != null) {
ContextManager.continued(context);
}
- if (callback != null) {
- callback.onComplete(result);
+ if (listener != null) {
+ listener.onComplete(result);
}
ContextManager.stopSpan();
}
-}
+}
\ No newline at end of file
diff --git a/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-client-9.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/v9/client/ResponseListenerWrapper.java b/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-client-9.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/v9/client/ResponseListenerWrapper.java
new file mode 100644
index 0000000000..09102cdc43
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-client-9.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/v9/client/ResponseListenerWrapper.java
@@ -0,0 +1,92 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.jetty.v9.client;
+
+import org.apache.skywalking.apm.agent.core.context.ContextManager;
+import org.apache.skywalking.apm.agent.core.context.ContextSnapshot;
+import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan;
+import org.apache.skywalking.apm.agent.core.context.trace.SpanLayer;
+import org.apache.skywalking.apm.network.trace.component.ComponentsDefine;
+import org.eclipse.jetty.client.api.Response;
+import org.eclipse.jetty.client.api.Result;
+import org.eclipse.jetty.http.HttpField;
+import org.eclipse.jetty.util.Callback;
+
+import java.nio.ByteBuffer;
+
+public class ResponseListenerWrapper implements Response.Listener {
+
+ private final Response.Listener listener;
+
+ private final ContextSnapshot context;
+
+ public ResponseListenerWrapper(Response.Listener listener, ContextSnapshot context) {
+ this.listener = listener;
+ this.context = context;
+ }
+
+ @Override
+ public void onComplete(Result result) {
+ AbstractSpan span = ContextManager.createLocalSpan(Constants.PLUGIN_NAME + "/CompleteListener/onComplete");
+ span.setComponent(ComponentsDefine.JETTY_CLIENT);
+ SpanLayer.asHttp(span);
+ if (context != null) {
+ ContextManager.continued(context);
+ }
+ if (listener != null) {
+ listener.onComplete(result);
+ }
+ ContextManager.stopSpan();
+ }
+
+ @Override
+ public void onHeaders(Response response) {
+ listener.onHeaders(response);
+ }
+
+ @Override
+ public void onContent(Response response, ByteBuffer content, Callback callback) {
+ listener.onContent(response, content, callback);
+ }
+
+ @Override
+ public void onContent(Response response, ByteBuffer content) {
+ listener.onContent(response, content);
+ }
+
+ @Override
+ public void onBegin(Response response) {
+ listener.onBegin(response);
+ }
+
+ @Override
+ public boolean onHeader(Response response, HttpField field) {
+ return listener.onHeader(response, field);
+ }
+
+ @Override
+ public void onSuccess(Response response) {
+ listener.onSuccess(response);
+ }
+
+ @Override
+ public void onFailure(Response response, Throwable failure) {
+ listener.onFailure(response, failure);
+ }
+}
\ No newline at end of file
diff --git a/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-client-9.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/jetty/v9/client/AsyncHttpRequestSendInterceptorTest.java b/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-client-9.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/jetty/v9/client/AsyncHttpRequestSendInterceptorTest.java
index ae3dc47db1..fb044435da 100644
--- a/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-client-9.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/jetty/v9/client/AsyncHttpRequestSendInterceptorTest.java
+++ b/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-client-9.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/jetty/v9/client/AsyncHttpRequestSendInterceptorTest.java
@@ -33,6 +33,7 @@
import org.apache.skywalking.apm.agent.test.tools.TracingSegmentRunner;
import org.apache.skywalking.apm.network.trace.component.ComponentsDefine;
import org.eclipse.jetty.client.HttpClient;
+import org.eclipse.jetty.client.HttpConversation;
import org.eclipse.jetty.client.HttpRequest;
import org.eclipse.jetty.client.ResponseNotifier;
import org.eclipse.jetty.client.api.Response;
@@ -82,8 +83,8 @@ public class AsyncHttpRequestSendInterceptorTest {
@Before
public void setUp() throws Exception {
- httpRequestEnhancedInstance = new MockHttpRequest(httpClient, uri);
- responseNotifierEnhancedInstance = new MockResponseNotifier(httpClient);
+ httpRequestEnhancedInstance = new MockHttpRequest(httpClient, new HttpConversation(), uri);
+ responseNotifierEnhancedInstance = new MockResponseNotifier();
Result results = new Result(httpRequestEnhancedInstance, response);
allArguments = new Object[]{(Response.CompleteListener) result -> { }, results};
@@ -146,8 +147,8 @@ private void assertJettySpan() {
}
private class MockHttpRequest extends HttpRequest implements EnhancedInstance {
- public MockHttpRequest(HttpClient httpClient, URI uri) {
- super(httpClient, uri);
+ public MockHttpRequest(HttpClient client, HttpConversation conversation, URI uri) {
+ super(httpClient, conversation, uri);
}
@Override
@@ -172,8 +173,8 @@ public void setSkyWalkingDynamicField(Object value) {
}
private class MockResponseNotifier extends ResponseNotifier implements EnhancedInstance {
- public MockResponseNotifier(HttpClient client) {
- super(client);
+ public MockResponseNotifier() {
+ super();
}
@Override
diff --git a/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-client-9.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/jetty/v9/client/SyncHttpRequestSendInterceptorTest.java b/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-client-9.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/jetty/v9/client/SyncHttpRequestSendInterceptorTest.java
index e4a861fbc7..6f9d2ec489 100644
--- a/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-client-9.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/jetty/v9/client/SyncHttpRequestSendInterceptorTest.java
+++ b/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-client-9.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/jetty/v9/client/SyncHttpRequestSendInterceptorTest.java
@@ -34,6 +34,7 @@
import org.apache.skywalking.apm.agent.test.tools.SpanAssert;
import org.apache.skywalking.apm.agent.test.tools.TracingSegmentRunner;
import org.eclipse.jetty.client.HttpClient;
+import org.eclipse.jetty.client.HttpConversation;
import org.eclipse.jetty.client.HttpRequest;
import org.junit.Assert;
import org.junit.Before;
@@ -67,7 +68,7 @@ public class SyncHttpRequestSendInterceptorTest {
@Before
public void setUp() throws Exception {
- enhancedInstance = new MockHttpRequest(httpClient, uri);
+ enhancedInstance = new MockHttpRequest(httpClient, new HttpConversation(), uri);
allArguments = new Object[] {
"OperationKey",
"OperationValue"
@@ -123,8 +124,8 @@ public void testMethodsAroundError() throws Throwable {
}
private class MockHttpRequest extends HttpRequest implements EnhancedInstance {
- public MockHttpRequest(HttpClient httpClient, URI uri) {
- super(httpClient, uri);
+ public MockHttpRequest(HttpClient client, HttpConversation conversation, URI uri) {
+ super(httpClient, conversation, uri);
}
@Override
diff --git a/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-12.x-plugin/pom.xml b/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-12.x-plugin/pom.xml
new file mode 100644
index 0000000000..dfc04b5933
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-12.x-plugin/pom.xml
@@ -0,0 +1,52 @@
+
+
+
+
+ jetty-plugins
+ org.apache.skywalking
+ 9.7.0-SNAPSHOT
+
+ 4.0.0
+
+ apm-jetty-server-12.x-plugin
+ jar
+
+ jetty-server-12.x-plugin
+ http://maven.apache.org
+
+
+
+ 12.0.36
+
+
+
+
+ org.eclipse.jetty
+ jetty-server
+ ${jetty-server.version}
+ provided
+
+
+
diff --git a/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-12.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/v12/server/HandleInterceptor.java b/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-12.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/v12/server/HandleInterceptor.java
new file mode 100644
index 0000000000..74e08614dd
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-12.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/v12/server/HandleInterceptor.java
@@ -0,0 +1,100 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.jetty.v12.server;
+
+import java.lang.reflect.Method;
+import org.apache.skywalking.apm.agent.core.context.CarrierItem;
+import org.apache.skywalking.apm.agent.core.context.ContextCarrier;
+import org.apache.skywalking.apm.agent.core.context.ContextManager;
+import org.apache.skywalking.apm.agent.core.context.tag.Tags;
+import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan;
+import org.apache.skywalking.apm.agent.core.context.trace.SpanLayer;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
+import org.apache.skywalking.apm.network.trace.component.ComponentsDefine;
+import org.eclipse.jetty.http.HttpFields;
+import org.eclipse.jetty.http.HttpURI;
+import org.eclipse.jetty.server.Request;
+import org.eclipse.jetty.server.Response;
+import org.eclipse.jetty.util.Callback;
+
+/**
+ * Enhances the core, namespace-neutral {@code org.eclipse.jetty.server.Server#handle(Request, Response,
+ * Callback)} — the single top-level entry invoked once per request in Jetty 12. Handling is async, so
+ * the entry span is prepared for async in beforeMethod, its synchronous segment ends in afterMethod, and
+ * it is finished (with the response status) when the wrapped {@link SwCallback} completes.
+ */
+public class HandleInterceptor implements InstanceMethodsAroundInterceptor {
+
+ private static final ThreadLocal HOLDER = new ThreadLocal();
+
+ @Override
+ public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes,
+ MethodInterceptResult result) throws Throwable {
+ Request request = (Request) allArguments[0];
+ Response response = (Response) allArguments[1];
+ Callback callback = (Callback) allArguments[2];
+
+ ContextCarrier contextCarrier = new ContextCarrier();
+ HttpFields headers = request.getHeaders();
+ CarrierItem next = contextCarrier.items();
+ while (next.hasNext()) {
+ next = next.next();
+ next.setHeadValue(headers.get(next.getHeadKey()));
+ }
+
+ HttpURI uri = request.getHttpURI();
+ AbstractSpan span = ContextManager.createEntrySpan(uri.getPath(), contextCarrier);
+ Tags.URL.set(span, uri.asString());
+ Tags.HTTP.METHOD.set(span, request.getMethod());
+ span.setComponent(ComponentsDefine.JETTY_SERVER);
+ SpanLayer.asHttp(span);
+ span.prepareForAsync();
+
+ SwCallback swCallback = new SwCallback(callback, response, span);
+ allArguments[2] = swCallback;
+ HOLDER.set(swCallback);
+ }
+
+ @Override
+ public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes,
+ Object ret) throws Throwable {
+ SwCallback swCallback = HOLDER.get();
+ HOLDER.remove();
+ ContextManager.stopSpan();
+ // ret == true: handled; the wrapped callback fires on response completion and finishes the span.
+ // ret == false: not handled — Jetty writes 404 on the original callback, bypassing ours.
+ // ret == null: handle() threw (see handleMethodException) — Jetty writes 500.
+ // For the latter two the wrapped callback never fires and the status is written only after
+ // handle() returns, so finish here with the status Jetty's contract guarantees.
+ if (swCallback != null && !Boolean.TRUE.equals(ret)) {
+ swCallback.finishWithStatus(ret == null ? 500 : 404);
+ }
+ return ret;
+ }
+
+ @Override
+ public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments,
+ Class>[] argumentsTypes, Throwable t) {
+ AbstractSpan span = ContextManager.activeSpan();
+ span.log(t);
+ span.errorOccurred();
+ }
+}
diff --git a/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-12.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/v12/server/SwCallback.java b/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-12.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/v12/server/SwCallback.java
new file mode 100644
index 0000000000..f5193d7c05
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-12.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/v12/server/SwCallback.java
@@ -0,0 +1,98 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.jetty.v12.server;
+
+import java.util.concurrent.atomic.AtomicBoolean;
+import org.apache.skywalking.apm.agent.core.context.tag.Tags;
+import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan;
+import org.eclipse.jetty.server.Response;
+import org.eclipse.jetty.util.Callback;
+import org.eclipse.jetty.util.thread.Invocable;
+
+/**
+ * Wraps the {@link Callback} passed to {@code Server#handle}. Jetty 12 request handling is async — the
+ * response status is only known when the callback completes on the (possibly different) response thread.
+ * On completion this reads the status, records it on the entry span and finishes the async span. It
+ * delegates every method to the original callback so Jetty's threading model is preserved.
+ */
+public class SwCallback implements Callback {
+
+ private final Callback delegate;
+ private final Response response;
+ private final AbstractSpan span;
+ private final AtomicBoolean finished = new AtomicBoolean();
+
+ public SwCallback(Callback delegate, Response response, AbstractSpan span) {
+ this.delegate = delegate;
+ this.response = response;
+ this.span = span;
+ }
+
+ @Override
+ public void succeeded() {
+ finishOnce();
+ delegate.succeeded();
+ }
+
+ @Override
+ public void failed(Throwable x) {
+ if (finished.compareAndSet(false, true)) {
+ span.log(x);
+ span.errorOccurred();
+ Tags.HTTP_RESPONSE_STATUS_CODE.set(span, response.getStatus());
+ span.asyncFinish();
+ }
+ delegate.failed(x);
+ }
+
+ @Override
+ public Invocable.InvocationType getInvocationType() {
+ return delegate.getInvocationType();
+ }
+
+ /**
+ * Records the response status and finishes the async span exactly once. Safe to call from either the
+ * callback completion or the interceptor's afterMethod fallback (not-handled / exception paths).
+ */
+ void finishOnce() {
+ if (finished.compareAndSet(false, true)) {
+ int statusCode = response.getStatus();
+ Tags.HTTP_RESPONSE_STATUS_CODE.set(span, statusCode);
+ if (statusCode >= 400) {
+ span.errorOccurred();
+ }
+ span.asyncFinish();
+ }
+ }
+
+ /**
+ * Finishes the async span exactly once with an explicit status. Used for the not-handled / exception
+ * fallback paths where Jetty writes the error status on the original callback after {@code handle()}
+ * returns — so the wrapped callback never fires and {@link Response#getStatus()} is still 0 (uncommitted).
+ */
+ void finishWithStatus(int statusCode) {
+ if (finished.compareAndSet(false, true)) {
+ Tags.HTTP_RESPONSE_STATUS_CODE.set(span, statusCode);
+ if (statusCode >= 400) {
+ span.errorOccurred();
+ }
+ span.asyncFinish();
+ }
+ }
+}
diff --git a/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-12.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/v12/server/define/Jetty12ServerInstrumentation.java b/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-12.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/v12/server/define/Jetty12ServerInstrumentation.java
new file mode 100644
index 0000000000..8b4d347af9
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-12.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/v12/server/define/Jetty12ServerInstrumentation.java
@@ -0,0 +1,89 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.jetty.v12.server.define;
+
+import java.util.Collections;
+import java.util.List;
+import net.bytebuddy.description.method.MethodDescription;
+import net.bytebuddy.matcher.ElementMatcher;
+import org.apache.skywalking.apm.agent.core.plugin.WitnessMethod;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine;
+import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
+
+import static net.bytebuddy.matcher.ElementMatchers.named;
+import static net.bytebuddy.matcher.ElementMatchers.takesArgument;
+import static net.bytebuddy.matcher.ElementMatchers.takesArguments;
+import static org.apache.skywalking.apm.agent.core.plugin.match.NameMatch.byName;
+
+/**
+ * Enhances {@code org.eclipse.jetty.server.Server#handle(Request, Response, Callback)} by
+ * {@code HandleInterceptor}. Only Jetty 12+ declares this three-argument, {@code Callback}-terminated
+ * signature, so the witness method both activates the plugin exclusively on Jetty 12 and keeps it from
+ * overlapping the merged jetty-server plugin (which enhances the Jetty 9/10/11 {@code HttpChannel},
+ * removed in Jetty 12).
+ */
+public class Jetty12ServerInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
+
+ private static final String ENHANCE_CLASS = "org.eclipse.jetty.server.Server";
+ private static final String ENHANCE_METHOD = "handle";
+ private static final String CALLBACK_CLASS = "org.eclipse.jetty.util.Callback";
+ private static final String INTERCEPT_CLASS = "org.apache.skywalking.apm.plugin.jetty.v12.server.HandleInterceptor";
+
+ @Override
+ protected List witnessMethods() {
+ return Collections.singletonList(new WitnessMethod(
+ ENHANCE_CLASS,
+ named(ENHANCE_METHOD).and(takesArgument(2, named(CALLBACK_CLASS)))
+ ));
+ }
+
+ @Override
+ public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
+ return new ConstructorInterceptPoint[0];
+ }
+
+ @Override
+ public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
+ return new InstanceMethodsInterceptPoint[] {
+ new InstanceMethodsInterceptPoint() {
+ @Override
+ public ElementMatcher getMethodsMatcher() {
+ return named(ENHANCE_METHOD).and(takesArguments(3)).and(takesArgument(2, named(CALLBACK_CLASS)));
+ }
+
+ @Override
+ public String getMethodsInterceptor() {
+ return INTERCEPT_CLASS;
+ }
+
+ @Override
+ public boolean isOverrideArgs() {
+ return true;
+ }
+ }
+ };
+ }
+
+ @Override
+ protected ClassMatch enhanceClass() {
+ return byName(ENHANCE_CLASS);
+ }
+}
diff --git a/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-12.x-plugin/src/main/resources/skywalking-plugin.def b/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-12.x-plugin/src/main/resources/skywalking-plugin.def
new file mode 100644
index 0000000000..2c466d5f66
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-12.x-plugin/src/main/resources/skywalking-plugin.def
@@ -0,0 +1,18 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+jetty-server-12.x=org.apache.skywalking.apm.plugin.jetty.v12.server.define.Jetty12ServerInstrumentation
diff --git a/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-plugin/pom.xml b/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-plugin/pom.xml
new file mode 100644
index 0000000000..8477c1b9b8
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-plugin/pom.xml
@@ -0,0 +1,58 @@
+
+
+
+
+ jetty-plugins
+ org.apache.skywalking
+ 9.7.0-SNAPSHOT
+
+ 4.0.0
+
+ apm-jetty-server-plugin
+ jar
+
+ jetty-server-plugin
+ http://maven.apache.org
+
+
+
+ 11.0.15
+
+
+
+
+ org.eclipse.jetty
+ jetty-server
+ ${jetty-server.version}
+ provided
+
+
+ org.apache.skywalking
+ apm-servlet-commons
+ ${project.version}
+ provided
+
+
+
diff --git a/apm-sniffer/apm-sdk-plugin/tomcat-10x-plugin/src/main/java/org/apache/skywalking/apm/plugin/tomcat10x/Constants.java b/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/server/Constants.java
similarity index 94%
rename from apm-sniffer/apm-sdk-plugin/tomcat-10x-plugin/src/main/java/org/apache/skywalking/apm/plugin/tomcat10x/Constants.java
rename to apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/server/Constants.java
index 3aa2d92ae3..22948d4a7d 100644
--- a/apm-sniffer/apm-sdk-plugin/tomcat-10x-plugin/src/main/java/org/apache/skywalking/apm/plugin/tomcat10x/Constants.java
+++ b/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/server/Constants.java
@@ -17,7 +17,7 @@
*
*/
-package org.apache.skywalking.apm.plugin.tomcat10x;
+package org.apache.skywalking.apm.plugin.jetty.server;
public class Constants {
public static final String FORWARD_REQUEST_FLAG = "SW_FORWARD_REQUEST_FLAG";
diff --git a/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-9.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/v9/server/ForwardInterceptor.java b/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/server/ForwardInterceptor.java
similarity index 97%
rename from apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-9.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/v9/server/ForwardInterceptor.java
rename to apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/server/ForwardInterceptor.java
index 669fae1770..0855f9961a 100644
--- a/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-9.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/v9/server/ForwardInterceptor.java
+++ b/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/server/ForwardInterceptor.java
@@ -17,11 +17,8 @@
*
*/
-package org.apache.skywalking.apm.plugin.jetty.v9.server;
+package org.apache.skywalking.apm.plugin.jetty.server;
-import java.lang.reflect.Method;
-import java.util.HashMap;
-import java.util.Map;
import org.apache.skywalking.apm.agent.core.context.ContextManager;
import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
@@ -29,6 +26,10 @@
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
+import java.lang.reflect.Method;
+import java.util.HashMap;
+import java.util.Map;
+
public class ForwardInterceptor implements InstanceMethodsAroundInterceptor, InstanceConstructorInterceptor {
@Override
diff --git a/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-11.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/v11/server/HandleInterceptor.java b/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/server/HandleInterceptor.java
similarity index 75%
rename from apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-11.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/v11/server/HandleInterceptor.java
rename to apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/server/HandleInterceptor.java
index a8f663a917..386587d270 100644
--- a/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-11.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/v11/server/HandleInterceptor.java
+++ b/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/server/HandleInterceptor.java
@@ -16,10 +16,8 @@
*
*/
-package org.apache.skywalking.apm.plugin.jetty.v11.server;
+package org.apache.skywalking.apm.plugin.jetty.server;
-import jakarta.servlet.http.HttpServletRequest;
-import jakarta.servlet.http.HttpServletResponse;
import org.apache.skywalking.apm.agent.core.context.CarrierItem;
import org.apache.skywalking.apm.agent.core.context.ContextCarrier;
import org.apache.skywalking.apm.agent.core.context.ContextManager;
@@ -30,6 +28,10 @@
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
import org.apache.skywalking.apm.network.trace.component.ComponentsDefine;
+import org.apache.skywalking.apm.plugin.servlet.HttpRequestWrapper;
+import org.apache.skywalking.apm.plugin.servlet.HttpRequestWrappers;
+import org.apache.skywalking.apm.plugin.servlet.HttpResponseWrapper;
+import org.apache.skywalking.apm.plugin.servlet.HttpResponseWrappers;
import org.eclipse.jetty.server.HttpChannel;
import java.lang.reflect.Method;
@@ -40,7 +42,9 @@ public class HandleInterceptor implements InstanceMethodsAroundInterceptor {
public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes,
MethodInterceptResult result) throws Throwable {
HttpChannel httpChannel = (HttpChannel) objInst;
- HttpServletRequest servletRequest = httpChannel.getRequest();
+ // getRequest() returns the concrete org.eclipse.jetty.server.Request; the wrapper resolves the
+ // javax vs jakarta servlet namespace at runtime, keeping this interceptor namespace-neutral.
+ HttpRequestWrapper servletRequest = HttpRequestWrappers.wrap(httpChannel.getRequest());
ContextCarrier contextCarrier = new ContextCarrier();
@@ -61,11 +65,15 @@ public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allAr
public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes,
Object ret) throws Throwable {
HttpChannel httpChannel = (HttpChannel) objInst;
- HttpServletResponse servletResponse = httpChannel.getResponse();
AbstractSpan span = ContextManager.activeSpan();
- Tags.HTTP_RESPONSE_STATUS_CODE.set(span, servletResponse.getStatus());
- if (servletResponse.getStatus() >= 400) {
- span.errorOccurred();
+ // A null wrapper means getStatus() is unavailable (pre-Servlet-3.0), matching the historical guard.
+ HttpResponseWrapper servletResponse = HttpResponseWrappers.wrap(httpChannel.getResponse());
+ if (servletResponse != null) {
+ int statusCode = servletResponse.getStatus();
+ Tags.HTTP_RESPONSE_STATUS_CODE.set(span, statusCode);
+ if (statusCode >= 400) {
+ span.errorOccurred();
+ }
}
ContextManager.stopSpan();
ContextManager.getRuntimeContext().remove(Constants.FORWARD_REQUEST_FLAG);
diff --git a/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-9.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/v9/server/define/AbstractWitnessInstrumentation.java b/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/server/define/AbstractWitnessInstrumentation.java
similarity index 75%
rename from apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-9.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/v9/server/define/AbstractWitnessInstrumentation.java
rename to apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/server/define/AbstractWitnessInstrumentation.java
index 9ed1aba497..3a0993fee7 100644
--- a/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-9.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/v9/server/define/AbstractWitnessInstrumentation.java
+++ b/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/server/define/AbstractWitnessInstrumentation.java
@@ -17,7 +17,7 @@
*
*/
-package org.apache.skywalking.apm.plugin.jetty.v9.server.define;
+package org.apache.skywalking.apm.plugin.jetty.server.define;
import org.apache.skywalking.apm.agent.core.plugin.WitnessMethod;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine;
@@ -31,9 +31,13 @@
public abstract class AbstractWitnessInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
@Override
protected List witnessMethods() {
+ // Match the Jetty Handler#handle whose request argument is either the javax (Jetty 9/10) or the
+ // jakarta (Jetty 11) servlet namespace, so a single merged plugin activates on both. A single
+ // Jetty distribution carries only one namespace, so exactly one branch matches at runtime.
return Collections.singletonList(new WitnessMethod(
"org.eclipse.jetty.server.Handler",
- named("handle").and(takesArgument(2, named("javax.servlet.http.HttpServletRequest")))
+ named("handle").and(takesArgument(2, named("javax.servlet.http.HttpServletRequest")
+ .or(named("jakarta.servlet.http.HttpServletRequest"))))
));
}
}
diff --git a/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-11.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/v11/server/define/DispatcherInstrumentation.java b/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/server/define/DispatcherInstrumentation.java
similarity index 96%
rename from apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-11.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/v11/server/define/DispatcherInstrumentation.java
rename to apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/server/define/DispatcherInstrumentation.java
index d843ae629f..ba468ad1b3 100644
--- a/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-11.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/v11/server/define/DispatcherInstrumentation.java
+++ b/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/server/define/DispatcherInstrumentation.java
@@ -17,7 +17,7 @@
*
*/
-package org.apache.skywalking.apm.plugin.jetty.v11.server.define;
+package org.apache.skywalking.apm.plugin.jetty.server.define;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.matcher.ElementMatcher;
@@ -32,7 +32,7 @@
public class DispatcherInstrumentation extends AbstractWitnessInstrumentation {
private static final String ENHANCE_CLASS = "org.eclipse.jetty.server.Dispatcher";
- public static final String INTERCEPT_CLASS = "org.apache.skywalking.apm.plugin.jetty.v11.server.ForwardInterceptor";
+ public static final String INTERCEPT_CLASS = "org.apache.skywalking.apm.plugin.jetty.server.ForwardInterceptor";
@Override
public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
diff --git a/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-11.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/v11/server/define/JettyInstrumentation.java b/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/server/define/JettyInstrumentation.java
similarity index 96%
rename from apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-11.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/v11/server/define/JettyInstrumentation.java
rename to apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/server/define/JettyInstrumentation.java
index 417dc67df3..1c8eb083ac 100644
--- a/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-11.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/v11/server/define/JettyInstrumentation.java
+++ b/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/server/define/JettyInstrumentation.java
@@ -16,7 +16,7 @@
*
*/
-package org.apache.skywalking.apm.plugin.jetty.v11.server.define;
+package org.apache.skywalking.apm.plugin.jetty.server.define;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.matcher.ElementMatcher;
@@ -35,7 +35,7 @@ public class JettyInstrumentation extends AbstractWitnessInstrumentation {
private static final String ENHANCE_CLASS = "org.eclipse.jetty.server.HttpChannel";
private static final String ENHANCE_METHOD = "handle";
- private static final String INTERCEPTOR_CLASS = "org.apache.skywalking.apm.plugin.jetty.v11.server" +
+ private static final String INTERCEPTOR_CLASS = "org.apache.skywalking.apm.plugin.jetty.server" +
".HandleInterceptor";
@Override
diff --git a/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-plugin/src/main/resources/skywalking-plugin.def b/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-plugin/src/main/resources/skywalking-plugin.def
new file mode 100644
index 0000000000..f54cd54edb
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-plugin/src/main/resources/skywalking-plugin.def
@@ -0,0 +1,18 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+jetty-server=org.apache.skywalking.apm.plugin.jetty.server.define.JettyInstrumentation
+jetty-server=org.apache.skywalking.apm.plugin.jetty.server.define.DispatcherInstrumentation
diff --git a/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-9.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/jetty/v9/server/HandleInterceptorTest.java b/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-plugin/src/test/java/org/apache/skywalking/apm/plugin/jetty/server/HandleInterceptorTest.java
similarity index 89%
rename from apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-9.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/jetty/v9/server/HandleInterceptorTest.java
rename to apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-plugin/src/test/java/org/apache/skywalking/apm/plugin/jetty/server/HandleInterceptorTest.java
index f4c8fef0dd..77100bf9d0 100644
--- a/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-9.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/jetty/v9/server/HandleInterceptorTest.java
+++ b/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-plugin/src/test/java/org/apache/skywalking/apm/plugin/jetty/server/HandleInterceptorTest.java
@@ -16,7 +16,7 @@
*
*/
-package org.apache.skywalking.apm.plugin.jetty.v9.server;
+package org.apache.skywalking.apm.plugin.jetty.server;
import static org.apache.skywalking.apm.agent.test.tools.SpanAssert.assertComponent;
import static org.hamcrest.CoreMatchers.is;
@@ -44,7 +44,6 @@
import org.eclipse.jetty.server.Connector;
import org.eclipse.jetty.server.HttpChannel;
import org.eclipse.jetty.server.HttpConfiguration;
-import org.eclipse.jetty.server.HttpInput;
import org.eclipse.jetty.server.HttpTransport;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.Response;
@@ -87,6 +86,7 @@ public void setUp() throws Exception {
jettyInvokeInterceptor = new HandleInterceptor();
when(request.getRequestURI()).thenReturn("/test/testRequestURL");
when(request.getRequestURL()).thenReturn(new StringBuffer("http://localhost:8080/test/testRequestURL"));
+ when(request.getMethod()).thenReturn("GET");
when(response.getStatus()).thenReturn(200);
when(service.getResponse()).thenReturn(response);
when(service.getRequest()).thenReturn(request);
@@ -152,11 +152,18 @@ private void assertHttpSpan(AbstractTracingSpan span) {
SpanAssert.assertLayer(span, SpanLayer.HTTP);
}
- public static class MockService extends HttpChannel implements EnhancedInstance {
+ /**
+ * The merged {@link HandleInterceptor} casts the enhanced instance to the concrete Jetty
+ * {@link HttpChannel} and reads the request/response through the servlet-commons wrappers, so the
+ * mock target must be a Jetty 11 (jakarta) {@link HttpChannel} whose {@link #getRequest()} /
+ * {@link #getResponse()} return jakarta servlet request/response objects. Declared abstract to
+ * skip Jetty 11 {@code HttpChannel}'s abstract members, which Mockito stubs automatically.
+ */
+ public abstract static class MockService extends HttpChannel implements EnhancedInstance {
public MockService(Connector connector, HttpConfiguration configuration, EndPoint endPoint,
- HttpTransport transport, HttpInput input) {
- super(connector, configuration, endPoint, transport, input);
+ HttpTransport transport) {
+ super(connector, configuration, endPoint, transport);
}
@Override
diff --git a/apm-sniffer/apm-sdk-plugin/jetty-plugin/pom.xml b/apm-sniffer/apm-sdk-plugin/jetty-plugin/pom.xml
index d939bf88b5..671cc92f91 100644
--- a/apm-sniffer/apm-sdk-plugin/jetty-plugin/pom.xml
+++ b/apm-sniffer/apm-sdk-plugin/jetty-plugin/pom.xml
@@ -23,15 +23,15 @@
org.apache.skywalking
apm-sdk-plugin
- 9.3.0-SNAPSHOT
+ 9.7.0-SNAPSHOT
jetty-plugins
jetty-client-9.x-plugin
- jetty-server-9.x-plugin
jetty-client-9.0-plugin
- jetty-server-11.x-plugin
+ jetty-server-plugin
+ jetty-server-12.x-plugin
jetty-client-11.x-plugin
pom
@@ -41,6 +41,5 @@
UTF-8
- /..
diff --git a/apm-sniffer/apm-sdk-plugin/jetty-thread-pool-plugin/pom.xml b/apm-sniffer/apm-sdk-plugin/jetty-thread-pool-plugin/pom.xml
index 101dcaae14..533868c65d 100644
--- a/apm-sniffer/apm-sdk-plugin/jetty-thread-pool-plugin/pom.xml
+++ b/apm-sniffer/apm-sdk-plugin/jetty-thread-pool-plugin/pom.xml
@@ -21,7 +21,7 @@
apm-sdk-plugin
org.apache.skywalking
- 9.3.0-SNAPSHOT
+ 9.7.0-SNAPSHOT
4.0.0
diff --git a/apm-sniffer/apm-sdk-plugin/jsonrpc4j-1.x-plugin/pom.xml b/apm-sniffer/apm-sdk-plugin/jsonrpc4j-1.x-plugin/pom.xml
index 533e961137..f4ef9b5118 100644
--- a/apm-sniffer/apm-sdk-plugin/jsonrpc4j-1.x-plugin/pom.xml
+++ b/apm-sniffer/apm-sdk-plugin/jsonrpc4j-1.x-plugin/pom.xml
@@ -21,7 +21,7 @@
apm-sdk-plugin
org.apache.skywalking
- 9.3.0-SNAPSHOT
+ 9.7.0-SNAPSHOT
4.0.0
diff --git a/apm-sniffer/apm-sdk-plugin/kafka-commons/pom.xml b/apm-sniffer/apm-sdk-plugin/kafka-commons/pom.xml
index bf86caceda..9870095054 100644
--- a/apm-sniffer/apm-sdk-plugin/kafka-commons/pom.xml
+++ b/apm-sniffer/apm-sdk-plugin/kafka-commons/pom.xml
@@ -23,7 +23,7 @@
org.apache.skywalking
apm-sdk-plugin
- 9.3.0-SNAPSHOT
+ 9.7.0-SNAPSHOT
apm-kafka-commons
diff --git a/apm-sniffer/apm-sdk-plugin/kafka-plugin/pom.xml b/apm-sniffer/apm-sdk-plugin/kafka-plugin/pom.xml
index c5e17d52ed..9c03ef164a 100644
--- a/apm-sniffer/apm-sdk-plugin/kafka-plugin/pom.xml
+++ b/apm-sniffer/apm-sdk-plugin/kafka-plugin/pom.xml
@@ -21,7 +21,7 @@
apm-sdk-plugin
org.apache.skywalking
- 9.3.0-SNAPSHOT
+ 9.7.0-SNAPSHOT
4.0.0
diff --git a/apm-sniffer/apm-sdk-plugin/kafka-plugin/src/main/java/org/apache/skywalking/apm/plugin/kafka/define/ClassicKafkaConsumerInstrumentation.java b/apm-sniffer/apm-sdk-plugin/kafka-plugin/src/main/java/org/apache/skywalking/apm/plugin/kafka/define/ClassicKafkaConsumerInstrumentation.java
new file mode 100644
index 0000000000..c2092c6de6
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/kafka-plugin/src/main/java/org/apache/skywalking/apm/plugin/kafka/define/ClassicKafkaConsumerInstrumentation.java
@@ -0,0 +1,40 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.kafka.define;
+
+import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
+
+import static org.apache.skywalking.apm.agent.core.plugin.match.NameMatch.byName;
+
+/**
+ * For Kafka 3.9.x change
+ *
+ *
+ * 1. The class named LegacyKafkaConsumer was rename to ClassicKafkaConsumer
+ * 2. Because of the enhance class was changed, so we should create new Instrumentation to enhance the new class
+ *
+ */
+public class ClassicKafkaConsumerInstrumentation extends KafkaConsumerInstrumentation {
+ private static final String ENHANCE_CLASS_39_CLASSIC = "org.apache.kafka.clients.consumer.internals.ClassicKafkaConsumer";
+
+ @Override
+ protected ClassMatch enhanceClass() {
+ return byName(ENHANCE_CLASS_39_CLASSIC);
+ }
+}
diff --git a/apm-sniffer/apm-sdk-plugin/kafka-plugin/src/main/java/org/apache/skywalking/apm/plugin/kafka/define/Kafka37AsyncConsumerInstrumentation.java b/apm-sniffer/apm-sdk-plugin/kafka-plugin/src/main/java/org/apache/skywalking/apm/plugin/kafka/define/Kafka37AsyncConsumerInstrumentation.java
new file mode 100644
index 0000000000..7c24a135ac
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/kafka-plugin/src/main/java/org/apache/skywalking/apm/plugin/kafka/define/Kafka37AsyncConsumerInstrumentation.java
@@ -0,0 +1,40 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.kafka.define;
+
+import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
+import static org.apache.skywalking.apm.agent.core.plugin.match.NameMatch.byName;
+
+/**
+ * For Kafka 3.7.x change
+ *
+ *
+ * 1. The method named pollForFetchs was removed from KafkaConsumer to AsyncKafkaConsumer and LegacyKafkaConsumer
+ * 2. Because of the enhance class was changed, so we should create new Instrumentation to intercept the method
+ *
+ */
+public class Kafka37AsyncConsumerInstrumentation extends KafkaConsumerInstrumentation {
+
+ private static final String ENHANCE_CLASS_37_ASYNC = "org.apache.kafka.clients.consumer.internals.AsyncKafkaConsumer";
+
+ @Override
+ protected ClassMatch enhanceClass() {
+ return byName(ENHANCE_CLASS_37_ASYNC);
+ }
+}
\ No newline at end of file
diff --git a/apm-sniffer/apm-sdk-plugin/kafka-plugin/src/main/java/org/apache/skywalking/apm/plugin/kafka/define/Kafka37LegacyConsumerInstrumentation.java b/apm-sniffer/apm-sdk-plugin/kafka-plugin/src/main/java/org/apache/skywalking/apm/plugin/kafka/define/Kafka37LegacyConsumerInstrumentation.java
new file mode 100644
index 0000000000..95f33bfe82
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/kafka-plugin/src/main/java/org/apache/skywalking/apm/plugin/kafka/define/Kafka37LegacyConsumerInstrumentation.java
@@ -0,0 +1,40 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.kafka.define;
+
+import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
+import static org.apache.skywalking.apm.agent.core.plugin.match.NameMatch.byName;
+
+/**
+ * For Kafka 3.7.x change
+ *
+ *
+ * 1. The method named pollForFetchs was removed from KafkaConsumer to AsyncKafkaConsumer and LegacyKafkaConsumer
+ * 2. Because of the enhance class was changed, so we should create new Instrumentation to intercept the method
+ *
+ */
+public class Kafka37LegacyConsumerInstrumentation extends KafkaConsumerInstrumentation {
+
+ private static final String ENHANCE_CLASS_37_LEGACY = "org.apache.kafka.clients.consumer.internals.LegacyKafkaConsumer";
+
+ @Override
+ protected ClassMatch enhanceClass() {
+ return byName(ENHANCE_CLASS_37_LEGACY);
+ }
+}
\ No newline at end of file
diff --git a/apm-sniffer/apm-sdk-plugin/kafka-plugin/src/main/resources/skywalking-plugin.def b/apm-sniffer/apm-sdk-plugin/kafka-plugin/src/main/resources/skywalking-plugin.def
index d807aceefe..bb98b86a97 100644
--- a/apm-sniffer/apm-sdk-plugin/kafka-plugin/src/main/resources/skywalking-plugin.def
+++ b/apm-sniffer/apm-sdk-plugin/kafka-plugin/src/main/resources/skywalking-plugin.def
@@ -18,4 +18,7 @@ kafka-0.11.x/1.x/2.x=org.apache.skywalking.apm.plugin.kafka.define.CallbackInstr
kafka-0.11.x/1.x/2.x=org.apache.skywalking.apm.plugin.kafka.define.KafkaConsumerInstrumentation
kafka-0.11.x/1.x/2.x=org.apache.skywalking.apm.plugin.kafka.define.KafkaProducerInstrumentation
kafka-0.11.x/1.x/2.x=org.apache.skywalking.apm.plugin.kafka.define.KafkaProducerMapInstrumentation
-kafka-0.11.x/1.x/2.x=org.apache.skywalking.apm.plugin.kafka.define.KafkaTemplateCallbackInstrumentation
\ No newline at end of file
+kafka-0.11.x/1.x/2.x=org.apache.skywalking.apm.plugin.kafka.define.KafkaTemplateCallbackInstrumentation
+kafka-3.7.x=org.apache.skywalking.apm.plugin.kafka.define.Kafka37AsyncConsumerInstrumentation
+kafka-3.7.x=org.apache.skywalking.apm.plugin.kafka.define.Kafka37LegacyConsumerInstrumentation
+kafka-3.9.x=org.apache.skywalking.apm.plugin.kafka.define.ClassicKafkaConsumerInstrumentation
\ No newline at end of file
diff --git a/apm-sniffer/apm-sdk-plugin/kylin-jdbc-2.6.x-3.x-4.x-plugin/pom.xml b/apm-sniffer/apm-sdk-plugin/kylin-jdbc-2.6.x-3.x-4.x-plugin/pom.xml
index 74ee2c3c55..54d4d9e605 100644
--- a/apm-sniffer/apm-sdk-plugin/kylin-jdbc-2.6.x-3.x-4.x-plugin/pom.xml
+++ b/apm-sniffer/apm-sdk-plugin/kylin-jdbc-2.6.x-3.x-4.x-plugin/pom.xml
@@ -21,7 +21,7 @@
apm-sdk-plugin
org.apache.skywalking
- 9.3.0-SNAPSHOT
+ 9.7.0-SNAPSHOT
4.0.0
diff --git a/apm-sniffer/apm-sdk-plugin/lettuce-plugins/lettuce-5.x-6.4.x-plugin/pom.xml b/apm-sniffer/apm-sdk-plugin/lettuce-plugins/lettuce-5.x-6.4.x-plugin/pom.xml
new file mode 100644
index 0000000000..c2158fcb4a
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/lettuce-plugins/lettuce-5.x-6.4.x-plugin/pom.xml
@@ -0,0 +1,53 @@
+
+
+
+
+ 4.0.0
+
+ org.apache.skywalking
+ lettuce-plugins
+ 9.7.0-SNAPSHOT
+
+
+ apm-lettuce-5.x-6.4.x-plugin
+ jar
+
+ lettuce-5.x-6.4.x-plugin
+
+
+ 5.0.0.RELEASE
+
+
+
+
+ org.apache.skywalking
+ apm-lettuce-common
+ ${project.version}
+ provided
+
+
+
+ io.lettuce
+ lettuce-core
+ ${lettuce-core.version}
+ provided
+
+
+
+
\ No newline at end of file
diff --git a/apm-sniffer/apm-sdk-plugin/lettuce-plugins/lettuce-5.x-6.4.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/lettuce/v5/RedisChannelWriterInterceptorV5.java b/apm-sniffer/apm-sdk-plugin/lettuce-plugins/lettuce-5.x-6.4.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/lettuce/v5/RedisChannelWriterInterceptorV5.java
new file mode 100644
index 0000000000..d4984d6fd0
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/lettuce-plugins/lettuce-5.x-6.4.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/lettuce/v5/RedisChannelWriterInterceptorV5.java
@@ -0,0 +1,29 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.lettuce.v5;
+
+import io.lettuce.core.protocol.ProtocolKeyword;
+import org.apache.skywalking.apm.plugin.lettuce.common.RedisChannelWriterInterceptor;
+
+public class RedisChannelWriterInterceptorV5 extends RedisChannelWriterInterceptor {
+ @Override
+ protected String getCommandName(final ProtocolKeyword protocol) {
+ return protocol.name();
+ }
+}
diff --git a/apm-sniffer/apm-sdk-plugin/lettuce-plugins/lettuce-5.x-6.4.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/lettuce/v5/RedisReactiveCreatePublisherMethodInterceptorV5.java b/apm-sniffer/apm-sdk-plugin/lettuce-plugins/lettuce-5.x-6.4.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/lettuce/v5/RedisReactiveCreatePublisherMethodInterceptorV5.java
new file mode 100644
index 0000000000..12ddea18f7
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/lettuce-plugins/lettuce-5.x-6.4.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/lettuce/v5/RedisReactiveCreatePublisherMethodInterceptorV5.java
@@ -0,0 +1,89 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.lettuce.v5;
+
+import org.apache.skywalking.apm.agent.core.context.ContextManager;
+import org.apache.skywalking.apm.agent.core.context.ContextSnapshot;
+import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan;
+import org.apache.skywalking.apm.agent.core.context.trace.SpanLayer;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.v2.InstanceMethodsAroundInterceptorV2;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.v2.MethodInvocationContext;
+import org.apache.skywalking.apm.network.trace.component.ComponentsDefine;
+import reactor.core.publisher.Flux;
+import reactor.core.publisher.Mono;
+import reactor.util.context.Context;
+
+import java.lang.reflect.Method;
+import java.util.function.Function;
+
+/**
+ * Intercepts reactive publisher factory methods (createMono/createFlux)
+ * to ensure the SkyWalking context snapshot is propagated via Reactor Context.
+ *
+ * If the Reactor Context does not already contain a snapshot, this interceptor
+ * captures the current active context and writes it into the subscriber context
+ * as a fallback propagation mechanism.
+ */
+public class RedisReactiveCreatePublisherMethodInterceptorV5 implements InstanceMethodsAroundInterceptorV2 {
+
+ private static final String SNAPSHOT_KEY = "SKYWALKING_CONTEXT_SNAPSHOT";
+
+ @Override
+ public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes,
+ MethodInvocationContext context) {
+ }
+
+ @Override
+ public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes, Object ret, MethodInvocationContext context) {
+
+ if (!(ret instanceof Mono) && !(ret instanceof Flux)) {
+ return ret;
+ }
+ final AbstractSpan localSpan = ContextManager.createLocalSpan("Lettuce/Reactive/" + method.getName());
+ localSpan.setComponent(ComponentsDefine.LETTUCE);
+ SpanLayer.asCache(localSpan);
+
+ try {
+ final ContextSnapshot snapshot = ContextManager.capture();
+
+ Function contextFunction = ctx -> {
+ if (ctx.hasKey(SNAPSHOT_KEY)) {
+ return ctx;
+ }
+ return ctx.put(SNAPSHOT_KEY, snapshot);
+ };
+
+ if (ret instanceof Mono) {
+ Mono> original = (Mono>) ret;
+ return original.subscriberContext(contextFunction);
+ } else {
+ Flux> original = (Flux>) ret;
+ return original.subscriberContext(contextFunction);
+ }
+ } finally {
+ ContextManager.stopSpan();
+ }
+ }
+
+ @Override
+ public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[]
+ argumentsTypes, Throwable t, MethodInvocationContext context) {
+ }
+}
diff --git a/apm-sniffer/apm-sdk-plugin/lettuce-5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/lettuce/v5/define/RedisChannelWriterInstrumentation.java b/apm-sniffer/apm-sdk-plugin/lettuce-plugins/lettuce-5.x-6.4.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/lettuce/v5/define/RedisChannelWriterInstrumentationV5.java
similarity index 81%
rename from apm-sniffer/apm-sdk-plugin/lettuce-5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/lettuce/v5/define/RedisChannelWriterInstrumentation.java
rename to apm-sniffer/apm-sdk-plugin/lettuce-plugins/lettuce-5.x-6.4.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/lettuce/v5/define/RedisChannelWriterInstrumentationV5.java
index e0a4d8c819..bf3e52f79c 100644
--- a/apm-sniffer/apm-sdk-plugin/lettuce-5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/lettuce/v5/define/RedisChannelWriterInstrumentation.java
+++ b/apm-sniffer/apm-sdk-plugin/lettuce-plugins/lettuce-5.x-6.4.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/lettuce/v5/define/RedisChannelWriterInstrumentationV5.java
@@ -18,27 +18,26 @@
package org.apache.skywalking.apm.plugin.lettuce.v5.define;
+import java.util.Collections;
+import java.util.List;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.matcher.ElementMatcher;
+import net.bytebuddy.matcher.ElementMatchers;
+import org.apache.skywalking.apm.agent.core.plugin.WitnessMethod;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine;
import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
-import java.util.List;
-
import static net.bytebuddy.matcher.ElementMatchers.named;
import static net.bytebuddy.matcher.ElementMatchers.takesArgument;
import static org.apache.skywalking.apm.agent.core.plugin.match.HierarchyMatch.byHierarchyMatch;
-/**
- * The writeAndFlush method is used in versions lower than 5.0.2.RELEASE
- */
-public class RedisChannelWriterInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
+public class RedisChannelWriterInstrumentationV5 extends ClassInstanceMethodsEnhancePluginDefine {
private static final String ENHANCE_CLASS = "io.lettuce.core.RedisChannelWriter";
- private static final String REDIS_CHANNEL_WRITER_INTERCEPTOR_CLASS = "org.apache.skywalking.apm.plugin.lettuce.v5.RedisChannelWriterInterceptor";
+ private static final String REDIS_CHANNEL_WRITER_INTERCEPTOR_CLASS = "org.apache.skywalking.apm.plugin.lettuce.v5.RedisChannelWriterInterceptorV5";
@Override
public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
@@ -47,12 +46,12 @@ public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
@Override
public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
- return new InstanceMethodsInterceptPoint[]{
+ return new InstanceMethodsInterceptPoint[] {
new InstanceMethodsInterceptPoint() {
@Override
public ElementMatcher getMethodsMatcher() {
return named("write").and(takesArgument(0, named("io.lettuce.core.protocol.RedisCommand")).or(
- takesArgument(0, List.class)));
+ takesArgument(0, List.class)));
}
@Override
@@ -65,11 +64,19 @@ public boolean isOverrideArgs() {
return false;
}
},
- };
+ };
}
@Override
public ClassMatch enhanceClass() {
return byHierarchyMatch(ENHANCE_CLASS);
}
+
+ @Override
+ protected List witnessMethods() {
+ return Collections.singletonList(new WitnessMethod(
+ "io.lettuce.core.protocol.ProtocolKeyword",
+ ElementMatchers.named("name")
+ ));
+ }
}
diff --git a/apm-sniffer/apm-sdk-plugin/lettuce-plugins/lettuce-5.x-6.4.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/lettuce/v5/define/RedisReactiveCommandsInstrumentationV5.java b/apm-sniffer/apm-sdk-plugin/lettuce-plugins/lettuce-5.x-6.4.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/lettuce/v5/define/RedisReactiveCommandsInstrumentationV5.java
new file mode 100644
index 0000000000..65716edd68
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/lettuce-plugins/lettuce-5.x-6.4.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/lettuce/v5/define/RedisReactiveCommandsInstrumentationV5.java
@@ -0,0 +1,89 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.lettuce.v5.define;
+
+import net.bytebuddy.description.method.MethodDescription;
+import net.bytebuddy.matcher.ElementMatcher;
+import org.apache.skywalking.apm.agent.core.plugin.WitnessMethod;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.v2.ClassInstanceMethodsEnhancePluginDefineV2;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.v2.InstanceMethodsInterceptV2Point;
+import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
+
+import java.util.Collections;
+import java.util.List;
+
+import static net.bytebuddy.matcher.ElementMatchers.named;
+import static net.bytebuddy.matcher.ElementMatchers.namedOneOf;
+import static net.bytebuddy.matcher.ElementMatchers.takesArguments;
+import static org.apache.skywalking.apm.agent.core.plugin.match.HierarchyMatch.byHierarchyMatch;
+
+/**
+ *
+ */
+public class RedisReactiveCommandsInstrumentationV5 extends ClassInstanceMethodsEnhancePluginDefineV2 {
+
+ private static final String ENHANCE_CLASS = "io.lettuce.core.AbstractRedisReactiveCommands";
+
+ private static final String REDIS_REACTIVE_CREATEMONO_METHOD_INTERCEPTOR = "org.apache.skywalking.apm.plugin.lettuce.v5.RedisReactiveCreatePublisherMethodInterceptorV5";
+
+ @Override
+ public InstanceMethodsInterceptV2Point[] getInstanceMethodsInterceptV2Points() {
+ return new InstanceMethodsInterceptV2Point[]{
+ new InstanceMethodsInterceptV2Point() {
+ @Override
+ public ElementMatcher getMethodsMatcher() {
+ return namedOneOf(
+ "createMono",
+ "createFlux",
+ "createDissolvingFlux"
+ ).and(takesArguments(1));
+ }
+
+ @Override
+ public String getMethodsInterceptorV2() {
+ return REDIS_REACTIVE_CREATEMONO_METHOD_INTERCEPTOR;
+ }
+
+ @Override
+ public boolean isOverrideArgs() {
+ return false;
+ }
+ }
+ };
+ }
+
+ @Override
+ public ClassMatch enhanceClass() {
+ return byHierarchyMatch(ENHANCE_CLASS);
+ }
+
+ @Override
+ public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
+ return new ConstructorInterceptPoint[0];
+ }
+
+ @Override
+ protected List witnessMethods() {
+ return Collections.singletonList(new WitnessMethod(
+ "reactor.core.publisher.Mono",
+ named("subscriberContext")
+ ));
+ }
+}
diff --git a/apm-sniffer/apm-sdk-plugin/lettuce-plugins/lettuce-5.x-6.4.x-plugin/src/main/resources/skywalking-plugin.def b/apm-sniffer/apm-sdk-plugin/lettuce-plugins/lettuce-5.x-6.4.x-plugin/src/main/resources/skywalking-plugin.def
new file mode 100644
index 0000000000..006ef23680
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/lettuce-plugins/lettuce-5.x-6.4.x-plugin/src/main/resources/skywalking-plugin.def
@@ -0,0 +1,18 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+lettuce-5.x-6.4.x=org.apache.skywalking.apm.plugin.lettuce.v5.define.RedisChannelWriterInstrumentationV5
+lettuce-5.x-6.4.x=org.apache.skywalking.apm.plugin.lettuce.v5.define.RedisReactiveCommandsInstrumentationV5
\ No newline at end of file
diff --git a/apm-sniffer/apm-sdk-plugin/lettuce-plugins/lettuce-6.5.x-plugin/pom.xml b/apm-sniffer/apm-sdk-plugin/lettuce-plugins/lettuce-6.5.x-plugin/pom.xml
new file mode 100644
index 0000000000..2bf20982cf
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/lettuce-plugins/lettuce-6.5.x-plugin/pom.xml
@@ -0,0 +1,53 @@
+
+
+
+
+ 4.0.0
+
+ org.apache.skywalking
+ lettuce-plugins
+ 9.7.0-SNAPSHOT
+
+ apm-lettuce-6.5.x-plugin
+
+ jar
+
+ lettuce-6.5.x-plugin
+
+
+ 6.5.0.RELEASE
+
+
+
+
+ org.apache.skywalking
+ apm-lettuce-common
+ ${project.version}
+ provided
+
+
+
+ io.lettuce
+ lettuce-core
+ ${lettuce-core.version}
+ provided
+
+
+
+
\ No newline at end of file
diff --git a/apm-sniffer/apm-sdk-plugin/lettuce-plugins/lettuce-6.5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/lettuce/v65/RedisChannelWriterInterceptorV65.java b/apm-sniffer/apm-sdk-plugin/lettuce-plugins/lettuce-6.5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/lettuce/v65/RedisChannelWriterInterceptorV65.java
new file mode 100644
index 0000000000..2205fa3519
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/lettuce-plugins/lettuce-6.5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/lettuce/v65/RedisChannelWriterInterceptorV65.java
@@ -0,0 +1,29 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.lettuce.v65;
+
+import io.lettuce.core.protocol.ProtocolKeyword;
+import org.apache.skywalking.apm.plugin.lettuce.common.RedisChannelWriterInterceptor;
+
+public class RedisChannelWriterInterceptorV65 extends RedisChannelWriterInterceptor {
+ @Override
+ protected String getCommandName(final ProtocolKeyword protocol) {
+ return protocol.toString();
+ }
+}
diff --git a/apm-sniffer/apm-sdk-plugin/lettuce-plugins/lettuce-6.5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/lettuce/v65/RedisReactiveCreatePublisherMethodInterceptorV65.java b/apm-sniffer/apm-sdk-plugin/lettuce-plugins/lettuce-6.5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/lettuce/v65/RedisReactiveCreatePublisherMethodInterceptorV65.java
new file mode 100644
index 0000000000..36320b5cd1
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/lettuce-plugins/lettuce-6.5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/lettuce/v65/RedisReactiveCreatePublisherMethodInterceptorV65.java
@@ -0,0 +1,93 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.lettuce.v65;
+
+import org.apache.skywalking.apm.agent.core.context.ContextManager;
+import org.apache.skywalking.apm.agent.core.context.ContextSnapshot;
+import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan;
+import org.apache.skywalking.apm.agent.core.context.trace.SpanLayer;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.v2.InstanceMethodsAroundInterceptorV2;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.v2.MethodInvocationContext;
+import org.apache.skywalking.apm.network.trace.component.ComponentsDefine;
+import org.reactivestreams.Publisher;
+import reactor.core.publisher.Flux;
+import reactor.core.publisher.Mono;
+
+import java.lang.reflect.Method;
+
+/**
+ * Intercepts reactive publisher factory methods (createMono/createFlux)
+ * to ensure the SkyWalking context snapshot is propagated via Reactor Context.
+ *
+ * If the Reactor Context does not already contain a snapshot, this interceptor
+ * captures the current active context and writes it into the subscriber context
+ * as a fallback propagation mechanism.
+ */
+public class RedisReactiveCreatePublisherMethodInterceptorV65 implements InstanceMethodsAroundInterceptorV2 {
+
+ private static final String SNAPSHOT_KEY = "SKYWALKING_CONTEXT_SNAPSHOT";
+
+ @Override
+ public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes,
+ MethodInvocationContext context) {
+ }
+
+ @Override
+ public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes, Object ret, MethodInvocationContext context) {
+
+ if (!(ret instanceof Mono) && !(ret instanceof Flux)) {
+ return ret;
+ }
+
+ final AbstractSpan localSpan = ContextManager.createLocalSpan("Lettuce/Reactive/" + method.getName());
+ localSpan.setComponent(ComponentsDefine.LETTUCE);
+ SpanLayer.asCache(localSpan);
+
+ try {
+ final ContextSnapshot snapshot = ContextManager.capture();
+
+ return wrapPublisher((Publisher>) ret, snapshot);
+ } finally {
+ ContextManager.stopSpan();
+ }
+ }
+
+ private Publisher wrapPublisher(Publisher original, ContextSnapshot snapshot) {
+ if (original instanceof Mono) {
+ return Mono.deferContextual(ctxView -> {
+ if (ctxView.hasKey(SNAPSHOT_KEY)) {
+ return (Mono) original;
+ }
+ return ((Mono) original).contextWrite(c -> c.put(SNAPSHOT_KEY, snapshot));
+ });
+ } else {
+ return Flux.deferContextual(ctxView -> {
+ if (ctxView.hasKey(SNAPSHOT_KEY)) {
+ return original;
+ }
+ return ((Flux) original).contextWrite(c -> c.put(SNAPSHOT_KEY, snapshot));
+ });
+ }
+ }
+
+ @Override
+ public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes, Throwable t, MethodInvocationContext context) {
+ }
+}
diff --git a/apm-sniffer/apm-sdk-plugin/lettuce-plugins/lettuce-6.5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/lettuce/v65/define/RedisChannelWriterInstrumentationV65.java b/apm-sniffer/apm-sdk-plugin/lettuce-plugins/lettuce-6.5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/lettuce/v65/define/RedisChannelWriterInstrumentationV65.java
new file mode 100644
index 0000000000..5e10c43561
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/lettuce-plugins/lettuce-6.5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/lettuce/v65/define/RedisChannelWriterInstrumentationV65.java
@@ -0,0 +1,82 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.lettuce.v65.define;
+
+import java.util.Collections;
+import java.util.List;
+import net.bytebuddy.description.method.MethodDescription;
+import net.bytebuddy.matcher.ElementMatcher;
+import net.bytebuddy.matcher.ElementMatchers;
+import org.apache.skywalking.apm.agent.core.plugin.WitnessMethod;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine;
+import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
+
+import static net.bytebuddy.matcher.ElementMatchers.named;
+import static net.bytebuddy.matcher.ElementMatchers.takesArgument;
+import static org.apache.skywalking.apm.agent.core.plugin.match.HierarchyMatch.byHierarchyMatch;
+
+public class RedisChannelWriterInstrumentationV65 extends ClassInstanceMethodsEnhancePluginDefine {
+
+ private static final String ENHANCE_CLASS = "io.lettuce.core.RedisChannelWriter";
+
+ private static final String REDIS_CHANNEL_WRITER_INTERCEPTOR_CLASS = "org.apache.skywalking.apm.plugin.lettuce.v65.RedisChannelWriterInterceptorV65";
+
+ @Override
+ public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
+ return new ConstructorInterceptPoint[0];
+ }
+
+ @Override
+ public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
+ return new InstanceMethodsInterceptPoint[] {
+ new InstanceMethodsInterceptPoint() {
+ @Override
+ public ElementMatcher getMethodsMatcher() {
+ return named("write").and(takesArgument(0, named("io.lettuce.core.protocol.RedisCommand")).or(
+ takesArgument(0, List.class)));
+ }
+
+ @Override
+ public String getMethodsInterceptor() {
+ return REDIS_CHANNEL_WRITER_INTERCEPTOR_CLASS;
+ }
+
+ @Override
+ public boolean isOverrideArgs() {
+ return false;
+ }
+ },
+ };
+ }
+
+ @Override
+ public ClassMatch enhanceClass() {
+ return byHierarchyMatch(ENHANCE_CLASS);
+ }
+
+ @Override
+ protected List witnessMethods() {
+ return Collections.singletonList(new WitnessMethod(
+ "io.lettuce.core.protocol.ProtocolKeyword",
+ ElementMatchers.named("toString")
+ ));
+ }
+}
diff --git a/apm-sniffer/apm-sdk-plugin/lettuce-plugins/lettuce-6.5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/lettuce/v65/define/RedisReactiveCommandsInstrumentationV65.java b/apm-sniffer/apm-sdk-plugin/lettuce-plugins/lettuce-6.5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/lettuce/v65/define/RedisReactiveCommandsInstrumentationV65.java
new file mode 100644
index 0000000000..f1c22b88ee
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/lettuce-plugins/lettuce-6.5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/lettuce/v65/define/RedisReactiveCommandsInstrumentationV65.java
@@ -0,0 +1,89 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.lettuce.v65.define;
+
+import net.bytebuddy.description.method.MethodDescription;
+import net.bytebuddy.matcher.ElementMatcher;
+import net.bytebuddy.matcher.ElementMatchers;
+import org.apache.skywalking.apm.agent.core.plugin.WitnessMethod;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.v2.ClassInstanceMethodsEnhancePluginDefineV2;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.v2.InstanceMethodsInterceptV2Point;
+import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
+
+import java.util.Collections;
+import java.util.List;
+
+import static net.bytebuddy.matcher.ElementMatchers.namedOneOf;
+import static net.bytebuddy.matcher.ElementMatchers.takesArguments;
+import static org.apache.skywalking.apm.agent.core.plugin.match.HierarchyMatch.byHierarchyMatch;
+
+/**
+ *
+ */
+public class RedisReactiveCommandsInstrumentationV65 extends ClassInstanceMethodsEnhancePluginDefineV2 {
+
+ private static final String ENHANCE_CLASS = "io.lettuce.core.AbstractRedisReactiveCommands";
+
+ private static final String REDIS_REACTIVE_CREATEMONO_METHOD_INTERCEPTOR = "org.apache.skywalking.apm.plugin.lettuce.v65.RedisReactiveCreatePublisherMethodInterceptorV65";
+
+ @Override
+ public InstanceMethodsInterceptV2Point[] getInstanceMethodsInterceptV2Points() {
+ return new InstanceMethodsInterceptV2Point[]{
+ new InstanceMethodsInterceptV2Point() {
+ @Override
+ public ElementMatcher getMethodsMatcher() {
+ return namedOneOf(
+ "createMono",
+ "createFlux",
+ "createDissolvingFlux"
+ ).and(takesArguments(1));
+ }
+
+ @Override
+ public String getMethodsInterceptorV2() {
+ return REDIS_REACTIVE_CREATEMONO_METHOD_INTERCEPTOR;
+ }
+
+ @Override
+ public boolean isOverrideArgs() {
+ return false;
+ }
+ }
+ };
+ }
+
+ @Override
+ public ClassMatch enhanceClass() {
+ return byHierarchyMatch(ENHANCE_CLASS);
+ }
+
+ @Override
+ public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
+ return new ConstructorInterceptPoint[0];
+ }
+
+ @Override
+ protected List witnessMethods() {
+ return Collections.singletonList(new WitnessMethod(
+ "reactor.core.publisher.Mono",
+ ElementMatchers.named("deferContextual")
+ ));
+ }
+}
diff --git a/apm-sniffer/apm-sdk-plugin/tomcat-7.x-8.x-plugin/src/main/resources/skywalking-plugin.def b/apm-sniffer/apm-sdk-plugin/lettuce-plugins/lettuce-6.5.x-plugin/src/main/resources/skywalking-plugin.def
similarity index 79%
rename from apm-sniffer/apm-sdk-plugin/tomcat-7.x-8.x-plugin/src/main/resources/skywalking-plugin.def
rename to apm-sniffer/apm-sdk-plugin/lettuce-plugins/lettuce-6.5.x-plugin/src/main/resources/skywalking-plugin.def
index 761d3970d3..aac68f9479 100644
--- a/apm-sniffer/apm-sdk-plugin/tomcat-7.x-8.x-plugin/src/main/resources/skywalking-plugin.def
+++ b/apm-sniffer/apm-sdk-plugin/lettuce-plugins/lettuce-6.5.x-plugin/src/main/resources/skywalking-plugin.def
@@ -14,5 +14,5 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-tomcat-7.x/8.x=org.apache.skywalking.apm.plugin.tomcat78x.define.TomcatInstrumentation
-tomcat-7.x/8.x=org.apache.skywalking.apm.plugin.tomcat78x.define.ApplicationDispatcherInstrumentation
+lettuce-6.5.x=org.apache.skywalking.apm.plugin.lettuce.v65.define.RedisChannelWriterInstrumentationV65
+lettuce-6.5.x=org.apache.skywalking.apm.plugin.lettuce.v65.define.RedisReactiveCommandsInstrumentationV65
\ No newline at end of file
diff --git a/apm-sniffer/apm-sdk-plugin/lettuce-5.x-plugin/pom.xml b/apm-sniffer/apm-sdk-plugin/lettuce-plugins/lettuce-common/pom.xml
similarity index 86%
rename from apm-sniffer/apm-sdk-plugin/lettuce-5.x-plugin/pom.xml
rename to apm-sniffer/apm-sdk-plugin/lettuce-plugins/lettuce-common/pom.xml
index ed057fe5ef..6062c90bce 100644
--- a/apm-sniffer/apm-sdk-plugin/lettuce-5.x-plugin/pom.xml
+++ b/apm-sniffer/apm-sdk-plugin/lettuce-plugins/lettuce-common/pom.xml
@@ -1,4 +1,4 @@
-
+
+
+
+ 4.0.0
+
+ org.apache.skywalking
+ apm-sdk-plugin
+ 9.7.0-SNAPSHOT
+
+
+ lettuce-plugins
+ pom
+
+
+ lettuce-common
+ lettuce-5.x-6.4.x-plugin
+ lettuce-6.5.x-plugin
+
+
+
\ No newline at end of file
diff --git a/apm-sniffer/apm-sdk-plugin/light4j-plugins/light4j-plugin/pom.xml b/apm-sniffer/apm-sdk-plugin/light4j-plugins/light4j-plugin/pom.xml
index 722371d8b5..12b4e3a59e 100644
--- a/apm-sniffer/apm-sdk-plugin/light4j-plugins/light4j-plugin/pom.xml
+++ b/apm-sniffer/apm-sdk-plugin/light4j-plugins/light4j-plugin/pom.xml
@@ -20,7 +20,7 @@
light4j-plugins
org.apache.skywalking
- 9.3.0-SNAPSHOT
+ 9.7.0-SNAPSHOT
4.0.0
diff --git a/apm-sniffer/apm-sdk-plugin/light4j-plugins/pom.xml b/apm-sniffer/apm-sdk-plugin/light4j-plugins/pom.xml
index 5d738e3b5f..cd9ab3c418 100644
--- a/apm-sniffer/apm-sdk-plugin/light4j-plugins/pom.xml
+++ b/apm-sniffer/apm-sdk-plugin/light4j-plugins/pom.xml
@@ -23,7 +23,7 @@
org.apache.skywalking
apm-sdk-plugin
- 9.3.0-SNAPSHOT
+ 9.7.0-SNAPSHOT
light4j-plugins
@@ -37,6 +37,5 @@
UTF-8
- /..
diff --git a/apm-sniffer/apm-sdk-plugin/mariadb-2.x-plugin/pom.xml b/apm-sniffer/apm-sdk-plugin/mariadb-2.x-plugin/pom.xml
index 05ab767ccb..2ec8ab3063 100644
--- a/apm-sniffer/apm-sdk-plugin/mariadb-2.x-plugin/pom.xml
+++ b/apm-sniffer/apm-sdk-plugin/mariadb-2.x-plugin/pom.xml
@@ -20,7 +20,7 @@
apm-sdk-plugin
org.apache.skywalking
- 9.3.0-SNAPSHOT
+ 9.7.0-SNAPSHOT
4.0.0
diff --git a/apm-sniffer/apm-sdk-plugin/mariadb-3.x-plugin/pom.xml b/apm-sniffer/apm-sdk-plugin/mariadb-3.x-plugin/pom.xml
new file mode 100644
index 0000000000..1011fdda12
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/mariadb-3.x-plugin/pom.xml
@@ -0,0 +1,60 @@
+
+
+
+
+ apm-sdk-plugin
+ org.apache.skywalking
+ 9.7.0-SNAPSHOT
+
+ 4.0.0
+
+ apm-mariadb-3.x-plugin
+ jar
+
+ mariadb-3.x-plugin
+ http://maven.apache.org
+
+
+ UTF-8
+ 3.5.1
+
+
+
+
+ org.mariadb.jdbc
+ mariadb-java-client
+ ${mariadb-java-client.version}
+ provided
+
+
+ org.apache.skywalking
+ apm-jdbc-commons
+ ${project.version}
+ provided
+
+
+
+
+
+
+ maven-deploy-plugin
+
+
+
+
diff --git a/apm-sniffer/apm-sdk-plugin/mariadb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jdbc/mariadb/v3/CreateCallableStatementInterceptor.java b/apm-sniffer/apm-sdk-plugin/mariadb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jdbc/mariadb/v3/CreateCallableStatementInterceptor.java
new file mode 100644
index 0000000000..e7642c9fbb
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/mariadb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jdbc/mariadb/v3/CreateCallableStatementInterceptor.java
@@ -0,0 +1,49 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.jdbc.mariadb.v3;
+
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
+import org.apache.skywalking.apm.plugin.jdbc.define.StatementEnhanceInfos;
+import org.apache.skywalking.apm.plugin.jdbc.trace.ConnectionInfo;
+
+import java.lang.reflect.Method;
+
+public class CreateCallableStatementInterceptor implements InstanceMethodsAroundInterceptor {
+ @Override
+ public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes,
+ MethodInterceptResult result) {
+
+ }
+
+ @Override
+ public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes,
+ Object ret) {
+ if (ret instanceof EnhancedInstance) {
+ ((EnhancedInstance) ret).setSkyWalkingDynamicField(new StatementEnhanceInfos((ConnectionInfo) objInst.getSkyWalkingDynamicField(), (String) allArguments[0], "CallableStatement"));
+ }
+ return ret;
+ }
+
+ @Override
+ public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments,
+ Class>[] argumentsTypes, Throwable t) {
+ }
+}
diff --git a/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-11.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/v11/server/ForwardInterceptor.java b/apm-sniffer/apm-sdk-plugin/mariadb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jdbc/mariadb/v3/CreatePreparedStatementInterceptor.java
similarity index 54%
rename from apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-11.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/v11/server/ForwardInterceptor.java
rename to apm-sniffer/apm-sdk-plugin/mariadb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jdbc/mariadb/v3/CreatePreparedStatementInterceptor.java
index f98e15c8af..a17b112718 100644
--- a/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-11.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/v11/server/ForwardInterceptor.java
+++ b/apm-sniffer/apm-sdk-plugin/mariadb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jdbc/mariadb/v3/CreatePreparedStatementInterceptor.java
@@ -6,7 +6,7 @@
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
@@ -14,50 +14,37 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*
- *
*/
-package org.apache.skywalking.apm.plugin.jetty.v11.server;
+package org.apache.skywalking.apm.plugin.jdbc.mariadb.v3;
-import org.apache.skywalking.apm.agent.core.context.ContextManager;
-import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
-import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceConstructorInterceptor;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
+import org.apache.skywalking.apm.plugin.jdbc.define.StatementEnhanceInfos;
+import org.apache.skywalking.apm.plugin.jdbc.trace.ConnectionInfo;
import java.lang.reflect.Method;
-import java.util.HashMap;
-import java.util.Map;
-
-public class ForwardInterceptor implements InstanceMethodsAroundInterceptor, InstanceConstructorInterceptor {
+public class CreatePreparedStatementInterceptor implements InstanceMethodsAroundInterceptor {
@Override
public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes,
- MethodInterceptResult result) throws Throwable {
- if (ContextManager.isActive()) {
- AbstractSpan abstractTracingSpan = ContextManager.activeSpan();
- Map eventMap = new HashMap();
- eventMap.put("forward-url", (String) objInst.getSkyWalkingDynamicField());
- abstractTracingSpan.log(System.currentTimeMillis(), eventMap);
- ContextManager.getRuntimeContext().put(Constants.FORWARD_REQUEST_FLAG, true);
- }
+ MethodInterceptResult result) {
+
}
@Override
public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes,
- Object ret) throws Throwable {
+ Object ret) {
+ if (ret instanceof EnhancedInstance) {
+ ((EnhancedInstance) ret).setSkyWalkingDynamicField(new StatementEnhanceInfos((ConnectionInfo) objInst.getSkyWalkingDynamicField(), (String) allArguments[0], "PreparedStatement"));
+ }
return ret;
}
@Override
public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments,
- Class>[] argumentsTypes, Throwable t) {
-
- }
+ Class>[] argumentsTypes, Throwable t) {
- @Override
- public void onConstruct(EnhancedInstance objInst, Object[] allArguments) {
- objInst.setSkyWalkingDynamicField(allArguments[2]);
}
}
diff --git a/apm-sniffer/apm-sdk-plugin/mariadb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jdbc/mariadb/v3/CreateStatementInterceptor.java b/apm-sniffer/apm-sdk-plugin/mariadb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jdbc/mariadb/v3/CreateStatementInterceptor.java
new file mode 100644
index 0000000000..036fe00a39
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/mariadb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jdbc/mariadb/v3/CreateStatementInterceptor.java
@@ -0,0 +1,50 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.jdbc.mariadb.v3;
+
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
+import org.apache.skywalking.apm.plugin.jdbc.define.StatementEnhanceInfos;
+import org.apache.skywalking.apm.plugin.jdbc.trace.ConnectionInfo;
+
+import java.lang.reflect.Method;
+
+public class CreateStatementInterceptor implements InstanceMethodsAroundInterceptor {
+ @Override
+ public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes,
+ MethodInterceptResult result) {
+
+ }
+
+ @Override
+ public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes,
+ Object ret) {
+ if (ret instanceof EnhancedInstance) {
+ ((EnhancedInstance) ret).setSkyWalkingDynamicField(new StatementEnhanceInfos((ConnectionInfo) objInst.getSkyWalkingDynamicField(), "", "Statement"));
+ }
+ return ret;
+ }
+
+ @Override
+ public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments,
+ Class>[] argumentsTypes, Throwable t) {
+
+ }
+}
diff --git a/apm-sniffer/apm-sdk-plugin/mariadb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jdbc/mariadb/v3/PreparedStatementExecuteMethodsInterceptor.java b/apm-sniffer/apm-sdk-plugin/mariadb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jdbc/mariadb/v3/PreparedStatementExecuteMethodsInterceptor.java
new file mode 100644
index 0000000000..8ec30304b7
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/mariadb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jdbc/mariadb/v3/PreparedStatementExecuteMethodsInterceptor.java
@@ -0,0 +1,93 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.jdbc.mariadb.v3;
+
+import org.apache.skywalking.apm.agent.core.context.ContextManager;
+import org.apache.skywalking.apm.agent.core.context.tag.Tags;
+import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan;
+import org.apache.skywalking.apm.agent.core.context.trace.SpanLayer;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
+import org.apache.skywalking.apm.plugin.jdbc.JDBCPluginConfig;
+import org.apache.skywalking.apm.plugin.jdbc.PreparedStatementParameterBuilder;
+import org.apache.skywalking.apm.plugin.jdbc.SqlBodyUtil;
+import org.apache.skywalking.apm.plugin.jdbc.define.StatementEnhanceInfos;
+import org.apache.skywalking.apm.plugin.jdbc.trace.ConnectionInfo;
+
+import java.lang.reflect.Method;
+
+public class PreparedStatementExecuteMethodsInterceptor implements InstanceMethodsAroundInterceptor {
+
+ @Override
+ public final void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments,
+ Class>[] argumentsTypes, MethodInterceptResult result) {
+ StatementEnhanceInfos cacheObject = (StatementEnhanceInfos) objInst.getSkyWalkingDynamicField();
+ ConnectionInfo connectInfo = cacheObject.getConnectionInfo();
+ if (connectInfo == null) {
+ return;
+ }
+ AbstractSpan span = ContextManager.createExitSpan(buildOperationName(connectInfo, method.getName(), cacheObject
+ .getStatementName()), connectInfo.getDatabasePeer());
+ Tags.DB_TYPE.set(span, connectInfo.getDBType());
+ Tags.DB_INSTANCE.set(span, connectInfo.getDatabaseName());
+ Tags.DB_STATEMENT.set(span, SqlBodyUtil.limitSqlBodySize(cacheObject.getSql()));
+ span.setComponent(connectInfo.getComponent());
+
+ if (JDBCPluginConfig.Plugin.JDBC.TRACE_SQL_PARAMETERS) {
+ final Object[] parameters = cacheObject.getParameters();
+ if (parameters != null && parameters.length > 0) {
+ int maxIndex = cacheObject.getMaxIndex();
+ Tags.SQL_PARAMETERS.set(span, getParameterString(parameters, maxIndex));
+ }
+ }
+
+ SpanLayer.asDB(span);
+ }
+
+ @Override
+ public final Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments,
+ Class>[] argumentsTypes, Object ret) {
+ StatementEnhanceInfos cacheObject = (StatementEnhanceInfos) objInst.getSkyWalkingDynamicField();
+ if (cacheObject.getConnectionInfo() != null) {
+ ContextManager.stopSpan();
+ }
+ return ret;
+ }
+
+ @Override
+ public final void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments,
+ Class>[] argumentsTypes, Throwable t) {
+ StatementEnhanceInfos cacheObject = (StatementEnhanceInfos) objInst.getSkyWalkingDynamicField();
+ if (cacheObject.getConnectionInfo() != null) {
+ ContextManager.activeSpan().log(t);
+ }
+ }
+
+ private String buildOperationName(ConnectionInfo connectionInfo, String methodName, String statementName) {
+ return connectionInfo.getDBType() + "/JDBC/" + statementName + "/" + methodName;
+ }
+
+ private String getParameterString(Object[] parameters, int maxIndex) {
+ return new PreparedStatementParameterBuilder()
+ .setParameters(parameters)
+ .setMaxIndex(maxIndex)
+ .build();
+ }
+}
diff --git a/apm-sniffer/apm-sdk-plugin/tomcat-7.x-8.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/tomcat78x/TomcatExceptionInterceptor.java b/apm-sniffer/apm-sdk-plugin/mariadb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jdbc/mariadb/v3/SetCatalogInterceptor.java
similarity index 71%
rename from apm-sniffer/apm-sdk-plugin/tomcat-7.x-8.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/tomcat78x/TomcatExceptionInterceptor.java
rename to apm-sniffer/apm-sdk-plugin/mariadb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jdbc/mariadb/v3/SetCatalogInterceptor.java
index 28c8a9a20a..48b9b3e926 100644
--- a/apm-sniffer/apm-sdk-plugin/tomcat-7.x-8.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/tomcat78x/TomcatExceptionInterceptor.java
+++ b/apm-sniffer/apm-sdk-plugin/mariadb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jdbc/mariadb/v3/SetCatalogInterceptor.java
@@ -16,30 +16,33 @@
*
*/
-package org.apache.skywalking.apm.plugin.tomcat78x;
+package org.apache.skywalking.apm.plugin.jdbc.mariadb.v3;
-import java.lang.reflect.Method;
-import org.apache.skywalking.apm.agent.core.context.ContextManager;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
+import org.apache.skywalking.apm.plugin.jdbc.trace.ConnectionInfo;
+
+import java.lang.reflect.Method;
-public class TomcatExceptionInterceptor implements InstanceMethodsAroundInterceptor {
+public class SetCatalogInterceptor implements InstanceMethodsAroundInterceptor {
@Override
public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes,
- MethodInterceptResult result) throws Throwable {
- ContextManager.activeSpan().log((Throwable) allArguments[2]);
+ MethodInterceptResult result) {
+ Object dynamicField = objInst.getSkyWalkingDynamicField();
+ if (dynamicField instanceof ConnectionInfo) {
+ ((ConnectionInfo) dynamicField).setDatabaseName(String.valueOf(allArguments[0]));
+ }
}
@Override
public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes,
- Object ret) throws Throwable {
+ Object ret) {
return ret;
}
@Override
public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments,
- Class>[] argumentsTypes, Throwable t) {
-
+ Class>[] argumentsTypes, Throwable t) {
}
}
diff --git a/apm-sniffer/apm-sdk-plugin/mariadb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jdbc/mariadb/v3/StatementExecuteMethodsInterceptor.java b/apm-sniffer/apm-sdk-plugin/mariadb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jdbc/mariadb/v3/StatementExecuteMethodsInterceptor.java
new file mode 100644
index 0000000000..c88f921881
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/mariadb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jdbc/mariadb/v3/StatementExecuteMethodsInterceptor.java
@@ -0,0 +1,75 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.jdbc.mariadb.v3;
+
+import org.apache.skywalking.apm.agent.core.context.ContextManager;
+import org.apache.skywalking.apm.agent.core.context.tag.Tags;
+import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan;
+import org.apache.skywalking.apm.agent.core.context.trace.SpanLayer;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
+import org.apache.skywalking.apm.plugin.jdbc.SqlBodyUtil;
+import org.apache.skywalking.apm.plugin.jdbc.define.StatementEnhanceInfos;
+import org.apache.skywalking.apm.plugin.jdbc.trace.ConnectionInfo;
+
+import java.lang.reflect.Method;
+
+public class StatementExecuteMethodsInterceptor implements InstanceMethodsAroundInterceptor {
+ @Override
+ public final void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments,
+ Class>[] argumentsTypes, MethodInterceptResult result) {
+ StatementEnhanceInfos cacheObject = (StatementEnhanceInfos) objInst.getSkyWalkingDynamicField();
+ ConnectionInfo connectInfo = cacheObject.getConnectionInfo();
+ if (connectInfo != null) {
+ AbstractSpan span = ContextManager.createExitSpan(buildOperationName(connectInfo, method.getName(), cacheObject
+ .getStatementName()), connectInfo.getDatabasePeer());
+ Tags.DB_TYPE.set(span, connectInfo.getDBType());
+ Tags.DB_INSTANCE.set(span, connectInfo.getDatabaseName());
+ String sql = allArguments.length > 0 ? (String) allArguments[0] : "";
+ sql = SqlBodyUtil.limitSqlBodySize(sql);
+ Tags.DB_STATEMENT.set(span, sql);
+ span.setComponent(connectInfo.getComponent());
+ SpanLayer.asDB(span);
+ }
+ }
+
+ @Override
+ public final Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments,
+ Class>[] argumentsTypes, Object ret) {
+ StatementEnhanceInfos cacheObject = (StatementEnhanceInfos) objInst.getSkyWalkingDynamicField();
+ if (cacheObject.getConnectionInfo() != null) {
+ ContextManager.stopSpan();
+ }
+ return ret;
+ }
+
+ @Override
+ public final void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments,
+ Class>[] argumentsTypes, Throwable t) {
+ StatementEnhanceInfos cacheObject = (StatementEnhanceInfos) objInst.getSkyWalkingDynamicField();
+ if (cacheObject.getConnectionInfo() != null) {
+ ContextManager.activeSpan().log(t);
+ }
+ }
+
+ private String buildOperationName(ConnectionInfo connectionInfo, String methodName, String statementName) {
+ return connectionInfo.getDBType() + "/JDBC/" + statementName + "/" + methodName;
+ }
+}
diff --git a/apm-sniffer/apm-sdk-plugin/mariadb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jdbc/mariadb/v3/define/ConnectionInstrumentation.java b/apm-sniffer/apm-sdk-plugin/mariadb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jdbc/mariadb/v3/define/ConnectionInstrumentation.java
new file mode 100644
index 0000000000..2f7083eca4
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/mariadb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jdbc/mariadb/v3/define/ConnectionInstrumentation.java
@@ -0,0 +1,144 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.jdbc.mariadb.v3.define;
+
+import net.bytebuddy.description.method.MethodDescription;
+import net.bytebuddy.matcher.ElementMatcher;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine;
+import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
+import org.apache.skywalking.apm.plugin.jdbc.define.Constants;
+
+import static net.bytebuddy.matcher.ElementMatchers.named;
+import static org.apache.skywalking.apm.agent.core.plugin.match.NameMatch.byName;
+
+public class ConnectionInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
+
+ private static final String ENHANCE_CLASS = "org.mariadb.jdbc.Connection";
+ private static final String CREATE_STATEMENT_INTERCEPTOR_CLASS = "org.apache.skywalking.apm.plugin.jdbc.mariadb.v3.CreateStatementInterceptor";
+ private static final String CREATE_PREPARED_STATEMENT_INTERCEPTOR_CLASS = "org.apache.skywalking.apm.plugin.jdbc.mariadb.v3.CreatePreparedStatementInterceptor";
+ private static final String CREATE_CALLABLE_STATEMENT_INTERCEPTOR_CLASS = "org.apache.skywalking.apm.plugin.jdbc.mariadb.v3.CreateCallableStatementInterceptor";
+ private static final String SET_CATALOG_INTERCEPTOR_CLASS = "org.apache.skywalking.apm.plugin.jdbc.mariadb.v3.SetCatalogInterceptor";
+
+ @Override
+ protected ClassMatch enhanceClass() {
+ return byName(ENHANCE_CLASS);
+ }
+
+ @Override
+ public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
+ return new ConstructorInterceptPoint[0];
+ }
+
+ @Override
+ public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
+ return new InstanceMethodsInterceptPoint[]{
+ new InstanceMethodsInterceptPoint() {
+ @Override
+ public ElementMatcher getMethodsMatcher() {
+ return named(Constants.CREATE_STATEMENT_METHOD_NAME);
+ }
+
+ @Override
+ public String getMethodsInterceptor() {
+ return CREATE_STATEMENT_INTERCEPTOR_CLASS;
+ }
+
+ @Override
+ public boolean isOverrideArgs() {
+ return false;
+ }
+ },
+ new InstanceMethodsInterceptPoint() {
+ @Override
+ public ElementMatcher getMethodsMatcher() {
+ return named(Constants.PREPARE_STATEMENT_METHOD_NAME);
+ }
+
+ @Override
+ public String getMethodsInterceptor() {
+ return CREATE_PREPARED_STATEMENT_INTERCEPTOR_CLASS;
+ }
+
+ @Override
+ public boolean isOverrideArgs() {
+ return false;
+ }
+ },
+ new InstanceMethodsInterceptPoint() {
+ @Override
+ public ElementMatcher getMethodsMatcher() {
+ return named(Constants.PREPARE_CALL_METHOD_NAME);
+ }
+
+ @Override
+ public String getMethodsInterceptor() {
+ return CREATE_CALLABLE_STATEMENT_INTERCEPTOR_CLASS;
+ }
+
+ @Override
+ public boolean isOverrideArgs() {
+ return false;
+ }
+ },
+ new InstanceMethodsInterceptPoint() {
+ @Override
+ public ElementMatcher getMethodsMatcher() {
+ return named(Constants.COMMIT_METHOD_NAME)
+ .or(named(Constants.ROLLBACK_METHOD_NAME))
+ .or(named(Constants.CLOSE_METHOD_NAME))
+ .or(named(Constants.RELEASE_SAVE_POINT_METHOD_NAME));
+ }
+
+ @Override
+ public String getMethodsInterceptor() {
+ return Constants.SERVICE_METHOD_INTERCEPT_CLASS;
+ }
+
+ @Override
+ public boolean isOverrideArgs() {
+ return false;
+ }
+ },
+ new InstanceMethodsInterceptPoint() {
+ @Override
+ public ElementMatcher getMethodsMatcher() {
+ return named("setCatalog");
+ }
+
+ @Override
+ public String getMethodsInterceptor() {
+ return SET_CATALOG_INTERCEPTOR_CLASS;
+ }
+
+ @Override
+ public boolean isOverrideArgs() {
+ return false;
+ }
+ }
+ };
+
+ }
+
+ @Override
+ protected String[] witnessClasses() {
+ return new String[]{"org.mariadb.jdbc.Connection"};
+ }
+}
diff --git a/apm-sniffer/apm-sdk-plugin/mariadb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jdbc/mariadb/v3/define/DriverInstrumentation.java b/apm-sniffer/apm-sdk-plugin/mariadb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jdbc/mariadb/v3/define/DriverInstrumentation.java
new file mode 100644
index 0000000000..b0a3dba6b0
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/mariadb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jdbc/mariadb/v3/define/DriverInstrumentation.java
@@ -0,0 +1,36 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.jdbc.mariadb.v3.define;
+
+import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
+import org.apache.skywalking.apm.plugin.jdbc.define.AbstractDriverInstrumentation;
+
+import static org.apache.skywalking.apm.agent.core.plugin.match.NameMatch.byName;
+
+/**
+ * {@link DriverInstrumentation} presents that skywalking intercepts {@link org.mariadb.jdbc.Driver}.
+ */
+public class DriverInstrumentation extends AbstractDriverInstrumentation {
+ private static final String ENHANCE_CLASS = "org.mariadb.jdbc.Driver";
+
+ @Override
+ protected ClassMatch enhanceClass() {
+ return byName(ENHANCE_CLASS);
+ }
+}
diff --git a/apm-sniffer/apm-sdk-plugin/mariadb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jdbc/mariadb/v3/define/PreparedStatementIgnoredSetterInstrumentation.java b/apm-sniffer/apm-sdk-plugin/mariadb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jdbc/mariadb/v3/define/PreparedStatementIgnoredSetterInstrumentation.java
new file mode 100644
index 0000000000..7e036281fb
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/mariadb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jdbc/mariadb/v3/define/PreparedStatementIgnoredSetterInstrumentation.java
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.jdbc.mariadb.v3.define;
+
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
+import org.apache.skywalking.apm.plugin.jdbc.PSSetterDefinitionOfJDBCInstrumentation;
+
+public class PreparedStatementIgnoredSetterInstrumentation extends PreparedStatementInstrumentation {
+
+ @Override
+ public final InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
+ return new InstanceMethodsInterceptPoint[]{
+ new PSSetterDefinitionOfJDBCInstrumentation(true)
+ };
+ }
+
+}
diff --git a/apm-sniffer/apm-sdk-plugin/mariadb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jdbc/mariadb/v3/define/PreparedStatementInstrumentation.java b/apm-sniffer/apm-sdk-plugin/mariadb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jdbc/mariadb/v3/define/PreparedStatementInstrumentation.java
new file mode 100644
index 0000000000..fced984b0b
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/mariadb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jdbc/mariadb/v3/define/PreparedStatementInstrumentation.java
@@ -0,0 +1,74 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.jdbc.mariadb.v3.define;
+
+import net.bytebuddy.description.method.MethodDescription;
+import net.bytebuddy.matcher.ElementMatcher;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine;
+import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
+
+import static net.bytebuddy.matcher.ElementMatchers.named;
+import static org.apache.skywalking.apm.agent.core.plugin.match.MultiClassNameMatch.byMultiClassMatch;
+
+public class PreparedStatementInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
+
+ private static final String CLIENT_PREPARED_STATEMENT_CLASS = "org.mariadb.jdbc.ClientPreparedStatement";
+ private static final String SERVER_PREPARED_STATEMENT_CLASS = "org.mariadb.jdbc.ServerPreparedStatement";
+ private static final String PREPARED_STATEMENT_EXECUTE_METHODS_INTERCEPTOR_CLASS = "org.apache.skywalking.apm.plugin.jdbc.mariadb.v3.PreparedStatementExecuteMethodsInterceptor";
+
+ @Override
+ protected ClassMatch enhanceClass() {
+ return byMultiClassMatch(
+ CLIENT_PREPARED_STATEMENT_CLASS,
+ SERVER_PREPARED_STATEMENT_CLASS
+ );
+ }
+
+ @Override
+ public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
+ return new ConstructorInterceptPoint[0];
+ }
+
+ @Override
+ public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
+ return new InstanceMethodsInterceptPoint[]{
+ new InstanceMethodsInterceptPoint() {
+ @Override
+ public ElementMatcher getMethodsMatcher() {
+ return named("execute")
+ .or(named("executeQuery"))
+ .or(named("executeUpdate"));
+ }
+
+ @Override
+ public String getMethodsInterceptor() {
+ return PREPARED_STATEMENT_EXECUTE_METHODS_INTERCEPTOR_CLASS;
+ }
+
+ @Override
+ public boolean isOverrideArgs() {
+ return false;
+ }
+ }
+ };
+
+ }
+}
diff --git a/apm-sniffer/apm-sdk-plugin/mariadb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jdbc/mariadb/v3/define/PreparedStatementNullSetterInstrumentation.java b/apm-sniffer/apm-sdk-plugin/mariadb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jdbc/mariadb/v3/define/PreparedStatementNullSetterInstrumentation.java
new file mode 100644
index 0000000000..30a1865174
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/mariadb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jdbc/mariadb/v3/define/PreparedStatementNullSetterInstrumentation.java
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.jdbc.mariadb.v3.define;
+
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
+import org.apache.skywalking.apm.plugin.jdbc.JDBCPreparedStatementNullSetterInstanceMethodsInterceptPoint;
+
+public class PreparedStatementNullSetterInstrumentation extends PreparedStatementInstrumentation {
+
+ @Override
+ public final InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
+ return new InstanceMethodsInterceptPoint[]{
+ new JDBCPreparedStatementNullSetterInstanceMethodsInterceptPoint()
+ };
+ }
+
+}
diff --git a/apm-sniffer/apm-sdk-plugin/mariadb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jdbc/mariadb/v3/define/PreparedStatementSetterInstrumentation.java b/apm-sniffer/apm-sdk-plugin/mariadb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jdbc/mariadb/v3/define/PreparedStatementSetterInstrumentation.java
new file mode 100644
index 0000000000..bc625974eb
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/mariadb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jdbc/mariadb/v3/define/PreparedStatementSetterInstrumentation.java
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.jdbc.mariadb.v3.define;
+
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
+import org.apache.skywalking.apm.plugin.jdbc.PSSetterDefinitionOfJDBCInstrumentation;
+
+public class PreparedStatementSetterInstrumentation extends PreparedStatementInstrumentation {
+
+ @Override
+ public final InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
+ return new InstanceMethodsInterceptPoint[]{
+ new PSSetterDefinitionOfJDBCInstrumentation(false)
+ };
+ }
+
+}
diff --git a/apm-sniffer/apm-sdk-plugin/mariadb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jdbc/mariadb/v3/define/StatementInstrumentation.java b/apm-sniffer/apm-sdk-plugin/mariadb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jdbc/mariadb/v3/define/StatementInstrumentation.java
new file mode 100644
index 0000000000..13a8c7e033
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/mariadb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jdbc/mariadb/v3/define/StatementInstrumentation.java
@@ -0,0 +1,71 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.jdbc.mariadb.v3.define;
+
+import net.bytebuddy.description.method.MethodDescription;
+import net.bytebuddy.matcher.ElementMatcher;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine;
+import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
+
+import static net.bytebuddy.matcher.ElementMatchers.named;
+import static org.apache.skywalking.apm.agent.core.plugin.match.NameMatch.byName;
+
+public class StatementInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
+ private static final String MARIADB_STATEMENT_CLASS_NAME = "org.mariadb.jdbc.Statement";
+ private static final String STATEMENT_EXECUTE_METHODS_INTERCEPTOR = "org.apache.skywalking.apm.plugin.jdbc.mariadb.v3.StatementExecuteMethodsInterceptor";
+
+ @Override
+ public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
+ return new ConstructorInterceptPoint[0];
+ }
+
+ @Override
+ public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
+ return new InstanceMethodsInterceptPoint[]{
+ new InstanceMethodsInterceptPoint() {
+ @Override
+ public ElementMatcher getMethodsMatcher() {
+ return named("execute")
+ .or(named("executeQuery"))
+ .or(named("executeUpdate"))
+ .or(named("executeLargeUpdate"))
+ .or(named("executeBatch"))
+ .or(named("executeLargeBatch"));
+ }
+
+ @Override
+ public String getMethodsInterceptor() {
+ return STATEMENT_EXECUTE_METHODS_INTERCEPTOR;
+ }
+
+ @Override
+ public boolean isOverrideArgs() {
+ return false;
+ }
+ }
+ };
+ }
+
+ @Override
+ protected ClassMatch enhanceClass() {
+ return byName(MARIADB_STATEMENT_CLASS_NAME);
+ }
+}
diff --git a/apm-sniffer/apm-sdk-plugin/mariadb-3.x-plugin/src/main/resources/skywalking-plugin.def b/apm-sniffer/apm-sdk-plugin/mariadb-3.x-plugin/src/main/resources/skywalking-plugin.def
new file mode 100644
index 0000000000..d1bdb703d4
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/mariadb-3.x-plugin/src/main/resources/skywalking-plugin.def
@@ -0,0 +1,23 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+mariadb-3.x=org.apache.skywalking.apm.plugin.jdbc.mariadb.v3.define.DriverInstrumentation
+mariadb-3.x=org.apache.skywalking.apm.plugin.jdbc.mariadb.v3.define.ConnectionInstrumentation
+mariadb-3.x=org.apache.skywalking.apm.plugin.jdbc.mariadb.v3.define.StatementInstrumentation
+mariadb-3.x=org.apache.skywalking.apm.plugin.jdbc.mariadb.v3.define.PreparedStatementInstrumentation
+mariadb-3.x=org.apache.skywalking.apm.plugin.jdbc.mariadb.v3.define.PreparedStatementSetterInstrumentation
+mariadb-3.x=org.apache.skywalking.apm.plugin.jdbc.mariadb.v3.define.PreparedStatementNullSetterInstrumentation
+mariadb-3.x=org.apache.skywalking.apm.plugin.jdbc.mariadb.v3.define.PreparedStatementIgnoredSetterInstrumentation
diff --git a/apm-sniffer/apm-sdk-plugin/mariadb-3.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/jdbc/mariadb/v3/CreateCallableStatementInterceptorTest.java b/apm-sniffer/apm-sdk-plugin/mariadb-3.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/jdbc/mariadb/v3/CreateCallableStatementInterceptorTest.java
new file mode 100644
index 0000000000..a034865659
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/mariadb-3.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/jdbc/mariadb/v3/CreateCallableStatementInterceptorTest.java
@@ -0,0 +1,67 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.jdbc.mariadb.v3;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
+import org.apache.skywalking.apm.plugin.jdbc.trace.ConnectionInfo;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnitRunner;
+
+@RunWith(MockitoJUnitRunner.class)
+public class CreateCallableStatementInterceptorTest {
+
+ private static final String SQL = "Select * from test";
+
+ private CreateCallableStatementInterceptor interceptor;
+
+ @Mock
+ private EnhancedInstance ret;
+
+ @Mock
+ private EnhancedInstance objectInstance;
+
+ @Mock
+ private ConnectionInfo connectionInfo;
+
+ @Before
+ public void setUp() {
+ interceptor = new CreateCallableStatementInterceptor();
+
+ when(objectInstance.getSkyWalkingDynamicField()).thenReturn(connectionInfo);
+ }
+
+ @Test
+ public void testResultIsEnhanceInstance() {
+ interceptor.afterMethod(objectInstance, null, new Object[]{SQL}, null, ret);
+ verify(ret).setSkyWalkingDynamicField(any());
+ }
+
+ @Test
+ public void testResultIsNotEnhanceInstance() {
+ interceptor.afterMethod(objectInstance, null, new Object[]{SQL}, null, new Object());
+ verify(ret, times(0)).setSkyWalkingDynamicField(any());
+ }
+}
diff --git a/apm-sniffer/apm-sdk-plugin/mariadb-3.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/jdbc/mariadb/v3/CreatePreparedStatementInterceptorTest.java b/apm-sniffer/apm-sdk-plugin/mariadb-3.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/jdbc/mariadb/v3/CreatePreparedStatementInterceptorTest.java
new file mode 100644
index 0000000000..0c2c51c9ad
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/mariadb-3.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/jdbc/mariadb/v3/CreatePreparedStatementInterceptorTest.java
@@ -0,0 +1,67 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.jdbc.mariadb.v3;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
+import org.apache.skywalking.apm.plugin.jdbc.trace.ConnectionInfo;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnitRunner;
+
+@RunWith(MockitoJUnitRunner.class)
+public class CreatePreparedStatementInterceptorTest {
+
+ private static final String SQL = "Select * from test";
+
+ private CreatePreparedStatementInterceptor interceptor;
+
+ @Mock
+ private EnhancedInstance ret;
+
+ @Mock
+ private EnhancedInstance objectInstance;
+
+ @Mock
+ private ConnectionInfo connectionInfo;
+
+ @Before
+ public void setUp() {
+ interceptor = new CreatePreparedStatementInterceptor();
+
+ when(objectInstance.getSkyWalkingDynamicField()).thenReturn(connectionInfo);
+ }
+
+ @Test
+ public void testResultIsEnhanceInstance() {
+ interceptor.afterMethod(objectInstance, null, new Object[]{SQL}, null, ret);
+ verify(ret).setSkyWalkingDynamicField(any());
+ }
+
+ @Test
+ public void testResultIsNotEnhanceInstance() {
+ interceptor.afterMethod(objectInstance, null, new Object[]{SQL}, null, new Object());
+ verify(ret, times(0)).setSkyWalkingDynamicField(any());
+ }
+}
diff --git a/apm-sniffer/apm-sdk-plugin/mariadb-3.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/jdbc/mariadb/v3/CreateStatementInterceptorTest.java b/apm-sniffer/apm-sdk-plugin/mariadb-3.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/jdbc/mariadb/v3/CreateStatementInterceptorTest.java
new file mode 100644
index 0000000000..663ce62d32
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/mariadb-3.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/jdbc/mariadb/v3/CreateStatementInterceptorTest.java
@@ -0,0 +1,67 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.jdbc.mariadb.v3;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
+import org.apache.skywalking.apm.plugin.jdbc.trace.ConnectionInfo;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnitRunner;
+
+@RunWith(MockitoJUnitRunner.class)
+public class CreateStatementInterceptorTest {
+
+ private static final String SQL = "Select * from test";
+
+ private CreateStatementInterceptor interceptor;
+
+ @Mock
+ private EnhancedInstance ret;
+
+ @Mock
+ private EnhancedInstance objectInstance;
+
+ @Mock
+ private ConnectionInfo connectionInfo;
+
+ @Before
+ public void setUp() {
+ interceptor = new CreateStatementInterceptor();
+
+ when(objectInstance.getSkyWalkingDynamicField()).thenReturn(connectionInfo);
+ }
+
+ @Test
+ public void testResultIsEnhanceInstance() {
+ interceptor.afterMethod(objectInstance, null, new Object[]{SQL}, null, ret);
+ verify(ret).setSkyWalkingDynamicField(any());
+ }
+
+ @Test
+ public void testResultIsNotEnhanceInstance() {
+ interceptor.afterMethod(objectInstance, null, new Object[]{SQL}, null, new Object());
+ verify(ret, times(0)).setSkyWalkingDynamicField(any());
+ }
+}
diff --git a/apm-sniffer/apm-sdk-plugin/mariadb-3.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/jdbc/mariadb/v3/PreparedStatementExecuteMethodsInterceptorTest.java b/apm-sniffer/apm-sdk-plugin/mariadb-3.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/jdbc/mariadb/v3/PreparedStatementExecuteMethodsInterceptorTest.java
new file mode 100644
index 0000000000..3e624d7952
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/mariadb-3.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/jdbc/mariadb/v3/PreparedStatementExecuteMethodsInterceptorTest.java
@@ -0,0 +1,153 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.jdbc.mariadb.v3;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertThat;
+import static org.mockito.Mockito.when;
+import java.lang.reflect.Method;
+import org.apache.skywalking.apm.agent.core.context.trace.AbstractTracingSpan;
+import org.apache.skywalking.apm.agent.core.context.trace.SpanLayer;
+import org.apache.skywalking.apm.agent.core.context.trace.TraceSegment;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
+import org.apache.skywalking.apm.agent.test.helper.SegmentHelper;
+import org.apache.skywalking.apm.agent.test.tools.AgentServiceRule;
+import org.apache.skywalking.apm.agent.test.tools.SegmentStorage;
+import org.apache.skywalking.apm.agent.test.tools.SegmentStoragePoint;
+import org.apache.skywalking.apm.agent.test.tools.SpanAssert;
+import org.apache.skywalking.apm.agent.test.tools.TracingSegmentRunner;
+import org.apache.skywalking.apm.network.trace.component.ComponentsDefine;
+import org.apache.skywalking.apm.plugin.jdbc.JDBCPluginConfig;
+import org.apache.skywalking.apm.plugin.jdbc.JDBCPreparedStatementSetterInterceptor;
+import org.apache.skywalking.apm.plugin.jdbc.define.StatementEnhanceInfos;
+import org.apache.skywalking.apm.plugin.jdbc.trace.ConnectionInfo;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+
+@RunWith(TracingSegmentRunner.class)
+public class PreparedStatementExecuteMethodsInterceptorTest {
+
+ private static final String SQL = "Select * from test where id = ?";
+
+ @SegmentStoragePoint
+ private SegmentStorage segmentStorage;
+
+ @Rule
+ public AgentServiceRule serviceRule = new AgentServiceRule();
+ @Rule
+ public MockitoRule rule = MockitoJUnit.rule();
+
+ private PreparedStatementExecuteMethodsInterceptor serviceMethodInterceptor;
+
+ private JDBCPreparedStatementSetterInterceptor preparedStatementSetterInterceptor;
+
+ @Mock
+ private ConnectionInfo connectionInfo;
+ @Mock
+ private EnhancedInstance objectInstance;
+ @Mock
+ private Method method;
+ private StatementEnhanceInfos enhanceRequireCacheObject;
+
+ @Before
+ public void setUp() {
+ JDBCPluginConfig.Plugin.JDBC.TRACE_SQL_PARAMETERS = true;
+ preparedStatementSetterInterceptor = new JDBCPreparedStatementSetterInterceptor();
+ serviceMethodInterceptor = new PreparedStatementExecuteMethodsInterceptor();
+
+ enhanceRequireCacheObject = new StatementEnhanceInfos(connectionInfo, SQL, "PreparedStatement");
+ when(objectInstance.getSkyWalkingDynamicField()).thenReturn(enhanceRequireCacheObject);
+ when(method.getName()).thenReturn("executeQuery");
+ when(connectionInfo.getComponent()).thenReturn(ComponentsDefine.MARIADB_JDBC);
+ when(connectionInfo.getDBType()).thenReturn("Mariadb");
+ when(connectionInfo.getDatabaseName()).thenReturn("test");
+ when(connectionInfo.getDatabasePeer()).thenReturn("localhost:3306");
+ }
+
+ @After
+ public void clean() {
+ JDBCPluginConfig.Plugin.JDBC.SQL_BODY_MAX_LENGTH = 2048;
+ JDBCPluginConfig.Plugin.JDBC.TRACE_SQL_PARAMETERS = false;
+ }
+
+ @Test
+ public void testExecutePreparedStatement() throws Throwable {
+ preparedStatementSetterInterceptor.beforeMethod(
+ objectInstance, method, new Object[] {
+ 1,
+ "abcd"
+ }, null, null);
+ preparedStatementSetterInterceptor.beforeMethod(
+ objectInstance, method, new Object[] {
+ 2,
+ "efgh"
+ }, null, null);
+
+ serviceMethodInterceptor.beforeMethod(objectInstance, method, new Object[] {SQL}, null, null);
+ serviceMethodInterceptor.afterMethod(objectInstance, method, new Object[] {SQL}, null, null);
+
+ assertThat(segmentStorage.getTraceSegments().size(), is(1));
+ TraceSegment segment = segmentStorage.getTraceSegments().get(0);
+ assertThat(SegmentHelper.getSpans(segment).size(), is(1));
+ AbstractTracingSpan span = SegmentHelper.getSpans(segment).get(0);
+ SpanAssert.assertLayer(span, SpanLayer.DB);
+ assertThat(span.getOperationName(), is("Mariadb/JDBC/PreparedStatement/executeQuery"));
+ SpanAssert.assertTag(span, 0, "Mariadb");
+ SpanAssert.assertTag(span, 1, "test");
+ SpanAssert.assertTag(span, 2, SQL);
+ SpanAssert.assertTag(span, 3, "[abcd,efgh]");
+ }
+
+ @Test
+ public void testExecutePreparedStatementWithLimitSqlBody() throws Throwable {
+ JDBCPluginConfig.Plugin.JDBC.SQL_BODY_MAX_LENGTH = 10;
+
+ preparedStatementSetterInterceptor.beforeMethod(
+ objectInstance, method, new Object[] {
+ 1,
+ "abcd"
+ }, null, null);
+ preparedStatementSetterInterceptor.beforeMethod(
+ objectInstance, method, new Object[] {
+ 2,
+ "efgh"
+ }, null, null);
+
+ serviceMethodInterceptor.beforeMethod(objectInstance, method, new Object[] {SQL}, null, null);
+ serviceMethodInterceptor.afterMethod(objectInstance, method, new Object[] {SQL}, null, null);
+
+ assertThat(segmentStorage.getTraceSegments().size(), is(1));
+ TraceSegment segment = segmentStorage.getTraceSegments().get(0);
+ assertThat(SegmentHelper.getSpans(segment).size(), is(1));
+ AbstractTracingSpan span = SegmentHelper.getSpans(segment).get(0);
+ SpanAssert.assertLayer(span, SpanLayer.DB);
+ assertThat(span.getOperationName(), is("Mariadb/JDBC/PreparedStatement/executeQuery"));
+ SpanAssert.assertTag(span, 0, "Mariadb");
+ SpanAssert.assertTag(span, 1, "test");
+ SpanAssert.assertTag(span, 2, "Select * f...");
+ SpanAssert.assertTag(span, 3, "[abcd,efgh]");
+ }
+
+}
diff --git a/apm-sniffer/apm-sdk-plugin/mariadb-3.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/jdbc/mariadb/v3/StatementExecuteMethodsInterceptorTest.java b/apm-sniffer/apm-sdk-plugin/mariadb-3.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/jdbc/mariadb/v3/StatementExecuteMethodsInterceptorTest.java
new file mode 100644
index 0000000000..ce2e83c69a
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/mariadb-3.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/jdbc/mariadb/v3/StatementExecuteMethodsInterceptorTest.java
@@ -0,0 +1,118 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.jdbc.mariadb.v3;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertThat;
+import static org.mockito.Mockito.when;
+import java.lang.reflect.Method;
+import org.apache.skywalking.apm.agent.core.context.trace.AbstractTracingSpan;
+import org.apache.skywalking.apm.agent.core.context.trace.SpanLayer;
+import org.apache.skywalking.apm.agent.core.context.trace.TraceSegment;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
+import org.apache.skywalking.apm.agent.test.helper.SegmentHelper;
+import org.apache.skywalking.apm.agent.test.tools.AgentServiceRule;
+import org.apache.skywalking.apm.agent.test.tools.SegmentStorage;
+import org.apache.skywalking.apm.agent.test.tools.SegmentStoragePoint;
+import org.apache.skywalking.apm.agent.test.tools.SpanAssert;
+import org.apache.skywalking.apm.agent.test.tools.TracingSegmentRunner;
+import org.apache.skywalking.apm.network.trace.component.ComponentsDefine;
+import org.apache.skywalking.apm.plugin.jdbc.JDBCPluginConfig;
+import org.apache.skywalking.apm.plugin.jdbc.define.StatementEnhanceInfos;
+import org.apache.skywalking.apm.plugin.jdbc.trace.ConnectionInfo;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+
+@RunWith(TracingSegmentRunner.class)
+public class StatementExecuteMethodsInterceptorTest {
+
+ private static final String SQL = "Select * from test";
+
+ @SegmentStoragePoint
+ private SegmentStorage segmentStorage;
+
+ @Rule
+ public AgentServiceRule serviceRule = new AgentServiceRule();
+ @Rule
+ public MockitoRule rule = MockitoJUnit.rule();
+
+ private StatementExecuteMethodsInterceptor serviceMethodInterceptor;
+
+ @Mock
+ private ConnectionInfo connectionInfo;
+ @Mock
+ private EnhancedInstance objectInstance;
+ @Mock
+ private Method method;
+ private StatementEnhanceInfos enhanceRequireCacheObject;
+
+ @Before
+ public void setUp() {
+ JDBCPluginConfig.Plugin.JDBC.SQL_BODY_MAX_LENGTH = 2048;
+
+ serviceMethodInterceptor = new StatementExecuteMethodsInterceptor();
+
+ enhanceRequireCacheObject = new StatementEnhanceInfos(connectionInfo, SQL, "CallableStatement");
+ when(objectInstance.getSkyWalkingDynamicField()).thenReturn(enhanceRequireCacheObject);
+ when(method.getName()).thenReturn("executeQuery");
+ when(connectionInfo.getComponent()).thenReturn(ComponentsDefine.MARIADB_JDBC);
+ when(connectionInfo.getDBType()).thenReturn("Mariadb");
+ when(connectionInfo.getDatabaseName()).thenReturn("test");
+ when(connectionInfo.getDatabasePeer()).thenReturn("localhost:3306");
+ }
+
+ @Test
+ public void testExecuteStatement() {
+ serviceMethodInterceptor.beforeMethod(objectInstance, method, new Object[]{SQL}, null, null);
+ serviceMethodInterceptor.afterMethod(objectInstance, method, new Object[]{SQL}, null, null);
+
+ assertThat(segmentStorage.getTraceSegments().size(), is(1));
+ TraceSegment segment = segmentStorage.getTraceSegments().get(0);
+ assertThat(SegmentHelper.getSpans(segment).size(), is(1));
+ AbstractTracingSpan span = SegmentHelper.getSpans(segment).get(0);
+ SpanAssert.assertLayer(span, SpanLayer.DB);
+ assertThat(span.getOperationName(), is("Mariadb/JDBC/CallableStatement/executeQuery"));
+ SpanAssert.assertTag(span, 0, "Mariadb");
+ SpanAssert.assertTag(span, 1, "test");
+ SpanAssert.assertTag(span, 2, SQL);
+ }
+
+ @Test
+ public void testExecuteStatementWithLimitSqlBody() {
+ JDBCPluginConfig.Plugin.JDBC.SQL_BODY_MAX_LENGTH = 10;
+ serviceMethodInterceptor.beforeMethod(objectInstance, method, new Object[]{SQL}, null, null);
+ serviceMethodInterceptor.afterMethod(objectInstance, method, new Object[]{SQL}, null, null);
+
+ assertThat(segmentStorage.getTraceSegments().size(), is(1));
+ TraceSegment segment = segmentStorage.getTraceSegments().get(0);
+ assertThat(SegmentHelper.getSpans(segment).size(), is(1));
+ AbstractTracingSpan span = SegmentHelper.getSpans(segment).get(0);
+ SpanAssert.assertLayer(span, SpanLayer.DB);
+ assertThat(span.getOperationName(), is("Mariadb/JDBC/CallableStatement/executeQuery"));
+ SpanAssert.assertTag(span, 0, "Mariadb");
+ SpanAssert.assertTag(span, 1, "test");
+ SpanAssert.assertTag(span, 2, "Select * f...");
+ }
+
+}
diff --git a/apm-sniffer/apm-sdk-plugin/micronaut-plugins/micronaut-http-client-plugin/pom.xml b/apm-sniffer/apm-sdk-plugin/micronaut-plugins/micronaut-http-client-plugin/pom.xml
index 30b35cca03..0dbafa710d 100644
--- a/apm-sniffer/apm-sdk-plugin/micronaut-plugins/micronaut-http-client-plugin/pom.xml
+++ b/apm-sniffer/apm-sdk-plugin/micronaut-plugins/micronaut-http-client-plugin/pom.xml
@@ -21,17 +21,12 @@
org.apache.skywalking
micronaut-plugins
- 9.3.0-SNAPSHOT
+ 9.7.0-SNAPSHOT
4.0.0
micronaut-http-client-plugin
-
- 8
- 8
-
-
io.projectreactor
diff --git a/apm-sniffer/apm-sdk-plugin/micronaut-plugins/micronaut-http-server-plugin/pom.xml b/apm-sniffer/apm-sdk-plugin/micronaut-plugins/micronaut-http-server-plugin/pom.xml
index 6f3b7c80bd..df12088c75 100644
--- a/apm-sniffer/apm-sdk-plugin/micronaut-plugins/micronaut-http-server-plugin/pom.xml
+++ b/apm-sniffer/apm-sdk-plugin/micronaut-plugins/micronaut-http-server-plugin/pom.xml
@@ -21,18 +21,13 @@
org.apache.skywalking
micronaut-plugins
- 9.3.0-SNAPSHOT
+ 9.7.0-SNAPSHOT
4.0.0
micronaut-http-server-plugin
jar
-
- 8
- 8
-
-
io.micronaut
diff --git a/apm-sniffer/apm-sdk-plugin/micronaut-plugins/pom.xml b/apm-sniffer/apm-sdk-plugin/micronaut-plugins/pom.xml
index 931bc20085..0025bcf432 100644
--- a/apm-sniffer/apm-sdk-plugin/micronaut-plugins/pom.xml
+++ b/apm-sniffer/apm-sdk-plugin/micronaut-plugins/pom.xml
@@ -20,7 +20,7 @@
apm-sdk-plugin
org.apache.skywalking
- 9.3.0-SNAPSHOT
+ 9.7.0-SNAPSHOT
4.0.0
@@ -29,7 +29,6 @@
UTF-8
- /..
diff --git a/apm-sniffer/apm-sdk-plugin/mongodb-2.x-plugin/pom.xml b/apm-sniffer/apm-sdk-plugin/mongodb-2.x-plugin/pom.xml
index 4fb80d5e87..e16638a4b9 100644
--- a/apm-sniffer/apm-sdk-plugin/mongodb-2.x-plugin/pom.xml
+++ b/apm-sniffer/apm-sdk-plugin/mongodb-2.x-plugin/pom.xml
@@ -21,7 +21,7 @@
apm-sdk-plugin
org.apache.skywalking
- 9.3.0-SNAPSHOT
+ 9.7.0-SNAPSHOT
4.0.0
diff --git a/apm-sniffer/apm-sdk-plugin/mongodb-3.x-plugin/pom.xml b/apm-sniffer/apm-sdk-plugin/mongodb-3.x-plugin/pom.xml
index 68c1ade2e2..212222c6d6 100644
--- a/apm-sniffer/apm-sdk-plugin/mongodb-3.x-plugin/pom.xml
+++ b/apm-sniffer/apm-sdk-plugin/mongodb-3.x-plugin/pom.xml
@@ -21,7 +21,7 @@
apm-sdk-plugin
org.apache.skywalking
- 9.3.0-SNAPSHOT
+ 9.7.0-SNAPSHOT
apm-mongodb-3.x-plugin
diff --git a/apm-sniffer/apm-sdk-plugin/mongodb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v3/define/readOperation/AggregateExplainOperationInstrumentation.java b/apm-sniffer/apm-sdk-plugin/mongodb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v3/define/readOperation/AggregateExplainOperationInstrumentation.java
new file mode 100644
index 0000000000..929935a2c1
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/mongodb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v3/define/readOperation/AggregateExplainOperationInstrumentation.java
@@ -0,0 +1,64 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.mongodb.v3.define.readOperation;
+
+import net.bytebuddy.description.method.MethodDescription;
+import net.bytebuddy.matcher.ElementMatcher;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine;
+import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
+import org.apache.skywalking.apm.agent.core.plugin.match.NameMatch;
+
+import static net.bytebuddy.matcher.ElementMatchers.any;
+
+public class AggregateExplainOperationInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
+
+ private static final String ENHANCE_CLASS = "com.mongodb.operation.AggregateExplainOperation";
+
+ private static final String INTERCEPTOR_CLASS = "org.apache.skywalking.apm.plugin.mongodb.v3.interceptor.operation.OperationNamespaceConstructInterceptor";
+
+ @Override
+ protected ClassMatch enhanceClass() {
+ return NameMatch.byName(ENHANCE_CLASS);
+ }
+
+ @Override
+ public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
+ return new ConstructorInterceptPoint[] {
+ new ConstructorInterceptPoint() {
+ @Override
+ public ElementMatcher getConstructorMatcher() {
+ return any();
+ }
+
+ @Override
+ public String getConstructorInterceptor() {
+ return INTERCEPTOR_CLASS;
+ }
+ }
+ };
+ }
+
+ @Override
+ public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
+ return new InstanceMethodsInterceptPoint[0];
+ }
+
+}
diff --git a/apm-sniffer/apm-sdk-plugin/mongodb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v3/define/readOperation/AggregateOperationImplInstrumentation.java b/apm-sniffer/apm-sdk-plugin/mongodb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v3/define/readOperation/AggregateOperationImplInstrumentation.java
new file mode 100644
index 0000000000..208d0a2146
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/mongodb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v3/define/readOperation/AggregateOperationImplInstrumentation.java
@@ -0,0 +1,64 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.mongodb.v3.define.readOperation;
+
+import net.bytebuddy.description.method.MethodDescription;
+import net.bytebuddy.matcher.ElementMatcher;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine;
+import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
+import org.apache.skywalking.apm.agent.core.plugin.match.NameMatch;
+
+import static net.bytebuddy.matcher.ElementMatchers.any;
+
+public class AggregateOperationImplInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
+
+ private static final String ENHANCE_CLASS = "com.mongodb.operation.AggregateOperationImpl";
+
+ private static final String INTERCEPTOR_CLASS = "org.apache.skywalking.apm.plugin.mongodb.v3.interceptor.operation.OperationNamespaceConstructInterceptor";
+
+ @Override
+ protected ClassMatch enhanceClass() {
+ return NameMatch.byName(ENHANCE_CLASS);
+ }
+
+ @Override
+ public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
+ return new ConstructorInterceptPoint[] {
+ new ConstructorInterceptPoint() {
+
+ @Override
+ public ElementMatcher getConstructorMatcher() {
+ return any();
+ }
+
+ @Override
+ public String getConstructorInterceptor() {
+ return INTERCEPTOR_CLASS;
+ }
+ }
+ };
+ }
+
+ @Override
+ public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
+ return new InstanceMethodsInterceptPoint[0];
+ }
+}
\ No newline at end of file
diff --git a/apm-sniffer/apm-sdk-plugin/mongodb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v3/define/readOperation/AggregateOperationInstrumentation.java b/apm-sniffer/apm-sdk-plugin/mongodb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v3/define/readOperation/AggregateOperationInstrumentation.java
new file mode 100644
index 0000000000..bffd857fcb
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/mongodb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v3/define/readOperation/AggregateOperationInstrumentation.java
@@ -0,0 +1,64 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.mongodb.v3.define.readOperation;
+
+import net.bytebuddy.description.method.MethodDescription;
+import net.bytebuddy.matcher.ElementMatcher;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine;
+import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
+import org.apache.skywalking.apm.agent.core.plugin.match.NameMatch;
+
+import static net.bytebuddy.matcher.ElementMatchers.any;
+
+public class AggregateOperationInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
+
+ private static final String ENHANCE_CLASS = "com.mongodb.operation.AggregateOperation";
+
+ private static final String INTERCEPTOR_CLASS = "org.apache.skywalking.apm.plugin.mongodb.v3.interceptor.operation.OperationNamespaceConstructInterceptor";
+
+ @Override
+ protected ClassMatch enhanceClass() {
+ return NameMatch.byName(ENHANCE_CLASS);
+ }
+
+ @Override
+ public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
+ return new ConstructorInterceptPoint[] {
+ new ConstructorInterceptPoint() {
+
+ @Override
+ public ElementMatcher getConstructorMatcher() {
+ return any();
+ }
+
+ @Override
+ public String getConstructorInterceptor() {
+ return INTERCEPTOR_CLASS;
+ }
+ }
+ };
+ }
+
+ @Override
+ public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
+ return new InstanceMethodsInterceptPoint[0];
+ }
+}
\ No newline at end of file
diff --git a/apm-sniffer/apm-sdk-plugin/mongodb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v3/define/readOperation/ChangeStreamOperationInstrumentation.java b/apm-sniffer/apm-sdk-plugin/mongodb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v3/define/readOperation/ChangeStreamOperationInstrumentation.java
new file mode 100644
index 0000000000..f71ba7e4db
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/mongodb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v3/define/readOperation/ChangeStreamOperationInstrumentation.java
@@ -0,0 +1,65 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.mongodb.v3.define.readOperation;
+
+import net.bytebuddy.description.method.MethodDescription;
+import net.bytebuddy.matcher.ElementMatcher;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine;
+import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
+import org.apache.skywalking.apm.agent.core.plugin.match.NameMatch;
+
+import static net.bytebuddy.matcher.ElementMatchers.takesArguments;
+
+public class ChangeStreamOperationInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
+
+ private static final String ENHANCE_CLASS = "com.mongodb.operation.ChangeStreamOperation";
+
+ private static final String INTERCEPTOR_CLASS = "org.apache.skywalking.apm.plugin.mongodb.v3.interceptor.operation.OperationNamespaceConstructInterceptor";
+
+ @Override
+ protected ClassMatch enhanceClass() {
+ return NameMatch.byName(ENHANCE_CLASS);
+ }
+
+ @Override
+ public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
+ return new ConstructorInterceptPoint[] {
+ new ConstructorInterceptPoint() {
+
+ @Override
+ public ElementMatcher getConstructorMatcher() {
+ return takesArguments(5);
+ }
+
+ @Override
+ public String getConstructorInterceptor() {
+ return INTERCEPTOR_CLASS;
+ }
+ }
+ };
+ }
+
+ @Override
+ public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
+ return new InstanceMethodsInterceptPoint[0];
+ }
+
+}
\ No newline at end of file
diff --git a/apm-sniffer/apm-sdk-plugin/mongodb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v3/define/readOperation/CommandReadOperationInstrumentation.java b/apm-sniffer/apm-sdk-plugin/mongodb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v3/define/readOperation/CommandReadOperationInstrumentation.java
new file mode 100644
index 0000000000..ab317963f2
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/mongodb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v3/define/readOperation/CommandReadOperationInstrumentation.java
@@ -0,0 +1,65 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.mongodb.v3.define.readOperation;
+
+import net.bytebuddy.description.method.MethodDescription;
+import net.bytebuddy.matcher.ElementMatcher;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine;
+import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
+import org.apache.skywalking.apm.agent.core.plugin.match.NameMatch;
+
+import static net.bytebuddy.matcher.ElementMatchers.any;
+
+public class CommandReadOperationInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
+
+ private static final String ENHANCE_CLASS = "com.mongodb.operation.CommandReadOperation";
+
+ private static final String INTERCEPTOR_CLASS = "org.apache.skywalking.apm.plugin.mongodb.v3.interceptor.operation.OperationDatabaseConstructInterceptor";
+
+ @Override
+ protected ClassMatch enhanceClass() {
+ return NameMatch.byName(ENHANCE_CLASS);
+ }
+
+ @Override
+ public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
+ return new ConstructorInterceptPoint[] {
+ new ConstructorInterceptPoint() {
+
+ @Override
+ public ElementMatcher getConstructorMatcher() {
+ return any();
+ }
+
+ @Override
+ public String getConstructorInterceptor() {
+ return INTERCEPTOR_CLASS;
+ }
+ }
+ };
+ }
+
+ @Override
+ public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
+ return new InstanceMethodsInterceptPoint[0];
+ }
+
+}
diff --git a/apm-sniffer/apm-sdk-plugin/mongodb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v3/define/readOperation/CountOperationInstrumentation.java b/apm-sniffer/apm-sdk-plugin/mongodb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v3/define/readOperation/CountOperationInstrumentation.java
new file mode 100644
index 0000000000..6ee8e1ea29
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/mongodb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v3/define/readOperation/CountOperationInstrumentation.java
@@ -0,0 +1,65 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.mongodb.v3.define.readOperation;
+
+import net.bytebuddy.description.method.MethodDescription;
+import net.bytebuddy.matcher.ElementMatcher;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine;
+import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
+import org.apache.skywalking.apm.agent.core.plugin.match.NameMatch;
+
+import static net.bytebuddy.matcher.ElementMatchers.any;
+
+public class CountOperationInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
+
+ private static final String ENHANCE_CLASS = "com.mongodb.operation.CountOperation";
+
+ private static final String INTERCEPTOR_CLASS = "org.apache.skywalking.apm.plugin.mongodb.v3.interceptor.operation.OperationNamespaceConstructInterceptor";
+
+ @Override
+ protected ClassMatch enhanceClass() {
+ return NameMatch.byName(ENHANCE_CLASS);
+ }
+
+ @Override
+ public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
+ return new ConstructorInterceptPoint[] {
+ new ConstructorInterceptPoint() {
+
+ @Override
+ public ElementMatcher getConstructorMatcher() {
+ return any();
+ }
+
+ @Override
+ public String getConstructorInterceptor() {
+ return INTERCEPTOR_CLASS;
+ }
+ }
+ };
+ }
+
+ @Override
+ public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
+ return new InstanceMethodsInterceptPoint[0];
+ }
+
+}
\ No newline at end of file
diff --git a/apm-sniffer/apm-sdk-plugin/mongodb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v3/define/readOperation/DistinctOperationInstrumentation.java b/apm-sniffer/apm-sdk-plugin/mongodb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v3/define/readOperation/DistinctOperationInstrumentation.java
new file mode 100644
index 0000000000..43cf1f9db3
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/mongodb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v3/define/readOperation/DistinctOperationInstrumentation.java
@@ -0,0 +1,64 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.mongodb.v3.define.readOperation;
+
+import net.bytebuddy.description.method.MethodDescription;
+import net.bytebuddy.matcher.ElementMatcher;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine;
+import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
+import org.apache.skywalking.apm.agent.core.plugin.match.NameMatch;
+
+import static net.bytebuddy.matcher.ElementMatchers.any;
+
+public class DistinctOperationInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
+
+ private static final String ENHANCE_CLASS = "com.mongodb.operation.DistinctOperation";
+
+ private static final String INTERCEPTOR_CLASS = "org.apache.skywalking.apm.plugin.mongodb.v3.interceptor.operation.OperationNamespaceConstructInterceptor";
+
+ @Override
+ protected ClassMatch enhanceClass() {
+ return NameMatch.byName(ENHANCE_CLASS);
+ }
+
+ @Override
+ public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
+ return new ConstructorInterceptPoint[] {
+ new ConstructorInterceptPoint() {
+ @Override
+ public ElementMatcher getConstructorMatcher() {
+ return any();
+ }
+
+ @Override
+ public String getConstructorInterceptor() {
+ return INTERCEPTOR_CLASS;
+ }
+ }
+ };
+ }
+
+ @Override
+ public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
+ return new InstanceMethodsInterceptPoint[0];
+ }
+
+}
\ No newline at end of file
diff --git a/apm-sniffer/apm-sdk-plugin/mongodb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v3/define/readOperation/FindOperationInstrumentation.java b/apm-sniffer/apm-sdk-plugin/mongodb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v3/define/readOperation/FindOperationInstrumentation.java
new file mode 100644
index 0000000000..702d78138a
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/mongodb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v3/define/readOperation/FindOperationInstrumentation.java
@@ -0,0 +1,64 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.mongodb.v3.define.readOperation;
+
+import net.bytebuddy.description.method.MethodDescription;
+import net.bytebuddy.matcher.ElementMatcher;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine;
+import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
+import org.apache.skywalking.apm.agent.core.plugin.match.NameMatch;
+
+import static net.bytebuddy.matcher.ElementMatchers.any;
+
+public class FindOperationInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
+
+ private static final String ENHANCE_CLASS = "com.mongodb.operation.FindOperation";
+
+ private static final String INTERCEPTOR_CLASS = "org.apache.skywalking.apm.plugin.mongodb.v3.interceptor.operation.OperationNamespaceConstructInterceptor";
+
+ @Override
+ protected ClassMatch enhanceClass() {
+ return NameMatch.byName(ENHANCE_CLASS);
+ }
+
+ @Override
+ public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
+ return new ConstructorInterceptPoint[] {
+ new ConstructorInterceptPoint() {
+ @Override
+ public ElementMatcher getConstructorMatcher() {
+ return any();
+ }
+
+ @Override
+ public String getConstructorInterceptor() {
+ return INTERCEPTOR_CLASS;
+ }
+ }
+ };
+ }
+
+ @Override
+ public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
+ return new InstanceMethodsInterceptPoint[0];
+ }
+
+}
\ No newline at end of file
diff --git a/apm-sniffer/apm-sdk-plugin/mongodb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v3/define/readOperation/GroupOperationInstrumentation.java b/apm-sniffer/apm-sdk-plugin/mongodb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v3/define/readOperation/GroupOperationInstrumentation.java
new file mode 100644
index 0000000000..0ad153cdef
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/mongodb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v3/define/readOperation/GroupOperationInstrumentation.java
@@ -0,0 +1,63 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.mongodb.v3.define.readOperation;
+
+import net.bytebuddy.description.method.MethodDescription;
+import net.bytebuddy.matcher.ElementMatcher;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine;
+import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
+import org.apache.skywalking.apm.agent.core.plugin.match.NameMatch;
+
+import static net.bytebuddy.matcher.ElementMatchers.any;
+
+public class GroupOperationInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
+
+ private static final String ENHANCE_CLASS = "com.mongodb.operation.GroupOperation";
+
+ private static final String INTERCEPTOR_CLASS = "org.apache.skywalking.apm.plugin.mongodb.v3.interceptor.operation.OperationNamespaceConstructInterceptor";
+
+ @Override
+ protected ClassMatch enhanceClass() {
+ return NameMatch.byName(ENHANCE_CLASS);
+ }
+
+ @Override
+ public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
+ return new ConstructorInterceptPoint[] {
+ new ConstructorInterceptPoint() {
+ @Override
+ public ElementMatcher getConstructorMatcher() {
+ return any();
+ }
+
+ @Override
+ public String getConstructorInterceptor() {
+ return INTERCEPTOR_CLASS;
+ }
+ }
+ };
+ }
+
+ @Override
+ public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
+ return new InstanceMethodsInterceptPoint[0];
+ }
+}
diff --git a/apm-sniffer/apm-sdk-plugin/mongodb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v3/define/readOperation/ListCollectionsOperationInstrumentation.java b/apm-sniffer/apm-sdk-plugin/mongodb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v3/define/readOperation/ListCollectionsOperationInstrumentation.java
new file mode 100644
index 0000000000..0eff3237db
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/mongodb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v3/define/readOperation/ListCollectionsOperationInstrumentation.java
@@ -0,0 +1,63 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.mongodb.v3.define.readOperation;
+
+import net.bytebuddy.description.method.MethodDescription;
+import net.bytebuddy.matcher.ElementMatcher;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine;
+import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
+import org.apache.skywalking.apm.agent.core.plugin.match.NameMatch;
+
+import static net.bytebuddy.matcher.ElementMatchers.any;
+
+public class ListCollectionsOperationInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
+
+ private static final String ENHANCE_CLASS = "com.mongodb.operation.ListCollectionsOperation";
+
+ private static final String INTERCEPTOR_CLASS = "org.apache.skywalking.apm.plugin.mongodb.v3.interceptor.operation.OperationDatabaseConstructInterceptor";
+
+ @Override
+ protected ClassMatch enhanceClass() {
+ return NameMatch.byName(ENHANCE_CLASS);
+ }
+
+ @Override
+ public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
+ return new ConstructorInterceptPoint[] {
+ new ConstructorInterceptPoint() {
+ @Override
+ public ElementMatcher getConstructorMatcher() {
+ return any();
+ }
+
+ @Override
+ public String getConstructorInterceptor() {
+ return INTERCEPTOR_CLASS;
+ }
+ }
+ };
+ }
+
+ @Override
+ public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
+ return new InstanceMethodsInterceptPoint[0];
+ }
+}
diff --git a/apm-sniffer/apm-sdk-plugin/mongodb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v3/define/readOperation/ListIndexesOperationInstrumentation.java b/apm-sniffer/apm-sdk-plugin/mongodb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v3/define/readOperation/ListIndexesOperationInstrumentation.java
new file mode 100644
index 0000000000..7a1870badc
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/mongodb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v3/define/readOperation/ListIndexesOperationInstrumentation.java
@@ -0,0 +1,64 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.mongodb.v3.define.readOperation;
+
+import net.bytebuddy.description.method.MethodDescription;
+import net.bytebuddy.matcher.ElementMatcher;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine;
+import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
+import org.apache.skywalking.apm.agent.core.plugin.match.NameMatch;
+
+import static net.bytebuddy.matcher.ElementMatchers.any;
+
+public class ListIndexesOperationInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
+
+ private static final String ENHANCE_CLASS = "com.mongodb.operation.ListIndexesOperation";
+
+ private static final String INTERCEPTOR_CLASS = "org.apache.skywalking.apm.plugin.mongodb.v3.interceptor.operation.OperationNamespaceConstructInterceptor";
+
+ @Override
+ protected ClassMatch enhanceClass() {
+ return NameMatch.byName(ENHANCE_CLASS);
+ }
+
+ @Override
+ public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
+ return new ConstructorInterceptPoint[] {
+ new ConstructorInterceptPoint() {
+ @Override
+ public ElementMatcher getConstructorMatcher() {
+ return any();
+ }
+
+ @Override
+ public String getConstructorInterceptor() {
+ return INTERCEPTOR_CLASS;
+ }
+ }
+ };
+ }
+
+ @Override
+ public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
+ return new InstanceMethodsInterceptPoint[0];
+ }
+
+}
\ No newline at end of file
diff --git a/apm-sniffer/apm-sdk-plugin/mongodb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v3/define/readOperation/MapReduceWithInlineResultsOperationInstrumentation.java b/apm-sniffer/apm-sdk-plugin/mongodb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v3/define/readOperation/MapReduceWithInlineResultsOperationInstrumentation.java
new file mode 100644
index 0000000000..e0fcadfecf
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/mongodb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v3/define/readOperation/MapReduceWithInlineResultsOperationInstrumentation.java
@@ -0,0 +1,64 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.mongodb.v3.define.readOperation;
+
+import net.bytebuddy.description.method.MethodDescription;
+import net.bytebuddy.matcher.ElementMatcher;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine;
+import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
+import org.apache.skywalking.apm.agent.core.plugin.match.NameMatch;
+
+import static net.bytebuddy.matcher.ElementMatchers.any;
+
+public class MapReduceWithInlineResultsOperationInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
+
+ private static final String ENHANCE_CLASS = "com.mongodb.operation.MapReduceWithInlineResultsOperation";
+
+ private static final String INTERCEPTOR_CLASS = "org.apache.skywalking.apm.plugin.mongodb.v3.interceptor.operation.OperationNamespaceConstructInterceptor";
+
+ @Override
+ protected ClassMatch enhanceClass() {
+ return NameMatch.byName(ENHANCE_CLASS);
+ }
+
+ @Override
+ public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
+ return new ConstructorInterceptPoint[] {
+ new ConstructorInterceptPoint() {
+ @Override
+ public ElementMatcher getConstructorMatcher() {
+ return any();
+ }
+
+ @Override
+ public String getConstructorInterceptor() {
+ return INTERCEPTOR_CLASS;
+ }
+ }
+ };
+ }
+
+ @Override
+ public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
+ return new InstanceMethodsInterceptPoint[0];
+ }
+
+}
\ No newline at end of file
diff --git a/apm-sniffer/apm-sdk-plugin/mongodb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v3/define/readOperation/ParallelCollectionScanOperationInstrumentation.java b/apm-sniffer/apm-sdk-plugin/mongodb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v3/define/readOperation/ParallelCollectionScanOperationInstrumentation.java
new file mode 100644
index 0000000000..554d178570
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/mongodb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v3/define/readOperation/ParallelCollectionScanOperationInstrumentation.java
@@ -0,0 +1,63 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.mongodb.v3.define.readOperation;
+
+import net.bytebuddy.description.method.MethodDescription;
+import net.bytebuddy.matcher.ElementMatcher;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine;
+import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
+import org.apache.skywalking.apm.agent.core.plugin.match.NameMatch;
+
+import static net.bytebuddy.matcher.ElementMatchers.any;
+
+public class ParallelCollectionScanOperationInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
+
+ private static final String ENHANCE_CLASS = "com.mongodb.operation.ParallelCollectionScanOperation";
+
+ private static final String INTERCEPTOR_CLASS = "org.apache.skywalking.apm.plugin.mongodb.v3.interceptor.operation.OperationNamespaceConstructInterceptor";
+
+ @Override
+ protected ClassMatch enhanceClass() {
+ return NameMatch.byName(ENHANCE_CLASS);
+ }
+
+ @Override
+ public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
+ return new ConstructorInterceptPoint[] {
+ new ConstructorInterceptPoint() {
+ @Override
+ public ElementMatcher getConstructorMatcher() {
+ return any();
+ }
+
+ @Override
+ public String getConstructorInterceptor() {
+ return INTERCEPTOR_CLASS;
+ }
+ }
+ };
+ }
+
+ @Override
+ public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
+ return new InstanceMethodsInterceptPoint[0];
+ }
+}
diff --git a/apm-sniffer/apm-sdk-plugin/mongodb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v3/define/readOperation/UserExistsOperationInstrumentation.java b/apm-sniffer/apm-sdk-plugin/mongodb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v3/define/readOperation/UserExistsOperationInstrumentation.java
new file mode 100644
index 0000000000..393b0096a7
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/mongodb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v3/define/readOperation/UserExistsOperationInstrumentation.java
@@ -0,0 +1,63 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.mongodb.v3.define.readOperation;
+
+import net.bytebuddy.description.method.MethodDescription;
+import net.bytebuddy.matcher.ElementMatcher;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine;
+import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
+import org.apache.skywalking.apm.agent.core.plugin.match.NameMatch;
+
+import static net.bytebuddy.matcher.ElementMatchers.any;
+
+public class UserExistsOperationInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
+
+ private static final String ENHANCE_CLASS = "com.mongodb.operation.UserExistsOperation";
+
+ private static final String INTERCEPTOR_CLASS = "org.apache.skywalking.apm.plugin.mongodb.v3.interceptor.operation.OperationDatabaseConstructInterceptor";
+
+ @Override
+ protected ClassMatch enhanceClass() {
+ return NameMatch.byName(ENHANCE_CLASS);
+ }
+
+ @Override
+ public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
+ return new ConstructorInterceptPoint[] {
+ new ConstructorInterceptPoint() {
+ @Override
+ public ElementMatcher getConstructorMatcher() {
+ return any();
+ }
+
+ @Override
+ public String getConstructorInterceptor() {
+ return INTERCEPTOR_CLASS;
+ }
+ }
+ };
+ }
+
+ @Override
+ public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
+ return new InstanceMethodsInterceptPoint[0];
+ }
+}
diff --git a/apm-sniffer/apm-sdk-plugin/mongodb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v3/define/readOperation/WrappedMapReduceReadOperationInstrumentation.java b/apm-sniffer/apm-sdk-plugin/mongodb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v3/define/readOperation/WrappedMapReduceReadOperationInstrumentation.java
new file mode 100644
index 0000000000..4e76a8e06c
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/mongodb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v3/define/readOperation/WrappedMapReduceReadOperationInstrumentation.java
@@ -0,0 +1,64 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.mongodb.v3.define.readOperation;
+
+import net.bytebuddy.description.method.MethodDescription;
+import net.bytebuddy.matcher.ElementMatcher;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine;
+import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
+import org.apache.skywalking.apm.agent.core.plugin.match.NameMatch;
+
+import static net.bytebuddy.matcher.ElementMatchers.any;
+
+public class WrappedMapReduceReadOperationInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
+
+ private static final String ENHANCE_CLASS = "com.mongodb.MapReduceIterableImpl";
+
+ private static final String INTERCEPTOR_CLASS = "org.apache.skywalking.apm.plugin.mongodb.v3.interceptor.operation.OperationNamespaceConstructInterceptor";
+
+ @Override
+ protected ClassMatch enhanceClass() {
+ return NameMatch.byName(ENHANCE_CLASS);
+ }
+
+ @Override
+ public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
+ return new ConstructorInterceptPoint[] {
+ new ConstructorInterceptPoint() {
+ @Override
+ public ElementMatcher getConstructorMatcher() {
+ return any();
+ }
+
+ @Override
+ public String getConstructorInterceptor() {
+ return INTERCEPTOR_CLASS;
+ }
+ }
+ };
+ }
+
+ @Override
+ public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
+ return new InstanceMethodsInterceptPoint[0];
+ }
+
+}
diff --git a/apm-sniffer/apm-sdk-plugin/mongodb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v3/define/v36/readOperation/WrappedMapReduceReadOperationInstrumentation.java b/apm-sniffer/apm-sdk-plugin/mongodb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v3/define/v36/readOperation/WrappedMapReduceReadOperationInstrumentation.java
new file mode 100644
index 0000000000..c3fabf603e
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/mongodb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v3/define/v36/readOperation/WrappedMapReduceReadOperationInstrumentation.java
@@ -0,0 +1,64 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.mongodb.v3.define.v36.readOperation;
+
+import net.bytebuddy.description.method.MethodDescription;
+import net.bytebuddy.matcher.ElementMatcher;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine;
+import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
+import org.apache.skywalking.apm.agent.core.plugin.match.NameMatch;
+
+import static net.bytebuddy.matcher.ElementMatchers.any;
+
+public class WrappedMapReduceReadOperationInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
+
+ private static final String ENHANCE_CLASS = "com.mongodb.client.internal.MapReduceIterableImpl$WrappedMapReduceReadOperation";
+
+ private static final String INTERCEPTOR_CLASS = "org.apache.skywalking.apm.plugin.mongodb.v3.interceptor.operation.WrappedMapReduceReadOperationInterceptor";
+
+ @Override
+ protected ClassMatch enhanceClass() {
+ return NameMatch.byName(ENHANCE_CLASS);
+ }
+
+ @Override
+ public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
+ return new ConstructorInterceptPoint[] {
+ new ConstructorInterceptPoint() {
+ @Override
+ public ElementMatcher getConstructorMatcher() {
+ return any();
+ }
+
+ @Override
+ public String getConstructorInterceptor() {
+ return INTERCEPTOR_CLASS;
+ }
+ }
+ };
+ }
+
+ @Override
+ public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
+ return new InstanceMethodsInterceptPoint[0];
+ }
+
+}
diff --git a/apm-sniffer/apm-sdk-plugin/mongodb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v3/define/writeOperation/AggregateToCollectionOperationInstrumentation.java b/apm-sniffer/apm-sdk-plugin/mongodb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v3/define/writeOperation/AggregateToCollectionOperationInstrumentation.java
new file mode 100644
index 0000000000..62bde0f7f8
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/mongodb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v3/define/writeOperation/AggregateToCollectionOperationInstrumentation.java
@@ -0,0 +1,64 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.mongodb.v3.define.writeOperation;
+
+import net.bytebuddy.description.method.MethodDescription;
+import net.bytebuddy.matcher.ElementMatcher;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine;
+import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
+import org.apache.skywalking.apm.agent.core.plugin.match.NameMatch;
+
+import static net.bytebuddy.matcher.ElementMatchers.takesArguments;
+
+public class AggregateToCollectionOperationInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
+
+ private static final String ENHANCE_CLASS = "com.mongodb.operation.AggregateToCollectionOperation";
+
+ private static final String INTERCEPTOR_CLASS = "org.apache.skywalking.apm.plugin.mongodb.v3.interceptor.operation.OperationNamespaceConstructInterceptor";
+
+ @Override
+ protected ClassMatch enhanceClass() {
+ return NameMatch.byName(ENHANCE_CLASS);
+ }
+
+ @Override
+ public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
+ return new ConstructorInterceptPoint[] {
+ new ConstructorInterceptPoint() {
+ @Override
+ public ElementMatcher getConstructorMatcher() {
+ return takesArguments(5);
+ }
+
+ @Override
+ public String getConstructorInterceptor() {
+ return INTERCEPTOR_CLASS;
+ }
+ }
+ };
+ }
+
+ @Override
+ public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
+ return new InstanceMethodsInterceptPoint[0];
+ }
+
+}
diff --git a/apm-sniffer/apm-sdk-plugin/mongodb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v3/define/writeOperation/BaseFindAndModifyOperationInstrumentation.java b/apm-sniffer/apm-sdk-plugin/mongodb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v3/define/writeOperation/BaseFindAndModifyOperationInstrumentation.java
new file mode 100644
index 0000000000..bb1c0445ee
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/mongodb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v3/define/writeOperation/BaseFindAndModifyOperationInstrumentation.java
@@ -0,0 +1,64 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.mongodb.v3.define.writeOperation;
+
+import net.bytebuddy.description.method.MethodDescription;
+import net.bytebuddy.matcher.ElementMatcher;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine;
+import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
+import org.apache.skywalking.apm.agent.core.plugin.match.NameMatch;
+
+import static net.bytebuddy.matcher.ElementMatchers.any;
+
+public class BaseFindAndModifyOperationInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
+
+ private static final String ENHANCE_CLASS = "com.mongodb.operation.BaseFindAndModifyOperation";
+
+ private static final String INTERCEPTOR_CLASS = "org.apache.skywalking.apm.plugin.mongodb.v3.interceptor.operation.OperationNamespaceConstructInterceptor";
+
+ @Override
+ protected ClassMatch enhanceClass() {
+ return NameMatch.byName(ENHANCE_CLASS);
+ }
+
+ @Override
+ public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
+ return new ConstructorInterceptPoint[] {
+ new ConstructorInterceptPoint() {
+ @Override
+ public ElementMatcher getConstructorMatcher() {
+ return any();
+ }
+
+ @Override
+ public String getConstructorInterceptor() {
+ return INTERCEPTOR_CLASS;
+ }
+ }
+ };
+ }
+
+ @Override
+ public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
+ return new InstanceMethodsInterceptPoint[0];
+ }
+
+}
diff --git a/apm-sniffer/apm-sdk-plugin/mongodb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v3/define/writeOperation/BaseWriteOperationInstrumentation.java b/apm-sniffer/apm-sdk-plugin/mongodb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v3/define/writeOperation/BaseWriteOperationInstrumentation.java
new file mode 100644
index 0000000000..fdb6b8ffe3
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/mongodb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v3/define/writeOperation/BaseWriteOperationInstrumentation.java
@@ -0,0 +1,64 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.mongodb.v3.define.writeOperation;
+
+import net.bytebuddy.description.method.MethodDescription;
+import net.bytebuddy.matcher.ElementMatcher;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine;
+import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
+import org.apache.skywalking.apm.agent.core.plugin.match.NameMatch;
+
+import static net.bytebuddy.matcher.ElementMatchers.takesArguments;
+
+public class BaseWriteOperationInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
+
+ private static final String ENHANCE_CLASS = "com.mongodb.operation.BaseWriteOperation";
+
+ private static final String INTERCEPTOR_CLASS = "org.apache.skywalking.apm.plugin.mongodb.v3.interceptor.operation.OperationNamespaceConstructInterceptor";
+
+ @Override
+ protected ClassMatch enhanceClass() {
+ return NameMatch.byName(ENHANCE_CLASS);
+ }
+
+ @Override
+ public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
+ return new ConstructorInterceptPoint[] {
+ new ConstructorInterceptPoint() {
+ @Override
+ public ElementMatcher getConstructorMatcher() {
+ return takesArguments(4);
+ }
+
+ @Override
+ public String getConstructorInterceptor() {
+ return INTERCEPTOR_CLASS;
+ }
+ }
+ };
+ }
+
+ @Override
+ public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
+ return new InstanceMethodsInterceptPoint[0];
+ }
+
+}
diff --git a/apm-sniffer/apm-sdk-plugin/mongodb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v3/define/writeOperation/CommandWriteOperationInstrumentation.java b/apm-sniffer/apm-sdk-plugin/mongodb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v3/define/writeOperation/CommandWriteOperationInstrumentation.java
new file mode 100644
index 0000000000..77d3d4f165
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/mongodb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v3/define/writeOperation/CommandWriteOperationInstrumentation.java
@@ -0,0 +1,63 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.mongodb.v3.define.writeOperation;
+
+import net.bytebuddy.description.method.MethodDescription;
+import net.bytebuddy.matcher.ElementMatcher;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine;
+import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
+import org.apache.skywalking.apm.agent.core.plugin.match.NameMatch;
+
+import static net.bytebuddy.matcher.ElementMatchers.any;
+
+public class CommandWriteOperationInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
+
+ private static final String ENHANCE_CLASS = "com.mongodb.operation.CommandWriteOperation";
+
+ private static final String INTERCEPTOR_CLASS = "org.apache.skywalking.apm.plugin.mongodb.v3.interceptor.operation.OperationDatabaseConstructInterceptor";
+
+ @Override
+ protected ClassMatch enhanceClass() {
+ return NameMatch.byName(ENHANCE_CLASS);
+ }
+
+ @Override
+ public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
+ return new ConstructorInterceptPoint[] {
+ new ConstructorInterceptPoint() {
+ @Override
+ public ElementMatcher getConstructorMatcher() {
+ return any();
+ }
+
+ @Override
+ public String getConstructorInterceptor() {
+ return INTERCEPTOR_CLASS;
+ }
+ }
+ };
+ }
+
+ @Override
+ public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
+ return new InstanceMethodsInterceptPoint[0];
+ }
+}
diff --git a/apm-sniffer/apm-sdk-plugin/mongodb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v3/define/writeOperation/CreateCollectionOperationInstrumentation.java b/apm-sniffer/apm-sdk-plugin/mongodb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v3/define/writeOperation/CreateCollectionOperationInstrumentation.java
new file mode 100644
index 0000000000..a5f45f68e3
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/mongodb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v3/define/writeOperation/CreateCollectionOperationInstrumentation.java
@@ -0,0 +1,63 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.mongodb.v3.define.writeOperation;
+
+import net.bytebuddy.description.method.MethodDescription;
+import net.bytebuddy.matcher.ElementMatcher;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine;
+import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
+import org.apache.skywalking.apm.agent.core.plugin.match.NameMatch;
+
+import static net.bytebuddy.matcher.ElementMatchers.takesArguments;
+
+public class CreateCollectionOperationInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
+
+ private static final String ENHANCE_CLASS = "com.mongodb.operation.CreateCollectionOperation";
+
+ private static final String INTERCEPTOR_CLASS = "org.apache.skywalking.apm.plugin.mongodb.v3.interceptor.operation.OperationDatabaseConstructInterceptor";
+
+ @Override
+ protected ClassMatch enhanceClass() {
+ return NameMatch.byName(ENHANCE_CLASS);
+ }
+
+ @Override
+ public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
+ return new ConstructorInterceptPoint[] {
+ new ConstructorInterceptPoint() {
+ @Override
+ public ElementMatcher getConstructorMatcher() {
+ return takesArguments(3);
+ }
+
+ @Override
+ public String getConstructorInterceptor() {
+ return INTERCEPTOR_CLASS;
+ }
+ }
+ };
+ }
+
+ @Override
+ public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
+ return new InstanceMethodsInterceptPoint[0];
+ }
+}
diff --git a/apm-sniffer/apm-sdk-plugin/mongodb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v3/define/writeOperation/CreateIndexesOperationInstrumentation.java b/apm-sniffer/apm-sdk-plugin/mongodb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v3/define/writeOperation/CreateIndexesOperationInstrumentation.java
new file mode 100644
index 0000000000..556205173a
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/mongodb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v3/define/writeOperation/CreateIndexesOperationInstrumentation.java
@@ -0,0 +1,64 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.mongodb.v3.define.writeOperation;
+
+import net.bytebuddy.description.method.MethodDescription;
+import net.bytebuddy.matcher.ElementMatcher;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine;
+import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
+import org.apache.skywalking.apm.agent.core.plugin.match.NameMatch;
+
+import static net.bytebuddy.matcher.ElementMatchers.takesArguments;
+
+public class CreateIndexesOperationInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
+
+ private static final String ENHANCE_CLASS = "com.mongodb.operation.CreateIndexesOperation";
+
+ private static final String INTERCEPTOR_CLASS = "org.apache.skywalking.apm.plugin.mongodb.v3.interceptor.operation.OperationNamespaceConstructInterceptor";
+
+ @Override
+ protected ClassMatch enhanceClass() {
+ return NameMatch.byName(ENHANCE_CLASS);
+ }
+
+ @Override
+ public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
+ return new ConstructorInterceptPoint[] {
+ new ConstructorInterceptPoint() {
+ @Override
+ public ElementMatcher getConstructorMatcher() {
+ return takesArguments(3);
+ }
+
+ @Override
+ public String getConstructorInterceptor() {
+ return INTERCEPTOR_CLASS;
+ }
+ }
+ };
+ }
+
+ @Override
+ public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
+ return new InstanceMethodsInterceptPoint[0];
+ }
+
+}
diff --git a/apm-sniffer/apm-sdk-plugin/mongodb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v3/define/writeOperation/CreateViewOperationInstrumentation.java b/apm-sniffer/apm-sdk-plugin/mongodb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v3/define/writeOperation/CreateViewOperationInstrumentation.java
new file mode 100644
index 0000000000..e16c434818
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/mongodb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v3/define/writeOperation/CreateViewOperationInstrumentation.java
@@ -0,0 +1,63 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.mongodb.v3.define.writeOperation;
+
+import net.bytebuddy.description.method.MethodDescription;
+import net.bytebuddy.matcher.ElementMatcher;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine;
+import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
+import org.apache.skywalking.apm.agent.core.plugin.match.NameMatch;
+
+import static net.bytebuddy.matcher.ElementMatchers.any;
+
+public class CreateViewOperationInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
+
+ private static final String ENHANCE_CLASS = "com.mongodb.operation.CreateViewOperation";
+
+ private static final String INTERCEPTOR_CLASS = "org.apache.skywalking.apm.plugin.mongodb.v3.interceptor.operation.OperationDatabaseConstructInterceptor";
+
+ @Override
+ protected ClassMatch enhanceClass() {
+ return NameMatch.byName(ENHANCE_CLASS);
+ }
+
+ @Override
+ public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
+ return new ConstructorInterceptPoint[] {
+ new ConstructorInterceptPoint() {
+ @Override
+ public ElementMatcher getConstructorMatcher() {
+ return any();
+ }
+
+ @Override
+ public String getConstructorInterceptor() {
+ return INTERCEPTOR_CLASS;
+ }
+ }
+ };
+ }
+
+ @Override
+ public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
+ return new InstanceMethodsInterceptPoint[0];
+ }
+}
diff --git a/apm-sniffer/apm-sdk-plugin/mongodb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v3/define/writeOperation/DropCollectionOperationInstrumentation.java b/apm-sniffer/apm-sdk-plugin/mongodb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v3/define/writeOperation/DropCollectionOperationInstrumentation.java
new file mode 100644
index 0000000000..88a04f6900
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/mongodb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v3/define/writeOperation/DropCollectionOperationInstrumentation.java
@@ -0,0 +1,64 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.mongodb.v3.define.writeOperation;
+
+import net.bytebuddy.description.method.MethodDescription;
+import net.bytebuddy.matcher.ElementMatcher;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine;
+import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
+import org.apache.skywalking.apm.agent.core.plugin.match.NameMatch;
+
+import static net.bytebuddy.matcher.ElementMatchers.takesArguments;
+
+public class DropCollectionOperationInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
+
+ private static final String ENHANCE_CLASS = "com.mongodb.operation.DropCollectionOperation";
+
+ private static final String INTERCEPTOR_CLASS = "org.apache.skywalking.apm.plugin.mongodb.v3.interceptor.operation.OperationNamespaceConstructInterceptor";
+
+ @Override
+ protected ClassMatch enhanceClass() {
+ return NameMatch.byName(ENHANCE_CLASS);
+ }
+
+ @Override
+ public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
+ return new ConstructorInterceptPoint[] {
+ new ConstructorInterceptPoint() {
+ @Override
+ public ElementMatcher getConstructorMatcher() {
+ return takesArguments(2);
+ }
+
+ @Override
+ public String getConstructorInterceptor() {
+ return INTERCEPTOR_CLASS;
+ }
+ }
+ };
+ }
+
+ @Override
+ public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
+ return new InstanceMethodsInterceptPoint[0];
+ }
+
+}
\ No newline at end of file
diff --git a/apm-sniffer/apm-sdk-plugin/mongodb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v3/define/writeOperation/DropDatabaseOperationInstrumentation.java b/apm-sniffer/apm-sdk-plugin/mongodb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v3/define/writeOperation/DropDatabaseOperationInstrumentation.java
new file mode 100644
index 0000000000..88450fec86
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/mongodb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v3/define/writeOperation/DropDatabaseOperationInstrumentation.java
@@ -0,0 +1,64 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.mongodb.v3.define.writeOperation;
+
+import net.bytebuddy.description.method.MethodDescription;
+import net.bytebuddy.matcher.ElementMatcher;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine;
+import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
+import org.apache.skywalking.apm.agent.core.plugin.match.NameMatch;
+
+import static net.bytebuddy.matcher.ElementMatchers.takesArguments;
+
+public class DropDatabaseOperationInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
+
+ private static final String ENHANCE_CLASS = "com.mongodb.operation.DropDatabaseOperation";
+
+ private static final String INTERCEPTOR_CLASS = "org.apache.skywalking.apm.plugin.mongodb.v3.interceptor.operation.OperationDatabaseConstructInterceptor";
+
+ @Override
+ protected ClassMatch enhanceClass() {
+ return NameMatch.byName(ENHANCE_CLASS);
+ }
+
+ @Override
+ public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
+ return new ConstructorInterceptPoint[] {
+ new ConstructorInterceptPoint() {
+ @Override
+ public ElementMatcher getConstructorMatcher() {
+ return takesArguments(2);
+ }
+
+ @Override
+ public String getConstructorInterceptor() {
+ return INTERCEPTOR_CLASS;
+ }
+ }
+ };
+ }
+
+ @Override
+ public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
+ return new InstanceMethodsInterceptPoint[0];
+ }
+
+}
\ No newline at end of file
diff --git a/apm-sniffer/apm-sdk-plugin/mongodb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v3/define/writeOperation/DropIndexOperationInstrumentation.java b/apm-sniffer/apm-sdk-plugin/mongodb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v3/define/writeOperation/DropIndexOperationInstrumentation.java
new file mode 100644
index 0000000000..8be077745b
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/mongodb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v3/define/writeOperation/DropIndexOperationInstrumentation.java
@@ -0,0 +1,64 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.mongodb.v3.define.writeOperation;
+
+import net.bytebuddy.description.method.MethodDescription;
+import net.bytebuddy.matcher.ElementMatcher;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine;
+import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
+import org.apache.skywalking.apm.agent.core.plugin.match.NameMatch;
+
+import static net.bytebuddy.matcher.ElementMatchers.takesArguments;
+
+public class DropIndexOperationInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
+
+ private static final String ENHANCE_CLASS = "com.mongodb.operation.DropIndexOperation";
+
+ private static final String INTERCEPTOR_CLASS = "org.apache.skywalking.apm.plugin.mongodb.v3.interceptor.operation.OperationNamespaceConstructInterceptor";
+
+ @Override
+ protected ClassMatch enhanceClass() {
+ return NameMatch.byName(ENHANCE_CLASS);
+ }
+
+ @Override
+ public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
+ return new ConstructorInterceptPoint[] {
+ new ConstructorInterceptPoint() {
+ @Override
+ public ElementMatcher getConstructorMatcher() {
+ return takesArguments(3);
+ }
+
+ @Override
+ public String getConstructorInterceptor() {
+ return INTERCEPTOR_CLASS;
+ }
+ }
+ };
+ }
+
+ @Override
+ public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
+ return new InstanceMethodsInterceptPoint[0];
+ }
+
+}
diff --git a/apm-sniffer/apm-sdk-plugin/mongodb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v3/define/writeOperation/MapReduceToCollectionOperationInstrumentation.java b/apm-sniffer/apm-sdk-plugin/mongodb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v3/define/writeOperation/MapReduceToCollectionOperationInstrumentation.java
new file mode 100644
index 0000000000..cc72bd315b
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/mongodb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v3/define/writeOperation/MapReduceToCollectionOperationInstrumentation.java
@@ -0,0 +1,64 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.mongodb.v3.define.writeOperation;
+
+import net.bytebuddy.description.method.MethodDescription;
+import net.bytebuddy.matcher.ElementMatcher;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine;
+import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
+import org.apache.skywalking.apm.agent.core.plugin.match.NameMatch;
+
+import static net.bytebuddy.matcher.ElementMatchers.takesArguments;
+
+public class MapReduceToCollectionOperationInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
+
+ private static final String ENHANCE_CLASS = "com.mongodb.operation.MapReduceToCollectionOperation";
+
+ private static final String INTERCEPTOR_CLASS = "org.apache.skywalking.apm.plugin.mongodb.v3.interceptor.operation.OperationNamespaceConstructInterceptor";
+
+ @Override
+ protected ClassMatch enhanceClass() {
+ return NameMatch.byName(ENHANCE_CLASS);
+ }
+
+ @Override
+ public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
+ return new ConstructorInterceptPoint[] {
+ new ConstructorInterceptPoint() {
+ @Override
+ public ElementMatcher getConstructorMatcher() {
+ return takesArguments(5);
+ }
+
+ @Override
+ public String getConstructorInterceptor() {
+ return INTERCEPTOR_CLASS;
+ }
+ }
+ };
+ }
+
+ @Override
+ public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
+ return new InstanceMethodsInterceptPoint[0];
+ }
+
+}
\ No newline at end of file
diff --git a/apm-sniffer/apm-sdk-plugin/mongodb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v3/define/writeOperation/MixedBulkWriteOperationInstrumentation.java b/apm-sniffer/apm-sdk-plugin/mongodb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v3/define/writeOperation/MixedBulkWriteOperationInstrumentation.java
new file mode 100644
index 0000000000..44a90e3001
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/mongodb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v3/define/writeOperation/MixedBulkWriteOperationInstrumentation.java
@@ -0,0 +1,64 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.mongodb.v3.define.writeOperation;
+
+import net.bytebuddy.description.method.MethodDescription;
+import net.bytebuddy.matcher.ElementMatcher;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine;
+import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
+import org.apache.skywalking.apm.agent.core.plugin.match.NameMatch;
+
+import static net.bytebuddy.matcher.ElementMatchers.any;
+
+public class MixedBulkWriteOperationInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
+
+ private static final String ENHANCE_CLASS = "com.mongodb.operation.MixedBulkWriteOperation";
+
+ private static final String INTERCEPTOR_CLASS = "org.apache.skywalking.apm.plugin.mongodb.v3.interceptor.operation.OperationNamespaceConstructInterceptor";
+
+ @Override
+ protected ClassMatch enhanceClass() {
+ return NameMatch.byName(ENHANCE_CLASS);
+ }
+
+ @Override
+ public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
+ return new ConstructorInterceptPoint[] {
+ new ConstructorInterceptPoint() {
+ @Override
+ public ElementMatcher getConstructorMatcher() {
+ return any();
+ }
+
+ @Override
+ public String getConstructorInterceptor() {
+ return INTERCEPTOR_CLASS;
+ }
+ }
+ };
+ }
+
+ @Override
+ public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
+ return new InstanceMethodsInterceptPoint[0];
+ }
+
+}
\ No newline at end of file
diff --git a/apm-sniffer/apm-sdk-plugin/mongodb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v3/define/writeOperation/RenameCollectionOperationInstrumentation.java b/apm-sniffer/apm-sdk-plugin/mongodb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v3/define/writeOperation/RenameCollectionOperationInstrumentation.java
new file mode 100644
index 0000000000..95c9a4fdb9
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/mongodb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v3/define/writeOperation/RenameCollectionOperationInstrumentation.java
@@ -0,0 +1,64 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.mongodb.v3.define.writeOperation;
+
+import net.bytebuddy.description.method.MethodDescription;
+import net.bytebuddy.matcher.ElementMatcher;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine;
+import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
+import org.apache.skywalking.apm.agent.core.plugin.match.NameMatch;
+
+import static net.bytebuddy.matcher.ElementMatchers.takesArguments;
+
+public class RenameCollectionOperationInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
+
+ private static final String ENHANCE_CLASS = "com.mongodb.operation.RenameCollectionOperation";
+
+ private static final String INTERCEPTOR_CLASS = "org.apache.skywalking.apm.plugin.mongodb.v3.interceptor.operation.OperationNamespaceConstructInterceptor";
+
+ @Override
+ protected ClassMatch enhanceClass() {
+ return NameMatch.byName(ENHANCE_CLASS);
+ }
+
+ @Override
+ public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
+ return new ConstructorInterceptPoint[] {
+ new ConstructorInterceptPoint() {
+ @Override
+ public ElementMatcher getConstructorMatcher() {
+ return takesArguments(3);
+ }
+
+ @Override
+ public String getConstructorInterceptor() {
+ return INTERCEPTOR_CLASS;
+ }
+ }
+ };
+ }
+
+ @Override
+ public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
+ return new InstanceMethodsInterceptPoint[0];
+ }
+
+}
\ No newline at end of file
diff --git a/apm-sniffer/apm-sdk-plugin/mongodb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v3/interceptor/operation/OperationDatabaseConstructInterceptor.java b/apm-sniffer/apm-sdk-plugin/mongodb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v3/interceptor/operation/OperationDatabaseConstructInterceptor.java
new file mode 100644
index 0000000000..a948de5128
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/mongodb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v3/interceptor/operation/OperationDatabaseConstructInterceptor.java
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.mongodb.v3.interceptor.operation;
+
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceConstructorInterceptor;
+import org.apache.skywalking.apm.plugin.mongodb.v3.support.MongoNamespaceInfo;
+
+public class OperationDatabaseConstructInterceptor implements InstanceConstructorInterceptor {
+
+ @Override
+ public void onConstruct(EnhancedInstance objInst, Object[] allArguments) {
+ String databaseName = (String) allArguments[0];
+ objInst.setSkyWalkingDynamicField(new MongoNamespaceInfo(databaseName));
+ }
+
+}
\ No newline at end of file
diff --git a/apm-sniffer/apm-sdk-plugin/mongodb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v3/interceptor/operation/OperationNamespaceConstructInterceptor.java b/apm-sniffer/apm-sdk-plugin/mongodb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v3/interceptor/operation/OperationNamespaceConstructInterceptor.java
new file mode 100644
index 0000000000..f6c97a6d37
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/mongodb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v3/interceptor/operation/OperationNamespaceConstructInterceptor.java
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.mongodb.v3.interceptor.operation;
+
+import com.mongodb.MongoNamespace;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceConstructorInterceptor;
+import org.apache.skywalking.apm.plugin.mongodb.v3.support.MongoNamespaceInfo;
+
+public class OperationNamespaceConstructInterceptor implements InstanceConstructorInterceptor {
+
+ @Override
+ public void onConstruct(EnhancedInstance objInst, Object[] allArguments) {
+ MongoNamespace mongoNamespace = (MongoNamespace) allArguments[0];
+ objInst.setSkyWalkingDynamicField(new MongoNamespaceInfo(mongoNamespace));
+ }
+
+}
diff --git a/apm-sniffer/apm-sdk-plugin/mongodb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v3/interceptor/operation/WrappedMapReduceReadOperationInterceptor.java b/apm-sniffer/apm-sdk-plugin/mongodb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v3/interceptor/operation/WrappedMapReduceReadOperationInterceptor.java
new file mode 100644
index 0000000000..3cb37c8cb5
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/mongodb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v3/interceptor/operation/WrappedMapReduceReadOperationInterceptor.java
@@ -0,0 +1,32 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.mongodb.v3.interceptor.operation;
+
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceConstructorInterceptor;
+
+public class WrappedMapReduceReadOperationInterceptor implements InstanceConstructorInterceptor {
+
+ @Override
+ public void onConstruct(EnhancedInstance objInst, Object[] allArguments) {
+ EnhancedInstance enhancedInstance = (EnhancedInstance) allArguments[0];
+ objInst.setSkyWalkingDynamicField(enhancedInstance.getSkyWalkingDynamicField());
+ }
+
+}
diff --git a/apm-sniffer/apm-sdk-plugin/mongodb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v3/support/MongoNamespaceInfo.java b/apm-sniffer/apm-sdk-plugin/mongodb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v3/support/MongoNamespaceInfo.java
new file mode 100644
index 0000000000..16ba7f8aae
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/mongodb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v3/support/MongoNamespaceInfo.java
@@ -0,0 +1,62 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.mongodb.v3.support;
+
+import com.mongodb.MongoNamespace;
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import org.apache.skywalking.apm.util.StringUtil;
+
+@EqualsAndHashCode
+@Getter
+public class MongoNamespaceInfo {
+
+ private final String databaseName;
+ private final String collectionName;
+
+ public MongoNamespaceInfo(String databaseName) {
+ this(databaseName, null);
+ }
+
+ public MongoNamespaceInfo(MongoNamespace mongoNamespace) {
+ this(mongoNamespace.getDatabaseName(), mongoNamespace.getCollectionName());
+ }
+
+ public MongoNamespaceInfo(String databaseName, String collectionName) {
+ this.databaseName = databaseName;
+ this.collectionName = collectionName;
+ }
+
+ public String getDatabaseName() {
+ return databaseName;
+ }
+
+ public String getCollectionName() {
+ return collectionName;
+ }
+
+ public String toString() {
+ if (StringUtil.isNotBlank(collectionName)) {
+ return databaseName + '.' + collectionName;
+ } else {
+ return databaseName;
+ }
+ }
+
+}
diff --git a/apm-sniffer/apm-sdk-plugin/mongodb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v3/support/MongoOperationHelper.java b/apm-sniffer/apm-sdk-plugin/mongodb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v3/support/MongoOperationHelper.java
index 99ab80c051..d68d642ec0 100644
--- a/apm-sniffer/apm-sdk-plugin/mongodb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v3/support/MongoOperationHelper.java
+++ b/apm-sniffer/apm-sdk-plugin/mongodb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v3/support/MongoOperationHelper.java
@@ -22,6 +22,7 @@
import com.mongodb.bulk.InsertRequest;
import com.mongodb.bulk.UpdateRequest;
import com.mongodb.bulk.WriteRequest;
+import com.mongodb.operation.AggregateOperation;
import com.mongodb.operation.CountOperation;
import com.mongodb.operation.CreateCollectionOperation;
import com.mongodb.operation.CreateIndexesOperation;
@@ -104,6 +105,9 @@ public static String getTraceParam(Object obj) {
} else if (obj instanceof FindAndUpdateOperation) {
BsonDocument filter = ((FindAndUpdateOperation) obj).getFilter();
return limitFilter(filter.toString());
+ } else if (obj instanceof AggregateOperation) {
+ List pipelines = ((AggregateOperation) obj).getPipeline();
+ return getPipelines(pipelines);
} else if (obj instanceof MapReduceToCollectionOperation) {
BsonDocument filter = ((MapReduceToCollectionOperation) obj).getFilter();
return limitFilter(filter.toString());
@@ -115,6 +119,18 @@ public static String getTraceParam(Object obj) {
}
}
+ private static String getPipelines(List pipelines) {
+ StringBuilder params = new StringBuilder();
+ for (BsonDocument pipeline : pipelines) {
+ params.append(pipeline.toString()).append(",");
+ final int filterLengthLimit = MongoPluginConfig.Plugin.MongoDB.FILTER_LENGTH_LIMIT;
+ if (filterLengthLimit > 0 && params.length() > filterLengthLimit) {
+ return params.substring(0, filterLengthLimit) + "...";
+ }
+ }
+ return params.toString();
+ }
+
private static String getFilter(List extends WriteRequest> writeRequestList) {
StringBuilder params = new StringBuilder();
for (WriteRequest request : writeRequestList) {
diff --git a/apm-sniffer/apm-sdk-plugin/mongodb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v3/support/MongoSpanHelper.java b/apm-sniffer/apm-sdk-plugin/mongodb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v3/support/MongoSpanHelper.java
index 759abc4cd0..c7a88151a4 100644
--- a/apm-sniffer/apm-sdk-plugin/mongodb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v3/support/MongoSpanHelper.java
+++ b/apm-sniffer/apm-sdk-plugin/mongodb-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v3/support/MongoSpanHelper.java
@@ -18,28 +18,48 @@
package org.apache.skywalking.apm.plugin.mongodb.v3.support;
+import lombok.SneakyThrows;
import org.apache.skywalking.apm.agent.core.context.ContextCarrier;
import org.apache.skywalking.apm.agent.core.context.ContextManager;
+import org.apache.skywalking.apm.agent.core.context.tag.AbstractTag;
import org.apache.skywalking.apm.agent.core.context.tag.Tags;
import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan;
import org.apache.skywalking.apm.agent.core.context.trace.SpanLayer;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
import org.apache.skywalking.apm.network.trace.component.ComponentsDefine;
import org.apache.skywalking.apm.plugin.mongodb.v3.MongoPluginConfig;
+import org.apache.skywalking.apm.util.StringUtil;
public class MongoSpanHelper {
+ private static final AbstractTag DB_COLLECTION_TAG = Tags.ofKey("db.collection");
+
private MongoSpanHelper() {
}
+ @SneakyThrows
public static void createExitSpan(String executeMethod, String remotePeer, Object operation) {
AbstractSpan span = ContextManager.createExitSpan(
- MongoConstants.MONGO_DB_OP_PREFIX + executeMethod, new ContextCarrier(), remotePeer);
+ MongoConstants.MONGO_DB_OP_PREFIX + executeMethod, new ContextCarrier(), remotePeer);
span.setComponent(ComponentsDefine.MONGO_DRIVER);
Tags.DB_TYPE.set(span, MongoConstants.DB_TYPE);
SpanLayer.asDB(span);
+ if (operation instanceof EnhancedInstance) {
+ MongoNamespaceInfo mongoNamespaceInfo = (MongoNamespaceInfo) ((EnhancedInstance) operation).getSkyWalkingDynamicField();
+ if (mongoNamespaceInfo != null) {
+ if (StringUtil.isNotEmpty(mongoNamespaceInfo.getDatabaseName())) {
+ Tags.DB_INSTANCE.set(span, mongoNamespaceInfo.getDatabaseName());
+ }
+ if (StringUtil.isNotEmpty(mongoNamespaceInfo.getCollectionName())) {
+ span.tag(DB_COLLECTION_TAG, mongoNamespaceInfo.getCollectionName());
+ }
+ }
+ }
+
if (MongoPluginConfig.Plugin.MongoDB.TRACE_PARAM) {
Tags.DB_BIND_VARIABLES.set(span, MongoOperationHelper.getTraceParam(operation));
}
}
+
}
diff --git a/apm-sniffer/apm-sdk-plugin/mongodb-3.x-plugin/src/main/resources/skywalking-plugin.def b/apm-sniffer/apm-sdk-plugin/mongodb-3.x-plugin/src/main/resources/skywalking-plugin.def
index 8416fd8e52..8e6b05fdf1 100644
--- a/apm-sniffer/apm-sdk-plugin/mongodb-3.x-plugin/src/main/resources/skywalking-plugin.def
+++ b/apm-sniffer/apm-sdk-plugin/mongodb-3.x-plugin/src/main/resources/skywalking-plugin.def
@@ -19,8 +19,40 @@ mongodb-3.x=org.apache.skywalking.apm.plugin.mongodb.v3.define.v30.MongoDBInstru
# v3.7.x~
mongodb-3.x=org.apache.skywalking.apm.plugin.mongodb.v3.define.v37.MongoDBClientDelegateInstrumentation
mongodb-3.x=org.apache.skywalking.apm.plugin.mongodb.v3.define.v37.MongoDBOperationExecutorInstrumentation
+mongodb-3.x=org.apache.skywalking.apm.plugin.mongodb.v3.define.v36.readOperation.WrappedMapReduceReadOperationInstrumentation
# v3.8.x~
mongodb-3.x=org.apache.skywalking.apm.plugin.mongodb.v3.define.v38.MongoDBOperationExecutorInstrumentation
# v3.6.x
mongodb-3.x=org.apache.skywalking.apm.plugin.mongodb.v3.define.v36.MongoDBInstrumentation
-mongodb-3.x=org.apache.skywalking.apm.plugin.mongodb.v3.define.v36.MongoDBOperationExecutorInstrumentation
\ No newline at end of file
+mongodb-3.x=org.apache.skywalking.apm.plugin.mongodb.v3.define.v36.MongoDBOperationExecutorInstrumentation
+
+# readOperation
+mongodb-3.x=org.apache.skywalking.apm.plugin.mongodb.v3.define.readOperation.AggregateExplainOperationInstrumentation
+mongodb-3.x=org.apache.skywalking.apm.plugin.mongodb.v3.define.readOperation.AggregateOperationImplInstrumentation
+mongodb-3.x=org.apache.skywalking.apm.plugin.mongodb.v3.define.readOperation.AggregateOperationInstrumentation
+mongodb-3.x=org.apache.skywalking.apm.plugin.mongodb.v3.define.readOperation.ChangeStreamOperationInstrumentation
+mongodb-3.x=org.apache.skywalking.apm.plugin.mongodb.v3.define.readOperation.CommandReadOperationInstrumentation
+mongodb-3.x=org.apache.skywalking.apm.plugin.mongodb.v3.define.readOperation.CountOperationInstrumentation
+mongodb-3.x=org.apache.skywalking.apm.plugin.mongodb.v3.define.readOperation.DistinctOperationInstrumentation
+mongodb-3.x=org.apache.skywalking.apm.plugin.mongodb.v3.define.readOperation.FindOperationInstrumentation
+mongodb-3.x=org.apache.skywalking.apm.plugin.mongodb.v3.define.readOperation.ListCollectionsOperationInstrumentation
+mongodb-3.x=org.apache.skywalking.apm.plugin.mongodb.v3.define.readOperation.ListIndexesOperationInstrumentation
+mongodb-3.x=org.apache.skywalking.apm.plugin.mongodb.v3.define.readOperation.MapReduceWithInlineResultsOperationInstrumentation
+mongodb-3.x=org.apache.skywalking.apm.plugin.mongodb.v3.define.readOperation.WrappedMapReduceReadOperationInstrumentation
+mongodb-3.x=org.apache.skywalking.apm.plugin.mongodb.v3.define.readOperation.GroupOperationInstrumentation
+mongodb-3.x=org.apache.skywalking.apm.plugin.mongodb.v3.define.readOperation.ParallelCollectionScanOperationInstrumentation
+mongodb-3.x=org.apache.skywalking.apm.plugin.mongodb.v3.define.readOperation.UserExistsOperationInstrumentation
+# writeOperation
+mongodb-3.x=org.apache.skywalking.apm.plugin.mongodb.v3.define.writeOperation.AggregateToCollectionOperationInstrumentation
+mongodb-3.x=org.apache.skywalking.apm.plugin.mongodb.v3.define.writeOperation.BaseFindAndModifyOperationInstrumentation
+mongodb-3.x=org.apache.skywalking.apm.plugin.mongodb.v3.define.writeOperation.BaseWriteOperationInstrumentation
+mongodb-3.x=org.apache.skywalking.apm.plugin.mongodb.v3.define.writeOperation.CommandWriteOperationInstrumentation
+mongodb-3.x=org.apache.skywalking.apm.plugin.mongodb.v3.define.writeOperation.CreateCollectionOperationInstrumentation
+mongodb-3.x=org.apache.skywalking.apm.plugin.mongodb.v3.define.writeOperation.CreateIndexesOperationInstrumentation
+mongodb-3.x=org.apache.skywalking.apm.plugin.mongodb.v3.define.writeOperation.CreateViewOperationInstrumentation
+mongodb-3.x=org.apache.skywalking.apm.plugin.mongodb.v3.define.writeOperation.DropCollectionOperationInstrumentation
+mongodb-3.x=org.apache.skywalking.apm.plugin.mongodb.v3.define.writeOperation.DropDatabaseOperationInstrumentation
+mongodb-3.x=org.apache.skywalking.apm.plugin.mongodb.v3.define.writeOperation.DropIndexOperationInstrumentation
+mongodb-3.x=org.apache.skywalking.apm.plugin.mongodb.v3.define.writeOperation.MapReduceToCollectionOperationInstrumentation
+mongodb-3.x=org.apache.skywalking.apm.plugin.mongodb.v3.define.writeOperation.MixedBulkWriteOperationInstrumentation
+mongodb-3.x=org.apache.skywalking.apm.plugin.mongodb.v3.define.writeOperation.RenameCollectionOperationInstrumentation
diff --git a/apm-sniffer/apm-sdk-plugin/mongodb-3.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/mongodb/v3/interceptor/v30/MongoDBInterceptorTest.java b/apm-sniffer/apm-sdk-plugin/mongodb-3.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/mongodb/v3/interceptor/v30/MongoDBInterceptorTest.java
index 62d28a6c14..2319ad54e3 100644
--- a/apm-sniffer/apm-sdk-plugin/mongodb-3.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/mongodb/v3/interceptor/v30/MongoDBInterceptorTest.java
+++ b/apm-sniffer/apm-sdk-plugin/mongodb-3.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/mongodb/v3/interceptor/v30/MongoDBInterceptorTest.java
@@ -18,12 +18,10 @@
package org.apache.skywalking.apm.plugin.mongodb.v3.interceptor.v30;
-import static org.hamcrest.CoreMatchers.is;
-import static org.junit.Assert.assertThat;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-import java.lang.reflect.Method;
-import java.util.List;
+import com.mongodb.Mongo;
+import com.mongodb.MongoNamespace;
+import com.mongodb.operation.AggregateOperation;
+import com.mongodb.operation.FindOperation;
import org.apache.skywalking.apm.agent.core.context.trace.AbstractTracingSpan;
import org.apache.skywalking.apm.agent.core.context.trace.LogDataEntity;
import org.apache.skywalking.apm.agent.core.context.trace.SpanLayer;
@@ -38,6 +36,7 @@
import org.apache.skywalking.apm.agent.test.tools.SpanAssert;
import org.apache.skywalking.apm.agent.test.tools.TracingSegmentRunner;
import org.apache.skywalking.apm.plugin.mongodb.v3.MongoPluginConfig;
+import org.apache.skywalking.apm.plugin.mongodb.v3.support.MongoNamespaceInfo;
import org.bson.BsonDocument;
import org.bson.BsonString;
import org.bson.codecs.Decoder;
@@ -48,11 +47,19 @@
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
+import org.mockito.Mockito;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
-import com.mongodb.Mongo;
-import com.mongodb.MongoNamespace;
-import com.mongodb.operation.FindOperation;
+
+import java.lang.reflect.Method;
+import java.util.Collections;
+import java.util.List;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.startsWith;
+import static org.junit.Assert.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
@RunWith(TracingSegmentRunner.class)
public class MongoDBInterceptorTest {
@@ -67,11 +74,16 @@ public class MongoDBInterceptorTest {
private MongoDBInterceptor interceptor;
+ private FindOperation enhancedInstanceForFindOperation;
+
@Mock
private EnhancedInstance enhancedInstance;
private Object[] arguments;
+
private Class[] argumentTypes;
+ private Decoder decoder;
+ private MongoNamespace mongoNamespace;
@SuppressWarnings({
"rawtypes",
@@ -88,12 +100,14 @@ public void setUp() throws Exception {
BsonDocument document = new BsonDocument();
document.append("name", new BsonString("by"));
- MongoNamespace mongoNamespace = new MongoNamespace("test.user");
- Decoder decoder = mock(Decoder.class);
+ mongoNamespace = new MongoNamespace("test.user");
+ decoder = mock(Decoder.class);
FindOperation findOperation = new FindOperation(mongoNamespace, decoder);
findOperation.filter(document);
-
- arguments = new Object[] {findOperation};
+ enhancedInstanceForFindOperation = mock(FindOperation.class, Mockito.withSettings().extraInterfaces(EnhancedInstance.class));
+ when(((EnhancedInstance) enhancedInstanceForFindOperation).getSkyWalkingDynamicField()).thenReturn(new MongoNamespaceInfo(mongoNamespace));
+ when(enhancedInstanceForFindOperation.getFilter()).thenReturn(findOperation.getFilter());
+ arguments = new Object[] {enhancedInstanceForFindOperation};
argumentTypes = new Class[] {findOperation.getClass()};
}
@@ -105,7 +119,29 @@ public void testIntercept() throws Throwable {
MatcherAssert.assertThat(segmentStorage.getTraceSegments().size(), is(1));
TraceSegment traceSegment = segmentStorage.getTraceSegments().get(0);
List spans = SegmentHelper.getSpans(traceSegment);
- assertRedisSpan(spans.get(0));
+ assertFindOperationSpan(spans.get(0));
+ }
+
+ @Test
+ public void testAggregateOperationIntercept() throws Throwable {
+ MongoNamespace mongoNamespace = new MongoNamespace("test.user");
+ BsonDocument matchStage = new BsonDocument("$match", new BsonDocument("name", new BsonString("by")));
+ List pipeline = Collections.singletonList(matchStage);
+ AggregateOperation aggregateOperation = new AggregateOperation(mongoNamespace, pipeline, decoder);
+
+ AggregateOperation enhancedInstanceForAggregateOperation = mock(AggregateOperation.class, Mockito.withSettings().extraInterfaces(EnhancedInstance.class));
+ when(((EnhancedInstance) enhancedInstanceForAggregateOperation).getSkyWalkingDynamicField()).thenReturn(new MongoNamespaceInfo(mongoNamespace));
+ when(enhancedInstanceForAggregateOperation.getPipeline()).thenReturn(aggregateOperation.getPipeline());
+ Object[] arguments = {enhancedInstanceForAggregateOperation};
+ Class[] argumentTypes = {aggregateOperation.getClass()};
+
+ interceptor.beforeMethod(enhancedInstance, getExecuteMethod(), arguments, argumentTypes, null);
+ interceptor.afterMethod(enhancedInstance, getExecuteMethod(), arguments, argumentTypes, null);
+
+ MatcherAssert.assertThat(segmentStorage.getTraceSegments().size(), is(1));
+ TraceSegment traceSegment = segmentStorage.getTraceSegments().get(0);
+ List spans = SegmentHelper.getSpans(traceSegment);
+ assertMongoAggregateOperationSpan(spans.get(0));
}
@Test
@@ -118,18 +154,32 @@ public void testInterceptWithException() throws Throwable {
MatcherAssert.assertThat(segmentStorage.getTraceSegments().size(), is(1));
TraceSegment traceSegment = segmentStorage.getTraceSegments().get(0);
List spans = SegmentHelper.getSpans(traceSegment);
- assertRedisSpan(spans.get(0));
+ assertFindOperationSpan(spans.get(0));
List logDataEntities = SpanHelper.getLogs(spans.get(0));
assertThat(logDataEntities.size(), is(1));
SpanAssert.assertException(logDataEntities.get(0), RuntimeException.class);
}
- private void assertRedisSpan(AbstractTracingSpan span) {
- assertThat(span.getOperationName(), is("MongoDB/FindOperation"));
+ private void assertFindOperationSpan(AbstractTracingSpan span) {
+ assertThat(span.getOperationName(), startsWith("MongoDB/FindOperation"));
+ assertThat(SpanHelper.getComponentId(span), is(42));
+ List tags = SpanHelper.getTags(span);
+ assertThat(tags.get(0).getValue(), is("MongoDB"));
+ assertThat(tags.get(1).getValue(), is("test"));
+ assertThat(tags.get(2).getValue(), is("user"));
+ assertThat(tags.get(3).getValue(), is("{\"name\": \"by\"}"));
+ assertThat(span.isExit(), is(true));
+ assertThat(SpanHelper.getLayer(span), CoreMatchers.is(SpanLayer.DB));
+ }
+
+ private void assertMongoAggregateOperationSpan(AbstractTracingSpan span) {
+ assertThat(span.getOperationName(), startsWith("MongoDB/AggregateOperation"));
assertThat(SpanHelper.getComponentId(span), is(42));
List tags = SpanHelper.getTags(span);
- assertThat(tags.get(1).getValue(), is("{\"name\": \"by\"}"));
assertThat(tags.get(0).getValue(), is("MongoDB"));
+ assertThat(tags.get(1).getValue(), is("test"));
+ assertThat(tags.get(2).getValue(), is("user"));
+ assertThat(tags.get(3).getValue(), is("{\"$match\": {\"name\": \"by\"}},"));
assertThat(span.isExit(), is(true));
assertThat(SpanHelper.getLayer(span), CoreMatchers.is(SpanLayer.DB));
}
diff --git a/apm-sniffer/apm-sdk-plugin/mongodb-3.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/mongodb/v3/interceptor/v37/MongoDBOperationExecutorInterceptorTest.java b/apm-sniffer/apm-sdk-plugin/mongodb-3.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/mongodb/v3/interceptor/v37/MongoDBOperationExecutorInterceptorTest.java
index 60de9f5c21..8c6112e7fc 100644
--- a/apm-sniffer/apm-sdk-plugin/mongodb-3.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/mongodb/v3/interceptor/v37/MongoDBOperationExecutorInterceptorTest.java
+++ b/apm-sniffer/apm-sdk-plugin/mongodb-3.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/mongodb/v3/interceptor/v37/MongoDBOperationExecutorInterceptorTest.java
@@ -18,12 +18,13 @@
package org.apache.skywalking.apm.plugin.mongodb.v3.interceptor.v37;
-import static org.hamcrest.CoreMatchers.is;
-import static org.junit.Assert.assertThat;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-import java.lang.reflect.Method;
-import java.util.List;
+import com.mongodb.MongoNamespace;
+import com.mongodb.ReadConcern;
+import com.mongodb.client.internal.OperationExecutor;
+import com.mongodb.operation.AggregateOperation;
+import com.mongodb.operation.CreateCollectionOperation;
+import com.mongodb.operation.FindOperation;
+import com.mongodb.operation.WriteOperation;
import org.apache.skywalking.apm.agent.core.context.trace.AbstractTracingSpan;
import org.apache.skywalking.apm.agent.core.context.trace.LogDataEntity;
import org.apache.skywalking.apm.agent.core.context.trace.SpanLayer;
@@ -38,6 +39,7 @@
import org.apache.skywalking.apm.agent.test.tools.SpanAssert;
import org.apache.skywalking.apm.agent.test.tools.TracingSegmentRunner;
import org.apache.skywalking.apm.plugin.mongodb.v3.MongoPluginConfig;
+import org.apache.skywalking.apm.plugin.mongodb.v3.support.MongoNamespaceInfo;
import org.bson.BsonDocument;
import org.bson.BsonString;
import org.bson.codecs.Decoder;
@@ -48,13 +50,19 @@
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
+import org.mockito.Mockito;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
-import com.mongodb.MongoNamespace;
-import com.mongodb.ReadConcern;
-import com.mongodb.client.internal.OperationExecutor;
-import com.mongodb.operation.FindOperation;
-import com.mongodb.operation.WriteOperation;
+
+import java.lang.reflect.Method;
+import java.util.Collections;
+import java.util.List;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.startsWith;
+import static org.junit.Assert.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
@RunWith(TracingSegmentRunner.class)
public class MongoDBOperationExecutorInterceptorTest {
@@ -70,11 +78,15 @@ public class MongoDBOperationExecutorInterceptorTest {
@Mock
private EnhancedInstance enhancedInstance;
+ private FindOperation enhancedInstanceForFindOperation;
+
private MongoDBOperationExecutorInterceptor interceptor;
private Object[] arguments;
private Class[] argumentTypes;
+ private Decoder decoder;
+ private MongoNamespace mongoNamespace;
@Before
public void setUp() {
@@ -87,12 +99,14 @@ public void setUp() {
BsonDocument document = new BsonDocument();
document.append("name", new BsonString("by"));
- MongoNamespace mongoNamespace = new MongoNamespace("test.user");
- Decoder decoder = mock(Decoder.class);
+ mongoNamespace = new MongoNamespace("test.user");
+ decoder = mock(Decoder.class);
FindOperation findOperation = new FindOperation(mongoNamespace, decoder);
findOperation.filter(document);
-
- arguments = new Object[] {findOperation};
+ enhancedInstanceForFindOperation = mock(FindOperation.class, Mockito.withSettings().extraInterfaces(EnhancedInstance.class));
+ when(((EnhancedInstance) enhancedInstanceForFindOperation).getSkyWalkingDynamicField()).thenReturn(new MongoNamespaceInfo(mongoNamespace));
+ when(enhancedInstanceForFindOperation.getFilter()).thenReturn(findOperation.getFilter());
+ arguments = new Object[] {enhancedInstanceForFindOperation};
argumentTypes = new Class[] {findOperation.getClass()};
}
@@ -104,11 +118,51 @@ public void testIntercept() throws Throwable {
MatcherAssert.assertThat(segmentStorage.getTraceSegments().size(), is(1));
TraceSegment traceSegment = segmentStorage.getTraceSegments().get(0);
List spans = SegmentHelper.getSpans(traceSegment);
- assertRedisSpan(spans.get(0));
+ assertMongoFindOperationSpan(spans.get(0));
}
@Test
- public void testInterceptWithException() throws Throwable {
+ public void testCreateCollectionOperationIntercept() throws Throwable {
+ CreateCollectionOperation createCollectionOperation = new CreateCollectionOperation("test", "user");
+ CreateCollectionOperation enhancedInstanceForCreateCollectionOperation = mock(CreateCollectionOperation.class, Mockito.withSettings().extraInterfaces(EnhancedInstance.class));
+ when(((EnhancedInstance) enhancedInstanceForCreateCollectionOperation).getSkyWalkingDynamicField()).thenReturn(new MongoNamespaceInfo(mongoNamespace));
+ when(enhancedInstanceForCreateCollectionOperation.getCollectionName()).thenReturn("user");
+ Object[] arguments = {enhancedInstanceForCreateCollectionOperation};
+ Class[] argumentTypes = {createCollectionOperation.getClass()};
+
+ interceptor.beforeMethod(enhancedInstance, getMethod(), arguments, argumentTypes, null);
+ interceptor.afterMethod(enhancedInstance, getMethod(), arguments, argumentTypes, null);
+
+ MatcherAssert.assertThat(segmentStorage.getTraceSegments().size(), is(1));
+ TraceSegment traceSegment = segmentStorage.getTraceSegments().get(0);
+ List spans = SegmentHelper.getSpans(traceSegment);
+ assertMongoCreateCollectionOperationSpan(spans.get(0));
+ }
+
+ @Test
+ public void testAggregateOperationIntercept() throws Throwable {
+ MongoNamespace mongoNamespace = new MongoNamespace("test.user");
+ BsonDocument matchStage = new BsonDocument("$match", new BsonDocument("name", new BsonString("by")));
+ List pipeline = Collections.singletonList(matchStage);
+ AggregateOperation aggregateOperation = new AggregateOperation(mongoNamespace, pipeline, decoder);
+
+ AggregateOperation enhancedInstanceForAggregateOperation = mock(AggregateOperation.class, Mockito.withSettings().extraInterfaces(EnhancedInstance.class));
+ when(((EnhancedInstance) enhancedInstanceForAggregateOperation).getSkyWalkingDynamicField()).thenReturn(new MongoNamespaceInfo(mongoNamespace));
+ when(enhancedInstanceForAggregateOperation.getPipeline()).thenReturn(aggregateOperation.getPipeline());
+ Object[] arguments = {enhancedInstanceForAggregateOperation};
+ Class[] argumentTypes = {aggregateOperation.getClass()};
+
+ interceptor.beforeMethod(enhancedInstance, getMethod(), arguments, argumentTypes, null);
+ interceptor.afterMethod(enhancedInstance, getMethod(), arguments, argumentTypes, null);
+
+ MatcherAssert.assertThat(segmentStorage.getTraceSegments().size(), is(1));
+ TraceSegment traceSegment = segmentStorage.getTraceSegments().get(0);
+ List spans = SegmentHelper.getSpans(traceSegment);
+ assertMongoAggregateOperationSpan(spans.get(0));
+ }
+
+ @Test
+ public void testInterceptFindOperationWithException() throws Throwable {
interceptor.beforeMethod(enhancedInstance, getMethod(), arguments, argumentTypes, null);
interceptor.handleMethodException(
enhancedInstance, getMethod(), arguments, argumentTypes, new RuntimeException());
@@ -117,18 +171,44 @@ public void testInterceptWithException() throws Throwable {
MatcherAssert.assertThat(segmentStorage.getTraceSegments().size(), is(1));
TraceSegment traceSegment = segmentStorage.getTraceSegments().get(0);
List spans = SegmentHelper.getSpans(traceSegment);
- assertRedisSpan(spans.get(0));
+ assertMongoFindOperationSpan(spans.get(0));
List logDataEntities = SpanHelper.getLogs(spans.get(0));
assertThat(logDataEntities.size(), is(1));
SpanAssert.assertException(logDataEntities.get(0), RuntimeException.class);
}
- private void assertRedisSpan(AbstractTracingSpan span) {
- assertThat(span.getOperationName(), is("MongoDB/FindOperation"));
+ private void assertMongoCreateCollectionOperationSpan(AbstractTracingSpan span) {
+ assertThat(span.getOperationName(), startsWith("MongoDB/CreateCollectionOperation"));
+ assertThat(SpanHelper.getComponentId(span), is(42));
+ List tags = SpanHelper.getTags(span);
+ assertThat(tags.get(0).getValue(), is("MongoDB"));
+ assertThat(tags.get(1).getValue(), is("test"));
+ assertThat(tags.get(2).getValue(), is("user"));
+ assertThat(tags.get(3).getValue(), is("user"));
+ assertThat(span.isExit(), is(true));
+ assertThat(SpanHelper.getLayer(span), CoreMatchers.is(SpanLayer.DB));
+ }
+
+ private void assertMongoAggregateOperationSpan(AbstractTracingSpan span) {
+ assertThat(span.getOperationName(), startsWith("MongoDB/AggregateOperation"));
+ assertThat(SpanHelper.getComponentId(span), is(42));
+ List tags = SpanHelper.getTags(span);
+ assertThat(tags.get(0).getValue(), is("MongoDB"));
+ assertThat(tags.get(1).getValue(), is("test"));
+ assertThat(tags.get(2).getValue(), is("user"));
+ assertThat(tags.get(3).getValue(), is("{\"$match\": {\"name\": \"by\"}},"));
+ assertThat(span.isExit(), is(true));
+ assertThat(SpanHelper.getLayer(span), CoreMatchers.is(SpanLayer.DB));
+ }
+
+ private void assertMongoFindOperationSpan(AbstractTracingSpan span) {
+ assertThat(span.getOperationName(), startsWith("MongoDB/FindOperation"));
assertThat(SpanHelper.getComponentId(span), is(42));
List tags = SpanHelper.getTags(span);
- assertThat(tags.get(1).getValue(), is("{\"name\": \"by\"}"));
assertThat(tags.get(0).getValue(), is("MongoDB"));
+ assertThat(tags.get(1).getValue(), is("test"));
+ assertThat(tags.get(2).getValue(), is("user"));
+ assertThat(tags.get(3).getValue(), is("{\"name\": \"by\"}"));
assertThat(span.isExit(), is(true));
assertThat(SpanHelper.getLayer(span), CoreMatchers.is(SpanLayer.DB));
}
diff --git a/apm-sniffer/apm-sdk-plugin/mongodb-4.x-plugin/pom.xml b/apm-sniffer/apm-sdk-plugin/mongodb-4.x-plugin/pom.xml
index 868f1d9ab7..cb0363cb8e 100644
--- a/apm-sniffer/apm-sdk-plugin/mongodb-4.x-plugin/pom.xml
+++ b/apm-sniffer/apm-sdk-plugin/mongodb-4.x-plugin/pom.xml
@@ -21,7 +21,7 @@
apm-sdk-plugin
org.apache.skywalking
- 9.3.0-SNAPSHOT
+ 9.7.0-SNAPSHOT
apm-mongodb-4.x-plugin
diff --git a/apm-sniffer/apm-sdk-plugin/mongodb-4.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v4/define/readOperation/AggregateOperationImplInstrumentation.java b/apm-sniffer/apm-sdk-plugin/mongodb-4.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v4/define/readOperation/AggregateOperationImplInstrumentation.java
index 49cb53e085..1e50102399 100644
--- a/apm-sniffer/apm-sdk-plugin/mongodb-4.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v4/define/readOperation/AggregateOperationImplInstrumentation.java
+++ b/apm-sniffer/apm-sdk-plugin/mongodb-4.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v4/define/readOperation/AggregateOperationImplInstrumentation.java
@@ -26,7 +26,7 @@
import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
import org.apache.skywalking.apm.agent.core.plugin.match.NameMatch;
-import static net.bytebuddy.matcher.ElementMatchers.takesArguments;
+import static net.bytebuddy.matcher.ElementMatchers.any;
public class AggregateOperationImplInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
@@ -53,7 +53,7 @@ public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
@Override
public ElementMatcher getConstructorMatcher() {
- return takesArguments(4);
+ return any();
}
@Override
diff --git a/apm-sniffer/apm-sdk-plugin/mongodb-4.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v4/define/readOperation/AggregateOperationInstrumentation.java b/apm-sniffer/apm-sdk-plugin/mongodb-4.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v4/define/readOperation/AggregateOperationInstrumentation.java
index b95124195b..6e56abd504 100644
--- a/apm-sniffer/apm-sdk-plugin/mongodb-4.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v4/define/readOperation/AggregateOperationInstrumentation.java
+++ b/apm-sniffer/apm-sdk-plugin/mongodb-4.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v4/define/readOperation/AggregateOperationInstrumentation.java
@@ -26,7 +26,7 @@
import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
import org.apache.skywalking.apm.agent.core.plugin.match.NameMatch;
-import static net.bytebuddy.matcher.ElementMatchers.takesArguments;
+import static net.bytebuddy.matcher.ElementMatchers.any;
public class AggregateOperationInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
@@ -53,7 +53,7 @@ public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
@Override
public ElementMatcher getConstructorMatcher() {
- return takesArguments(5);
+ return any();
}
@Override
diff --git a/apm-sniffer/apm-sdk-plugin/mongodb-4.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v4/interceptor/operation/OperationDatabaseConstructInterceptor.java b/apm-sniffer/apm-sdk-plugin/mongodb-4.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v4/interceptor/operation/OperationDatabaseConstructInterceptor.java
index a643e3f201..850b625153 100644
--- a/apm-sniffer/apm-sdk-plugin/mongodb-4.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v4/interceptor/operation/OperationDatabaseConstructInterceptor.java
+++ b/apm-sniffer/apm-sdk-plugin/mongodb-4.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v4/interceptor/operation/OperationDatabaseConstructInterceptor.java
@@ -20,13 +20,14 @@
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceConstructorInterceptor;
+import org.apache.skywalking.apm.plugin.mongodb.v4.support.MongoNamespaceInfo;
public class OperationDatabaseConstructInterceptor implements InstanceConstructorInterceptor {
@Override
public void onConstruct(EnhancedInstance objInst, Object[] allArguments) {
String databaseName = (String) allArguments[0];
- objInst.setSkyWalkingDynamicField(databaseName);
+ objInst.setSkyWalkingDynamicField(new MongoNamespaceInfo(databaseName));
}
}
\ No newline at end of file
diff --git a/apm-sniffer/apm-sdk-plugin/mongodb-4.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v4/interceptor/operation/OperationNamespaceConstructInterceptor.java b/apm-sniffer/apm-sdk-plugin/mongodb-4.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v4/interceptor/operation/OperationNamespaceConstructInterceptor.java
index 6641012fbf..9a9fec49f0 100644
--- a/apm-sniffer/apm-sdk-plugin/mongodb-4.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v4/interceptor/operation/OperationNamespaceConstructInterceptor.java
+++ b/apm-sniffer/apm-sdk-plugin/mongodb-4.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v4/interceptor/operation/OperationNamespaceConstructInterceptor.java
@@ -21,14 +21,14 @@
import com.mongodb.MongoNamespace;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceConstructorInterceptor;
+import org.apache.skywalking.apm.plugin.mongodb.v4.support.MongoNamespaceInfo;
public class OperationNamespaceConstructInterceptor implements InstanceConstructorInterceptor {
@Override
public void onConstruct(EnhancedInstance objInst, Object[] allArguments) {
MongoNamespace mongoNamespace = (MongoNamespace) allArguments[0];
- String databaseName = mongoNamespace.getDatabaseName();
- objInst.setSkyWalkingDynamicField(databaseName);
+ objInst.setSkyWalkingDynamicField(new MongoNamespaceInfo(mongoNamespace));
}
}
diff --git a/apm-sniffer/apm-sdk-plugin/mongodb-4.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v4/interceptor/operation/WrappedMapReduceReadOperationInterceptor.java b/apm-sniffer/apm-sdk-plugin/mongodb-4.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v4/interceptor/operation/WrappedMapReduceReadOperationInterceptor.java
index 39c4699ffb..90614d3fc7 100644
--- a/apm-sniffer/apm-sdk-plugin/mongodb-4.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v4/interceptor/operation/WrappedMapReduceReadOperationInterceptor.java
+++ b/apm-sniffer/apm-sdk-plugin/mongodb-4.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v4/interceptor/operation/WrappedMapReduceReadOperationInterceptor.java
@@ -25,11 +25,8 @@ public class WrappedMapReduceReadOperationInterceptor implements InstanceConstru
@Override
public void onConstruct(EnhancedInstance objInst, Object[] allArguments) {
- if (allArguments[0] instanceof EnhancedInstance) {
EnhancedInstance enhancedInstance = (EnhancedInstance) allArguments[0];
- String databaseName = (String) enhancedInstance.getSkyWalkingDynamicField();
- objInst.setSkyWalkingDynamicField(databaseName);
- }
+ objInst.setSkyWalkingDynamicField(enhancedInstance.getSkyWalkingDynamicField());
}
}
diff --git a/apm-sniffer/apm-sdk-plugin/mongodb-4.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v4/support/LegacyOperationHelper.java b/apm-sniffer/apm-sdk-plugin/mongodb-4.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v4/support/LegacyOperationHelper.java
new file mode 100644
index 0000000000..3c3a19a7b7
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/mongodb-4.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v4/support/LegacyOperationHelper.java
@@ -0,0 +1,59 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.mongodb.v4.support;
+
+import com.mongodb.internal.bulk.DeleteRequest;
+import com.mongodb.internal.bulk.InsertRequest;
+import com.mongodb.internal.bulk.UpdateRequest;
+import com.mongodb.internal.operation.DeleteOperation;
+import com.mongodb.internal.operation.InsertOperation;
+import com.mongodb.internal.operation.UpdateOperation;
+
+import java.util.List;
+
+/**
+ * Handles trace parameter extraction for legacy MongoDB driver versions (4.0 - 4.8).
+ * InsertOperation, DeleteOperation, and UpdateOperation were removed in driver 4.9.
+ * This class is only loaded when those classes exist (guarded by
+ * {@link MongoOperationHelper#HAS_LEGACY_WRITE_OPERATIONS}).
+ */
+@SuppressWarnings("deprecation")
+class LegacyOperationHelper {
+
+ private LegacyOperationHelper() {
+ }
+
+ /**
+ * Extract trace parameters from legacy write operation types.
+ * @return the trace parameter string, or null if obj is not a legacy write operation
+ */
+ static String getTraceParam(Object obj) {
+ if (obj instanceof DeleteOperation) {
+ List writeRequestList = ((DeleteOperation) obj).getDeleteRequests();
+ return MongoOperationHelper.getFilter(writeRequestList);
+ } else if (obj instanceof InsertOperation) {
+ List writeRequestList = ((InsertOperation) obj).getInsertRequests();
+ return MongoOperationHelper.getFilter(writeRequestList);
+ } else if (obj instanceof UpdateOperation) {
+ List writeRequestList = ((UpdateOperation) obj).getUpdateRequests();
+ return MongoOperationHelper.getFilter(writeRequestList);
+ }
+ return null;
+ }
+}
diff --git a/apm-sniffer/apm-sdk-plugin/mongodb-4.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v4/support/MongoNamespaceInfo.java b/apm-sniffer/apm-sdk-plugin/mongodb-4.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v4/support/MongoNamespaceInfo.java
new file mode 100644
index 0000000000..54d54b4d8a
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/mongodb-4.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v4/support/MongoNamespaceInfo.java
@@ -0,0 +1,62 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.mongodb.v4.support;
+
+import com.mongodb.MongoNamespace;
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import org.apache.skywalking.apm.util.StringUtil;
+
+@EqualsAndHashCode
+@Getter
+public class MongoNamespaceInfo {
+
+ private final String databaseName;
+ private final String collectionName;
+
+ public MongoNamespaceInfo(String databaseName) {
+ this(databaseName, null);
+ }
+
+ public MongoNamespaceInfo(MongoNamespace mongoNamespace) {
+ this(mongoNamespace.getDatabaseName(), mongoNamespace.getCollectionName());
+ }
+
+ public MongoNamespaceInfo(String databaseName, String collectionName) {
+ this.databaseName = databaseName;
+ this.collectionName = collectionName;
+ }
+
+ public String getDatabaseName() {
+ return databaseName;
+ }
+
+ public String getCollectionName() {
+ return collectionName;
+ }
+
+ public String toString() {
+ if (StringUtil.isNotBlank(collectionName)) {
+ return databaseName + '.' + collectionName;
+ } else {
+ return databaseName;
+ }
+ }
+
+}
diff --git a/apm-sniffer/apm-sdk-plugin/mongodb-4.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v4/support/MongoOperationHelper.java b/apm-sniffer/apm-sdk-plugin/mongodb-4.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v4/support/MongoOperationHelper.java
index 45d0481fbc..96cf84c985 100644
--- a/apm-sniffer/apm-sdk-plugin/mongodb-4.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v4/support/MongoOperationHelper.java
+++ b/apm-sniffer/apm-sdk-plugin/mongodb-4.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v4/support/MongoOperationHelper.java
@@ -22,22 +22,20 @@
import com.mongodb.internal.bulk.InsertRequest;
import com.mongodb.internal.bulk.UpdateRequest;
import com.mongodb.internal.bulk.WriteRequest;
+import com.mongodb.internal.operation.AggregateOperation;
import com.mongodb.internal.operation.CountOperation;
import com.mongodb.internal.operation.CreateCollectionOperation;
import com.mongodb.internal.operation.CreateIndexesOperation;
import com.mongodb.internal.operation.CreateViewOperation;
-import com.mongodb.internal.operation.DeleteOperation;
import com.mongodb.internal.operation.DistinctOperation;
import com.mongodb.internal.operation.FindAndDeleteOperation;
import com.mongodb.internal.operation.FindAndReplaceOperation;
import com.mongodb.internal.operation.FindAndUpdateOperation;
import com.mongodb.internal.operation.FindOperation;
-import com.mongodb.internal.operation.InsertOperation;
import com.mongodb.internal.operation.ListCollectionsOperation;
import com.mongodb.internal.operation.MapReduceToCollectionOperation;
import com.mongodb.internal.operation.MapReduceWithInlineResultsOperation;
import com.mongodb.internal.operation.MixedBulkWriteOperation;
-import com.mongodb.internal.operation.UpdateOperation;
import org.bson.BsonDocument;
import java.util.List;
@@ -48,6 +46,21 @@
})
public class MongoOperationHelper {
+ // InsertOperation, DeleteOperation, UpdateOperation were removed in MongoDB driver 4.9.
+ // Use class existence check to determine which extraction path to use.
+ private static final boolean HAS_LEGACY_WRITE_OPERATIONS;
+
+ static {
+ boolean hasLegacy;
+ try {
+ Class.forName("com.mongodb.internal.operation.InsertOperation");
+ hasLegacy = true;
+ } catch (ClassNotFoundException e) {
+ hasLegacy = false;
+ }
+ HAS_LEGACY_WRITE_OPERATIONS = hasLegacy;
+ }
+
private MongoOperationHelper() {
}
@@ -68,22 +81,25 @@ public static String getTraceParam(Object obj) {
} else if (obj instanceof FindOperation) {
BsonDocument filter = ((FindOperation) obj).getFilter();
return limitFilter(filter.toString());
- } else if (obj instanceof ListCollectionsOperation) {
+ } else if (obj instanceof ListCollectionsOperation) {
BsonDocument filter = ((ListCollectionsOperation) obj).getFilter();
return limitFilter(filter.toString());
} else if (obj instanceof MapReduceWithInlineResultsOperation) {
BsonDocument filter = ((MapReduceWithInlineResultsOperation) obj).getFilter();
return limitFilter(filter.toString());
- } else if (obj instanceof DeleteOperation) {
- List writeRequestList = ((DeleteOperation) obj).getDeleteRequests();
- return getFilter(writeRequestList);
- } else if (obj instanceof InsertOperation) {
- List writeRequestList = ((InsertOperation) obj).getInsertRequests();
- return getFilter(writeRequestList);
- } else if (obj instanceof UpdateOperation) {
- List writeRequestList = ((UpdateOperation) obj).getUpdateRequests();
- return getFilter(writeRequestList);
- } else if (obj instanceof CreateCollectionOperation) {
+ } else if (HAS_LEGACY_WRITE_OPERATIONS) {
+ String result = LegacyOperationHelper.getTraceParam(obj);
+ if (result != null) {
+ return result;
+ }
+ return getCommonTraceParam(obj);
+ } else {
+ return getCommonTraceParam(obj);
+ }
+ }
+
+ private static String getCommonTraceParam(Object obj) {
+ if (obj instanceof CreateCollectionOperation) {
String filter = ((CreateCollectionOperation) obj).getCollectionName();
return limitFilter(filter);
} else if (obj instanceof CreateIndexesOperation) {
@@ -101,6 +117,9 @@ public static String getTraceParam(Object obj) {
} else if (obj instanceof FindAndUpdateOperation) {
BsonDocument filter = ((FindAndUpdateOperation) obj).getFilter();
return limitFilter(filter.toString());
+ } else if (obj instanceof AggregateOperation) {
+ List pipelines = ((AggregateOperation) obj).getPipeline();
+ return getPipelines(pipelines);
} else if (obj instanceof MapReduceToCollectionOperation) {
BsonDocument filter = ((MapReduceToCollectionOperation) obj).getFilter();
return limitFilter(filter.toString());
@@ -112,7 +131,19 @@ public static String getTraceParam(Object obj) {
}
}
- private static String getFilter(List extends WriteRequest> writeRequestList) {
+ private static String getPipelines(List pipelines) {
+ StringBuilder params = new StringBuilder();
+ for (BsonDocument pipeline : pipelines) {
+ params.append(pipeline.toString()).append(",");
+ final int filterLengthLimit = MongoPluginConfig.Plugin.MongoDB.FILTER_LENGTH_LIMIT;
+ if (filterLengthLimit > 0 && params.length() > filterLengthLimit) {
+ return params.substring(0, filterLengthLimit) + "...";
+ }
+ }
+ return params.toString();
+ }
+
+ static String getFilter(List extends WriteRequest> writeRequestList) {
StringBuilder params = new StringBuilder();
for (WriteRequest request : writeRequestList) {
if (request instanceof InsertRequest) {
diff --git a/apm-sniffer/apm-sdk-plugin/mongodb-4.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v4/support/MongoRemotePeerHelper.java b/apm-sniffer/apm-sdk-plugin/mongodb-4.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v4/support/MongoRemotePeerHelper.java
index 1dcdb288f8..8fec2f8f4b 100644
--- a/apm-sniffer/apm-sdk-plugin/mongodb-4.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v4/support/MongoRemotePeerHelper.java
+++ b/apm-sniffer/apm-sdk-plugin/mongodb-4.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v4/support/MongoRemotePeerHelper.java
@@ -35,7 +35,7 @@ private MongoRemotePeerHelper() {
*/
public static String getRemotePeer(Cluster cluster) {
StringBuilder peersBuilder = new StringBuilder();
- for (ServerDescription description : cluster.getDescription().getServerDescriptions()) {
+ for (ServerDescription description : cluster.getCurrentDescription().getServerDescriptions()) {
ServerAddress address = description.getAddress();
peersBuilder.append(address.getHost()).append(":").append(address.getPort()).append(";");
}
diff --git a/apm-sniffer/apm-sdk-plugin/mongodb-4.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v4/support/MongoSpanHelper.java b/apm-sniffer/apm-sdk-plugin/mongodb-4.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v4/support/MongoSpanHelper.java
index 4f81a0f058..d87b66a825 100644
--- a/apm-sniffer/apm-sdk-plugin/mongodb-4.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v4/support/MongoSpanHelper.java
+++ b/apm-sniffer/apm-sdk-plugin/mongodb-4.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v4/support/MongoSpanHelper.java
@@ -20,34 +20,44 @@
import org.apache.skywalking.apm.agent.core.context.ContextCarrier;
import org.apache.skywalking.apm.agent.core.context.ContextManager;
+import org.apache.skywalking.apm.agent.core.context.tag.AbstractTag;
import org.apache.skywalking.apm.agent.core.context.tag.Tags;
import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan;
import org.apache.skywalking.apm.agent.core.context.trace.SpanLayer;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
import org.apache.skywalking.apm.network.trace.component.ComponentsDefine;
+import org.apache.skywalking.apm.util.StringUtil;
public class MongoSpanHelper {
+ private static final AbstractTag DB_COLLECTION_TAG = Tags.ofKey("db.collection");
+
private MongoSpanHelper() {
}
/**
* createExitSpan
+ *
* @param executeMethod executeMethod
- * @param remotePeer remotePeer
- * @param operation operation
+ * @param remotePeer remotePeer
+ * @param operation operation
*/
public static void createExitSpan(String executeMethod, String remotePeer, Object operation) {
AbstractSpan span = ContextManager.createExitSpan(
- MongoConstants.MONGO_DB_OP_PREFIX + executeMethod, new ContextCarrier(), remotePeer);
+ MongoConstants.MONGO_DB_OP_PREFIX + executeMethod, new ContextCarrier(), remotePeer);
span.setComponent(ComponentsDefine.MONGO_DRIVER);
Tags.DB_TYPE.set(span, MongoConstants.DB_TYPE);
SpanLayer.asDB(span);
if (operation instanceof EnhancedInstance) {
- Object databaseName = ((EnhancedInstance) operation).getSkyWalkingDynamicField();
- if (databaseName != null) {
- Tags.DB_INSTANCE.set(span, (String) databaseName);
+ MongoNamespaceInfo mongoNamespaceInfo = (MongoNamespaceInfo) ((EnhancedInstance) operation).getSkyWalkingDynamicField();
+ if (mongoNamespaceInfo != null) {
+ if (StringUtil.isNotEmpty(mongoNamespaceInfo.getDatabaseName())) {
+ Tags.DB_INSTANCE.set(span, mongoNamespaceInfo.getDatabaseName());
+ }
+ if (StringUtil.isNotEmpty(mongoNamespaceInfo.getCollectionName())) {
+ span.tag(DB_COLLECTION_TAG, mongoNamespaceInfo.getCollectionName());
+ }
}
}
@@ -56,3 +66,4 @@ public static void createExitSpan(String executeMethod, String remotePeer, Objec
}
}
}
+
diff --git a/apm-sniffer/apm-sdk-plugin/mongodb-4.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/mongodb/v4/MongoDBOperationExecutorInterceptorTest.java b/apm-sniffer/apm-sdk-plugin/mongodb-4.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/mongodb/v4/MongoDBOperationExecutorInterceptorTest.java
index ed2154056e..4bb4b1213b 100644
--- a/apm-sniffer/apm-sdk-plugin/mongodb-4.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/mongodb/v4/MongoDBOperationExecutorInterceptorTest.java
+++ b/apm-sniffer/apm-sdk-plugin/mongodb-4.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/mongodb/v4/MongoDBOperationExecutorInterceptorTest.java
@@ -18,12 +18,13 @@
package org.apache.skywalking.apm.plugin.mongodb.v4;
-import static org.hamcrest.CoreMatchers.is;
-import static org.junit.Assert.assertThat;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-import java.lang.reflect.Method;
-import java.util.List;
+import com.mongodb.MongoNamespace;
+import com.mongodb.ReadConcern;
+import com.mongodb.client.internal.OperationExecutor;
+import com.mongodb.internal.operation.AggregateOperation;
+import com.mongodb.internal.operation.CreateCollectionOperation;
+import com.mongodb.internal.operation.FindOperation;
+import com.mongodb.internal.operation.WriteOperation;
import org.apache.skywalking.apm.agent.core.context.trace.AbstractTracingSpan;
import org.apache.skywalking.apm.agent.core.context.trace.LogDataEntity;
import org.apache.skywalking.apm.agent.core.context.trace.SpanLayer;
@@ -38,24 +39,34 @@
import org.apache.skywalking.apm.agent.test.tools.SpanAssert;
import org.apache.skywalking.apm.agent.test.tools.TracingSegmentRunner;
import org.apache.skywalking.apm.plugin.mongodb.v4.interceptor.MongoDBOperationExecutorInterceptor;
+import org.apache.skywalking.apm.plugin.mongodb.v4.support.MongoNamespaceInfo;
+import org.apache.skywalking.apm.plugin.mongodb.v4.interceptor.operation.OperationNamespaceConstructInterceptor;
import org.apache.skywalking.apm.plugin.mongodb.v4.support.MongoPluginConfig;
import org.bson.BsonDocument;
import org.bson.BsonString;
import org.bson.codecs.Decoder;
import org.hamcrest.CoreMatchers;
import org.hamcrest.MatcherAssert;
+import org.hamcrest.core.Is;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.Spy;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
-import com.mongodb.MongoNamespace;
-import com.mongodb.ReadConcern;
-import com.mongodb.client.internal.OperationExecutor;
-import com.mongodb.internal.operation.FindOperation;
-import com.mongodb.internal.operation.WriteOperation;
+
+import java.lang.reflect.Method;
+import java.util.Collections;
+import java.util.List;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.startsWith;
+import static org.junit.Assert.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
@RunWith(TracingSegmentRunner.class)
public class MongoDBOperationExecutorInterceptorTest {
@@ -71,32 +82,85 @@ public class MongoDBOperationExecutorInterceptorTest {
@Mock
private EnhancedInstance enhancedInstance;
+ private FindOperation enhancedInstanceForFindOperation;
+
+ @Spy
+ private EnhancedInstance enhancedObjInstance = new EnhancedInstance() {
+ private MongoNamespaceInfo namespace;
+
+ @Override
+ public Object getSkyWalkingDynamicField() {
+ return namespace;
+ }
+
+ @Override
+ public void setSkyWalkingDynamicField(Object value) {
+ this.namespace = (MongoNamespaceInfo) value;
+ }
+ };
+
private MongoDBOperationExecutorInterceptor interceptor;
+ private OperationNamespaceConstructInterceptor constructInterceptor;
+
private Object[] arguments;
private Class[] argumentTypes;
+ private Decoder decoder;
+
+ private MongoNamespace mongoNamespace;
+
+ private MongoNamespaceInfo mongoNamespaceInfo;
+
@Before
public void setUp() {
interceptor = new MongoDBOperationExecutorInterceptor();
-
+ constructInterceptor = new OperationNamespaceConstructInterceptor();
+ enhancedInstanceForFindOperation = mock(FindOperation.class, Mockito.withSettings().extraInterfaces(EnhancedInstance.class));
MongoPluginConfig.Plugin.MongoDB.TRACE_PARAM = true;
-
- when(enhancedInstance.getSkyWalkingDynamicField()).thenReturn("127.0.0.1:27017");
-
+ decoder = mock(Decoder.class);
+ mongoNamespace = new MongoNamespace("test.user");
+ mongoNamespaceInfo = new MongoNamespaceInfo(mongoNamespace);
BsonDocument document = new BsonDocument();
document.append("name", new BsonString("by"));
- MongoNamespace mongoNamespace = new MongoNamespace("test.user");
- Decoder decoder = mock(Decoder.class);
+
FindOperation findOperation = new FindOperation(mongoNamespace, decoder);
findOperation.filter(document);
-
- arguments = new Object[] {findOperation};
+ decoder = mock(Decoder.class);
+ when(enhancedInstance.getSkyWalkingDynamicField()).thenReturn("127.0.0.1:27017");
+ enhancedInstanceForFindOperation = mock(FindOperation.class, Mockito.withSettings().extraInterfaces(EnhancedInstance.class));
+ when(((EnhancedInstance) enhancedInstanceForFindOperation).getSkyWalkingDynamicField()).thenReturn(mongoNamespaceInfo);
+ when(enhancedInstanceForFindOperation.getFilter()).thenReturn(findOperation.getFilter());
+ arguments = new Object[] {enhancedInstanceForFindOperation};
argumentTypes = new Class[] {findOperation.getClass()};
}
+ @Test
+ public void testConstructIntercept() throws Throwable {
+ constructInterceptor.onConstruct(enhancedObjInstance, new Object[]{mongoNamespace});
+ MatcherAssert.assertThat(enhancedObjInstance.getSkyWalkingDynamicField(), Is.is(new MongoNamespaceInfo(mongoNamespace)));
+ }
+
+ @Test
+ public void testCreateCollectionOperationIntercept() throws Throwable {
+ CreateCollectionOperation createCollectionOperation = new CreateCollectionOperation("test", "user");
+ CreateCollectionOperation enhancedInstanceForCreateCollectionOperation = mock(CreateCollectionOperation.class, Mockito.withSettings().extraInterfaces(EnhancedInstance.class));
+ when(((EnhancedInstance) enhancedInstanceForCreateCollectionOperation).getSkyWalkingDynamicField()).thenReturn(new MongoNamespaceInfo("test"));
+ when(enhancedInstanceForCreateCollectionOperation.getCollectionName()).thenReturn("user");
+
+ Object[] arguments = {enhancedInstanceForCreateCollectionOperation};
+ Class[] argumentTypes = {createCollectionOperation.getClass()};
+ interceptor.beforeMethod(enhancedInstance, getMethod(), arguments, argumentTypes, null);
+ interceptor.afterMethod(enhancedInstance, getMethod(), arguments, argumentTypes, null);
+
+ MatcherAssert.assertThat(segmentStorage.getTraceSegments().size(), is(1));
+ TraceSegment traceSegment = segmentStorage.getTraceSegments().get(0);
+ List spans = SegmentHelper.getSpans(traceSegment);
+ assertMongoCreateCollectionOperationSpan(spans.get(0));
+ }
+
@Test
public void testIntercept() throws Throwable {
interceptor.beforeMethod(enhancedInstance, getMethod(), arguments, argumentTypes, null);
@@ -105,31 +169,77 @@ public void testIntercept() throws Throwable {
MatcherAssert.assertThat(segmentStorage.getTraceSegments().size(), is(1));
TraceSegment traceSegment = segmentStorage.getTraceSegments().get(0);
List spans = SegmentHelper.getSpans(traceSegment);
- assertMongoSpan(spans.get(0));
+ assertMongoFindOperationSpan(spans.get(0));
+ }
+
+ @Test
+ public void testAggregateOperationIntercept() throws Throwable {
+ MongoNamespace mongoNamespace = new MongoNamespace("test.user");
+ BsonDocument matchStage = new BsonDocument("$match", new BsonDocument("name", new BsonString("by")));
+ List pipeline = Collections.singletonList(matchStage);
+ AggregateOperation aggregateOperation = new AggregateOperation(mongoNamespace, pipeline, decoder);
+
+ AggregateOperation enhancedInstanceForAggregateOperation = mock(AggregateOperation.class, Mockito.withSettings().extraInterfaces(EnhancedInstance.class));
+ when(((EnhancedInstance) enhancedInstanceForAggregateOperation).getSkyWalkingDynamicField()).thenReturn(new MongoNamespaceInfo(mongoNamespace));
+ when(enhancedInstanceForAggregateOperation.getPipeline()).thenReturn(aggregateOperation.getPipeline());
+ Object[] arguments = {enhancedInstanceForAggregateOperation};
+ Class[] argumentTypes = {aggregateOperation.getClass()};
+
+ interceptor.beforeMethod(enhancedInstance, getMethod(), arguments, argumentTypes, null);
+ interceptor.afterMethod(enhancedInstance, getMethod(), arguments, argumentTypes, null);
+
+ MatcherAssert.assertThat(segmentStorage.getTraceSegments().size(), is(1));
+ TraceSegment traceSegment = segmentStorage.getTraceSegments().get(0);
+ List spans = SegmentHelper.getSpans(traceSegment);
+ assertMongoAggregateOperationSpan(spans.get(0));
}
@Test
public void testInterceptWithException() throws Throwable {
interceptor.beforeMethod(enhancedInstance, getMethod(), arguments, argumentTypes, null);
- interceptor.handleMethodException(
- enhancedInstance, getMethod(), arguments, argumentTypes, new RuntimeException());
+ interceptor.handleMethodException(enhancedInstance, getMethod(), arguments, argumentTypes, new RuntimeException());
interceptor.afterMethod(enhancedInstance, getMethod(), arguments, argumentTypes, null);
MatcherAssert.assertThat(segmentStorage.getTraceSegments().size(), is(1));
TraceSegment traceSegment = segmentStorage.getTraceSegments().get(0);
List spans = SegmentHelper.getSpans(traceSegment);
- assertMongoSpan(spans.get(0));
+ assertMongoFindOperationSpan(spans.get(0));
List logDataEntities = SpanHelper.getLogs(spans.get(0));
assertThat(logDataEntities.size(), is(1));
SpanAssert.assertException(logDataEntities.get(0), RuntimeException.class);
}
- private void assertMongoSpan(AbstractTracingSpan span) {
- assertThat(span.getOperationName(), is("MongoDB/FindOperation"));
+ private void assertMongoFindOperationSpan(AbstractTracingSpan span) {
+ assertThat(span.getOperationName(), startsWith("MongoDB/FindOperation"));
+ assertThat(SpanHelper.getComponentId(span), is(42));
+ List tags = SpanHelper.getTags(span);
+ assertThat(tags.get(0).getValue(), is("MongoDB"));
+ assertThat(tags.get(1).getValue(), is("test"));
+ assertThat(tags.get(2).getValue(), is("user"));
+ assertThat(tags.get(3).getValue(), is("{\"name\": \"by\"}"));
+ assertThat(span.isExit(), is(true));
+ assertThat(SpanHelper.getLayer(span), CoreMatchers.is(SpanLayer.DB));
+ }
+
+ private void assertMongoCreateCollectionOperationSpan(AbstractTracingSpan span) {
+ assertThat(span.getOperationName(), startsWith("MongoDB/CreateCollectionOperation"));
+ assertThat(SpanHelper.getComponentId(span), is(42));
+ List tags = SpanHelper.getTags(span);
+ assertThat(tags.get(0).getValue(), is("MongoDB"));
+ assertThat(tags.get(1).getValue(), is("test"));
+ assertThat(tags.get(2).getValue(), is("user"));
+ assertThat(span.isExit(), is(true));
+ assertThat(SpanHelper.getLayer(span), CoreMatchers.is(SpanLayer.DB));
+ }
+
+ private void assertMongoAggregateOperationSpan(AbstractTracingSpan span) {
+ assertThat(span.getOperationName(), startsWith("MongoDB/AggregateOperation"));
assertThat(SpanHelper.getComponentId(span), is(42));
List tags = SpanHelper.getTags(span);
- assertThat(tags.get(1).getValue(), is("{\"name\": \"by\"}"));
assertThat(tags.get(0).getValue(), is("MongoDB"));
+ assertThat(tags.get(1).getValue(), is("test"));
+ assertThat(tags.get(2).getValue(), is("user"));
+ assertThat(tags.get(3).getValue(), is("{\"$match\": {\"name\": \"by\"}},"));
assertThat(span.isExit(), is(true));
assertThat(SpanHelper.getLayer(span), CoreMatchers.is(SpanLayer.DB));
}
diff --git a/apm-sniffer/apm-sdk-plugin/mongodb-5.x-plugin/pom.xml b/apm-sniffer/apm-sdk-plugin/mongodb-5.x-plugin/pom.xml
new file mode 100644
index 0000000000..141dbd464a
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/mongodb-5.x-plugin/pom.xml
@@ -0,0 +1,50 @@
+
+
+
+
+ 4.0.0
+
+
+ apm-sdk-plugin
+ org.apache.skywalking
+ 9.7.0-SNAPSHOT
+
+
+ apm-mongodb-5.x-plugin
+ jar
+
+ mongodb-5.x-plugin
+
+
+
+ org.mongodb
+ mongodb-driver-sync
+ 5.2.0
+ provided
+
+
+ org.apache.skywalking
+ apm-mongodb-4.x-plugin
+ ${project.version}
+ provided
+
+
+
diff --git a/apm-sniffer/apm-sdk-plugin/tomcat-10x-plugin/src/main/java/org/apache/skywalking/apm/plugin/tomcat10x/define/ApplicationDispatcherInstrumentation.java b/apm-sniffer/apm-sdk-plugin/mongodb-5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v5/define/MongoClusterImplInstrumentation.java
similarity index 71%
rename from apm-sniffer/apm-sdk-plugin/tomcat-10x-plugin/src/main/java/org/apache/skywalking/apm/plugin/tomcat10x/define/ApplicationDispatcherInstrumentation.java
rename to apm-sniffer/apm-sdk-plugin/mongodb-5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v5/define/MongoClusterImplInstrumentation.java
index 048ee28f38..96b834fbca 100644
--- a/apm-sniffer/apm-sdk-plugin/tomcat-10x-plugin/src/main/java/org/apache/skywalking/apm/plugin/tomcat10x/define/ApplicationDispatcherInstrumentation.java
+++ b/apm-sniffer/apm-sdk-plugin/mongodb-5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v5/define/MongoClusterImplInstrumentation.java
@@ -16,7 +16,7 @@
*
*/
-package org.apache.skywalking.apm.plugin.tomcat10x.define;
+package org.apache.skywalking.apm.plugin.mongodb.v5.define;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.matcher.ElementMatcher;
@@ -25,19 +25,30 @@
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine;
import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
-import static net.bytebuddy.matcher.ElementMatchers.any;
import static net.bytebuddy.matcher.ElementMatchers.named;
+import static org.apache.skywalking.apm.agent.core.plugin.bytebuddy.ArgumentTypeNameMatch.takesArgumentWithType;
import static org.apache.skywalking.apm.agent.core.plugin.match.NameMatch.byName;
-public class ApplicationDispatcherInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
+/**
+ * Enhance {@code com.mongodb.client.internal.MongoClusterImpl} which replaces
+ * {@code MongoClientDelegate} in MongoDB driver 5.2+.
+ * Extract remotePeer from Cluster (constructor arg[1]) and store in dynamic field.
+ */
+public class MongoClusterImplInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
+
+ private static final String ENHANCE_CLASS = "com.mongodb.client.internal.MongoClusterImpl";
- private static final String ENHANCE_CLASS = "org.apache.catalina.core.ApplicationDispatcher";
- private static final String ENHANCE_METHOD = "forward";
- public static final String INTERCEPTOR_CLASS = "org.apache.skywalking.apm.plugin.tomcat10x.ForwardInterceptor";
+ private static final String CONSTRUCTOR_INTERCEPTOR =
+ "org.apache.skywalking.apm.plugin.mongodb.v5.interceptor.MongoClusterImplConstructorInterceptor";
@Override
protected String[] witnessClasses() {
- return new String[]{"jakarta.servlet.http.HttpServletResponse"};
+ return new String[] {ENHANCE_CLASS};
+ }
+
+ @Override
+ protected ClassMatch enhanceClass() {
+ return byName(ENHANCE_CLASS);
}
@Override
@@ -46,12 +57,12 @@ public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
new ConstructorInterceptPoint() {
@Override
public ElementMatcher getConstructorMatcher() {
- return any();
+ return takesArgumentWithType(1, "com.mongodb.internal.connection.Cluster");
}
@Override
public String getConstructorInterceptor() {
- return INTERCEPTOR_CLASS;
+ return CONSTRUCTOR_INTERCEPTOR;
}
}
};
@@ -63,12 +74,12 @@ public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
new InstanceMethodsInterceptPoint() {
@Override
public ElementMatcher getMethodsMatcher() {
- return named(ENHANCE_METHOD);
+ return named("getOperationExecutor");
}
@Override
public String getMethodsInterceptor() {
- return INTERCEPTOR_CLASS;
+ return CONSTRUCTOR_INTERCEPTOR;
}
@Override
@@ -78,9 +89,4 @@ public boolean isOverrideArgs() {
}
};
}
-
- @Override
- protected ClassMatch enhanceClass() {
- return byName(ENHANCE_CLASS);
- }
}
diff --git a/apm-sniffer/apm-sdk-plugin/mongodb-5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v5/define/MongoClusterOperationExecutorInstrumentation.java b/apm-sniffer/apm-sdk-plugin/mongodb-5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v5/define/MongoClusterOperationExecutorInstrumentation.java
new file mode 100644
index 0000000000..53bdb6da93
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/mongodb-5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v5/define/MongoClusterOperationExecutorInstrumentation.java
@@ -0,0 +1,107 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.mongodb.v5.define;
+
+import net.bytebuddy.description.method.MethodDescription;
+import net.bytebuddy.matcher.ElementMatcher;
+import net.bytebuddy.matcher.ElementMatchers;
+import org.apache.skywalking.apm.agent.core.plugin.bytebuddy.ArgumentTypeNameMatch;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine;
+import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
+import org.apache.skywalking.apm.agent.core.plugin.match.NameMatch;
+
+/**
+ * Enhance {@code MongoClusterImpl$OperationExecutorImpl} in MongoDB driver 5.2+.
+ *
+ * Constructor interception: propagate remotePeer from enclosing MongoClusterImpl
+ * (synthetic arg[0] for non-static inner class).
+ *
+ * Method interception: create exit spans on execute() calls.
+ * Reuses the 4.x MongoDBOperationExecutorInterceptor.
+ */
+public class MongoClusterOperationExecutorInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
+
+ private static final String ENHANCE_CLASS =
+ "com.mongodb.client.internal.MongoClusterImpl$OperationExecutorImpl";
+
+ private static final String CONSTRUCTOR_INTERCEPTOR =
+ "org.apache.skywalking.apm.plugin.mongodb.v5.interceptor.OperationExecutorImplConstructorInterceptor";
+
+ private static final String EXECUTE_INTERCEPTOR =
+ "org.apache.skywalking.apm.plugin.mongodb.v4.interceptor.MongoDBOperationExecutorInterceptor";
+
+ private static final String METHOD_NAME = "execute";
+
+ private static final String ARGUMENT_TYPE = "com.mongodb.client.ClientSession";
+
+ @Override
+ protected String[] witnessClasses() {
+ return new String[] {"com.mongodb.client.internal.MongoClusterImpl"};
+ }
+
+ @Override
+ protected ClassMatch enhanceClass() {
+ return NameMatch.byName(ENHANCE_CLASS);
+ }
+
+ @Override
+ public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
+ return new ConstructorInterceptPoint[] {
+ new ConstructorInterceptPoint() {
+ @Override
+ public ElementMatcher getConstructorMatcher() {
+ return ElementMatchers.any();
+ }
+
+ @Override
+ public String getConstructorInterceptor() {
+ return CONSTRUCTOR_INTERCEPTOR;
+ }
+ }
+ };
+ }
+
+ @Override
+ public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
+ return new InstanceMethodsInterceptPoint[] {
+ new InstanceMethodsInterceptPoint() {
+ @Override
+ public ElementMatcher getMethodsMatcher() {
+ return ElementMatchers
+ .named(METHOD_NAME)
+ .and(ArgumentTypeNameMatch.takesArgumentWithType(2, ARGUMENT_TYPE))
+ .or(ElementMatchers.named(METHOD_NAME)
+ .and(ArgumentTypeNameMatch.takesArgumentWithType(3, ARGUMENT_TYPE)));
+ }
+
+ @Override
+ public String getMethodsInterceptor() {
+ return EXECUTE_INTERCEPTOR;
+ }
+
+ @Override
+ public boolean isOverrideArgs() {
+ return false;
+ }
+ }
+ };
+ }
+}
diff --git a/apm-sniffer/apm-sdk-plugin/mongodb-5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v5/interceptor/MongoClusterImplConstructorInterceptor.java b/apm-sniffer/apm-sdk-plugin/mongodb-5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v5/interceptor/MongoClusterImplConstructorInterceptor.java
new file mode 100644
index 0000000000..242b450c45
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/mongodb-5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v5/interceptor/MongoClusterImplConstructorInterceptor.java
@@ -0,0 +1,89 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.mongodb.v5.interceptor;
+
+import com.mongodb.internal.connection.Cluster;
+import org.apache.skywalking.apm.agent.core.logging.api.ILog;
+import org.apache.skywalking.apm.agent.core.logging.api.LogManager;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceConstructorInterceptor;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
+import org.apache.skywalking.apm.plugin.mongodb.v4.support.MongoRemotePeerHelper;
+
+import java.lang.reflect.Method;
+
+/**
+ * Intercept {@code MongoClusterImpl} constructor and {@code getOperationExecutor()}.
+ *
+ * Constructor: extract remotePeer from Cluster (arg[1]) and store in dynamic field.
+ * getOperationExecutor(): pass remotePeer to the returned OperationExecutor.
+ */
+public class MongoClusterImplConstructorInterceptor
+ implements InstanceConstructorInterceptor, InstanceMethodsAroundInterceptor {
+
+ private static final ILog LOGGER = LogManager.getLogger(MongoClusterImplConstructorInterceptor.class);
+
+ @Override
+ public void onConstruct(EnhancedInstance objInst, Object[] allArguments) {
+ Cluster cluster = (Cluster) allArguments[1];
+ String remotePeer = MongoRemotePeerHelper.getRemotePeer(cluster);
+ objInst.setSkyWalkingDynamicField(remotePeer);
+
+ // The OperationExecutorImpl is created INSIDE this constructor (before onConstruct fires),
+ // so its constructor interceptor couldn't read the peer yet. Set it now.
+ // MongoClusterImpl is package-private and loaded by application classloader.
+ // Same-package helpers from agent classloader cannot access it (different runtime packages).
+ // Use setAccessible reflection to call getOperationExecutor().
+ try {
+ java.lang.reflect.Method getExecutor = objInst.getClass().getMethod("getOperationExecutor");
+ getExecutor.setAccessible(true);
+ Object executor = getExecutor.invoke(objInst);
+ if (executor instanceof EnhancedInstance) {
+ ((EnhancedInstance) executor).setSkyWalkingDynamicField(remotePeer);
+ }
+ } catch (Exception e) {
+ LOGGER.warn("Failed to set remotePeer on OperationExecutor", e);
+ }
+ }
+
+ @Override
+ public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments,
+ Class>[] argumentsTypes, MethodInterceptResult result) {
+ }
+
+ @Override
+ public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments,
+ Class>[] argumentsTypes, Object ret) {
+ if (ret instanceof EnhancedInstance) {
+ EnhancedInstance retInstance = (EnhancedInstance) ret;
+ String remotePeer = (String) objInst.getSkyWalkingDynamicField();
+ if (LOGGER.isDebugEnable()) {
+ LOGGER.debug("Mark OperationExecutor remotePeer: {}", remotePeer);
+ }
+ retInstance.setSkyWalkingDynamicField(remotePeer);
+ }
+ return ret;
+ }
+
+ @Override
+ public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments,
+ Class>[] argumentsTypes, Throwable t) {
+ }
+}
diff --git a/apm-sniffer/apm-sdk-plugin/mongodb-5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v5/interceptor/OperationExecutorImplConstructorInterceptor.java b/apm-sniffer/apm-sdk-plugin/mongodb-5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v5/interceptor/OperationExecutorImplConstructorInterceptor.java
new file mode 100644
index 0000000000..0b7c11862e
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/mongodb-5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mongodb/v5/interceptor/OperationExecutorImplConstructorInterceptor.java
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.mongodb.v5.interceptor;
+
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceConstructorInterceptor;
+
+/**
+ * Intercept {@code MongoClusterImpl$OperationExecutorImpl} constructor.
+ * As a non-static inner class, the compiled constructor has the enclosing
+ * {@code MongoClusterImpl} instance as a synthetic first argument (arg index 0).
+ *
+ * Note: This interceptor fires during MongoClusterImpl's constructor, before
+ * MongoClusterImpl.onConstruct() sets the remotePeer. So the dynamic field
+ * on the enclosing instance is not yet set. The primary peer propagation
+ * happens in MongoClusterImplConstructorInterceptor.onConstruct() which
+ * calls getOperationExecutor() after the constructor completes.
+ *
+ * This interceptor serves as a secondary path for OperationExecutorImpl
+ * instances created later (e.g., via withTimeoutSettings()).
+ */
+public class OperationExecutorImplConstructorInterceptor implements InstanceConstructorInterceptor {
+
+ @Override
+ public void onConstruct(EnhancedInstance objInst, Object[] allArguments) {
+ for (Object arg : allArguments) {
+ if (arg instanceof EnhancedInstance) {
+ EnhancedInstance enclosingInstance = (EnhancedInstance) arg;
+ String remotePeer = (String) enclosingInstance.getSkyWalkingDynamicField();
+ if (remotePeer != null && !remotePeer.isEmpty()) {
+ objInst.setSkyWalkingDynamicField(remotePeer);
+ return;
+ }
+ }
+ }
+ }
+}
diff --git a/apm-sniffer/apm-sdk-plugin/mongodb-5.x-plugin/src/main/resources/skywalking-plugin.def b/apm-sniffer/apm-sdk-plugin/mongodb-5.x-plugin/src/main/resources/skywalking-plugin.def
new file mode 100644
index 0000000000..fcd2e7be8f
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/mongodb-5.x-plugin/src/main/resources/skywalking-plugin.def
@@ -0,0 +1,19 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# MongoDB 5.2+ (MongoClusterImpl replaces MongoClientDelegate)
+mongodb-5.x=org.apache.skywalking.apm.plugin.mongodb.v5.define.MongoClusterImplInstrumentation
+mongodb-5.x=org.apache.skywalking.apm.plugin.mongodb.v5.define.MongoClusterOperationExecutorInstrumentation
diff --git a/apm-sniffer/apm-sdk-plugin/motan-plugin/pom.xml b/apm-sniffer/apm-sdk-plugin/motan-plugin/pom.xml
index 51b3fec800..b74bc6d54d 100644
--- a/apm-sniffer/apm-sdk-plugin/motan-plugin/pom.xml
+++ b/apm-sniffer/apm-sdk-plugin/motan-plugin/pom.xml
@@ -20,7 +20,7 @@
apm-sdk-plugin
org.apache.skywalking
- 9.3.0-SNAPSHOT
+ 9.7.0-SNAPSHOT
4.0.0
diff --git a/apm-sniffer/apm-sdk-plugin/mssql-commons/pom.xml b/apm-sniffer/apm-sdk-plugin/mssql-commons/pom.xml
index 6cbcb3a4af..ff9f083f6d 100644
--- a/apm-sniffer/apm-sdk-plugin/mssql-commons/pom.xml
+++ b/apm-sniffer/apm-sdk-plugin/mssql-commons/pom.xml
@@ -20,7 +20,7 @@
apm-sdk-plugin
org.apache.skywalking
- 9.3.0-SNAPSHOT
+ 9.7.0-SNAPSHOT
4.0.0
diff --git a/apm-sniffer/apm-sdk-plugin/mssql-jdbc-plugin/pom.xml b/apm-sniffer/apm-sdk-plugin/mssql-jdbc-plugin/pom.xml
index e8da306dd9..ff678a1a00 100644
--- a/apm-sniffer/apm-sdk-plugin/mssql-jdbc-plugin/pom.xml
+++ b/apm-sniffer/apm-sdk-plugin/mssql-jdbc-plugin/pom.xml
@@ -20,7 +20,7 @@
apm-sdk-plugin
org.apache.skywalking
- 9.3.0-SNAPSHOT
+ 9.7.0-SNAPSHOT
4.0.0
diff --git a/apm-sniffer/apm-sdk-plugin/mssql-jtds-1.x-plugin/pom.xml b/apm-sniffer/apm-sdk-plugin/mssql-jtds-1.x-plugin/pom.xml
index be33212cbe..2f3dd90ea6 100644
--- a/apm-sniffer/apm-sdk-plugin/mssql-jtds-1.x-plugin/pom.xml
+++ b/apm-sniffer/apm-sdk-plugin/mssql-jtds-1.x-plugin/pom.xml
@@ -20,7 +20,7 @@
apm-sdk-plugin
org.apache.skywalking
- 9.3.0-SNAPSHOT
+ 9.7.0-SNAPSHOT
4.0.0
diff --git a/apm-sniffer/apm-sdk-plugin/mysql-5.x-plugin/pom.xml b/apm-sniffer/apm-sdk-plugin/mysql-5.x-plugin/pom.xml
index babac7d15d..361f5bc821 100755
--- a/apm-sniffer/apm-sdk-plugin/mysql-5.x-plugin/pom.xml
+++ b/apm-sniffer/apm-sdk-plugin/mysql-5.x-plugin/pom.xml
@@ -20,7 +20,7 @@
apm-sdk-plugin
org.apache.skywalking
- 9.3.0-SNAPSHOT
+ 9.7.0-SNAPSHOT
4.0.0
diff --git a/apm-sniffer/apm-sdk-plugin/mysql-6.x-plugin/pom.xml b/apm-sniffer/apm-sdk-plugin/mysql-6.x-plugin/pom.xml
index 932e2aadf6..edaef2cf28 100755
--- a/apm-sniffer/apm-sdk-plugin/mysql-6.x-plugin/pom.xml
+++ b/apm-sniffer/apm-sdk-plugin/mysql-6.x-plugin/pom.xml
@@ -20,7 +20,7 @@
apm-sdk-plugin
org.apache.skywalking
- 9.3.0-SNAPSHOT
+ 9.7.0-SNAPSHOT
4.0.0
diff --git a/apm-sniffer/apm-sdk-plugin/mysql-8.x-plugin/pom.xml b/apm-sniffer/apm-sdk-plugin/mysql-8.x-plugin/pom.xml
index fd95d69452..11ee950a57 100755
--- a/apm-sniffer/apm-sdk-plugin/mysql-8.x-plugin/pom.xml
+++ b/apm-sniffer/apm-sdk-plugin/mysql-8.x-plugin/pom.xml
@@ -20,7 +20,7 @@
apm-sdk-plugin
org.apache.skywalking
- 9.3.0-SNAPSHOT
+ 9.7.0-SNAPSHOT
4.0.0
diff --git a/apm-sniffer/apm-sdk-plugin/mysql-common/pom.xml b/apm-sniffer/apm-sdk-plugin/mysql-common/pom.xml
index 4ce77ba866..92aa8ee5d8 100755
--- a/apm-sniffer/apm-sdk-plugin/mysql-common/pom.xml
+++ b/apm-sniffer/apm-sdk-plugin/mysql-common/pom.xml
@@ -20,7 +20,7 @@
apm-sdk-plugin
org.apache.skywalking
- 9.3.0-SNAPSHOT
+ 9.7.0-SNAPSHOT
4.0.0
diff --git a/apm-sniffer/apm-sdk-plugin/mysql-common/src/main/java/org/apache/skywalking/apm/plugin/jdbc/mysql/StatementExecuteMethodsInterceptor.java b/apm-sniffer/apm-sdk-plugin/mysql-common/src/main/java/org/apache/skywalking/apm/plugin/jdbc/mysql/StatementExecuteMethodsInterceptor.java
index 8895e118a5..0c2f5047b9 100644
--- a/apm-sniffer/apm-sdk-plugin/mysql-common/src/main/java/org/apache/skywalking/apm/plugin/jdbc/mysql/StatementExecuteMethodsInterceptor.java
+++ b/apm-sniffer/apm-sdk-plugin/mysql-common/src/main/java/org/apache/skywalking/apm/plugin/jdbc/mysql/StatementExecuteMethodsInterceptor.java
@@ -28,6 +28,7 @@
import org.apache.skywalking.apm.plugin.jdbc.SqlBodyUtil;
import org.apache.skywalking.apm.plugin.jdbc.define.StatementEnhanceInfos;
import org.apache.skywalking.apm.plugin.jdbc.trace.ConnectionInfo;
+import org.apache.skywalking.apm.util.StringUtil;
import java.lang.reflect.Method;
@@ -52,14 +53,17 @@ public final void beforeMethod(EnhancedInstance objInst, Method method, Object[]
Tags.DB_INSTANCE.set(span, connectInfo.getDatabaseName());
/**
- * The first argument of all intercept method in `com.mysql.jdbc.StatementImpl` class is SQL, except the
- * `executeBatch` method that the jdbc plugin need to trace, because of this method argument size is zero.
+ * Except for the `executeBatch` method, the first parameter of all enhanced methods in `com.mysql.jdbc.StatementImpl` is the SQL statement.
+ * Therefore, executeBatch will attempt to obtain the SQL from `cacheObject`.
*/
String sql = "";
if (allArguments.length > 0) {
sql = (String) allArguments[0];
sql = SqlBodyUtil.limitSqlBodySize(sql);
+ } else if (StringUtil.isNotBlank(cacheObject.getSql())) {
+ sql = SqlBodyUtil.limitSqlBodySize(cacheObject.getSql());
}
+
Tags.DB_STATEMENT.set(span, sql);
span.setComponent(connectInfo.getComponent());
diff --git a/apm-sniffer/apm-sdk-plugin/mysql-common/src/test/java/org/apache/skywalking/apm/plugin/jdbc/mysql/StatementExecuteMethodsInterceptorTest.java b/apm-sniffer/apm-sdk-plugin/mysql-common/src/test/java/org/apache/skywalking/apm/plugin/jdbc/mysql/StatementExecuteMethodsInterceptorTest.java
index e3ceaa6228..df2769b8cd 100644
--- a/apm-sniffer/apm-sdk-plugin/mysql-common/src/test/java/org/apache/skywalking/apm/plugin/jdbc/mysql/StatementExecuteMethodsInterceptorTest.java
+++ b/apm-sniffer/apm-sdk-plugin/mysql-common/src/test/java/org/apache/skywalking/apm/plugin/jdbc/mysql/StatementExecuteMethodsInterceptorTest.java
@@ -72,7 +72,8 @@ public void setUp() {
JDBCPluginConfig.Plugin.JDBC.SQL_BODY_MAX_LENGTH = 2048;
serviceMethodInterceptor = new StatementExecuteMethodsInterceptor();
- enhanceRequireCacheObject = new StatementEnhanceInfos(connectionInfo, "SELECT * FROM test", "CallableStatement");
+ enhanceRequireCacheObject = new StatementEnhanceInfos(connectionInfo, SQL, "CallableStatement");
+
when(objectInstance.getSkyWalkingDynamicField()).thenReturn(enhanceRequireCacheObject);
when(method.getName()).thenReturn("executeQuery");
when(connectionInfo.getComponent()).thenReturn(ComponentsDefine.H2_JDBC_DRIVER);
@@ -81,6 +82,24 @@ public void setUp() {
when(connectionInfo.getDatabasePeer()).thenReturn("localhost:3307");
}
+ @Test
+ public void testCreateDatabaseSpanWithNoMethodParamButWithCache() throws Throwable {
+ JDBCPluginConfig.Plugin.JDBC.SQL_BODY_MAX_LENGTH = 2048;
+
+ serviceMethodInterceptor.beforeMethod(objectInstance, method, new Object[0], null, null);
+ serviceMethodInterceptor.afterMethod(objectInstance, method, new Object[0], null, null);
+
+ assertThat(segmentStorage.getTraceSegments().size(), is(1));
+ TraceSegment segment = segmentStorage.getTraceSegments().get(0);
+ assertThat(SegmentHelper.getSpans(segment).size(), is(1));
+ AbstractTracingSpan span = SegmentHelper.getSpans(segment).get(0);
+ SpanAssert.assertLayer(span, SpanLayer.DB);
+ assertThat(span.getOperationName(), is("H2/JDBC/CallableStatement/executeQuery"));
+ SpanAssert.assertTag(span, 0, "H2");
+ SpanAssert.assertTag(span, 1, "test");
+ SpanAssert.assertTag(span, 2, SQL);
+ }
+
@Test
public void testCreateDatabaseSpan() throws Throwable {
JDBCPluginConfig.Plugin.JDBC.SQL_BODY_MAX_LENGTH = 2048;
diff --git a/apm-sniffer/apm-sdk-plugin/nats-2.14.x-2.15.x-plugin/pom.xml b/apm-sniffer/apm-sdk-plugin/nats-2.14.x-2.16.5-plugin/pom.xml
similarity index 85%
rename from apm-sniffer/apm-sdk-plugin/nats-2.14.x-2.15.x-plugin/pom.xml
rename to apm-sniffer/apm-sdk-plugin/nats-2.14.x-2.16.5-plugin/pom.xml
index 8ec619ea33..6e115d8ade 100644
--- a/apm-sniffer/apm-sdk-plugin/nats-2.14.x-2.15.x-plugin/pom.xml
+++ b/apm-sniffer/apm-sdk-plugin/nats-2.14.x-2.16.5-plugin/pom.xml
@@ -21,19 +21,14 @@
apm-sdk-plugin
org.apache.skywalking
- 9.3.0-SNAPSHOT
+ 9.7.0-SNAPSHOT
4.0.0
- nats-2.14.x-2.15.x-plugin
+ nats-2.14.x-2.16.5-plugin
jar
-
- 8
- 8
-
-
io.nats
diff --git a/apm-sniffer/apm-sdk-plugin/nats-2.14.x-2.15.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/nats/client/CreateDispatcherInterceptor.java b/apm-sniffer/apm-sdk-plugin/nats-2.14.x-2.16.5-plugin/src/main/java/org/apache/skywalking/apm/plugin/nats/client/CreateDispatcherInterceptor.java
similarity index 100%
rename from apm-sniffer/apm-sdk-plugin/nats-2.14.x-2.15.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/nats/client/CreateDispatcherInterceptor.java
rename to apm-sniffer/apm-sdk-plugin/nats-2.14.x-2.16.5-plugin/src/main/java/org/apache/skywalking/apm/plugin/nats/client/CreateDispatcherInterceptor.java
diff --git a/apm-sniffer/apm-sdk-plugin/nats-2.14.x-2.15.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/nats/client/CreateSubInterceptor.java b/apm-sniffer/apm-sdk-plugin/nats-2.14.x-2.16.5-plugin/src/main/java/org/apache/skywalking/apm/plugin/nats/client/CreateSubInterceptor.java
similarity index 100%
rename from apm-sniffer/apm-sdk-plugin/nats-2.14.x-2.15.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/nats/client/CreateSubInterceptor.java
rename to apm-sniffer/apm-sdk-plugin/nats-2.14.x-2.16.5-plugin/src/main/java/org/apache/skywalking/apm/plugin/nats/client/CreateSubInterceptor.java
diff --git a/apm-sniffer/apm-sdk-plugin/nats-2.14.x-2.15.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/nats/client/DeliverReplyInterceptor.java b/apm-sniffer/apm-sdk-plugin/nats-2.14.x-2.16.5-plugin/src/main/java/org/apache/skywalking/apm/plugin/nats/client/DeliverReplyInterceptor.java
similarity index 100%
rename from apm-sniffer/apm-sdk-plugin/nats-2.14.x-2.15.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/nats/client/DeliverReplyInterceptor.java
rename to apm-sniffer/apm-sdk-plugin/nats-2.14.x-2.16.5-plugin/src/main/java/org/apache/skywalking/apm/plugin/nats/client/DeliverReplyInterceptor.java
diff --git a/apm-sniffer/apm-sdk-plugin/nats-2.14.x-2.15.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/nats/client/NatsCommons.java b/apm-sniffer/apm-sdk-plugin/nats-2.14.x-2.16.5-plugin/src/main/java/org/apache/skywalking/apm/plugin/nats/client/NatsCommons.java
similarity index 100%
rename from apm-sniffer/apm-sdk-plugin/nats-2.14.x-2.15.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/nats/client/NatsCommons.java
rename to apm-sniffer/apm-sdk-plugin/nats-2.14.x-2.16.5-plugin/src/main/java/org/apache/skywalking/apm/plugin/nats/client/NatsCommons.java
diff --git a/apm-sniffer/apm-sdk-plugin/nats-2.14.x-2.15.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/nats/client/NatsConnectionWriterConstructorInterceptor.java b/apm-sniffer/apm-sdk-plugin/nats-2.14.x-2.16.5-plugin/src/main/java/org/apache/skywalking/apm/plugin/nats/client/NatsConnectionWriterConstructorInterceptor.java
similarity index 100%
rename from apm-sniffer/apm-sdk-plugin/nats-2.14.x-2.15.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/nats/client/NatsConnectionWriterConstructorInterceptor.java
rename to apm-sniffer/apm-sdk-plugin/nats-2.14.x-2.16.5-plugin/src/main/java/org/apache/skywalking/apm/plugin/nats/client/NatsConnectionWriterConstructorInterceptor.java
diff --git a/apm-sniffer/apm-sdk-plugin/nats-2.14.x-2.15.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/nats/client/NatsJetStreamConstructorInterceptor.java b/apm-sniffer/apm-sdk-plugin/nats-2.14.x-2.16.5-plugin/src/main/java/org/apache/skywalking/apm/plugin/nats/client/NatsJetStreamConstructorInterceptor.java
similarity index 100%
rename from apm-sniffer/apm-sdk-plugin/nats-2.14.x-2.15.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/nats/client/NatsJetStreamConstructorInterceptor.java
rename to apm-sniffer/apm-sdk-plugin/nats-2.14.x-2.16.5-plugin/src/main/java/org/apache/skywalking/apm/plugin/nats/client/NatsJetStreamConstructorInterceptor.java
diff --git a/apm-sniffer/apm-sdk-plugin/nats-2.14.x-2.15.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/nats/client/NatsMessageInterceptor.java b/apm-sniffer/apm-sdk-plugin/nats-2.14.x-2.16.5-plugin/src/main/java/org/apache/skywalking/apm/plugin/nats/client/NatsMessageInterceptor.java
similarity index 100%
rename from apm-sniffer/apm-sdk-plugin/nats-2.14.x-2.15.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/nats/client/NatsMessageInterceptor.java
rename to apm-sniffer/apm-sdk-plugin/nats-2.14.x-2.16.5-plugin/src/main/java/org/apache/skywalking/apm/plugin/nats/client/NatsMessageInterceptor.java
diff --git a/apm-sniffer/apm-sdk-plugin/nats-2.14.x-2.15.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/nats/client/NatsSubscriptionConstructorInterceptor.java b/apm-sniffer/apm-sdk-plugin/nats-2.14.x-2.16.5-plugin/src/main/java/org/apache/skywalking/apm/plugin/nats/client/NatsSubscriptionConstructorInterceptor.java
similarity index 100%
rename from apm-sniffer/apm-sdk-plugin/nats-2.14.x-2.15.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/nats/client/NatsSubscriptionConstructorInterceptor.java
rename to apm-sniffer/apm-sdk-plugin/nats-2.14.x-2.16.5-plugin/src/main/java/org/apache/skywalking/apm/plugin/nats/client/NatsSubscriptionConstructorInterceptor.java
diff --git a/apm-sniffer/apm-sdk-plugin/nats-2.14.x-2.15.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/nats/client/SubscriptionNextMsgInterceptor.java b/apm-sniffer/apm-sdk-plugin/nats-2.14.x-2.16.5-plugin/src/main/java/org/apache/skywalking/apm/plugin/nats/client/SubscriptionNextMsgInterceptor.java
similarity index 100%
rename from apm-sniffer/apm-sdk-plugin/nats-2.14.x-2.15.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/nats/client/SubscriptionNextMsgInterceptor.java
rename to apm-sniffer/apm-sdk-plugin/nats-2.14.x-2.16.5-plugin/src/main/java/org/apache/skywalking/apm/plugin/nats/client/SubscriptionNextMsgInterceptor.java
diff --git a/apm-sniffer/apm-sdk-plugin/nats-2.14.x-2.15.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/nats/client/WriterQueueInterceptor.java b/apm-sniffer/apm-sdk-plugin/nats-2.14.x-2.16.5-plugin/src/main/java/org/apache/skywalking/apm/plugin/nats/client/WriterQueueInterceptor.java
similarity index 100%
rename from apm-sniffer/apm-sdk-plugin/nats-2.14.x-2.15.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/nats/client/WriterQueueInterceptor.java
rename to apm-sniffer/apm-sdk-plugin/nats-2.14.x-2.16.5-plugin/src/main/java/org/apache/skywalking/apm/plugin/nats/client/WriterQueueInterceptor.java
diff --git a/apm-sniffer/apm-sdk-plugin/nats-2.14.x-2.15.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/nats/client/WriterSendMessageBatchInterceptor.java b/apm-sniffer/apm-sdk-plugin/nats-2.14.x-2.16.5-plugin/src/main/java/org/apache/skywalking/apm/plugin/nats/client/WriterSendMessageBatchInterceptor.java
similarity index 100%
rename from apm-sniffer/apm-sdk-plugin/nats-2.14.x-2.15.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/nats/client/WriterSendMessageBatchInterceptor.java
rename to apm-sniffer/apm-sdk-plugin/nats-2.14.x-2.16.5-plugin/src/main/java/org/apache/skywalking/apm/plugin/nats/client/WriterSendMessageBatchInterceptor.java
diff --git a/apm-sniffer/apm-sdk-plugin/nats-2.14.x-2.16.5-plugin/src/main/java/org/apache/skywalking/apm/plugin/nats/client/define/AbstractWitnessInstrumentation.java b/apm-sniffer/apm-sdk-plugin/nats-2.14.x-2.16.5-plugin/src/main/java/org/apache/skywalking/apm/plugin/nats/client/define/AbstractWitnessInstrumentation.java
new file mode 100644
index 0000000000..1acf6e525e
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/nats-2.14.x-2.16.5-plugin/src/main/java/org/apache/skywalking/apm/plugin/nats/client/define/AbstractWitnessInstrumentation.java
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.skywalking.apm.plugin.nats.client.define;
+
+import java.util.Collections;
+import java.util.List;
+import org.apache.skywalking.apm.agent.core.plugin.WitnessMethod;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine;
+
+import static net.bytebuddy.matcher.ElementMatchers.named;
+
+public abstract class AbstractWitnessInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
+
+ /*
+ * Currently, we only support 2.14.x-2.16.5, as there is no proper way and opportunity
+ * to change the message header and re-calculate the message length for 2.16.5+ yet.
+ * This method prevents users from applying this plugin to unsupported versions,
+ * which may cause unknown errors.
+ * For more information: https://github.com/apache/skywalking/discussions/11650
+ */
+ @Override
+ protected List witnessMethods() {
+ return Collections.singletonList(new WitnessMethod(
+ "io.nats.client.impl.NatsMessage",
+ named("calculateIfDirty")
+ ));
+ }
+}
diff --git a/apm-sniffer/apm-sdk-plugin/nats-2.14.x-2.15.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/nats/client/define/NatsConnectionInstrumentation.java b/apm-sniffer/apm-sdk-plugin/nats-2.14.x-2.16.5-plugin/src/main/java/org/apache/skywalking/apm/plugin/nats/client/define/NatsConnectionInstrumentation.java
similarity index 94%
rename from apm-sniffer/apm-sdk-plugin/nats-2.14.x-2.15.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/nats/client/define/NatsConnectionInstrumentation.java
rename to apm-sniffer/apm-sdk-plugin/nats-2.14.x-2.16.5-plugin/src/main/java/org/apache/skywalking/apm/plugin/nats/client/define/NatsConnectionInstrumentation.java
index 1822732b15..9b2d5087d7 100644
--- a/apm-sniffer/apm-sdk-plugin/nats-2.14.x-2.15.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/nats/client/define/NatsConnectionInstrumentation.java
+++ b/apm-sniffer/apm-sdk-plugin/nats-2.14.x-2.16.5-plugin/src/main/java/org/apache/skywalking/apm/plugin/nats/client/define/NatsConnectionInstrumentation.java
@@ -21,14 +21,13 @@
import net.bytebuddy.matcher.ElementMatcher;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
-import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine;
import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
import static net.bytebuddy.matcher.ElementMatchers.named;
import static net.bytebuddy.matcher.ElementMatchers.takesArguments;
import static org.apache.skywalking.apm.agent.core.plugin.match.NameMatch.byName;
-public class NatsConnectionInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
+public class NatsConnectionInstrumentation extends AbstractWitnessInstrumentation {
private static final String ENHANCE_CLASS = "io.nats.client.impl.NatsConnection";
@@ -82,4 +81,4 @@ public boolean isOverrideArgs() {
}
};
}
-}
\ No newline at end of file
+}
diff --git a/apm-sniffer/apm-sdk-plugin/nats-2.14.x-2.15.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/nats/client/define/NatsConnectionWriterInstrumentation.java b/apm-sniffer/apm-sdk-plugin/nats-2.14.x-2.16.5-plugin/src/main/java/org/apache/skywalking/apm/plugin/nats/client/define/NatsConnectionWriterInstrumentation.java
similarity index 95%
rename from apm-sniffer/apm-sdk-plugin/nats-2.14.x-2.15.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/nats/client/define/NatsConnectionWriterInstrumentation.java
rename to apm-sniffer/apm-sdk-plugin/nats-2.14.x-2.16.5-plugin/src/main/java/org/apache/skywalking/apm/plugin/nats/client/define/NatsConnectionWriterInstrumentation.java
index f3a315314f..b6e56ddc4a 100644
--- a/apm-sniffer/apm-sdk-plugin/nats-2.14.x-2.15.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/nats/client/define/NatsConnectionWriterInstrumentation.java
+++ b/apm-sniffer/apm-sdk-plugin/nats-2.14.x-2.16.5-plugin/src/main/java/org/apache/skywalking/apm/plugin/nats/client/define/NatsConnectionWriterInstrumentation.java
@@ -21,14 +21,13 @@
import net.bytebuddy.matcher.ElementMatcher;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
-import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine;
import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
import static net.bytebuddy.matcher.ElementMatchers.named;
import static net.bytebuddy.matcher.ElementMatchers.takesArguments;
import static org.apache.skywalking.apm.agent.core.plugin.match.NameMatch.byName;
-public class NatsConnectionWriterInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
+public class NatsConnectionWriterInstrumentation extends AbstractWitnessInstrumentation {
private static final String ENHANCE_CLASS = "io.nats.client.impl.NatsConnectionWriter";
private static final String PUBLISH_INTERCEPTOR_CLASS_NAME = "org.apache.skywalking.apm.plugin.nats.client.WriterSendMessageBatchInterceptor";
diff --git a/apm-sniffer/apm-sdk-plugin/nats-2.14.x-2.15.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/nats/client/define/NatsJetStreamInstrumentation.java b/apm-sniffer/apm-sdk-plugin/nats-2.14.x-2.16.5-plugin/src/main/java/org/apache/skywalking/apm/plugin/nats/client/define/NatsJetStreamInstrumentation.java
similarity index 94%
rename from apm-sniffer/apm-sdk-plugin/nats-2.14.x-2.15.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/nats/client/define/NatsJetStreamInstrumentation.java
rename to apm-sniffer/apm-sdk-plugin/nats-2.14.x-2.16.5-plugin/src/main/java/org/apache/skywalking/apm/plugin/nats/client/define/NatsJetStreamInstrumentation.java
index a635658c4a..cf940e7e39 100644
--- a/apm-sniffer/apm-sdk-plugin/nats-2.14.x-2.15.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/nats/client/define/NatsJetStreamInstrumentation.java
+++ b/apm-sniffer/apm-sdk-plugin/nats-2.14.x-2.16.5-plugin/src/main/java/org/apache/skywalking/apm/plugin/nats/client/define/NatsJetStreamInstrumentation.java
@@ -21,14 +21,13 @@
import net.bytebuddy.matcher.ElementMatcher;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
-import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine;
import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
import static net.bytebuddy.matcher.ElementMatchers.named;
import static net.bytebuddy.matcher.ElementMatchers.takesArguments;
import static org.apache.skywalking.apm.agent.core.plugin.match.NameMatch.byName;
-public class NatsJetStreamInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
+public class NatsJetStreamInstrumentation extends AbstractWitnessInstrumentation {
private static final String ENHANCE_CLASS = "io.nats.client.impl.NatsJetStream";
private static final String CREATE_SUB_INTERCEPTOR = "org.apache.skywalking.apm.plugin.nats.client.CreateSubInterceptor";
@@ -78,4 +77,4 @@ public boolean isOverrideArgs() {
};
}
-}
\ No newline at end of file
+}
diff --git a/apm-sniffer/apm-sdk-plugin/nats-2.14.x-2.15.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/nats/client/define/NatsMessageInstrumentation.java b/apm-sniffer/apm-sdk-plugin/nats-2.14.x-2.16.5-plugin/src/main/java/org/apache/skywalking/apm/plugin/nats/client/define/NatsMessageInstrumentation.java
similarity index 93%
rename from apm-sniffer/apm-sdk-plugin/nats-2.14.x-2.15.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/nats/client/define/NatsMessageInstrumentation.java
rename to apm-sniffer/apm-sdk-plugin/nats-2.14.x-2.16.5-plugin/src/main/java/org/apache/skywalking/apm/plugin/nats/client/define/NatsMessageInstrumentation.java
index 79d061a396..95d229690b 100644
--- a/apm-sniffer/apm-sdk-plugin/nats-2.14.x-2.15.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/nats/client/define/NatsMessageInstrumentation.java
+++ b/apm-sniffer/apm-sdk-plugin/nats-2.14.x-2.16.5-plugin/src/main/java/org/apache/skywalking/apm/plugin/nats/client/define/NatsMessageInstrumentation.java
@@ -21,7 +21,6 @@
import net.bytebuddy.matcher.ElementMatcher;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
-import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine;
import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
import static net.bytebuddy.matcher.ElementMatchers.named;
@@ -35,7 +34,7 @@
*
* BTW , ACK is done by publishing a message , So we needn't enhance ACK method
*/
-public class NatsMessageInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
+public class NatsMessageInstrumentation extends AbstractWitnessInstrumentation {
private static final String ENHANCE_CLASS = "io.nats.client.impl.NatsMessage";
private static final String PUBLISH_INTERCEPTOR = "org.apache.skywalking.apm.plugin.nats.client.NatsMessageInterceptor";
diff --git a/apm-sniffer/apm-sdk-plugin/nats-2.14.x-2.15.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/nats/client/define/NatsSubscriptionInstrumentation.java b/apm-sniffer/apm-sdk-plugin/nats-2.14.x-2.16.5-plugin/src/main/java/org/apache/skywalking/apm/plugin/nats/client/define/NatsSubscriptionInstrumentation.java
similarity index 93%
rename from apm-sniffer/apm-sdk-plugin/nats-2.14.x-2.15.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/nats/client/define/NatsSubscriptionInstrumentation.java
rename to apm-sniffer/apm-sdk-plugin/nats-2.14.x-2.16.5-plugin/src/main/java/org/apache/skywalking/apm/plugin/nats/client/define/NatsSubscriptionInstrumentation.java
index a04433722a..62bc14b017 100644
--- a/apm-sniffer/apm-sdk-plugin/nats-2.14.x-2.15.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/nats/client/define/NatsSubscriptionInstrumentation.java
+++ b/apm-sniffer/apm-sdk-plugin/nats-2.14.x-2.16.5-plugin/src/main/java/org/apache/skywalking/apm/plugin/nats/client/define/NatsSubscriptionInstrumentation.java
@@ -21,14 +21,13 @@
import net.bytebuddy.matcher.ElementMatcher;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
-import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine;
import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
import static net.bytebuddy.matcher.ElementMatchers.named;
import static net.bytebuddy.matcher.ElementMatchers.takesArguments;
import static org.apache.skywalking.apm.agent.core.plugin.match.NameMatch.byName;
-public class NatsSubscriptionInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
+public class NatsSubscriptionInstrumentation extends AbstractWitnessInstrumentation {
private static final String ENHANCE_CLASS = "io.nats.client.impl.NatsSubscription";
private static final String NEXT_MSG_INTERCEPTOR = "org.apache.skywalking.apm.plugin.nats.client.SubscriptionNextMsgInterceptor";
diff --git a/apm-sniffer/apm-sdk-plugin/nats-2.14.x-2.15.x-plugin/src/main/resources/skywalking-plugin.def b/apm-sniffer/apm-sdk-plugin/nats-2.14.x-2.16.5-plugin/src/main/resources/skywalking-plugin.def
similarity index 72%
rename from apm-sniffer/apm-sdk-plugin/nats-2.14.x-2.15.x-plugin/src/main/resources/skywalking-plugin.def
rename to apm-sniffer/apm-sdk-plugin/nats-2.14.x-2.16.5-plugin/src/main/resources/skywalking-plugin.def
index cc15654fcf..cbbf148d66 100644
--- a/apm-sniffer/apm-sdk-plugin/nats-2.14.x-2.15.x-plugin/src/main/resources/skywalking-plugin.def
+++ b/apm-sniffer/apm-sdk-plugin/nats-2.14.x-2.16.5-plugin/src/main/resources/skywalking-plugin.def
@@ -14,8 +14,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-nats-client-2.14.x-2.15.x=org.apache.skywalking.apm.plugin.nats.client.define.NatsMessageInstrumentation
-nats-client-2.14.x-2.15.x=org.apache.skywalking.apm.plugin.nats.client.define.NatsConnectionInstrumentation
-nats-client-2.14.x-2.15.x=org.apache.skywalking.apm.plugin.nats.client.define.NatsConnectionWriterInstrumentation
-nats-client-2.14.x-2.15.x=org.apache.skywalking.apm.plugin.nats.client.define.NatsSubscriptionInstrumentation
-nats-client-2.14.x-2.15.x=org.apache.skywalking.apm.plugin.nats.client.define.NatsJetStreamInstrumentation
\ No newline at end of file
+nats-client-2.14.x-2.16.5=org.apache.skywalking.apm.plugin.nats.client.define.NatsMessageInstrumentation
+nats-client-2.14.x-2.16.5=org.apache.skywalking.apm.plugin.nats.client.define.NatsConnectionInstrumentation
+nats-client-2.14.x-2.16.5=org.apache.skywalking.apm.plugin.nats.client.define.NatsConnectionWriterInstrumentation
+nats-client-2.14.x-2.16.5=org.apache.skywalking.apm.plugin.nats.client.define.NatsSubscriptionInstrumentation
+nats-client-2.14.x-2.16.5=org.apache.skywalking.apm.plugin.nats.client.define.NatsJetStreamInstrumentation
diff --git a/apm-sniffer/apm-sdk-plugin/neo4j-4.x-plugin/pom.xml b/apm-sniffer/apm-sdk-plugin/neo4j-4.x-plugin/pom.xml
index 8cb025d1be..1bf1de4bfd 100644
--- a/apm-sniffer/apm-sdk-plugin/neo4j-4.x-plugin/pom.xml
+++ b/apm-sniffer/apm-sdk-plugin/neo4j-4.x-plugin/pom.xml
@@ -21,7 +21,7 @@
apm-sdk-plugin
org.apache.skywalking
- 9.3.0-SNAPSHOT
+ 9.7.0-SNAPSHOT
4.0.0
diff --git a/apm-sniffer/apm-sdk-plugin/netty-socketio-plugin/pom.xml b/apm-sniffer/apm-sdk-plugin/netty-socketio-plugin/pom.xml
index bd80a20010..2fc96f1c2f 100644
--- a/apm-sniffer/apm-sdk-plugin/netty-socketio-plugin/pom.xml
+++ b/apm-sniffer/apm-sdk-plugin/netty-socketio-plugin/pom.xml
@@ -21,7 +21,7 @@
apm-sdk-plugin
org.apache.skywalking
- 9.3.0-SNAPSHOT
+ 9.7.0-SNAPSHOT
4.0.0
diff --git a/apm-sniffer/apm-sdk-plugin/nutz-plugins/http-1.x-plugin/pom.xml b/apm-sniffer/apm-sdk-plugin/nutz-plugins/http-1.x-plugin/pom.xml
index da79858c39..3f2b4d0b67 100644
--- a/apm-sniffer/apm-sdk-plugin/nutz-plugins/http-1.x-plugin/pom.xml
+++ b/apm-sniffer/apm-sdk-plugin/nutz-plugins/http-1.x-plugin/pom.xml
@@ -20,7 +20,7 @@
nutz-plugins
org.apache.skywalking
- 9.3.0-SNAPSHOT
+ 9.7.0-SNAPSHOT
4.0.0
diff --git a/apm-sniffer/apm-sdk-plugin/nutz-plugins/mvc-annotation-1.x-plugin/pom.xml b/apm-sniffer/apm-sdk-plugin/nutz-plugins/mvc-annotation-1.x-plugin/pom.xml
index b9ba31e760..cd772375c6 100644
--- a/apm-sniffer/apm-sdk-plugin/nutz-plugins/mvc-annotation-1.x-plugin/pom.xml
+++ b/apm-sniffer/apm-sdk-plugin/nutz-plugins/mvc-annotation-1.x-plugin/pom.xml
@@ -20,7 +20,7 @@
nutz-plugins
org.apache.skywalking
- 9.3.0-SNAPSHOT
+ 9.7.0-SNAPSHOT
4.0.0
diff --git a/apm-sniffer/apm-sdk-plugin/nutz-plugins/pom.xml b/apm-sniffer/apm-sdk-plugin/nutz-plugins/pom.xml
index 669753f580..0b8fe2d545 100644
--- a/apm-sniffer/apm-sdk-plugin/nutz-plugins/pom.xml
+++ b/apm-sniffer/apm-sdk-plugin/nutz-plugins/pom.xml
@@ -23,7 +23,7 @@
org.apache.skywalking
apm-sdk-plugin
- 9.3.0-SNAPSHOT
+ 9.7.0-SNAPSHOT
nutz-plugins
@@ -39,7 +39,6 @@
UTF-8
- /..
diff --git a/apm-sniffer/apm-sdk-plugin/okhttp-2.x-plugin/pom.xml b/apm-sniffer/apm-sdk-plugin/okhttp-2.x-plugin/pom.xml
index 770d413b09..14d05d0135 100644
--- a/apm-sniffer/apm-sdk-plugin/okhttp-2.x-plugin/pom.xml
+++ b/apm-sniffer/apm-sdk-plugin/okhttp-2.x-plugin/pom.xml
@@ -21,7 +21,7 @@
apm-sdk-plugin
org.apache.skywalking
- 9.3.0-SNAPSHOT
+ 9.7.0-SNAPSHOT
4.0.0
diff --git a/apm-sniffer/apm-sdk-plugin/okhttp-3.x-plugin/pom.xml b/apm-sniffer/apm-sdk-plugin/okhttp-3.x-plugin/pom.xml
index eca6ff770b..b25f764a6e 100644
--- a/apm-sniffer/apm-sdk-plugin/okhttp-3.x-plugin/pom.xml
+++ b/apm-sniffer/apm-sdk-plugin/okhttp-3.x-plugin/pom.xml
@@ -21,7 +21,7 @@
org.apache.skywalking
apm-sdk-plugin
- 9.3.0-SNAPSHOT
+ 9.7.0-SNAPSHOT
4.0.0
diff --git a/apm-sniffer/apm-sdk-plugin/okhttp-4.x-plugin/pom.xml b/apm-sniffer/apm-sdk-plugin/okhttp-4.x-plugin/pom.xml
index ce9ce36b53..ce5434d9cb 100644
--- a/apm-sniffer/apm-sdk-plugin/okhttp-4.x-plugin/pom.xml
+++ b/apm-sniffer/apm-sdk-plugin/okhttp-4.x-plugin/pom.xml
@@ -21,7 +21,7 @@
org.apache.skywalking
apm-sdk-plugin
- 9.3.0-SNAPSHOT
+ 9.7.0-SNAPSHOT
4.0.0
diff --git a/apm-sniffer/apm-sdk-plugin/okhttp-common/pom.xml b/apm-sniffer/apm-sdk-plugin/okhttp-common/pom.xml
index 3881fd2396..68437b314a 100644
--- a/apm-sniffer/apm-sdk-plugin/okhttp-common/pom.xml
+++ b/apm-sniffer/apm-sdk-plugin/okhttp-common/pom.xml
@@ -21,7 +21,7 @@
apm-sdk-plugin
org.apache.skywalking
- 9.3.0-SNAPSHOT
+ 9.7.0-SNAPSHOT
4.0.0
diff --git a/apm-sniffer/apm-sdk-plugin/play-2.x-plugin/pom.xml b/apm-sniffer/apm-sdk-plugin/play-2.x-plugin/pom.xml
index e5ce15cff8..5c74e133d8 100644
--- a/apm-sniffer/apm-sdk-plugin/play-2.x-plugin/pom.xml
+++ b/apm-sniffer/apm-sdk-plugin/play-2.x-plugin/pom.xml
@@ -22,7 +22,7 @@
apm-sdk-plugin
org.apache.skywalking
- 9.3.0-SNAPSHOT
+ 9.7.0-SNAPSHOT
apm-play-2.x-plugin
diff --git a/apm-sniffer/apm-sdk-plugin/pom.xml b/apm-sniffer/apm-sdk-plugin/pom.xml
index bf07afa7a6..8bc2e1faaa 100644
--- a/apm-sniffer/apm-sdk-plugin/pom.xml
+++ b/apm-sniffer/apm-sdk-plugin/pom.xml
@@ -23,26 +23,28 @@
org.apache.skywalking
java-agent-sniffer
- 9.3.0-SNAPSHOT
+ 9.7.0-SNAPSHOT
apm-sdk-plugin
dubbo-plugin
jdbc-commons
+ servlet-commons
httpClient-4.x-plugin
redisson-3.x-plugin
- tomcat-7.x-8.x-plugin
- tomcat-10x-plugin
+ tomcat-plugin
motan-plugin
mongodb-3.x-plugin
mongodb-4.x-plugin
+ mongodb-5.x-plugin
feign-default-http-9.x-plugin
okhttp-3.x-plugin
okhttp-4.x-plugin
okhttp-common
spring-plugins
struts2-2.x-plugin
+ struts2-7.x-plugin
nutz-plugins
jetty-plugin
spymemcached-2.x-plugin
@@ -70,6 +72,7 @@
elasticsearch-5.x-plugin
elasticsearch-6.x-plugin
elasticsearch-7.x-plugin
+ elasticsearch-java-plugin
undertow-plugins
rabbitmq-plugin
dubbo-conflict-patch
@@ -87,11 +90,12 @@
netty-socketio-plugin
httpclient-3.x-plugin
play-2.x-plugin
- lettuce-5.x-plugin
+ lettuce-plugins
avro-plugin
finagle-6.25.x-plugin
quasar-plugin
mariadb-2.x-plugin
+ mariadb-3.x-plugin
influxdb-2.x-plugin
baidu-brpc-plugin
baidu-brpc-3.x-plugin
@@ -123,7 +127,7 @@
guava-eventbus-plugin
hutool-plugins
micronaut-plugins
- nats-2.14.x-2.15.x-plugin
+ nats-2.14.x-2.16.5-plugin
jedis-plugins
apm-armeria-plugins
jetty-thread-pool-plugin
@@ -136,6 +140,8 @@
aerospike-plugin
rocketMQ-client-java-5.x-plugin
activemq-artemis-jakarta-client-2.x-plugin
+ c3p0-0.9.x-plugin
+ solon-2.x-plugin
pom
@@ -144,13 +150,10 @@
UTF-8
-
net.bytebuddy
${shade.package}.${shade.net.bytebuddy.source}
- ${project.build.directory}${sdk.plugin.related.dir}/../../../../skywalking-agent
-
- ${agent.package.dest.dir}/plugins
+ ${maven.multiModuleProjectDirectory}/skywalking-agent/plugins
1.0b3
1.8.1
@@ -166,7 +169,6 @@
net.bytebuddy
byte-buddy
- ${bytebuddy.version}
provided
diff --git a/apm-sniffer/apm-sdk-plugin/postgresql-8.x-plugin/pom.xml b/apm-sniffer/apm-sdk-plugin/postgresql-8.x-plugin/pom.xml
index 46da28a309..181a48d08c 100755
--- a/apm-sniffer/apm-sdk-plugin/postgresql-8.x-plugin/pom.xml
+++ b/apm-sniffer/apm-sdk-plugin/postgresql-8.x-plugin/pom.xml
@@ -20,7 +20,7 @@
apm-sdk-plugin
org.apache.skywalking
- 9.3.0-SNAPSHOT
+ 9.7.0-SNAPSHOT
4.0.0
diff --git a/apm-sniffer/apm-sdk-plugin/pulsar-2.2-2.7-plugin/pom.xml b/apm-sniffer/apm-sdk-plugin/pulsar-2.2-2.7-plugin/pom.xml
index 27dbb81b6a..862269d01e 100644
--- a/apm-sniffer/apm-sdk-plugin/pulsar-2.2-2.7-plugin/pom.xml
+++ b/apm-sniffer/apm-sdk-plugin/pulsar-2.2-2.7-plugin/pom.xml
@@ -21,7 +21,7 @@
apm-sdk-plugin
org.apache.skywalking
- 9.3.0-SNAPSHOT
+ 9.7.0-SNAPSHOT
4.0.0
diff --git a/apm-sniffer/apm-sdk-plugin/pulsar-2.8.x-plugin/pom.xml b/apm-sniffer/apm-sdk-plugin/pulsar-2.8.x-plugin/pom.xml
index 7f219a6086..c464911398 100644
--- a/apm-sniffer/apm-sdk-plugin/pulsar-2.8.x-plugin/pom.xml
+++ b/apm-sniffer/apm-sdk-plugin/pulsar-2.8.x-plugin/pom.xml
@@ -21,7 +21,7 @@
apm-sdk-plugin
org.apache.skywalking
- 9.3.0-SNAPSHOT
+ 9.7.0-SNAPSHOT
4.0.0
diff --git a/apm-sniffer/apm-sdk-plugin/pulsar-common/pom.xml b/apm-sniffer/apm-sdk-plugin/pulsar-common/pom.xml
index ab1a87f751..9679ea88fb 100644
--- a/apm-sniffer/apm-sdk-plugin/pulsar-common/pom.xml
+++ b/apm-sniffer/apm-sdk-plugin/pulsar-common/pom.xml
@@ -21,7 +21,7 @@
apm-sdk-plugin
org.apache.skywalking
- 9.3.0-SNAPSHOT
+ 9.7.0-SNAPSHOT
4.0.0
diff --git a/apm-sniffer/apm-sdk-plugin/quasar-plugin/pom.xml b/apm-sniffer/apm-sdk-plugin/quasar-plugin/pom.xml
index a0a5219174..a980a658d8 100644
--- a/apm-sniffer/apm-sdk-plugin/quasar-plugin/pom.xml
+++ b/apm-sniffer/apm-sdk-plugin/quasar-plugin/pom.xml
@@ -22,7 +22,7 @@
org.apache.skywalking
apm-sdk-plugin
- 9.3.0-SNAPSHOT
+ 9.7.0-SNAPSHOT
apm-quasar-plugin
diff --git a/apm-sniffer/apm-sdk-plugin/rabbitmq-plugin/pom.xml b/apm-sniffer/apm-sdk-plugin/rabbitmq-plugin/pom.xml
index a4ffebf7d3..492b479b07 100644
--- a/apm-sniffer/apm-sdk-plugin/rabbitmq-plugin/pom.xml
+++ b/apm-sniffer/apm-sdk-plugin/rabbitmq-plugin/pom.xml
@@ -21,7 +21,7 @@
apm-sdk-plugin
org.apache.skywalking
- 9.3.0-SNAPSHOT
+ 9.7.0-SNAPSHOT
4.0.0
diff --git a/apm-sniffer/apm-sdk-plugin/rabbitmq-plugin/src/main/java/org/apache/skywalking/apm/plugin/rabbitmq/RabbitMQConsumerInterceptor.java b/apm-sniffer/apm-sdk-plugin/rabbitmq-plugin/src/main/java/org/apache/skywalking/apm/plugin/rabbitmq/RabbitMQConsumerInterceptor.java
index 50240c9729..3ac0caf121 100644
--- a/apm-sniffer/apm-sdk-plugin/rabbitmq-plugin/src/main/java/org/apache/skywalking/apm/plugin/rabbitmq/RabbitMQConsumerInterceptor.java
+++ b/apm-sniffer/apm-sdk-plugin/rabbitmq-plugin/src/main/java/org/apache/skywalking/apm/plugin/rabbitmq/RabbitMQConsumerInterceptor.java
@@ -26,10 +26,19 @@
public class RabbitMQConsumerInterceptor implements InstanceMethodsAroundInterceptor {
+ public static final String SMLC_INTERNAL_CONSUMER = "org.springframework.amqp.rabbit.listener.BlockingQueueConsumer$InternalConsumer";
+ public static final String DMLC_INTERNAL_CONSUMER = "org.springframework.amqp.rabbit.listener.DirectMessageListenerContainer$SimpleConsumer";
+
@Override
public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes,
MethodInterceptResult result) throws Throwable {
Consumer consumer = (Consumer) allArguments[6];
+ if (consumer != null) {
+ String className = consumer.getClass().getName();
+ if (SMLC_INTERNAL_CONSUMER.equals(className) || DMLC_INTERNAL_CONSUMER.equals(className)) {
+ return;
+ }
+ }
allArguments[6] = new TracerConsumer(consumer, (String) objInst.getSkyWalkingDynamicField());
}
diff --git a/apm-sniffer/apm-sdk-plugin/rabbitmq-plugin/src/main/java/org/apache/skywalking/apm/plugin/rabbitmq/TracerConsumer.java b/apm-sniffer/apm-sdk-plugin/rabbitmq-plugin/src/main/java/org/apache/skywalking/apm/plugin/rabbitmq/TracerConsumer.java
index bb6f134fca..c3ae14470e 100644
--- a/apm-sniffer/apm-sdk-plugin/rabbitmq-plugin/src/main/java/org/apache/skywalking/apm/plugin/rabbitmq/TracerConsumer.java
+++ b/apm-sniffer/apm-sdk-plugin/rabbitmq-plugin/src/main/java/org/apache/skywalking/apm/plugin/rabbitmq/TracerConsumer.java
@@ -50,7 +50,7 @@ public void handleConsumeOk(final String consumerTag) {
@Override
public void handleCancelOk(final String consumerTag) {
- this.delegate.handleRecoverOk(consumerTag);
+ this.delegate.handleCancelOk(consumerTag);
}
@Override
diff --git a/apm-sniffer/apm-sdk-plugin/redisson-3.x-plugin/pom.xml b/apm-sniffer/apm-sdk-plugin/redisson-3.x-plugin/pom.xml
index 2e0d14219d..7ba9d05be3 100644
--- a/apm-sniffer/apm-sdk-plugin/redisson-3.x-plugin/pom.xml
+++ b/apm-sniffer/apm-sdk-plugin/redisson-3.x-plugin/pom.xml
@@ -22,7 +22,7 @@
org.apache.skywalking
apm-sdk-plugin
- 9.3.0-SNAPSHOT
+ 9.7.0-SNAPSHOT
apm-redisson-3.x-plugin
@@ -31,7 +31,7 @@
redisson-3.x-plugin
http://maven.apache.org
- 3.6.0
+ 3.20.0
diff --git a/apm-sniffer/apm-sdk-plugin/redisson-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/redisson/v3/ConnectionManagerInterceptor.java b/apm-sniffer/apm-sdk-plugin/redisson-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/redisson/v3/ConnectionManagerInterceptor.java
index d4b352deea..8cdb79b9ff 100644
--- a/apm-sniffer/apm-sdk-plugin/redisson-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/redisson/v3/ConnectionManagerInterceptor.java
+++ b/apm-sniffer/apm-sdk-plugin/redisson-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/redisson/v3/ConnectionManagerInterceptor.java
@@ -18,6 +18,7 @@
package org.apache.skywalking.apm.plugin.redisson.v3;
+import java.util.Objects;
import org.apache.skywalking.apm.agent.core.context.util.PeerFormat;
import org.apache.skywalking.apm.agent.core.logging.api.ILog;
import org.apache.skywalking.apm.agent.core.logging.api.LogManager;
@@ -26,11 +27,12 @@
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
import org.apache.skywalking.apm.plugin.redisson.v3.util.ClassUtil;
import org.redisson.config.Config;
-import org.redisson.connection.ConnectionManager;
import java.lang.reflect.Method;
import java.net.URI;
import java.util.Collection;
+import org.redisson.connection.MasterSlaveConnectionManager;
+import org.redisson.connection.ServiceManager;
public class ConnectionManagerInterceptor implements InstanceMethodsAroundInterceptor {
@@ -45,14 +47,19 @@ public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allAr
public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes,
Object ret) throws Throwable {
try {
- ConnectionManager connectionManager = (ConnectionManager) objInst;
- Config config = connectionManager.getCfg();
-
- Object singleServerConfig = ClassUtil.getObjectField(config, "singleServerConfig");
- Object sentinelServersConfig = ClassUtil.getObjectField(config, "sentinelServersConfig");
- Object masterSlaveServersConfig = ClassUtil.getObjectField(config, "masterSlaveServersConfig");
- Object clusterServersConfig = ClassUtil.getObjectField(config, "clusterServersConfig");
- Object replicatedServersConfig = ClassUtil.getObjectField(config, "replicatedServersConfig");
+ Config config = getConfig(objInst);
+ Object singleServerConfig = null;
+ Object sentinelServersConfig = null;
+ Object masterSlaveServersConfig = null;
+ Object clusterServersConfig = null;
+ Object replicatedServersConfig = null;
+ if (Objects.nonNull(config)) {
+ singleServerConfig = ClassUtil.getObjectField(config, "singleServerConfig");
+ sentinelServersConfig = ClassUtil.getObjectField(config, "sentinelServersConfig");
+ masterSlaveServersConfig = ClassUtil.getObjectField(config, "masterSlaveServersConfig");
+ clusterServersConfig = ClassUtil.getObjectField(config, "clusterServersConfig");
+ replicatedServersConfig = ClassUtil.getObjectField(config, "replicatedServersConfig");
+ }
StringBuilder peer = new StringBuilder();
EnhancedInstance retInst = (EnhancedInstance) ret;
@@ -70,7 +77,7 @@ public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allA
}
if (masterSlaveServersConfig != null) {
Object masterAddress = ClassUtil.getObjectField(masterSlaveServersConfig, "masterAddress");
- peer.append(getPeer(masterAddress));
+ peer.append(getPeer(masterAddress)).append(";");
appendAddresses(peer, (Collection) ClassUtil.getObjectField(masterSlaveServersConfig, "slaveAddresses"));
retInst.setSkyWalkingDynamicField(PeerFormat.shorten(peer.toString()));
return ret;
@@ -118,6 +125,22 @@ static String getPeer(Object obj) {
}
}
+ private Config getConfig(EnhancedInstance objInst) {
+ Config config = null;
+ MasterSlaveConnectionManager connectionManager = (MasterSlaveConnectionManager) objInst;
+ try {
+ config = (Config) ClassUtil.getObjectField(connectionManager, "cfg");
+ } catch (NoSuchFieldException | IllegalAccessException ignore) {
+ try {
+ ServiceManager serviceManager = (ServiceManager) ClassUtil.getObjectField(
+ connectionManager, "serviceManager");
+ config = serviceManager.getCfg();
+ } catch (NoSuchFieldException | IllegalAccessException ignore2) {
+ }
+ }
+ return config;
+ }
+
@Override
public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments,
Class>[] argumentsTypes, Throwable t) {
diff --git a/apm-sniffer/apm-sdk-plugin/redisson-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/redisson/v3/RedisConnectionMethodInterceptor.java b/apm-sniffer/apm-sdk-plugin/redisson-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/redisson/v3/RedisConnectionMethodInterceptor.java
index 60956c7a64..d475382c8f 100644
--- a/apm-sniffer/apm-sdk-plugin/redisson-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/redisson/v3/RedisConnectionMethodInterceptor.java
+++ b/apm-sniffer/apm-sdk-plugin/redisson-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/redisson/v3/RedisConnectionMethodInterceptor.java
@@ -19,6 +19,9 @@
package org.apache.skywalking.apm.plugin.redisson.v3;
import io.netty.channel.Channel;
+
+import java.util.Objects;
+import java.util.stream.Collectors;
import org.apache.skywalking.apm.agent.core.context.ContextManager;
import org.apache.skywalking.apm.agent.core.context.tag.Tags;
import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan;
@@ -27,8 +30,8 @@
import org.apache.skywalking.apm.agent.core.logging.api.LogManager;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceConstructorInterceptor;
-import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
-import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.v2.InstanceMethodsAroundInterceptorV2;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.v2.MethodInvocationContext;
import org.apache.skywalking.apm.network.trace.component.ComponentsDefine;
import org.apache.skywalking.apm.plugin.redisson.v3.util.ClassUtil;
import org.apache.skywalking.apm.util.StringUtil;
@@ -41,17 +44,17 @@
import java.net.InetSocketAddress;
import java.util.Optional;
-public class RedisConnectionMethodInterceptor implements InstanceMethodsAroundInterceptor, InstanceConstructorInterceptor {
+public class RedisConnectionMethodInterceptor implements InstanceMethodsAroundInterceptorV2, InstanceConstructorInterceptor {
private static final ILog LOGGER = LogManager.getLogger(RedisConnectionMethodInterceptor.class);
private static final String ABBR = "...";
private static final String QUESTION_MARK = "?";
private static final String DELIMITER_SPACE = " ";
+ public static final Object STOP_SPAN_FLAG = new Object();
@Override
- public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes,
- MethodInterceptResult result) throws Throwable {
+ public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes, MethodInvocationContext context) throws Throwable {
String peer = (String) objInst.getSkyWalkingDynamicField();
RedisConnection connection = (RedisConnection) objInst;
@@ -66,14 +69,22 @@ public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allAr
if (allArguments[0] instanceof CommandsData) {
operationName = operationName + "BATCH_EXECUTE";
command = "BATCH_EXECUTE";
+ if (RedissonPluginConfig.Plugin.Redisson.SHOW_BATCH_COMMANDS) {
+ command += ":" + showBatchCommands((CommandsData) allArguments[0]);
+ }
} else if (allArguments[0] instanceof CommandData) {
CommandData commandData = (CommandData) allArguments[0];
command = commandData.getCommand().getName();
- operationName = operationName + command;
- arguments = commandData.getParams();
+ if ("PING".equals(command) && !RedissonPluginConfig.Plugin.Redisson.SHOW_PING_COMMAND) {
+ return;
+ } else {
+ operationName = operationName + command;
+ arguments = commandData.getParams();
+ }
}
AbstractSpan span = ContextManager.createExitSpan(operationName, peer);
+ context.setContext(STOP_SPAN_FLAG);
span.setComponent(ComponentsDefine.REDISSON);
Tags.CACHE_TYPE.set(span, "Redis");
Tags.CACHE_INSTANCE.set(span, dbInstance);
@@ -85,17 +96,19 @@ public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allAr
}
@Override
- public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes,
- Object ret) throws Throwable {
- ContextManager.stopSpan();
+ public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes, Object ret, MethodInvocationContext context) throws Throwable {
+ if (Objects.nonNull(context.getContext())) {
+ ContextManager.stopSpan();
+ }
return ret;
}
@Override
- public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments,
- Class>[] argumentsTypes, Throwable t) {
- AbstractSpan span = ContextManager.activeSpan();
- span.log(t);
+ public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes, Throwable t, MethodInvocationContext context) {
+ if (Objects.nonNull(context.getContext())) {
+ AbstractSpan span = ContextManager.activeSpan();
+ span.log(t);
+ }
}
@Override
@@ -143,4 +156,11 @@ private Optional parseOperation(String cmd) {
}
return Optional.empty();
}
+
+ private String showBatchCommands(CommandsData commandsData) {
+ return commandsData.getCommands()
+ .stream()
+ .map(data -> data.getCommand().getName())
+ .collect(Collectors.joining(";"));
+ }
}
diff --git a/apm-sniffer/apm-sdk-plugin/redisson-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/redisson/v3/RedissonPluginConfig.java b/apm-sniffer/apm-sdk-plugin/redisson-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/redisson/v3/RedissonPluginConfig.java
index 52dedcb10a..aeb0a5f270 100644
--- a/apm-sniffer/apm-sdk-plugin/redisson-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/redisson/v3/RedissonPluginConfig.java
+++ b/apm-sniffer/apm-sdk-plugin/redisson-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/redisson/v3/RedissonPluginConfig.java
@@ -40,6 +40,14 @@ public static class Redisson {
* Set a negative number to save specified length of parameter string to the tag.
*/
public static int REDIS_PARAMETER_MAX_LENGTH = 128;
+ /**
+ * If set to true, the PING command would be collected.
+ */
+ public static boolean SHOW_PING_COMMAND = false;
+ /**
+ * If set to true, the detail of the Redis batch commands would be collected.
+ */
+ public static boolean SHOW_BATCH_COMMANDS = false;
/**
* Operation represent a cache span is "write" or "read" action , and "op"(operation) is tagged with key "cache.op" usually
diff --git a/apm-sniffer/apm-sdk-plugin/redisson-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/redisson/v3/define/RedisConnectionInstrumentation.java b/apm-sniffer/apm-sdk-plugin/redisson-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/redisson/v3/define/RedisConnectionInstrumentation.java
index 84bc82535f..34678af6b7 100644
--- a/apm-sniffer/apm-sdk-plugin/redisson-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/redisson/v3/define/RedisConnectionInstrumentation.java
+++ b/apm-sniffer/apm-sdk-plugin/redisson-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/redisson/v3/define/RedisConnectionInstrumentation.java
@@ -21,15 +21,15 @@
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.matcher.ElementMatcher;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
-import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
-import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.v2.ClassInstanceMethodsEnhancePluginDefineV2;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.v2.InstanceMethodsInterceptV2Point;
import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
import static net.bytebuddy.matcher.ElementMatchers.named;
import static org.apache.skywalking.apm.agent.core.plugin.bytebuddy.ArgumentTypeNameMatch.takesArgumentWithType;
import static org.apache.skywalking.apm.agent.core.plugin.match.NameMatch.byName;
-public class RedisConnectionInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
+public class RedisConnectionInstrumentation extends ClassInstanceMethodsEnhancePluginDefineV2 {
private static final String ENHANCE_CLASS = "org.redisson.client.RedisConnection";
@@ -53,16 +53,16 @@ public String getConstructorInterceptor() {
}
@Override
- public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
- return new InstanceMethodsInterceptPoint[] {
- new InstanceMethodsInterceptPoint() {
+ public InstanceMethodsInterceptV2Point[] getInstanceMethodsInterceptV2Points() {
+ return new InstanceMethodsInterceptV2Point[] {
+ new InstanceMethodsInterceptV2Point() {
@Override
public ElementMatcher getMethodsMatcher() {
return named("send");
}
@Override
- public String getMethodsInterceptor() {
+ public String getMethodsInterceptorV2() {
return REDISSON_METHOD_INTERCEPTOR_CLASS;
}
diff --git a/apm-sniffer/apm-sdk-plugin/resteasy-plugin/pom.xml b/apm-sniffer/apm-sdk-plugin/resteasy-plugin/pom.xml
index aca4e0a2e2..4f661c38ba 100644
--- a/apm-sniffer/apm-sdk-plugin/resteasy-plugin/pom.xml
+++ b/apm-sniffer/apm-sdk-plugin/resteasy-plugin/pom.xml
@@ -21,7 +21,7 @@
org.apache.skywalking
apm-sdk-plugin
- 9.3.0-SNAPSHOT
+ 9.7.0-SNAPSHOT
resteasy-plugin
@@ -38,6 +38,5 @@
UTF-8
- /..
\ No newline at end of file
diff --git a/apm-sniffer/apm-sdk-plugin/resteasy-plugin/resteasy-server-3.x-plugin/pom.xml b/apm-sniffer/apm-sdk-plugin/resteasy-plugin/resteasy-server-3.x-plugin/pom.xml
index 7f911f2507..83b9d357cc 100644
--- a/apm-sniffer/apm-sdk-plugin/resteasy-plugin/resteasy-server-3.x-plugin/pom.xml
+++ b/apm-sniffer/apm-sdk-plugin/resteasy-plugin/resteasy-server-3.x-plugin/pom.xml
@@ -21,7 +21,7 @@
resteasy-plugin
org.apache.skywalking
- 9.3.0-SNAPSHOT
+ 9.7.0-SNAPSHOT
resteasy-server-3.x-plugin
diff --git a/apm-sniffer/apm-sdk-plugin/resteasy-plugin/resteasy-server-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/resteasy/v3/server/define/SynchronousDispatcherInstrumentation.java b/apm-sniffer/apm-sdk-plugin/resteasy-plugin/resteasy-server-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/resteasy/v3/server/define/SynchronousDispatcherInstrumentation.java
index aaade19398..77093e85a8 100644
--- a/apm-sniffer/apm-sdk-plugin/resteasy-plugin/resteasy-server-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/resteasy/v3/server/define/SynchronousDispatcherInstrumentation.java
+++ b/apm-sniffer/apm-sdk-plugin/resteasy-plugin/resteasy-server-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/resteasy/v3/server/define/SynchronousDispatcherInstrumentation.java
@@ -83,4 +83,9 @@ public boolean isOverrideArgs() {
protected ClassMatch enhanceClass() {
return NameMatch.byName(ENHANCE_CLASS);
}
+
+ @Override
+ protected String[] witnessClasses() {
+ return new String[]{"org.jboss.resteasy.core.Dispatcher"};
+ }
}
diff --git a/apm-sniffer/apm-sdk-plugin/resteasy-plugin/resteasy-server-4.x-plugin/pom.xml b/apm-sniffer/apm-sdk-plugin/resteasy-plugin/resteasy-server-4.x-plugin/pom.xml
index 4590d8e2ec..63eb0c4826 100644
--- a/apm-sniffer/apm-sdk-plugin/resteasy-plugin/resteasy-server-4.x-plugin/pom.xml
+++ b/apm-sniffer/apm-sdk-plugin/resteasy-plugin/resteasy-server-4.x-plugin/pom.xml
@@ -21,7 +21,7 @@
resteasy-plugin
org.apache.skywalking
- 9.3.0-SNAPSHOT
+ 9.7.0-SNAPSHOT
resteasy-server-4.x-plugin
diff --git a/apm-sniffer/apm-sdk-plugin/resteasy-plugin/resteasy-server-4.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/resteasy/v4/server/define/SynchronousDispatcherInstrumentation.java b/apm-sniffer/apm-sdk-plugin/resteasy-plugin/resteasy-server-4.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/resteasy/v4/server/define/SynchronousDispatcherInstrumentation.java
index 245994dc69..206af100d8 100644
--- a/apm-sniffer/apm-sdk-plugin/resteasy-plugin/resteasy-server-4.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/resteasy/v4/server/define/SynchronousDispatcherInstrumentation.java
+++ b/apm-sniffer/apm-sdk-plugin/resteasy-plugin/resteasy-server-4.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/resteasy/v4/server/define/SynchronousDispatcherInstrumentation.java
@@ -20,13 +20,18 @@
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.matcher.ElementMatcher;
+import org.apache.skywalking.apm.agent.core.plugin.WitnessMethod;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine;
import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
import org.apache.skywalking.apm.agent.core.plugin.match.NameMatch;
+import java.util.Collections;
+import java.util.List;
+
import static net.bytebuddy.matcher.ElementMatchers.named;
+import static net.bytebuddy.matcher.ElementMatchers.returns;
import static net.bytebuddy.matcher.ElementMatchers.takesArguments;
public class SynchronousDispatcherInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
@@ -83,4 +88,17 @@ public boolean isOverrideArgs() {
protected ClassMatch enhanceClass() {
return NameMatch.byName(ENHANCE_CLASS);
}
+
+ @Override
+ protected String[] witnessClasses() {
+ return new String[]{"org.jboss.resteasy.core.InternalDispatcher"};
+ }
+
+ @Override
+ protected List witnessMethods() {
+ return Collections.singletonList(new WitnessMethod(
+ "org.jboss.resteasy.spi.Dispatcher",
+ named("internalInvocation").and(returns(named("javax.ws.rs.core.Response")))
+ ));
+ }
}
diff --git a/apm-sniffer/apm-sdk-plugin/resteasy-plugin/resteasy-server-6.x-plugin/pom.xml b/apm-sniffer/apm-sdk-plugin/resteasy-plugin/resteasy-server-6.x-plugin/pom.xml
index 1b91053387..f20ab70b3e 100644
--- a/apm-sniffer/apm-sdk-plugin/resteasy-plugin/resteasy-server-6.x-plugin/pom.xml
+++ b/apm-sniffer/apm-sdk-plugin/resteasy-plugin/resteasy-server-6.x-plugin/pom.xml
@@ -21,7 +21,7 @@
resteasy-plugin
org.apache.skywalking
- 9.3.0-SNAPSHOT
+ 9.7.0-SNAPSHOT
resteasy-server-6.x-plugin
diff --git a/apm-sniffer/apm-sdk-plugin/resteasy-plugin/resteasy-server-6.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/resteasy/v6/server/define/SynchronousDispatcherInstrumentation.java b/apm-sniffer/apm-sdk-plugin/resteasy-plugin/resteasy-server-6.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/resteasy/v6/server/define/SynchronousDispatcherInstrumentation.java
index c4a472487c..d38fb5775d 100644
--- a/apm-sniffer/apm-sdk-plugin/resteasy-plugin/resteasy-server-6.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/resteasy/v6/server/define/SynchronousDispatcherInstrumentation.java
+++ b/apm-sniffer/apm-sdk-plugin/resteasy-plugin/resteasy-server-6.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/resteasy/v6/server/define/SynchronousDispatcherInstrumentation.java
@@ -20,13 +20,18 @@
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.matcher.ElementMatcher;
+import org.apache.skywalking.apm.agent.core.plugin.WitnessMethod;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine;
import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
import org.apache.skywalking.apm.agent.core.plugin.match.NameMatch;
+import java.util.Collections;
+import java.util.List;
+
import static net.bytebuddy.matcher.ElementMatchers.named;
+import static net.bytebuddy.matcher.ElementMatchers.returns;
import static net.bytebuddy.matcher.ElementMatchers.takesArguments;
public class SynchronousDispatcherInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
@@ -83,4 +88,17 @@ public boolean isOverrideArgs() {
protected ClassMatch enhanceClass() {
return NameMatch.byName(ENHANCE_CLASS);
}
+
+ @Override
+ protected String[] witnessClasses() {
+ return new String[]{"org.jboss.resteasy.core.InternalDispatcher"};
+ }
+
+ @Override
+ protected List witnessMethods() {
+ return Collections.singletonList(new WitnessMethod(
+ "org.jboss.resteasy.spi.Dispatcher",
+ named("internalInvocation").and(returns(named("jakarta.ws.rs.core.Response")))
+ ));
+ }
}
diff --git a/apm-sniffer/apm-sdk-plugin/rocketMQ-3.x-plugin/pom.xml b/apm-sniffer/apm-sdk-plugin/rocketMQ-3.x-plugin/pom.xml
index 72feb352bf..5a7c711dd2 100644
--- a/apm-sniffer/apm-sdk-plugin/rocketMQ-3.x-plugin/pom.xml
+++ b/apm-sniffer/apm-sdk-plugin/rocketMQ-3.x-plugin/pom.xml
@@ -21,7 +21,7 @@
apm-sdk-plugin
org.apache.skywalking
- 9.3.0-SNAPSHOT
+ 9.7.0-SNAPSHOT
4.0.0
diff --git a/apm-sniffer/apm-sdk-plugin/rocketMQ-3.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/rocketMQ/v3/OnExceptionInterceptorTest.java b/apm-sniffer/apm-sdk-plugin/rocketMQ-3.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/rocketMQ/v3/OnExceptionInterceptorTest.java
index 59bf780148..6b5ba982f8 100644
--- a/apm-sniffer/apm-sdk-plugin/rocketMQ-3.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/rocketMQ/v3/OnExceptionInterceptorTest.java
+++ b/apm-sniffer/apm-sdk-plugin/rocketMQ-3.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/rocketMQ/v3/OnExceptionInterceptorTest.java
@@ -23,6 +23,7 @@
import static org.mockito.Mockito.when;
import java.util.List;
import org.apache.skywalking.apm.agent.core.context.ContextSnapshot;
+import org.apache.skywalking.apm.agent.core.context.MockContextSnapshot;
import org.apache.skywalking.apm.agent.core.context.trace.AbstractTracingSpan;
import org.apache.skywalking.apm.agent.core.context.trace.TraceSegment;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
@@ -55,7 +56,6 @@ public class OnExceptionInterceptorTest {
@Rule
public MockitoRule rule = MockitoJUnit.rule();
- @Mock
private ContextSnapshot contextSnapshot;
private SendCallBackEnhanceInfo enhanceInfo;
@@ -65,6 +65,7 @@ public class OnExceptionInterceptorTest {
@Before
public void setUp() {
exceptionInterceptor = new OnExceptionInterceptor();
+ contextSnapshot = MockContextSnapshot.INSTANCE.mockContextSnapshot();
enhanceInfo = new SendCallBackEnhanceInfo("test", contextSnapshot);
when(enhancedInstance.getSkyWalkingDynamicField()).thenReturn(enhanceInfo);
diff --git a/apm-sniffer/apm-sdk-plugin/rocketMQ-3.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/rocketMQ/v3/OnSuccessInterceptorTest.java b/apm-sniffer/apm-sdk-plugin/rocketMQ-3.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/rocketMQ/v3/OnSuccessInterceptorTest.java
index 0927f8a793..77c69a01e6 100644
--- a/apm-sniffer/apm-sdk-plugin/rocketMQ-3.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/rocketMQ/v3/OnSuccessInterceptorTest.java
+++ b/apm-sniffer/apm-sdk-plugin/rocketMQ-3.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/rocketMQ/v3/OnSuccessInterceptorTest.java
@@ -23,6 +23,7 @@
import static org.mockito.Mockito.when;
import java.util.List;
import org.apache.skywalking.apm.agent.core.context.ContextSnapshot;
+import org.apache.skywalking.apm.agent.core.context.MockContextSnapshot;
import org.apache.skywalking.apm.agent.core.context.trace.AbstractTracingSpan;
import org.apache.skywalking.apm.agent.core.context.trace.TraceSegment;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
@@ -57,7 +58,6 @@ public class OnSuccessInterceptorTest {
@Rule
public MockitoRule rule = MockitoJUnit.rule();
- @Mock
private ContextSnapshot contextSnapshot;
@Mock
private SendResult sendResult;
@@ -70,6 +70,7 @@ public class OnSuccessInterceptorTest {
@Before
public void setUp() {
successInterceptor = new OnSuccessInterceptor();
+ contextSnapshot = MockContextSnapshot.INSTANCE.mockContextSnapshot();
enhanceInfo = new SendCallBackEnhanceInfo("test", contextSnapshot);
when(enhancedInstance.getSkyWalkingDynamicField()).thenReturn(enhanceInfo);
diff --git a/apm-sniffer/apm-sdk-plugin/rocketMQ-4.x-plugin/pom.xml b/apm-sniffer/apm-sdk-plugin/rocketMQ-4.x-plugin/pom.xml
index 7b3c637a92..a30e1b09e0 100644
--- a/apm-sniffer/apm-sdk-plugin/rocketMQ-4.x-plugin/pom.xml
+++ b/apm-sniffer/apm-sdk-plugin/rocketMQ-4.x-plugin/pom.xml
@@ -21,7 +21,7 @@
apm-sdk-plugin
org.apache.skywalking
- 9.3.0-SNAPSHOT
+ 9.7.0-SNAPSHOT
4.0.0
diff --git a/apm-sniffer/apm-sdk-plugin/rocketMQ-4.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/rocketMQ/v4/OnExceptionInterceptorTest.java b/apm-sniffer/apm-sdk-plugin/rocketMQ-4.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/rocketMQ/v4/OnExceptionInterceptorTest.java
index 169c3b59bb..3bc9436b1d 100644
--- a/apm-sniffer/apm-sdk-plugin/rocketMQ-4.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/rocketMQ/v4/OnExceptionInterceptorTest.java
+++ b/apm-sniffer/apm-sdk-plugin/rocketMQ-4.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/rocketMQ/v4/OnExceptionInterceptorTest.java
@@ -23,6 +23,7 @@
import static org.mockito.Mockito.when;
import java.util.List;
import org.apache.skywalking.apm.agent.core.context.ContextSnapshot;
+import org.apache.skywalking.apm.agent.core.context.MockContextSnapshot;
import org.apache.skywalking.apm.agent.core.context.trace.AbstractTracingSpan;
import org.apache.skywalking.apm.agent.core.context.trace.TraceSegment;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
@@ -55,7 +56,6 @@ public class OnExceptionInterceptorTest {
@Rule
public MockitoRule rule = MockitoJUnit.rule();
- @Mock
private ContextSnapshot contextSnapshot;
private SendCallBackEnhanceInfo enhanceInfo;
@@ -69,6 +69,7 @@ public void setUp() {
@Test
public void testOnException() throws Throwable {
+ contextSnapshot = MockContextSnapshot.INSTANCE.mockContextSnapshot();
enhanceInfo = new SendCallBackEnhanceInfo("test", contextSnapshot);
when(enhancedInstance.getSkyWalkingDynamicField()).thenReturn(enhanceInfo);
diff --git a/apm-sniffer/apm-sdk-plugin/rocketMQ-4.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/rocketMQ/v4/OnSuccessInterceptorTest.java b/apm-sniffer/apm-sdk-plugin/rocketMQ-4.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/rocketMQ/v4/OnSuccessInterceptorTest.java
index d432daafd8..40c718d9b3 100644
--- a/apm-sniffer/apm-sdk-plugin/rocketMQ-4.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/rocketMQ/v4/OnSuccessInterceptorTest.java
+++ b/apm-sniffer/apm-sdk-plugin/rocketMQ-4.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/rocketMQ/v4/OnSuccessInterceptorTest.java
@@ -25,6 +25,7 @@
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.client.producer.SendStatus;
import org.apache.skywalking.apm.agent.core.context.ContextSnapshot;
+import org.apache.skywalking.apm.agent.core.context.MockContextSnapshot;
import org.apache.skywalking.apm.agent.core.context.trace.AbstractTracingSpan;
import org.apache.skywalking.apm.agent.core.context.trace.TraceSegment;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
@@ -57,7 +58,6 @@ public class OnSuccessInterceptorTest {
@Rule
public MockitoRule rule = MockitoJUnit.rule();
- @Mock
private ContextSnapshot contextSnapshot;
@Mock
private SendResult sendResult;
@@ -70,6 +70,7 @@ public class OnSuccessInterceptorTest {
@Before
public void setUp() {
successInterceptor = new OnSuccessInterceptor();
+ contextSnapshot = MockContextSnapshot.INSTANCE.mockContextSnapshot();
enhanceInfo = new SendCallBackEnhanceInfo("test", contextSnapshot);
when(enhancedInstance.getSkyWalkingDynamicField()).thenReturn(enhanceInfo);
diff --git a/apm-sniffer/apm-sdk-plugin/rocketMQ-5.x-plugin/pom.xml b/apm-sniffer/apm-sdk-plugin/rocketMQ-5.x-plugin/pom.xml
index 5669605bb4..62c1fbb3e3 100644
--- a/apm-sniffer/apm-sdk-plugin/rocketMQ-5.x-plugin/pom.xml
+++ b/apm-sniffer/apm-sdk-plugin/rocketMQ-5.x-plugin/pom.xml
@@ -21,7 +21,7 @@
apm-sdk-plugin
org.apache.skywalking
- 9.3.0-SNAPSHOT
+ 9.7.0-SNAPSHOT
4.0.0
diff --git a/apm-sniffer/apm-sdk-plugin/rocketMQ-client-java-5.x-plugin/pom.xml b/apm-sniffer/apm-sdk-plugin/rocketMQ-client-java-5.x-plugin/pom.xml
index c48f2da760..e4dc8d8988 100644
--- a/apm-sniffer/apm-sdk-plugin/rocketMQ-client-java-5.x-plugin/pom.xml
+++ b/apm-sniffer/apm-sdk-plugin/rocketMQ-client-java-5.x-plugin/pom.xml
@@ -21,7 +21,7 @@
apm-sdk-plugin
org.apache.skywalking
- 9.3.0-SNAPSHOT
+ 9.7.0-SNAPSHOT
4.0.0
diff --git a/apm-sniffer/apm-sdk-plugin/servicecomb-plugin/pom.xml b/apm-sniffer/apm-sdk-plugin/servicecomb-plugin/pom.xml
index 9a64259d48..06f9d58672 100644
--- a/apm-sniffer/apm-sdk-plugin/servicecomb-plugin/pom.xml
+++ b/apm-sniffer/apm-sdk-plugin/servicecomb-plugin/pom.xml
@@ -21,7 +21,7 @@
apm-sdk-plugin
org.apache.skywalking
- 9.3.0-SNAPSHOT
+ 9.7.0-SNAPSHOT
4.0.0
@@ -37,6 +37,5 @@
UTF-8
- /..
diff --git a/apm-sniffer/apm-sdk-plugin/servicecomb-plugin/servicecomb-java-chassis-2.x-plugin/pom.xml b/apm-sniffer/apm-sdk-plugin/servicecomb-plugin/servicecomb-java-chassis-2.x-plugin/pom.xml
index 71b5934e03..6c26908ce4 100644
--- a/apm-sniffer/apm-sdk-plugin/servicecomb-plugin/servicecomb-java-chassis-2.x-plugin/pom.xml
+++ b/apm-sniffer/apm-sdk-plugin/servicecomb-plugin/servicecomb-java-chassis-2.x-plugin/pom.xml
@@ -21,7 +21,7 @@
servicecomb-plugin
org.apache.skywalking
- 9.3.0-SNAPSHOT
+ 9.7.0-SNAPSHOT
4.0.0
diff --git a/apm-sniffer/apm-sdk-plugin/servlet-commons/pom.xml b/apm-sniffer/apm-sdk-plugin/servlet-commons/pom.xml
new file mode 100644
index 0000000000..55fc22ab3e
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/servlet-commons/pom.xml
@@ -0,0 +1,75 @@
+
+
+
+
+ org.apache.skywalking
+ apm-sdk-plugin
+ 9.7.0-SNAPSHOT
+
+ 4.0.0
+
+ apm-servlet-commons
+ jar
+
+ servlet-commons
+
+
+ 3.0.1
+ 6.0.0
+
+
+
+
+
+ javax.servlet
+ javax.servlet-api
+ ${javax-servlet-api.version}
+ provided
+
+
+ jakarta.servlet
+ jakarta.servlet-api
+ ${jakarta-servlet-api.version}
+ provided
+
+
+
+ junit
+ junit
+ test
+
+
+ org.mockito
+ mockito-core
+ test
+
+
+
diff --git a/apm-sniffer/apm-sdk-plugin/servlet-commons/src/main/java/org/apache/skywalking/apm/plugin/servlet/HttpRequestWrapper.java b/apm-sniffer/apm-sdk-plugin/servlet-commons/src/main/java/org/apache/skywalking/apm/plugin/servlet/HttpRequestWrapper.java
new file mode 100644
index 0000000000..eee5d80dfe
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/servlet-commons/src/main/java/org/apache/skywalking/apm/plugin/servlet/HttpRequestWrapper.java
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.servlet;
+
+import java.util.Enumeration;
+import java.util.Map;
+
+/**
+ * A namespace-agnostic view over a servlet HTTP request. It abstracts away the javax.servlet vs
+ * jakarta.servlet split so servlet plugin code can be written once. Obtain instances via
+ * {@link HttpRequestWrappers#wrap(Object)}.
+ *
+ * The method set is the union of what every servlet plugin actually reads; it intentionally does
+ * not expose cookies, sessions, multipart parts or the servlet context, none of which are collected.
+ */
+public interface HttpRequestWrapper {
+
+ String getHeader(String name);
+
+ Enumeration getHeaders(String name);
+
+ String getMethod();
+
+ String getRequestURI();
+
+ StringBuffer getRequestURL();
+
+ String getRemoteHost();
+
+ Map getParameterMap();
+}
diff --git a/apm-sniffer/apm-sdk-plugin/servlet-commons/src/main/java/org/apache/skywalking/apm/plugin/servlet/HttpRequestWrappers.java b/apm-sniffer/apm-sdk-plugin/servlet-commons/src/main/java/org/apache/skywalking/apm/plugin/servlet/HttpRequestWrappers.java
new file mode 100644
index 0000000000..6b35d9925b
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/servlet-commons/src/main/java/org/apache/skywalking/apm/plugin/servlet/HttpRequestWrappers.java
@@ -0,0 +1,158 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.servlet;
+
+import java.util.Enumeration;
+import java.util.Map;
+
+/**
+ * Factory producing a {@link HttpRequestWrapper} from either a {@code javax.servlet} or a
+ * {@code jakarta.servlet} {@code HttpServletRequest}, selected at runtime by the concrete type of
+ * the argument. Both servlet namespaces may be present on the classpath at once (e.g. a Jakarta
+ * application that also carries {@code javax.servlet-api} transitively); the flags below are
+ * computed independently so the live request type — not classpath presence order — decides.
+ *
+ * CLASSLOADING INVARIANT — DO NOT VIOLATE: every {@code javax}/{@code jakarta} reference lives
+ * inside its own nested wrapper class and is reached only through its {@link #IS_JAVAX} /
+ * {@link #IS_JAKARTA} flag guarded by a {@code &&} short-circuit. Never move a servlet type into
+ * {@link #wrap(Object)}'s shared body, never widen a method descriptor of this class to a servlet
+ * type, and never add a typed public {@code wrap(javax...)}/{@code wrap(jakarta...)} overload. Any
+ * of those makes the JVM eagerly resolve an absent namespace and reintroduces
+ * {@code NoClassDefFoundError} in single-namespace applications. Lazy constant-pool resolution
+ * keeps the guarded-but-unexecuted branch safe.
+ */
+public final class HttpRequestWrappers {
+
+ private static final boolean IS_JAVAX = classExists("javax.servlet.http.HttpServletRequest");
+ private static final boolean IS_JAKARTA = classExists("jakarta.servlet.http.HttpServletRequest");
+
+ private HttpRequestWrappers() {
+ }
+
+ /**
+ * @param request any object; typically the servlet request captured by a plugin.
+ * @return a wrapper when {@code request} is a javax or jakarta {@code HttpServletRequest}, or
+ * {@code null} otherwise (e.g. a reactive request or an unrecognized type), letting the caller
+ * fall through to its own non-servlet handling.
+ */
+ public static HttpRequestWrapper wrap(Object request) {
+ if (IS_JAVAX && request instanceof javax.servlet.http.HttpServletRequest) {
+ return new JavaxHttpServletRequest((javax.servlet.http.HttpServletRequest) request);
+ }
+ if (IS_JAKARTA && request instanceof jakarta.servlet.http.HttpServletRequest) {
+ return new JakartaHttpServletRequest((jakarta.servlet.http.HttpServletRequest) request);
+ }
+ return null;
+ }
+
+ private static boolean classExists(String className) {
+ try {
+ Class.forName(className, false, HttpRequestWrappers.class.getClassLoader());
+ return true;
+ } catch (Throwable ignore) {
+ return false;
+ }
+ }
+
+ private static final class JavaxHttpServletRequest implements HttpRequestWrapper {
+ private final javax.servlet.http.HttpServletRequest request;
+
+ private JavaxHttpServletRequest(javax.servlet.http.HttpServletRequest request) {
+ this.request = request;
+ }
+
+ @Override
+ public String getHeader(String name) {
+ return request.getHeader(name);
+ }
+
+ @Override
+ public Enumeration getHeaders(String name) {
+ return request.getHeaders(name);
+ }
+
+ @Override
+ public String getMethod() {
+ return request.getMethod();
+ }
+
+ @Override
+ public String getRequestURI() {
+ return request.getRequestURI();
+ }
+
+ @Override
+ public StringBuffer getRequestURL() {
+ return request.getRequestURL();
+ }
+
+ @Override
+ public String getRemoteHost() {
+ return request.getRemoteHost();
+ }
+
+ @Override
+ public Map getParameterMap() {
+ return request.getParameterMap();
+ }
+ }
+
+ private static final class JakartaHttpServletRequest implements HttpRequestWrapper {
+ private final jakarta.servlet.http.HttpServletRequest request;
+
+ private JakartaHttpServletRequest(jakarta.servlet.http.HttpServletRequest request) {
+ this.request = request;
+ }
+
+ @Override
+ public String getHeader(String name) {
+ return request.getHeader(name);
+ }
+
+ @Override
+ public Enumeration getHeaders(String name) {
+ return request.getHeaders(name);
+ }
+
+ @Override
+ public String getMethod() {
+ return request.getMethod();
+ }
+
+ @Override
+ public String getRequestURI() {
+ return request.getRequestURI();
+ }
+
+ @Override
+ public StringBuffer getRequestURL() {
+ return request.getRequestURL();
+ }
+
+ @Override
+ public String getRemoteHost() {
+ return request.getRemoteHost();
+ }
+
+ @Override
+ public Map getParameterMap() {
+ return request.getParameterMap();
+ }
+ }
+}
diff --git a/apm-sniffer/apm-sdk-plugin/servlet-commons/src/main/java/org/apache/skywalking/apm/plugin/servlet/HttpResponseWrapper.java b/apm-sniffer/apm-sdk-plugin/servlet-commons/src/main/java/org/apache/skywalking/apm/plugin/servlet/HttpResponseWrapper.java
new file mode 100644
index 0000000000..b31ded6456
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/servlet-commons/src/main/java/org/apache/skywalking/apm/plugin/servlet/HttpResponseWrapper.java
@@ -0,0 +1,29 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.servlet;
+
+/**
+ * A namespace-agnostic view over a servlet HTTP response. Obtain instances via
+ * {@link HttpResponseWrappers#wrap(Object)}. Only the response status code is exposed — the sole
+ * response datum servlet plugins collect.
+ */
+public interface HttpResponseWrapper {
+
+ int getStatus();
+}
diff --git a/apm-sniffer/apm-sdk-plugin/servlet-commons/src/main/java/org/apache/skywalking/apm/plugin/servlet/HttpResponseWrappers.java b/apm-sniffer/apm-sdk-plugin/servlet-commons/src/main/java/org/apache/skywalking/apm/plugin/servlet/HttpResponseWrappers.java
new file mode 100644
index 0000000000..4a85c44bac
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/servlet-commons/src/main/java/org/apache/skywalking/apm/plugin/servlet/HttpResponseWrappers.java
@@ -0,0 +1,100 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.servlet;
+
+/**
+ * Factory producing a {@link HttpResponseWrapper} from either a {@code javax.servlet} or a
+ * {@code jakarta.servlet} {@code HttpServletResponse}, selected at runtime.
+ *
+ * Detection deliberately checks that the {@code getStatus()} method exists (added in Servlet 3.0),
+ * not merely that the response class is present, preserving the guard for pre-3.0 containers where
+ * status is unavailable. {@link #servletStatusSupported()} lets a caller gate a non-servlet (e.g.
+ * reactive) status fallback on the same capability.
+ *
+ * The same CLASSLOADING INVARIANT as {@link HttpRequestWrappers} applies: keep every
+ * {@code javax}/{@code jakarta} reference inside its nested class behind its {@code &&}-guarded
+ * flag, and never widen this class's method descriptors to a servlet type.
+ */
+public final class HttpResponseWrappers {
+
+ private static final boolean IS_JAVAX_STATUS = statusMethodExists("javax.servlet.http.HttpServletResponse");
+ private static final boolean IS_JAKARTA_STATUS = statusMethodExists("jakarta.servlet.http.HttpServletResponse");
+
+ private HttpResponseWrappers() {
+ }
+
+ /**
+ * @return {@code true} when a servlet {@code getStatus()} is available in either namespace.
+ */
+ public static boolean servletStatusSupported() {
+ return IS_JAVAX_STATUS || IS_JAKARTA_STATUS;
+ }
+
+ /**
+ * @param response any object; typically the servlet response captured by a plugin.
+ * @return a wrapper when {@code response} is a javax or jakarta {@code HttpServletResponse} that
+ * exposes {@code getStatus()}, or {@code null} otherwise (e.g. a reactive response), letting the
+ * caller fall through to its own handling.
+ */
+ public static HttpResponseWrapper wrap(Object response) {
+ if (IS_JAVAX_STATUS && response instanceof javax.servlet.http.HttpServletResponse) {
+ return new JavaxHttpServletResponse((javax.servlet.http.HttpServletResponse) response);
+ }
+ if (IS_JAKARTA_STATUS && response instanceof jakarta.servlet.http.HttpServletResponse) {
+ return new JakartaHttpServletResponse((jakarta.servlet.http.HttpServletResponse) response);
+ }
+ return null;
+ }
+
+ private static boolean statusMethodExists(String className) {
+ try {
+ Class> clazz = Class.forName(className, false, HttpResponseWrappers.class.getClassLoader());
+ clazz.getMethod("getStatus");
+ return true;
+ } catch (Throwable ignore) {
+ return false;
+ }
+ }
+
+ private static final class JavaxHttpServletResponse implements HttpResponseWrapper {
+ private final javax.servlet.http.HttpServletResponse response;
+
+ private JavaxHttpServletResponse(javax.servlet.http.HttpServletResponse response) {
+ this.response = response;
+ }
+
+ @Override
+ public int getStatus() {
+ return response.getStatus();
+ }
+ }
+
+ private static final class JakartaHttpServletResponse implements HttpResponseWrapper {
+ private final jakarta.servlet.http.HttpServletResponse response;
+
+ private JakartaHttpServletResponse(jakarta.servlet.http.HttpServletResponse response) {
+ this.response = response;
+ }
+
+ @Override
+ public int getStatus() {
+ return response.getStatus();
+ }
+ }
+}
diff --git a/apm-sniffer/apm-sdk-plugin/servlet-commons/src/test/java/org/apache/skywalking/apm/plugin/servlet/HttpRequestWrappersTest.java b/apm-sniffer/apm-sdk-plugin/servlet-commons/src/test/java/org/apache/skywalking/apm/plugin/servlet/HttpRequestWrappersTest.java
new file mode 100644
index 0000000000..87cd1a1a91
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/servlet-commons/src/test/java/org/apache/skywalking/apm/plugin/servlet/HttpRequestWrappersTest.java
@@ -0,0 +1,80 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.servlet;
+
+import java.util.Collections;
+import java.util.Enumeration;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+/**
+ * Both javax.servlet-api and jakarta.servlet-api are on this module's test classpath, reproducing the
+ * exact apache/skywalking#13938 condition: both namespaces present at once. These tests assert that
+ * {@link HttpRequestWrappers#wrap(Object)} selects the wrapper matching the live request type rather
+ * than the classpath-presence order that the old exclusive detection got wrong.
+ */
+public class HttpRequestWrappersTest {
+
+ @Test
+ public void wrapJakartaRequest() {
+ jakarta.servlet.http.HttpServletRequest request = mock(jakarta.servlet.http.HttpServletRequest.class);
+ when(request.getHeader("h")).thenReturn("v");
+ when(request.getMethod()).thenReturn("GET");
+ when(request.getRequestURI()).thenReturn("/uri");
+ when(request.getRequestURL()).thenReturn(new StringBuffer("http://localhost/uri"));
+ when(request.getRemoteHost()).thenReturn("remote");
+ when(request.getHeaders("h")).thenReturn(Collections.enumeration(Collections.singletonList("v")));
+
+ HttpRequestWrapper wrapper = HttpRequestWrappers.wrap(request);
+
+ assertTrue(wrapper instanceof HttpRequestWrapper);
+ assertEquals("v", wrapper.getHeader("h"));
+ assertEquals("GET", wrapper.getMethod());
+ assertEquals("/uri", wrapper.getRequestURI());
+ assertEquals("http://localhost/uri", wrapper.getRequestURL().toString());
+ assertEquals("remote", wrapper.getRemoteHost());
+ Enumeration headers = wrapper.getHeaders("h");
+ assertEquals("v", headers.nextElement());
+ }
+
+ @Test
+ public void wrapJavaxRequest() {
+ javax.servlet.http.HttpServletRequest request = mock(javax.servlet.http.HttpServletRequest.class);
+ when(request.getHeader("h")).thenReturn("v");
+ when(request.getMethod()).thenReturn("POST");
+
+ HttpRequestWrapper wrapper = HttpRequestWrappers.wrap(request);
+
+ assertTrue(wrapper instanceof HttpRequestWrapper);
+ assertEquals("v", wrapper.getHeader("h"));
+ assertEquals("POST", wrapper.getMethod());
+ }
+
+ @Test
+ public void wrapNonServletReturnsNull() {
+ assertNull(HttpRequestWrappers.wrap(new Object()));
+ assertNull(HttpRequestWrappers.wrap("not a request"));
+ assertNull(HttpRequestWrappers.wrap(null));
+ }
+}
diff --git a/apm-sniffer/apm-sdk-plugin/servlet-commons/src/test/java/org/apache/skywalking/apm/plugin/servlet/HttpResponseWrappersTest.java b/apm-sniffer/apm-sdk-plugin/servlet-commons/src/test/java/org/apache/skywalking/apm/plugin/servlet/HttpResponseWrappersTest.java
new file mode 100644
index 0000000000..c470a2c19b
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/servlet-commons/src/test/java/org/apache/skywalking/apm/plugin/servlet/HttpResponseWrappersTest.java
@@ -0,0 +1,65 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.servlet;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class HttpResponseWrappersTest {
+
+ @Test
+ public void wrapJakartaResponse() {
+ jakarta.servlet.http.HttpServletResponse response = mock(jakarta.servlet.http.HttpServletResponse.class);
+ when(response.getStatus()).thenReturn(503);
+
+ HttpResponseWrapper wrapper = HttpResponseWrappers.wrap(response);
+
+ assertNotNull(wrapper);
+ assertEquals(503, wrapper.getStatus());
+ }
+
+ @Test
+ public void wrapJavaxResponse() {
+ javax.servlet.http.HttpServletResponse response = mock(javax.servlet.http.HttpServletResponse.class);
+ when(response.getStatus()).thenReturn(200);
+
+ HttpResponseWrapper wrapper = HttpResponseWrappers.wrap(response);
+
+ assertNotNull(wrapper);
+ assertEquals(200, wrapper.getStatus());
+ }
+
+ @Test
+ public void servletStatusSupportedWhenApiPresent() {
+ // Both servlet APIs (with getStatus, added in Servlet 3.0) are on the test classpath.
+ assertTrue(HttpResponseWrappers.servletStatusSupported());
+ }
+
+ @Test
+ public void wrapNonServletReturnsNull() {
+ assertNull(HttpResponseWrappers.wrap(new Object()));
+ assertNull(HttpResponseWrappers.wrap(null));
+ }
+}
diff --git a/apm-sniffer/apm-sdk-plugin/shardingsphere-plugins/pom.xml b/apm-sniffer/apm-sdk-plugin/shardingsphere-plugins/pom.xml
index 7f124736d2..6d38f040f2 100644
--- a/apm-sniffer/apm-sdk-plugin/shardingsphere-plugins/pom.xml
+++ b/apm-sniffer/apm-sdk-plugin/shardingsphere-plugins/pom.xml
@@ -21,7 +21,7 @@
apm-sdk-plugin
org.apache.skywalking
- 9.3.0-SNAPSHOT
+ 9.7.0-SNAPSHOT
4.0.0
pom
@@ -36,6 +36,5 @@
UTF-8
- /..
diff --git a/apm-sniffer/apm-sdk-plugin/shardingsphere-plugins/sharding-sphere-3.x-plugin/pom.xml b/apm-sniffer/apm-sdk-plugin/shardingsphere-plugins/sharding-sphere-3.x-plugin/pom.xml
index 41131a2b2d..033f5afc04 100644
--- a/apm-sniffer/apm-sdk-plugin/shardingsphere-plugins/sharding-sphere-3.x-plugin/pom.xml
+++ b/apm-sniffer/apm-sdk-plugin/shardingsphere-plugins/sharding-sphere-3.x-plugin/pom.xml
@@ -21,7 +21,7 @@
shardingsphere-plugins
org.apache.skywalking
- 9.3.0-SNAPSHOT
+ 9.7.0-SNAPSHOT
4.0.0
diff --git a/apm-sniffer/apm-sdk-plugin/shardingsphere-plugins/sharding-sphere-4.0.x-plugin/pom.xml b/apm-sniffer/apm-sdk-plugin/shardingsphere-plugins/sharding-sphere-4.0.x-plugin/pom.xml
index 3493c95e09..fa282b6571 100644
--- a/apm-sniffer/apm-sdk-plugin/shardingsphere-plugins/sharding-sphere-4.0.x-plugin/pom.xml
+++ b/apm-sniffer/apm-sdk-plugin/shardingsphere-plugins/sharding-sphere-4.0.x-plugin/pom.xml
@@ -20,7 +20,7 @@
shardingsphere-plugins
org.apache.skywalking
- 9.3.0-SNAPSHOT
+ 9.7.0-SNAPSHOT
4.0.0
diff --git a/apm-sniffer/apm-sdk-plugin/shardingsphere-plugins/sharding-sphere-4.1.0-plugin/pom.xml b/apm-sniffer/apm-sdk-plugin/shardingsphere-plugins/sharding-sphere-4.1.0-plugin/pom.xml
index b86c520ac5..803c61dbeb 100644
--- a/apm-sniffer/apm-sdk-plugin/shardingsphere-plugins/sharding-sphere-4.1.0-plugin/pom.xml
+++ b/apm-sniffer/apm-sdk-plugin/shardingsphere-plugins/sharding-sphere-4.1.0-plugin/pom.xml
@@ -20,7 +20,7 @@
shardingsphere-plugins
org.apache.skywalking
- 9.3.0-SNAPSHOT
+ 9.7.0-SNAPSHOT
4.0.0
diff --git a/apm-sniffer/apm-sdk-plugin/shardingsphere-plugins/sharding-sphere-5.0.0-plugin/pom.xml b/apm-sniffer/apm-sdk-plugin/shardingsphere-plugins/sharding-sphere-5.0.0-plugin/pom.xml
index 176dba0ace..e17d47b46d 100644
--- a/apm-sniffer/apm-sdk-plugin/shardingsphere-plugins/sharding-sphere-5.0.0-plugin/pom.xml
+++ b/apm-sniffer/apm-sdk-plugin/shardingsphere-plugins/sharding-sphere-5.0.0-plugin/pom.xml
@@ -21,7 +21,7 @@
shardingsphere-plugins
org.apache.skywalking
- 9.3.0-SNAPSHOT
+ 9.7.0-SNAPSHOT
4.0.0
diff --git a/apm-sniffer/apm-sdk-plugin/sofarpc-plugin/pom.xml b/apm-sniffer/apm-sdk-plugin/sofarpc-plugin/pom.xml
index 5a6e57662a..21f8795238 100644
--- a/apm-sniffer/apm-sdk-plugin/sofarpc-plugin/pom.xml
+++ b/apm-sniffer/apm-sdk-plugin/sofarpc-plugin/pom.xml
@@ -20,7 +20,7 @@
apm-sdk-plugin
org.apache.skywalking
- 9.3.0-SNAPSHOT
+ 9.7.0-SNAPSHOT
4.0.0
diff --git a/apm-sniffer/apm-sdk-plugin/sofarpc-plugin/src/test/java/org/apache/skywalking/apm/plugin/sofarpc/InvokeCallbackWrapperTest.java b/apm-sniffer/apm-sdk-plugin/sofarpc-plugin/src/test/java/org/apache/skywalking/apm/plugin/sofarpc/InvokeCallbackWrapperTest.java
index ef9c9f3cb0..d05d4026c2 100644
--- a/apm-sniffer/apm-sdk-plugin/sofarpc-plugin/src/test/java/org/apache/skywalking/apm/plugin/sofarpc/InvokeCallbackWrapperTest.java
+++ b/apm-sniffer/apm-sdk-plugin/sofarpc-plugin/src/test/java/org/apache/skywalking/apm/plugin/sofarpc/InvokeCallbackWrapperTest.java
@@ -141,7 +141,10 @@ public void testOnResponse() throws InterruptedException {
TraceSegment traceSegment2 = segmentStorage.getTraceSegments().get(1);
List spans2 = SegmentHelper.getSpans(traceSegment2);
assertThat(spans2.size(), is(1));
- assertEquals("sofarpc", traceSegment2.getRef().getParentEndpoint());
+
+ // Segment order is non-deterministic; find the child segment (the one with a ref)
+ TraceSegment childSegment = traceSegment.getRef() != null ? traceSegment : traceSegment2;
+ assertEquals("sofarpc", childSegment.getRef().getParentEndpoint());
}
@Test
@@ -162,7 +165,11 @@ public void testOnException() throws InterruptedException {
TraceSegment traceSegment2 = segmentStorage.getTraceSegments().get(1);
List spans2 = SegmentHelper.getSpans(traceSegment2);
assertThat(spans2.size(), is(1));
- assertThat(SpanHelper.getLogs(spans2.get(0)).size(), is(1));
+
+ // Segment order is non-deterministic; find the child segment (the one with a ref)
+ TraceSegment childSegment = traceSegment.getRef() != null ? traceSegment : traceSegment2;
+ List childSpans = SegmentHelper.getSpans(childSegment);
+ assertThat(SpanHelper.getLogs(childSpans.get(0)).size(), is(1));
}
diff --git a/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-11.x-plugin/pom.xml b/apm-sniffer/apm-sdk-plugin/solon-2.x-plugin/pom.xml
similarity index 73%
rename from apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-11.x-plugin/pom.xml
rename to apm-sniffer/apm-sdk-plugin/solon-2.x-plugin/pom.xml
index 2f0ae53188..543d27c2c4 100644
--- a/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-11.x-plugin/pom.xml
+++ b/apm-sniffer/apm-sdk-plugin/solon-2.x-plugin/pom.xml
@@ -1,3 +1,4 @@
+
+ 4.0.0
- jetty-plugins
+ apm-sdk-plugin
org.apache.skywalking
- 9.3.0-SNAPSHOT
+ 9.7.0-SNAPSHOT
- 4.0.0
- apm-jetty-server-11.x-plugin
+ solon-2.x-plugin
jar
- jetty-server-11.x-plugin
+ solon-2.x-plugin
http://maven.apache.org
- 11.0.15
+ UTF-8
+ 4.3
+ 4.12
- org.eclipse.jetty
- jetty-server
- ${jetty-server.version}
+ org.noear
+ solon-lib
+ 2.8.3
provided
diff --git a/apm-sniffer/apm-sdk-plugin/solon-2.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/solon/SolonActionExecuteInterceptor.java b/apm-sniffer/apm-sdk-plugin/solon-2.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/solon/SolonActionExecuteInterceptor.java
new file mode 100644
index 0000000000..239e21cb80
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/solon-2.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/solon/SolonActionExecuteInterceptor.java
@@ -0,0 +1,104 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.solon;
+
+import lombok.extern.slf4j.Slf4j;
+import org.apache.skywalking.apm.agent.core.context.CarrierItem;
+import org.apache.skywalking.apm.agent.core.context.ContextCarrier;
+import org.apache.skywalking.apm.agent.core.context.ContextManager;
+import org.apache.skywalking.apm.agent.core.context.tag.Tags;
+import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan;
+import org.apache.skywalking.apm.agent.core.context.trace.SpanLayer;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.v2.InstanceMethodsAroundInterceptorV2;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.v2.MethodInvocationContext;
+import org.apache.skywalking.apm.network.trace.component.ComponentsDefine;
+import org.apache.skywalking.apm.util.StringUtil;
+import org.noear.solon.core.NvMap;
+import org.noear.solon.core.handle.Context;
+
+import java.lang.reflect.Method;
+
+@Slf4j
+public class SolonActionExecuteInterceptor implements InstanceMethodsAroundInterceptorV2 {
+
+ @Override
+ public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes, MethodInvocationContext context) throws Throwable {
+ Context ctx = (Context) allArguments[0];
+ ContextCarrier contextCarrier = new ContextCarrier();
+ CarrierItem next = contextCarrier.items();
+ while (next.hasNext()) {
+ next = next.next();
+ next.setHeadValue(ctx.header(next.getHeadKey()));
+ }
+ String operationName = ctx.method() + ":" + ctx.path();
+ AbstractSpan span = ContextManager.createEntrySpan(operationName, contextCarrier);
+ span.setComponent(ComponentsDefine.SOLON_MVC);
+ SpanLayer.asHttp(span);
+ Tags.URL.set(span, ctx.url());
+ Tags.HTTP.METHOD.set(span, ctx.method());
+ if (SolonPluginConfig.Plugin.Solon.INCLUDE_HTTP_HEADERS != null && !SolonPluginConfig.Plugin.Solon.INCLUDE_HTTP_HEADERS.isEmpty()) {
+ NvMap includeHeaders = new NvMap();
+ for (String header : SolonPluginConfig.Plugin.Solon.INCLUDE_HTTP_HEADERS) {
+ String value = ctx.header(header);
+ if (StringUtil.isNotBlank(value)) {
+ includeHeaders.put(header, value);
+ }
+ }
+ Tags.HTTP.HEADERS.set(span, includeHeaders.toString());
+ }
+ if (SolonPluginConfig.Plugin.Solon.HTTP_BODY_LENGTH_THRESHOLD != 0) {
+ String body = ctx.body();
+ if (StringUtil.isNotBlank(body)) {
+ if (SolonPluginConfig.Plugin.Solon.HTTP_BODY_LENGTH_THRESHOLD > 0 && body.length() > SolonPluginConfig.Plugin.Solon.HTTP_BODY_LENGTH_THRESHOLD) {
+ body = body.substring(0, SolonPluginConfig.Plugin.Solon.HTTP_BODY_LENGTH_THRESHOLD);
+ }
+ Tags.HTTP.BODY.set(span, body);
+ }
+ }
+ if (SolonPluginConfig.Plugin.Solon.HTTP_PARAMS_LENGTH_THRESHOLD != 0) {
+ String param = ctx.paramMap().toString();
+ if (SolonPluginConfig.Plugin.Solon.HTTP_PARAMS_LENGTH_THRESHOLD > 0 && param.length() > SolonPluginConfig.Plugin.Solon.HTTP_PARAMS_LENGTH_THRESHOLD) {
+ param = param.substring(0, SolonPluginConfig.Plugin.Solon.HTTP_PARAMS_LENGTH_THRESHOLD);
+ }
+ Tags.HTTP.PARAMS.set(span, param);
+ }
+ }
+
+ @Override
+ public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes, Object ret, MethodInvocationContext context) {
+ Context ctx = (Context) allArguments[0];
+ Tags.HTTP_RESPONSE_STATUS_CODE.set(ContextManager.activeSpan(), ctx.status());
+ if (ctx.errors != null && context.getContext() == null) {
+ AbstractSpan activeSpan = ContextManager.activeSpan();
+ activeSpan.errorOccurred();
+ activeSpan.log(ctx.errors);
+ }
+ ContextManager.stopSpan();
+ return ret;
+ }
+
+ @Override
+ public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes, Throwable t, MethodInvocationContext context) {
+ AbstractSpan activeSpan = ContextManager.activeSpan();
+ activeSpan.errorOccurred();
+ activeSpan.log(t);
+ context.setContext(true);
+ }
+}
diff --git a/apm-sniffer/apm-sdk-plugin/tomcat-7.x-8.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/tomcat78x/TomcatPluginConfig.java b/apm-sniffer/apm-sdk-plugin/solon-2.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/solon/SolonPluginConfig.java
similarity index 55%
rename from apm-sniffer/apm-sdk-plugin/tomcat-7.x-8.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/tomcat78x/TomcatPluginConfig.java
rename to apm-sniffer/apm-sdk-plugin/solon-2.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/solon/SolonPluginConfig.java
index 4bc6174d73..63a3f3ba98 100644
--- a/apm-sniffer/apm-sdk-plugin/tomcat-7.x-8.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/tomcat78x/TomcatPluginConfig.java
+++ b/apm-sniffer/apm-sdk-plugin/solon-2.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/solon/SolonPluginConfig.java
@@ -16,28 +16,28 @@
*
*/
-package org.apache.skywalking.apm.plugin.tomcat78x;
+package org.apache.skywalking.apm.plugin.solon;
import org.apache.skywalking.apm.agent.core.boot.PluginConfig;
-public class TomcatPluginConfig {
+import java.util.List;
+
+public class SolonPluginConfig {
public static class Plugin {
- @PluginConfig(root = TomcatPluginConfig.class)
- public static class Tomcat {
+ @PluginConfig(root = SolonPluginConfig.class)
+ public static class Solon {
/**
- * This config item controls that whether the Tomcat plugin should collect the parameters of the request.
+ * Define the max length of collected HTTP parameters. The default value(=0) means not collecting.
*/
- public static boolean COLLECT_HTTP_PARAMS = false;
- }
-
- @PluginConfig(root = TomcatPluginConfig.class)
- public static class Http {
+ public static int HTTP_PARAMS_LENGTH_THRESHOLD = 0;
+ /**
+ * Define the max length of collected HTTP body. The default value(=0) means not collecting.
+ */
+ public static int HTTP_BODY_LENGTH_THRESHOLD = 0;
/**
- * When either {@link Tomcat#COLLECT_HTTP_PARAMS} is enabled, how many characters to keep and send to the
- * OAP backend, use negative values to keep and send the complete parameters, NB. this config item is added
- * for the sake of performance
+ * It controls what header data should be collected, values must be in lower case, if empty, no header data will be collected. default is empty.
*/
- public static int HTTP_PARAMS_LENGTH_THRESHOLD = 1024;
+ public static List INCLUDE_HTTP_HEADERS ;
}
}
}
diff --git a/apm-sniffer/apm-sdk-plugin/solon-2.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/solon/define/SolonActionInstrumentation.java b/apm-sniffer/apm-sdk-plugin/solon-2.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/solon/define/SolonActionInstrumentation.java
new file mode 100644
index 0000000000..d41d15ed45
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/solon-2.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/solon/define/SolonActionInstrumentation.java
@@ -0,0 +1,66 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.solon.define;
+
+import net.bytebuddy.description.method.MethodDescription;
+import net.bytebuddy.matcher.ElementMatcher;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.v2.ClassInstanceMethodsEnhancePluginDefineV2;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.v2.InstanceMethodsInterceptV2Point;
+import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
+import org.apache.skywalking.apm.agent.core.plugin.match.NameMatch;
+
+import static net.bytebuddy.matcher.ElementMatchers.named;
+
+public class SolonActionInstrumentation extends ClassInstanceMethodsEnhancePluginDefineV2 {
+
+ private static final String INTERCEPT_CLASS = "org.apache.skywalking.apm.plugin.solon.SolonActionExecuteInterceptor";
+
+ @Override
+ public ClassMatch enhanceClass() {
+ return NameMatch.byName("org.noear.solon.SolonApp");
+ }
+
+ @Override
+ public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
+ return new ConstructorInterceptPoint[0];
+ }
+
+ @Override
+ public InstanceMethodsInterceptV2Point[] getInstanceMethodsInterceptV2Points() {
+ return new InstanceMethodsInterceptV2Point[] {
+ new InstanceMethodsInterceptV2Point() {
+ @Override
+ public ElementMatcher getMethodsMatcher() {
+ return named("tryHandle");
+ }
+
+ @Override
+ public String getMethodsInterceptorV2() {
+ return INTERCEPT_CLASS;
+ }
+
+ @Override
+ public boolean isOverrideArgs() {
+ return true;
+ }
+ }
+ };
+ }
+}
diff --git a/apm-sniffer/apm-sdk-plugin/solon-2.x-plugin/src/main/resources/skywalking-plugin.def b/apm-sniffer/apm-sdk-plugin/solon-2.x-plugin/src/main/resources/skywalking-plugin.def
new file mode 100644
index 0000000000..01e6af6f77
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/solon-2.x-plugin/src/main/resources/skywalking-plugin.def
@@ -0,0 +1,17 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+solon-2.x=org.apache.skywalking.apm.plugin.solon.define.SolonActionInstrumentation
\ No newline at end of file
diff --git a/apm-sniffer/apm-sdk-plugin/solrj-7.x-plugin/pom.xml b/apm-sniffer/apm-sdk-plugin/solrj-7.x-plugin/pom.xml
index 64a46cd10c..2377a233f7 100644
--- a/apm-sniffer/apm-sdk-plugin/solrj-7.x-plugin/pom.xml
+++ b/apm-sniffer/apm-sdk-plugin/solrj-7.x-plugin/pom.xml
@@ -20,7 +20,7 @@
apm-sdk-plugin
org.apache.skywalking
- 9.3.0-SNAPSHOT
+ 9.7.0-SNAPSHOT
4.0.0
diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/async-annotation-plugin/pom.xml b/apm-sniffer/apm-sdk-plugin/spring-plugins/async-annotation-plugin/pom.xml
index c0484a07f1..337a154135 100644
--- a/apm-sniffer/apm-sdk-plugin/spring-plugins/async-annotation-plugin/pom.xml
+++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/async-annotation-plugin/pom.xml
@@ -20,7 +20,7 @@
spring-plugins
org.apache.skywalking
- 9.3.0-SNAPSHOT
+ 9.7.0-SNAPSHOT
4.0.0
diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/concurrent-util-4.x-plugin/pom.xml b/apm-sniffer/apm-sdk-plugin/spring-plugins/concurrent-util-4.x-plugin/pom.xml
index 0c49963f86..fa85530d61 100644
--- a/apm-sniffer/apm-sdk-plugin/spring-plugins/concurrent-util-4.x-plugin/pom.xml
+++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/concurrent-util-4.x-plugin/pom.xml
@@ -20,7 +20,7 @@
spring-plugins
org.apache.skywalking
- 9.3.0-SNAPSHOT
+ 9.7.0-SNAPSHOT
4.0.0
diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/core-patch/pom.xml b/apm-sniffer/apm-sdk-plugin/spring-plugins/core-patch/pom.xml
index 5807a025ba..58e530913a 100644
--- a/apm-sniffer/apm-sdk-plugin/spring-plugins/core-patch/pom.xml
+++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/core-patch/pom.xml
@@ -21,7 +21,7 @@
spring-plugins
org.apache.skywalking
- 9.3.0-SNAPSHOT
+ 9.7.0-SNAPSHOT
4.0.0
diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/core-patch/src/main/java/org/apache/skywalking/apm/plugin/spring/patch/AutoProxyCreatorInterceptor.java b/apm-sniffer/apm-sdk-plugin/spring-plugins/core-patch/src/main/java/org/apache/skywalking/apm/plugin/spring/patch/AutoProxyCreatorInterceptor.java
new file mode 100644
index 0000000000..943ac8983d
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/core-patch/src/main/java/org/apache/skywalking/apm/plugin/spring/patch/AutoProxyCreatorInterceptor.java
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.spring.patch;
+
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
+
+import java.lang.reflect.Method;
+
+/**
+ * AutoProxyCreatorInterceptor determines whether the given interface is {@link EnhancedInstance},
+ * and therefore does not consider it a reasonable proxy interface.
+ */
+public class AutoProxyCreatorInterceptor implements InstanceMethodsAroundInterceptor {
+
+ @Override
+ public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes,
+ MethodInterceptResult result) throws Throwable {
+
+ }
+
+ @Override
+ public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes,
+ Object ret) throws Throwable {
+
+ Class> ifc = (Class>) allArguments[0];
+ return ((boolean) ret) || ifc.getName().equals("org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance");
+ }
+
+ @Override
+ public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments,
+ Class>[] argumentsTypes, Throwable t) {
+
+ }
+
+}
diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/core-patch/src/main/java/org/apache/skywalking/apm/plugin/spring/patch/CreateAopProxyInterceptor.java b/apm-sniffer/apm-sdk-plugin/spring-plugins/core-patch/src/main/java/org/apache/skywalking/apm/plugin/spring/patch/CreateAopProxyInterceptor.java
index 97bab4ad33..6e55d80b1a 100644
--- a/apm-sniffer/apm-sdk-plugin/spring-plugins/core-patch/src/main/java/org/apache/skywalking/apm/plugin/spring/patch/CreateAopProxyInterceptor.java
+++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/core-patch/src/main/java/org/apache/skywalking/apm/plugin/spring/patch/CreateAopProxyInterceptor.java
@@ -18,12 +18,14 @@
package org.apache.skywalking.apm.plugin.spring.patch;
-import java.lang.reflect.Method;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
+import org.springframework.aop.SpringProxy;
import org.springframework.aop.framework.AdvisedSupport;
+import java.lang.reflect.Method;
+
/**
* CreateAopProxyInterceptor check that the bean has been implement {@link EnhancedInstance}.
* if yes, true will be returned.
@@ -32,25 +34,45 @@ public class CreateAopProxyInterceptor implements InstanceMethodsAroundIntercept
@Override
public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes,
- MethodInterceptResult result) throws Throwable {
+ MethodInterceptResult result) throws Throwable {
}
@Override
public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes,
- Object ret) throws Throwable {
+ Object ret) throws Throwable {
AdvisedSupport advisedSupport = (AdvisedSupport) allArguments[0];
- Class targetClass = advisedSupport.getTargetClass();
- if (targetClass != null && EnhancedInstance.class.isAssignableFrom(targetClass)) {
- return true;
+ if (maybeHasUserSuppliedProxyInterfaces(ret)) {
+ Class targetClass = advisedSupport.getTargetClass();
+ if (targetClass != null) {
+ if (onlyImplementsEnhancedInstance(advisedSupport) || onlyImplementsEnhancedInstanceAndSpringProxy(advisedSupport)) {
+ return true;
+ }
+ }
}
return ret;
}
+ private boolean maybeHasUserSuppliedProxyInterfaces(Object ret) {
+ return !(Boolean) ret;
+ }
+
+ private boolean onlyImplementsEnhancedInstanceAndSpringProxy(AdvisedSupport advisedSupport) {
+ Class>[] ifcs = advisedSupport.getProxiedInterfaces();
+ Class targetClass = advisedSupport.getTargetClass();
+ return ifcs.length == 2 && EnhancedInstance.class.isAssignableFrom(targetClass) && SpringProxy.class.isAssignableFrom(targetClass);
+ }
+
+ private boolean onlyImplementsEnhancedInstance(AdvisedSupport advisedSupport) {
+ Class>[] ifcs = advisedSupport.getProxiedInterfaces();
+ Class targetClass = advisedSupport.getTargetClass();
+ return ifcs.length == 1 && EnhancedInstance.class.isAssignableFrom(targetClass);
+ }
+
@Override
public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments,
- Class>[] argumentsTypes, Throwable t) {
+ Class>[] argumentsTypes, Throwable t) {
}
}
diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/core-patch/src/main/java/org/apache/skywalking/apm/plugin/spring/patch/ProxyProcessorSupportInterceptor.java b/apm-sniffer/apm-sdk-plugin/spring-plugins/core-patch/src/main/java/org/apache/skywalking/apm/plugin/spring/patch/ProxyProcessorSupportInterceptor.java
new file mode 100644
index 0000000000..d8840d4ef2
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/core-patch/src/main/java/org/apache/skywalking/apm/plugin/spring/patch/ProxyProcessorSupportInterceptor.java
@@ -0,0 +1,52 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.spring.patch;
+
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
+
+import java.lang.reflect.Method;
+
+/**
+ * ProxyProcessorSupportInterceptor determines whether the given interface is {@link EnhancedInstance},
+ * and therefore does not consider it a reasonable proxy interface.
+ */
+public class ProxyProcessorSupportInterceptor implements InstanceMethodsAroundInterceptor {
+
+ @Override
+ public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes,
+ MethodInterceptResult result) throws Throwable {
+
+ }
+
+ @Override
+ public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes,
+ Object ret) throws Throwable {
+ Class> ifc = (Class>) allArguments[0];
+ return ((boolean) ret) || ifc.getName().equals("org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance");
+ }
+
+ @Override
+ public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments,
+ Class>[] argumentsTypes, Throwable t) {
+
+ }
+
+}
diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/core-patch/src/main/java/org/apache/skywalking/apm/plugin/spring/patch/define/AutoProxyCreatorInstrumentation.java b/apm-sniffer/apm-sdk-plugin/spring-plugins/core-patch/src/main/java/org/apache/skywalking/apm/plugin/spring/patch/define/AutoProxyCreatorInstrumentation.java
new file mode 100644
index 0000000000..26e6147e69
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/core-patch/src/main/java/org/apache/skywalking/apm/plugin/spring/patch/define/AutoProxyCreatorInstrumentation.java
@@ -0,0 +1,78 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.spring.patch.define;
+
+import net.bytebuddy.description.method.MethodDescription;
+import net.bytebuddy.matcher.ElementMatcher;
+import org.apache.skywalking.apm.agent.core.plugin.WitnessMethod;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine;
+import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
+import org.apache.skywalking.apm.agent.core.plugin.match.NameMatch;
+
+import java.util.Collections;
+import java.util.List;
+
+import static net.bytebuddy.matcher.ElementMatchers.named;
+
+public class AutoProxyCreatorInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
+
+ private static final String ENHANCE_CLASS = "org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator";
+ public static final String ENHANCE_METHOD = "isConfigurationCallbackInterface";
+ public static final String INTERCEPT_CLASS = "org.apache.skywalking.apm.plugin.spring.patch.AutoProxyCreatorInterceptor";
+
+ @Override
+ public final ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
+ return new ConstructorInterceptPoint[0];
+ }
+
+ @Override
+ public final InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
+ return new InstanceMethodsInterceptPoint[] {
+ new InstanceMethodsInterceptPoint() {
+ @Override
+ public ElementMatcher getMethodsMatcher() {
+ return named(ENHANCE_METHOD);
+ }
+
+ @Override
+ public String getMethodsInterceptor() {
+ return INTERCEPT_CLASS;
+ }
+
+ @Override
+ public boolean isOverrideArgs() {
+ return false;
+ }
+ }
+ };
+ }
+
+ @Override
+ protected ClassMatch enhanceClass() {
+ return NameMatch.byName(ENHANCE_CLASS);
+ }
+
+ @Override
+ protected List witnessMethods() {
+ return Collections.singletonList(new WitnessMethod(ENHANCE_CLASS, named(ENHANCE_METHOD)));
+ }
+
+}
diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/core-patch/src/main/java/org/apache/skywalking/apm/plugin/spring/patch/define/ProxyProcessorSupportInstrumentation.java b/apm-sniffer/apm-sdk-plugin/spring-plugins/core-patch/src/main/java/org/apache/skywalking/apm/plugin/spring/patch/define/ProxyProcessorSupportInstrumentation.java
new file mode 100644
index 0000000000..78de2969c2
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/core-patch/src/main/java/org/apache/skywalking/apm/plugin/spring/patch/define/ProxyProcessorSupportInstrumentation.java
@@ -0,0 +1,69 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.spring.patch.define;
+
+import net.bytebuddy.description.method.MethodDescription;
+import net.bytebuddy.matcher.ElementMatcher;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine;
+import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
+import org.apache.skywalking.apm.agent.core.plugin.match.NameMatch;
+
+import static net.bytebuddy.matcher.ElementMatchers.named;
+
+public class ProxyProcessorSupportInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
+
+ private static final String ENHANCE_CLASS = "org.springframework.aop.framework.ProxyProcessorSupport";
+ public static final String ENHANCE_METHOD = "isInternalLanguageInterface";
+ public static final String INTERCEPT_CLASS = "org.apache.skywalking.apm.plugin.spring.patch.ProxyProcessorSupportInterceptor";
+
+ @Override
+ public final ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
+ return new ConstructorInterceptPoint[0];
+ }
+
+ @Override
+ public final InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
+ return new InstanceMethodsInterceptPoint[] {
+ new InstanceMethodsInterceptPoint() {
+ @Override
+ public ElementMatcher getMethodsMatcher() {
+ return named(ENHANCE_METHOD);
+ }
+
+ @Override
+ public String getMethodsInterceptor() {
+ return INTERCEPT_CLASS;
+ }
+
+ @Override
+ public boolean isOverrideArgs() {
+ return false;
+ }
+ }
+ };
+ }
+
+ @Override
+ protected ClassMatch enhanceClass() {
+ return NameMatch.byName(ENHANCE_CLASS);
+ }
+
+}
diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/core-patch/src/main/resources/skywalking-plugin.def b/apm-sniffer/apm-sdk-plugin/spring-plugins/core-patch/src/main/resources/skywalking-plugin.def
index e51178b97b..3a21d2b4aa 100644
--- a/apm-sniffer/apm-sdk-plugin/spring-plugins/core-patch/src/main/resources/skywalking-plugin.def
+++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/core-patch/src/main/resources/skywalking-plugin.def
@@ -19,3 +19,5 @@ spring-core-patch=org.apache.skywalking.apm.plugin.spring.patch.define.Autowired
spring-core-patch=org.apache.skywalking.apm.plugin.spring.patch.define.AopExpressionMatchInstrumentation
spring-core-patch=org.apache.skywalking.apm.plugin.spring.patch.define.AspectJExpressionPointCutInstrumentation
spring-core-patch=org.apache.skywalking.apm.plugin.spring.patch.define.BeanWrapperImplInstrumentation
+spring-core-patch=org.apache.skywalking.apm.plugin.spring.patch.define.ProxyProcessorSupportInstrumentation
+spring-core-patch=org.apache.skywalking.apm.plugin.spring.patch.define.AutoProxyCreatorInstrumentation
diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/core-patch/src/test/java/org/apache/skywalking/apm/plugin/spring/patch/CreateAopProxyInterceptorTest.java b/apm-sniffer/apm-sdk-plugin/spring-plugins/core-patch/src/test/java/org/apache/skywalking/apm/plugin/spring/patch/CreateAopProxyInterceptorTest.java
index 12b5c96633..ae513567da 100644
--- a/apm-sniffer/apm-sdk-plugin/spring-plugins/core-patch/src/test/java/org/apache/skywalking/apm/plugin/spring/patch/CreateAopProxyInterceptorTest.java
+++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/core-patch/src/test/java/org/apache/skywalking/apm/plugin/spring/patch/CreateAopProxyInterceptorTest.java
@@ -24,6 +24,7 @@
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
+import org.springframework.aop.SpringProxy;
import org.springframework.aop.framework.AdvisedSupport;
import static org.hamcrest.core.Is.is;
@@ -48,18 +49,69 @@ public void setUp() {
}
@Test
- public void testInterceptNormalObject() throws Throwable {
- doReturn(Object.class).when(advisedSupport).getTargetClass();
+ public void testInterceptClassImplementsNoInterfaces() throws Throwable {
+ // doReturn(Object.class).when(advisedSupport).getTargetClass();
+ // doReturn(Object.class.getInterfaces()).when(advisedSupport).getProxiedInterfaces();
+ assertThat(true, is(interceptor.afterMethod(enhancedInstance, null, new Object[] {advisedSupport}, new Class[] {Object.class}, true)));
+ }
+
+ @Test
+ public void testInterceptClassImplementsUserSuppliedInterface() throws Throwable {
+ doReturn(MockClassImplementsUserSuppliedInterface.class).when(advisedSupport).getTargetClass();
+ doReturn(MockClassImplementsUserSuppliedInterface.class.getInterfaces()).when(advisedSupport).getProxiedInterfaces();
assertThat(false, is(interceptor.afterMethod(enhancedInstance, null, new Object[] {advisedSupport}, new Class[] {Object.class}, false)));
}
@Test
- public void testInterceptEnhanceInstanceObject() throws Throwable {
- doReturn(MockClass.class).when(advisedSupport).getTargetClass();
+ public void testInterceptClassImplementsSpringProxy() throws Throwable {
+ // doReturn(MockClassImplementsSpringProxy.class).when(advisedSupport).getTargetClass();
+ // doReturn(MockClassImplementsSpringProxy.class.getInterfaces()).when(advisedSupport).getProxiedInterfaces();
+ assertThat(true, is(interceptor.afterMethod(enhancedInstance, null, new Object[] {advisedSupport}, new Class[] {Object.class}, true)));
+ }
+
+ @Test
+ public void testInterceptClassImplementsEnhancedInstance() throws Throwable {
+ doReturn(MockClassImplementsEnhancedInstance.class).when(advisedSupport).getTargetClass();
+ doReturn(MockClassImplementsEnhancedInstance.class.getInterfaces()).when(advisedSupport).getProxiedInterfaces();
assertThat(true, is(interceptor.afterMethod(enhancedInstance, null, new Object[] {advisedSupport}, new Class[] {Object.class}, false)));
}
- private class MockClass implements EnhancedInstance {
+ @Test
+ public void testClassImplementsEnhancedInstanceAndUserSuppliedInterface() throws Throwable {
+ doReturn(MockClassImplementsSpringProxyAndUserSuppliedInterface.class).when(advisedSupport).getTargetClass();
+ doReturn(MockClassImplementsSpringProxyAndUserSuppliedInterface.class.getInterfaces()).when(advisedSupport).getProxiedInterfaces();
+ assertThat(false, is(interceptor.afterMethod(enhancedInstance, null, new Object[] {advisedSupport}, new Class[] {Object.class}, false)));
+ }
+
+ @Test
+ public void testInterceptClassImplementsSpringProxyAndEnhancedInstance() throws Throwable {
+ doReturn(MockClassImplementsSpringProxyAndEnhancedInstance.class).when(advisedSupport).getTargetClass();
+ doReturn(MockClassImplementsSpringProxyAndEnhancedInstance.class.getInterfaces()).when(advisedSupport).getProxiedInterfaces();
+ assertThat(true, is(interceptor.afterMethod(enhancedInstance, null, new Object[] {advisedSupport}, new Class[] {Object.class}, false)));
+ }
+
+ @Test
+ public void testInterceptClassImplementsSpringProxyAndUserSuppliedInterface() throws Throwable {
+ doReturn(MockClassImplementsSpringProxyAndUserSuppliedInterface.class).when(advisedSupport).getTargetClass();
+ doReturn(MockClassImplementsSpringProxyAndUserSuppliedInterface.class.getInterfaces()).when(advisedSupport).getProxiedInterfaces();
+ assertThat(false, is(interceptor.afterMethod(enhancedInstance, null, new Object[] {advisedSupport}, new Class[] {Object.class}, false)));
+ }
+
+ @Test
+ public void testInterceptClassImplementsEnhancedInstanceAndUserSuppliedInterface() throws Throwable {
+ doReturn(MockClassImplementsEnhancedInstanceAndUserSuppliedInterface.class).when(advisedSupport).getTargetClass();
+ doReturn(MockClassImplementsEnhancedInstanceAndUserSuppliedInterface.class.getInterfaces()).when(advisedSupport).getProxiedInterfaces();
+ assertThat(false, is(interceptor.afterMethod(enhancedInstance, null, new Object[] {advisedSupport}, new Class[] {Object.class}, false)));
+ }
+
+ @Test
+ public void testInterceptClassImplementsSpringProxyAndEnhancedInstanceAndUserSuppliedInterface() throws Throwable {
+ doReturn(MockClassImplementsSpringProxyAndEnhancedInstanceAndUserSuppliedInterface.class).when(advisedSupport).getTargetClass();
+ doReturn(MockClassImplementsSpringProxyAndEnhancedInstanceAndUserSuppliedInterface.class.getInterfaces()).when(advisedSupport).getProxiedInterfaces();
+ assertThat(false, is(interceptor.afterMethod(enhancedInstance, null, new Object[] {advisedSupport}, new Class[] {Object.class}, false)));
+ }
+
+ private class MockClassImplementsEnhancedInstance implements EnhancedInstance {
@Override
public Object getSkyWalkingDynamicField() {
@@ -72,4 +124,81 @@ public void setSkyWalkingDynamicField(Object value) {
}
}
+ private class MockClassImplementsUserSuppliedInterface implements UserSuppliedInterface {
+
+ @Override
+ public void methodOfUserSuppliedInterface() {
+
+ }
+
+ }
+
+ private class MockClassImplementsSpringProxy implements SpringProxy {
+
+ }
+
+ private class MockClassImplementsSpringProxyAndEnhancedInstance implements EnhancedInstance, SpringProxy {
+
+ @Override
+ public Object getSkyWalkingDynamicField() {
+ return null;
+ }
+
+ @Override
+ public void setSkyWalkingDynamicField(Object value) {
+
+ }
+
+ }
+
+ private class MockClassImplementsEnhancedInstanceAndUserSuppliedInterface implements EnhancedInstance, UserSuppliedInterface {
+
+ @Override
+ public Object getSkyWalkingDynamicField() {
+ return null;
+ }
+
+ @Override
+ public void setSkyWalkingDynamicField(Object value) {
+
+ }
+
+ @Override
+ public void methodOfUserSuppliedInterface() {
+ }
+
+ }
+
+ private class MockClassImplementsSpringProxyAndUserSuppliedInterface implements SpringProxy, UserSuppliedInterface {
+
+ @Override
+ public void methodOfUserSuppliedInterface() {
+ }
+
+ }
+
+ private class MockClassImplementsSpringProxyAndEnhancedInstanceAndUserSuppliedInterface implements EnhancedInstance, SpringProxy, UserSuppliedInterface {
+
+ @Override
+ public Object getSkyWalkingDynamicField() {
+ return null;
+ }
+
+ @Override
+ public void setSkyWalkingDynamicField(Object value) {
+
+ }
+
+ @Override
+ public void methodOfUserSuppliedInterface() {
+ }
+
+ }
+
+ interface UserSuppliedInterface {
+
+ void methodOfUserSuppliedInterface();
+
+ }
+
}
diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-3.x-plugin/pom.xml b/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-3.x-plugin/pom.xml
index dfab514b02..02fa8639d0 100644
--- a/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-3.x-plugin/pom.xml
+++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-3.x-plugin/pom.xml
@@ -20,7 +20,7 @@
spring-plugins
org.apache.skywalking
- 9.3.0-SNAPSHOT
+ 9.7.0-SNAPSHOT
4.0.0
diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-4.x-plugin/pom.xml b/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-4.x-plugin/pom.xml
index 0d6d45e1e4..006febb79f 100644
--- a/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-4.x-plugin/pom.xml
+++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-4.x-plugin/pom.xml
@@ -20,7 +20,7 @@
spring-plugins
org.apache.skywalking
- 9.3.0-SNAPSHOT
+ 9.7.0-SNAPSHOT
4.0.0
@@ -61,5 +61,14 @@
${project.version}
provided
+
+
+ org.apache.skywalking
+ apm-servlet-commons
+ ${project.version}
+ provided
+
diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-5.x-plugin/pom.xml b/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-5.x-plugin/pom.xml
index f74cf3733c..bea4ce00a9 100644
--- a/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-5.x-plugin/pom.xml
+++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-5.x-plugin/pom.xml
@@ -19,7 +19,7 @@
spring-plugins
org.apache.skywalking
- 9.3.0-SNAPSHOT
+ 9.7.0-SNAPSHOT
4.0.0
diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-commons/pom.xml b/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-commons/pom.xml
index eb71af642d..07bb6769f1 100644
--- a/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-commons/pom.xml
+++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-commons/pom.xml
@@ -20,7 +20,7 @@
spring-plugins
org.apache.skywalking
- 9.3.0-SNAPSHOT
+ 9.7.0-SNAPSHOT
4.0.0
@@ -55,16 +55,24 @@
5.2.4.RELEASE
provided
+
- javax.servlet
- javax.servlet-api
- ${javax-servlet-api.version}
+ org.apache.skywalking
+ apm-servlet-commons
+ ${project.version}
provided
- jakarta.servlet
- jakarta.servlet-api
- 6.0.0
+ javax.servlet
+ javax.servlet-api
+ ${javax-servlet-api.version}
provided
diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-commons/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/commons/RequestUtil.java b/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-commons/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/commons/RequestUtil.java
index b278c8f9e2..f6cc0168d8 100644
--- a/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-commons/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/commons/RequestUtil.java
+++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-commons/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/commons/RequestUtil.java
@@ -20,10 +20,10 @@
import org.apache.skywalking.apm.agent.core.context.tag.Tags;
import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan;
import org.apache.skywalking.apm.agent.core.util.CollectionUtil;
+import org.apache.skywalking.apm.plugin.servlet.HttpRequestWrapper;
import org.apache.skywalking.apm.util.StringUtil;
import org.springframework.http.server.reactive.ServerHttpRequest;
-import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
@@ -32,17 +32,7 @@
import java.util.Map;
public class RequestUtil {
- public static void collectHttpParam(HttpServletRequest request, AbstractSpan span) {
- final Map parameterMap = request.getParameterMap();
- if (parameterMap != null && !parameterMap.isEmpty()) {
- String tagValue = CollectionUtil.toString(parameterMap);
- tagValue = SpringMVCPluginConfig.Plugin.Http.HTTP_PARAMS_LENGTH_THRESHOLD > 0 ?
- StringUtil.cut(tagValue, SpringMVCPluginConfig.Plugin.Http.HTTP_PARAMS_LENGTH_THRESHOLD) : tagValue;
- Tags.HTTP.PARAMS.set(span, tagValue);
- }
- }
-
- public static void collectHttpParam(jakarta.servlet.http.HttpServletRequest request, AbstractSpan span) {
+ public static void collectHttpParam(HttpRequestWrapper request, AbstractSpan span) {
final Map parameterMap = request.getParameterMap();
if (parameterMap != null && !parameterMap.isEmpty()) {
String tagValue = CollectionUtil.toString(parameterMap);
@@ -65,26 +55,7 @@ public static void collectHttpParam(ServerHttpRequest request, AbstractSpan span
}
}
- public static void collectHttpHeaders(HttpServletRequest request, AbstractSpan span) {
- final List headersList = new ArrayList<>(SpringMVCPluginConfig.Plugin.Http.INCLUDE_HTTP_HEADERS.size());
- SpringMVCPluginConfig.Plugin.Http.INCLUDE_HTTP_HEADERS.stream()
- .filter(
- headerName -> request.getHeaders(headerName) != null)
- .forEach(headerName -> {
- Enumeration headerValues = request.getHeaders(
- headerName);
- List valueList = Collections.list(
- headerValues);
- if (!CollectionUtil.isEmpty(valueList)) {
- String headerValue = valueList.toString();
- headersList.add(headerName + "=" + headerValue);
- }
- });
-
- collectHttpHeaders(headersList, span);
- }
-
- public static void collectHttpHeaders(jakarta.servlet.http.HttpServletRequest request, AbstractSpan span) {
+ public static void collectHttpHeaders(HttpRequestWrapper request, AbstractSpan span) {
final List headersList = new ArrayList<>(SpringMVCPluginConfig.Plugin.Http.INCLUDE_HTTP_HEADERS.size());
SpringMVCPluginConfig.Plugin.Http.INCLUDE_HTTP_HEADERS.stream()
.filter(
diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-commons/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/commons/interceptor/AbstractMethodInterceptor.java b/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-commons/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/commons/interceptor/AbstractMethodInterceptor.java
index df3aa7583f..8f70a71b3c 100644
--- a/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-commons/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/commons/interceptor/AbstractMethodInterceptor.java
+++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-commons/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/commons/interceptor/AbstractMethodInterceptor.java
@@ -18,6 +18,7 @@
package org.apache.skywalking.apm.plugin.spring.mvc.commons.interceptor;
+import java.lang.reflect.Method;
import org.apache.skywalking.apm.agent.core.context.CarrierItem;
import org.apache.skywalking.apm.agent.core.context.ContextCarrier;
import org.apache.skywalking.apm.agent.core.context.ContextManager;
@@ -33,6 +34,10 @@
import org.apache.skywalking.apm.agent.core.util.CollectionUtil;
import org.apache.skywalking.apm.agent.core.util.MethodUtil;
import org.apache.skywalking.apm.network.trace.component.ComponentsDefine;
+import org.apache.skywalking.apm.plugin.servlet.HttpRequestWrapper;
+import org.apache.skywalking.apm.plugin.servlet.HttpRequestWrappers;
+import org.apache.skywalking.apm.plugin.servlet.HttpResponseWrapper;
+import org.apache.skywalking.apm.plugin.servlet.HttpResponseWrappers;
import org.apache.skywalking.apm.plugin.spring.mvc.commons.EnhanceRequireObjectCache;
import org.apache.skywalking.apm.plugin.spring.mvc.commons.RequestUtil;
import org.apache.skywalking.apm.plugin.spring.mvc.commons.SpringMVCPluginConfig;
@@ -41,10 +46,6 @@
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import java.lang.reflect.Method;
-
import static org.apache.skywalking.apm.plugin.spring.mvc.commons.Constants.CONTROLLER_METHOD_STACK_DEPTH;
import static org.apache.skywalking.apm.plugin.spring.mvc.commons.Constants.FORWARD_REQUEST_FLAG;
import static org.apache.skywalking.apm.plugin.spring.mvc.commons.Constants.REACTIVE_ASYNC_SPAN_IN_RUNTIME_CONTEXT;
@@ -56,37 +57,6 @@
*/
public abstract class AbstractMethodInterceptor implements InstanceMethodsAroundInterceptor {
private static final ILog LOGGER = LogManager.getLogger(AbstractMethodInterceptor.class);
- private static boolean IS_SERVLET_GET_STATUS_METHOD_EXIST;
- private static boolean IS_JAKARTA_SERVLET_GET_STATUS_METHOD_EXIST;
- private static final String SERVLET_RESPONSE_CLASS = "javax.servlet.http.HttpServletResponse";
- private static final String JAKARTA_SERVLET_RESPONSE_CLASS = "jakarta.servlet.http.HttpServletResponse";
- private static final String GET_STATUS_METHOD = "getStatus";
-
- private static boolean IN_SERVLET_CONTAINER;
- private static boolean IS_JAVAX = false;
- private static boolean IS_JAKARTA = false;
-
- static {
- IS_SERVLET_GET_STATUS_METHOD_EXIST = MethodUtil.isMethodExist(
- AbstractMethodInterceptor.class.getClassLoader(), SERVLET_RESPONSE_CLASS, GET_STATUS_METHOD);
- IS_JAKARTA_SERVLET_GET_STATUS_METHOD_EXIST = MethodUtil.isMethodExist(
- AbstractMethodInterceptor.class.getClassLoader(),
- JAKARTA_SERVLET_RESPONSE_CLASS, GET_STATUS_METHOD);
- try {
- Class.forName(SERVLET_RESPONSE_CLASS, true, AbstractMethodInterceptor.class.getClassLoader());
- IN_SERVLET_CONTAINER = true;
- IS_JAVAX = true;
- } catch (Exception ignore) {
- try {
- Class.forName(
- JAKARTA_SERVLET_RESPONSE_CLASS, true, AbstractMethodInterceptor.class.getClassLoader());
- IN_SERVLET_CONTAINER = true;
- IS_JAKARTA = true;
- } catch (Exception ignore2) {
- IN_SERVLET_CONTAINER = false;
- }
- }
- }
public abstract String getRequestURL(Method method);
@@ -111,55 +81,10 @@ public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allAr
if (stackDepth == null) {
final ContextCarrier contextCarrier = new ContextCarrier();
- if (IN_SERVLET_CONTAINER && IS_JAVAX && HttpServletRequest.class.isAssignableFrom(request.getClass())) {
- final HttpServletRequest httpServletRequest = (HttpServletRequest) request;
- CarrierItem next = contextCarrier.items();
- while (next.hasNext()) {
- next = next.next();
- next.setHeadValue(httpServletRequest.getHeader(next.getHeadKey()));
- }
-
- String operationName = this.buildOperationName(method, httpServletRequest.getMethod(),
- (EnhanceRequireObjectCache) objInst.getSkyWalkingDynamicField());
- AbstractSpan span = ContextManager.createEntrySpan(operationName, contextCarrier);
- Tags.URL.set(span, httpServletRequest.getRequestURL().toString());
- Tags.HTTP.METHOD.set(span, httpServletRequest.getMethod());
- span.setComponent(ComponentsDefine.SPRING_MVC_ANNOTATION);
- SpanLayer.asHttp(span);
+ final HttpRequestWrapper httpServletRequest = HttpRequestWrappers.wrap(request);
+ if (httpServletRequest != null) {
+ handleBeforeMethod(objInst, method, httpServletRequest, contextCarrier);
- if (SpringMVCPluginConfig.Plugin.SpringMVC.COLLECT_HTTP_PARAMS) {
- RequestUtil.collectHttpParam(httpServletRequest, span);
- }
-
- if (!CollectionUtil.isEmpty(SpringMVCPluginConfig.Plugin.Http.INCLUDE_HTTP_HEADERS)) {
- RequestUtil.collectHttpHeaders(httpServletRequest, span);
- }
- } else if (IN_SERVLET_CONTAINER && IS_JAKARTA && jakarta.servlet.http.HttpServletRequest.class.isAssignableFrom(request.getClass())) {
- final jakarta.servlet.http.HttpServletRequest httpServletRequest = (jakarta.servlet.http.HttpServletRequest) request;
- CarrierItem next = contextCarrier.items();
- while (next.hasNext()) {
- next = next.next();
- next.setHeadValue(httpServletRequest.getHeader(next.getHeadKey()));
- }
-
- String operationName =
- this.buildOperationName(method, httpServletRequest.getMethod(),
- (EnhanceRequireObjectCache) objInst.getSkyWalkingDynamicField());
- AbstractSpan span =
- ContextManager.createEntrySpan(operationName, contextCarrier);
- Tags.URL.set(span, httpServletRequest.getRequestURL().toString());
- Tags.HTTP.METHOD.set(span, httpServletRequest.getMethod());
- span.setComponent(ComponentsDefine.SPRING_MVC_ANNOTATION);
- SpanLayer.asHttp(span);
-
- if (SpringMVCPluginConfig.Plugin.SpringMVC.COLLECT_HTTP_PARAMS) {
- RequestUtil.collectHttpParam(httpServletRequest, span);
- }
-
- if (!CollectionUtil
- .isEmpty(SpringMVCPluginConfig.Plugin.Http.INCLUDE_HTTP_HEADERS)) {
- RequestUtil.collectHttpHeaders(httpServletRequest, span);
- }
} else if (ServerHttpRequest.class.isAssignableFrom(request.getClass())) {
final ServerHttpRequest serverHttpRequest = (ServerHttpRequest) request;
CarrierItem next = contextCarrier.items();
@@ -168,8 +93,10 @@ public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allAr
next.setHeadValue(serverHttpRequest.getHeaders().getFirst(next.getHeadKey()));
}
- String operationName = this.buildOperationName(method, serverHttpRequest.getMethod().name(),
- (EnhanceRequireObjectCache) objInst.getSkyWalkingDynamicField());
+ String operationName = this.buildOperationName(
+ method, serverHttpRequest.getMethod().name(),
+ (EnhanceRequireObjectCache) objInst.getSkyWalkingDynamicField()
+ );
AbstractSpan span = ContextManager.createEntrySpan(operationName, contextCarrier);
Tags.URL.set(span, serverHttpRequest.getURI().toString());
Tags.HTTP.METHOD.set(span, serverHttpRequest.getMethod().name());
@@ -198,6 +125,31 @@ public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allAr
}
}
+ private void handleBeforeMethod(EnhancedInstance objInst, Method method,
+ HttpRequestWrapper httpServletRequest, ContextCarrier contextCarrier) {
+ CarrierItem next = contextCarrier.items();
+ while (next.hasNext()) {
+ next = next.next();
+ next.setHeadValue(httpServletRequest.getHeader(next.getHeadKey()));
+ }
+
+ String operationName = this.buildOperationName(
+ method, httpServletRequest.getMethod(), (EnhanceRequireObjectCache) objInst.getSkyWalkingDynamicField());
+ AbstractSpan span = ContextManager.createEntrySpan(operationName, contextCarrier);
+ Tags.URL.set(span, httpServletRequest.getRequestURL().toString());
+ Tags.HTTP.METHOD.set(span, httpServletRequest.getMethod());
+ span.setComponent(ComponentsDefine.SPRING_MVC_ANNOTATION);
+ SpanLayer.asHttp(span);
+
+ if (SpringMVCPluginConfig.Plugin.SpringMVC.COLLECT_HTTP_PARAMS) {
+ RequestUtil.collectHttpParam(httpServletRequest, span);
+ }
+
+ if (!CollectionUtil.isEmpty(SpringMVCPluginConfig.Plugin.Http.INCLUDE_HTTP_HEADERS)) {
+ RequestUtil.collectHttpHeaders(httpServletRequest, span);
+ }
+ }
+
@Override
public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes,
Object ret) throws Throwable {
@@ -232,12 +184,11 @@ public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allA
Integer statusCode = null;
- if (IS_SERVLET_GET_STATUS_METHOD_EXIST && HttpServletResponse.class.isAssignableFrom(response.getClass())) {
- statusCode = ((HttpServletResponse) response).getStatus();
- } else if (IS_JAKARTA_SERVLET_GET_STATUS_METHOD_EXIST && jakarta.servlet.http.HttpServletResponse.class.isAssignableFrom(response.getClass())) {
- statusCode = ((jakarta.servlet.http.HttpServletResponse) response).getStatus();
+ final HttpResponseWrapper httpServletResponse = HttpResponseWrappers.wrap(response);
+ if (httpServletResponse != null) {
+ statusCode = httpServletResponse.getStatus();
} else if (ServerHttpResponse.class.isAssignableFrom(response.getClass())) {
- if (IS_SERVLET_GET_STATUS_METHOD_EXIST || IS_JAKARTA_SERVLET_GET_STATUS_METHOD_EXIST) {
+ if (HttpResponseWrappers.servletStatusSupported()) {
statusCode = ((ServerHttpResponse) response).getRawStatusCode();
}
Object context = runtimeContext.get(REACTIVE_ASYNC_SPAN_IN_RUNTIME_CONTEXT);
@@ -261,10 +212,9 @@ public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allA
// Active HTTP parameter collection automatically in the profiling context.
if (!SpringMVCPluginConfig.Plugin.SpringMVC.COLLECT_HTTP_PARAMS && span.isProfiling()) {
- if (IS_JAVAX && HttpServletRequest.class.isAssignableFrom(request.getClass())) {
- RequestUtil.collectHttpParam((HttpServletRequest) request, span);
- } else if (IS_JAKARTA && jakarta.servlet.http.HttpServletRequest.class.isAssignableFrom(request.getClass())) {
- RequestUtil.collectHttpParam((jakarta.servlet.http.HttpServletRequest) request, span);
+ final HttpRequestWrapper httpServletRequest = HttpRequestWrappers.wrap(request);
+ if (httpServletRequest != null) {
+ RequestUtil.collectHttpParam(httpServletRequest, span);
} else if (ServerHttpRequest.class.isAssignableFrom(request.getClass())) {
RequestUtil.collectHttpParam((ServerHttpRequest) request, span);
}
@@ -309,7 +259,7 @@ private String buildOperationName(Method method, String httpMethod, EnhanceRequi
pathMappingCache.addPathMapping(method, requestURL);
requestURL = pathMappingCache.findPathMapping(method);
}
- operationName = String.join(":", httpMethod, requestURL);
+ operationName = String.join(":", httpMethod, requestURL);
}
return operationName;
diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/pom.xml b/apm-sniffer/apm-sdk-plugin/spring-plugins/pom.xml
index 64abfdb7eb..4326ec7354 100644
--- a/apm-sniffer/apm-sdk-plugin/spring-plugins/pom.xml
+++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/pom.xml
@@ -23,7 +23,7 @@
org.apache.skywalking
apm-sdk-plugin
- 9.3.0-SNAPSHOT
+ 9.7.0-SNAPSHOT
spring-plugins
@@ -45,15 +45,16 @@
spring-webflux-5.x-webclient-plugin
spring-webflux-6.x-webclient-plugin
resttemplate-commons
+ spring-ai-1.x-plugin
+ spring-rabbitmq-plugin
pom
- apm-sdk-plugin
+ spring-plugins
http://maven.apache.org
UTF-8
- /..
diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/resttemplate-3.x-plugin/pom.xml b/apm-sniffer/apm-sdk-plugin/spring-plugins/resttemplate-3.x-plugin/pom.xml
index 4814e20078..2dab6a46c9 100644
--- a/apm-sniffer/apm-sdk-plugin/spring-plugins/resttemplate-3.x-plugin/pom.xml
+++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/resttemplate-3.x-plugin/pom.xml
@@ -20,7 +20,7 @@
spring-plugins
org.apache.skywalking
- 9.3.0-SNAPSHOT
+ 9.7.0-SNAPSHOT
4.0.0
diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/resttemplate-4.x-plugin/pom.xml b/apm-sniffer/apm-sdk-plugin/spring-plugins/resttemplate-4.x-plugin/pom.xml
index 08789aa954..966de1995f 100644
--- a/apm-sniffer/apm-sdk-plugin/spring-plugins/resttemplate-4.x-plugin/pom.xml
+++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/resttemplate-4.x-plugin/pom.xml
@@ -20,7 +20,7 @@
spring-plugins
org.apache.skywalking
- 9.3.0-SNAPSHOT
+ 9.7.0-SNAPSHOT
4.0.0
diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/resttemplate-commons/pom.xml b/apm-sniffer/apm-sdk-plugin/spring-plugins/resttemplate-commons/pom.xml
index 4976c79954..19ecc7989c 100644
--- a/apm-sniffer/apm-sdk-plugin/spring-plugins/resttemplate-commons/pom.xml
+++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/resttemplate-commons/pom.xml
@@ -20,7 +20,7 @@
spring-plugins
org.apache.skywalking
- 9.3.0-SNAPSHOT
+ 9.7.0-SNAPSHOT
4.0.0
diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/scheduled-annotation-plugin/pom.xml b/apm-sniffer/apm-sdk-plugin/spring-plugins/scheduled-annotation-plugin/pom.xml
index 23a5790757..c4dfd6d15f 100644
--- a/apm-sniffer/apm-sdk-plugin/spring-plugins/scheduled-annotation-plugin/pom.xml
+++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/scheduled-annotation-plugin/pom.xml
@@ -20,7 +20,7 @@
spring-plugins
org.apache.skywalking
- 9.3.0-SNAPSHOT
+ 9.7.0-SNAPSHOT
4.0.0
diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/scheduled-annotation-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/scheduled/define/ScheduledMethodInterceptorInstrumentation.java b/apm-sniffer/apm-sdk-plugin/spring-plugins/scheduled-annotation-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/scheduled/define/ScheduledMethodInterceptorInstrumentation.java
index 2aacd3720b..44b36778bb 100644
--- a/apm-sniffer/apm-sdk-plugin/spring-plugins/scheduled-annotation-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/scheduled/define/ScheduledMethodInterceptorInstrumentation.java
+++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/scheduled-annotation-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/scheduled/define/ScheduledMethodInterceptorInstrumentation.java
@@ -82,6 +82,19 @@ public ElementMatcher getConstructorMatcher() {
public String getConstructorInterceptor() {
return CONSTRUCTOR_WITH_STRING_INTERCEPTOR_CLASS;
}
+ },
+ new ConstructorInterceptPoint() {
+ @Override
+ public ElementMatcher getConstructorMatcher() {
+ return takesArguments(4)
+ .and(takesArgument(0, Object.class))
+ .and(takesArgument(1, Method.class));
+ }
+
+ @Override
+ public String getConstructorInterceptor() {
+ return CONSTRUCTOR_WITH_METHOD_INTERCEPTOR_CLASS;
+ }
}
};
}
diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/spring-ai-1.x-plugin/pom.xml b/apm-sniffer/apm-sdk-plugin/spring-plugins/spring-ai-1.x-plugin/pom.xml
new file mode 100644
index 0000000000..583ce9c90c
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/spring-ai-1.x-plugin/pom.xml
@@ -0,0 +1,69 @@
+
+
+
+
+
+ spring-plugins
+ org.apache.skywalking
+ 9.7.0-SNAPSHOT
+
+ 4.0.0
+
+ spring-ai-1.x-plugin
+ jar
+
+ spring-ai-1.x-plugin
+ http://maven.apache.org
+
+
+
+
+
+
+
+
+ org.springframework.ai
+ spring-ai-client-chat
+ 1.1.0
+ provided
+
+
+
+ org.springframework.ai
+ spring-ai-vector-store
+ 1.1.0
+ provided
+
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-javadoc-plugin
+
+ false
+
+
+
+
+
\ No newline at end of file
diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/spring-ai-1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/ai/v1/AbstractObservationVectorStoreConstructorInterceptor.java b/apm-sniffer/apm-sdk-plugin/spring-plugins/spring-ai-1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/ai/v1/AbstractObservationVectorStoreConstructorInterceptor.java
new file mode 100644
index 0000000000..faefa999bc
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/spring-ai-1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/ai/v1/AbstractObservationVectorStoreConstructorInterceptor.java
@@ -0,0 +1,48 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.spring.ai.v1;
+
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceConstructorInterceptor;
+import org.apache.skywalking.apm.plugin.spring.ai.v1.common.EmbeddingModelEnhanceContext;
+
+public class AbstractObservationVectorStoreConstructorInterceptor implements InstanceConstructorInterceptor {
+
+ @Override
+ public void onConstruct(EnhancedInstance objInst, Object[] allArguments) {
+ objInst.setSkyWalkingDynamicField(new VectorStoreEnhanceContext(resolveContextFromArgument(allArguments[0])));
+ }
+
+ private EmbeddingModelEnhanceContext resolveContextFromArgument(Object argument) {
+ if (argument instanceof EnhancedInstance) {
+ return getOrCreateContext((EnhancedInstance) argument);
+ }
+ return null;
+ }
+
+ private EmbeddingModelEnhanceContext getOrCreateContext(EnhancedInstance embeddingModel) {
+ Object context = embeddingModel.getSkyWalkingDynamicField();
+ if (context instanceof EmbeddingModelEnhanceContext) {
+ return (EmbeddingModelEnhanceContext) context;
+ }
+ EmbeddingModelEnhanceContext embeddingModelEnhanceContext = new EmbeddingModelEnhanceContext();
+ embeddingModel.setSkyWalkingDynamicField(embeddingModelEnhanceContext);
+ return embeddingModelEnhanceContext;
+ }
+}
diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/spring-ai-1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/ai/v1/AbstractObservationVectorStoreInterceptor.java b/apm-sniffer/apm-sdk-plugin/spring-plugins/spring-ai-1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/ai/v1/AbstractObservationVectorStoreInterceptor.java
new file mode 100644
index 0000000000..473ffb5b95
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/spring-ai-1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/ai/v1/AbstractObservationVectorStoreInterceptor.java
@@ -0,0 +1,171 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.spring.ai.v1;
+
+import org.apache.skywalking.apm.agent.core.context.ContextManager;
+import org.apache.skywalking.apm.agent.core.context.tag.Tags;
+import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan;
+import org.apache.skywalking.apm.agent.core.context.trace.SpanLayer;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
+import org.apache.skywalking.apm.agent.core.util.GsonUtil;
+import org.apache.skywalking.apm.network.trace.component.ComponentsDefine;
+import org.apache.skywalking.apm.plugin.spring.ai.v1.common.ErrorTypeResolver;
+import org.apache.skywalking.apm.plugin.spring.ai.v1.config.SpringAiPluginConfig;
+import org.apache.skywalking.apm.plugin.spring.ai.v1.contant.Constants;
+import org.springframework.ai.document.Document;
+import org.springframework.ai.vectorstore.SearchRequest;
+import org.springframework.ai.vectorstore.observation.AbstractObservationVectorStore;
+import org.springframework.ai.vectorstore.observation.VectorStoreObservationContext;
+import org.springframework.util.StringUtils;
+
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+public class AbstractObservationVectorStoreInterceptor implements InstanceMethodsAroundInterceptor {
+
+ @Override
+ public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes,
+ MethodInterceptResult result) throws Throwable {
+ SearchRequest request = (SearchRequest) allArguments[0];
+ String dataSourceId = objInst.getClass().getSimpleName();
+
+ try {
+ VectorStoreObservationContext context =
+ createObservationContext(objInst, request);
+
+ String resolved =
+ resolveDataSourceId(context, objInst);
+
+ if (StringUtils.hasText(resolved)) {
+ dataSourceId = resolved;
+ }
+ } catch (Throwable ignored) {
+
+ }
+
+ AbstractSpan span = ContextManager.createExitSpan(Constants.RETRIEVAL + "/" + dataSourceId, dataSourceId);
+
+ SpanLayer.asGenAI(span);
+ span.setComponent(ComponentsDefine.SPRING_AI);
+ Tags.GEN_AI_OPERATION_NAME.set(span, Constants.RETRIEVAL);
+ Tags.GEN_AI_DATA_SOURCE_ID.set(span, dataSourceId);
+ String model = resolveEmbeddingModelName(objInst);
+ if (StringUtils.hasText(model)) {
+ Tags.GEN_AI_REQUEST_MODEL.set(span, model);
+ }
+
+ if (request != null) {
+ Tags.GEN_AI_TOP_K.set(span, String.valueOf(request.getTopK()));
+ String query = request.getQuery();
+ if (StringUtils.hasText(query) && SpringAiPluginConfig.Plugin.SpringAi.COLLECT_RETRIEVAL_QUERY) {
+ int limit = SpringAiPluginConfig.Plugin.SpringAi.RETRIEVAL_QUERY_LENGTH_LIMIT;
+ if (limit >= 0 && query.length() > limit) {
+ query = query.substring(0, limit);
+ }
+ Tags.GEN_AI_RETRIEVAL_QUERY_TEXT.set(span, query);
+ }
+ }
+ }
+
+ @Override
+ public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes,
+ Object ret) throws Throwable {
+ if (!ContextManager.isActive()) {
+ return ret;
+ }
+ try {
+ if (ret instanceof List> && SpringAiPluginConfig.Plugin.SpringAi.COLLECT_RETRIEVAL_DOCUMENTS) {
+ Tags.GEN_AI_RETRIEVAL_DOCUMENTS.set(ContextManager.activeSpan(), toDocumentsJson((List>) ret));
+ }
+ } finally {
+ ContextManager.stopSpan();
+ }
+ return ret;
+ }
+
+ @Override
+ public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments,
+ Class>[] argumentsTypes, Throwable t) {
+ if (ContextManager.isActive()) {
+ AbstractSpan span = ContextManager.activeSpan();
+ span.log(t);
+ ErrorTypeResolver.setErrorType(span, t);
+ }
+ }
+
+ private VectorStoreObservationContext createObservationContext(EnhancedInstance objInst, SearchRequest request) {
+ VectorStoreObservationContext.Builder builder = ((AbstractObservationVectorStore) objInst)
+ .createObservationContextBuilder(VectorStoreObservationContext.Operation.QUERY.value());
+ if (request != null) {
+ builder.queryRequest(request);
+ }
+ return builder.build();
+ }
+
+ private String resolveEmbeddingModelName(EnhancedInstance objInst) {
+ Object context = objInst.getSkyWalkingDynamicField();
+ if (context instanceof VectorStoreEnhanceContext) {
+ return ((VectorStoreEnhanceContext) context).getEmbeddingModelName();
+ }
+ return null;
+ }
+
+ private String resolveDataSourceId(VectorStoreObservationContext context, EnhancedInstance objInst) {
+ StringBuilder dataSourceId = new StringBuilder();
+ appendDataSourcePart(dataSourceId, context.getDatabaseSystem());
+ appendDataSourcePart(dataSourceId, context.getNamespace());
+ appendDataSourcePart(dataSourceId, context.getCollectionName());
+ if (dataSourceId.length() > 0) {
+ return dataSourceId.toString();
+ }
+ return objInst.getClass().getSimpleName();
+ }
+
+ private void appendDataSourcePart(StringBuilder dataSourceId, String value) {
+ if (!StringUtils.hasText(value)) {
+ return;
+ }
+ if (dataSourceId.length() > 0) {
+ dataSourceId.append('/');
+ }
+ dataSourceId.append(value);
+ }
+
+ private String toDocumentsJson(List> documents) {
+ List
diff --git a/apm-sniffer/apm-sdk-plugin/xmemcached-2.x-plugin/pom.xml b/apm-sniffer/apm-sdk-plugin/xmemcached-2.x-plugin/pom.xml
index 841535f8db..35876e8aff 100644
--- a/apm-sniffer/apm-sdk-plugin/xmemcached-2.x-plugin/pom.xml
+++ b/apm-sniffer/apm-sdk-plugin/xmemcached-2.x-plugin/pom.xml
@@ -21,7 +21,7 @@
org.apache.skywalking
apm-sdk-plugin
- 9.3.0-SNAPSHOT
+ 9.7.0-SNAPSHOT
apm-xmemcached-2.x-plugin
diff --git a/apm-sniffer/apm-sdk-plugin/xxl-job-2.x-plugin/pom.xml b/apm-sniffer/apm-sdk-plugin/xxl-job-2.x-plugin/pom.xml
index a008627a7a..da1409f18d 100644
--- a/apm-sniffer/apm-sdk-plugin/xxl-job-2.x-plugin/pom.xml
+++ b/apm-sniffer/apm-sdk-plugin/xxl-job-2.x-plugin/pom.xml
@@ -21,7 +21,7 @@
apm-sdk-plugin
org.apache.skywalking
- 9.3.0-SNAPSHOT
+ 9.7.0-SNAPSHOT
4.0.0
diff --git a/apm-sniffer/apm-test-tools/pom.xml b/apm-sniffer/apm-test-tools/pom.xml
index db5fa5298b..9dd0f43cb3 100644
--- a/apm-sniffer/apm-test-tools/pom.xml
+++ b/apm-sniffer/apm-test-tools/pom.xml
@@ -22,7 +22,7 @@
org.apache.skywalking
java-agent-sniffer
- 9.3.0-SNAPSHOT
+ 9.7.0-SNAPSHOT
apm-test-tools
@@ -38,7 +38,6 @@
junit
junit
- ${junit.version}
provided
diff --git a/apm-sniffer/apm-test-tools/src/main/java/org/apache/skywalking/apm/agent/core/context/MockContextSnapshot.java b/apm-sniffer/apm-test-tools/src/main/java/org/apache/skywalking/apm/agent/core/context/MockContextSnapshot.java
index 505a4924a9..c6d5f91fcc 100644
--- a/apm-sniffer/apm-test-tools/src/main/java/org/apache/skywalking/apm/agent/core/context/MockContextSnapshot.java
+++ b/apm-sniffer/apm-test-tools/src/main/java/org/apache/skywalking/apm/agent/core/context/MockContextSnapshot.java
@@ -26,6 +26,8 @@ public enum MockContextSnapshot {
private ContextSnapshot contextSnapshot;
+ private ContextSnapshot ignoreContextSnapshot;
+
MockContextSnapshot() {
contextSnapshot = new ContextSnapshot(
"1, 2, 3",
@@ -36,9 +38,21 @@ public enum MockContextSnapshot {
new ExtensionContext(),
ProfileStatusContext.createWithNone()
);
+ ignoreContextSnapshot = new ContextSnapshot(
+ null,
+ -1,
+ null,
+ null,
+ new CorrelationContext(),
+ new ExtensionContext(),
+ ProfileStatusContext.createWithNone());
}
public ContextSnapshot mockContextSnapshot() {
return contextSnapshot;
}
+
+ public ContextSnapshot mockIgnoreContextSnapshot() {
+ return ignoreContextSnapshot;
+ }
}
diff --git a/apm-sniffer/apm-test-tools/src/main/java/org/apache/skywalking/apm/agent/test/tools/TracingSegmentRunner.java b/apm-sniffer/apm-test-tools/src/main/java/org/apache/skywalking/apm/agent/test/tools/TracingSegmentRunner.java
index 0626f36d01..8dbb6cf1a3 100644
--- a/apm-sniffer/apm-test-tools/src/main/java/org/apache/skywalking/apm/agent/test/tools/TracingSegmentRunner.java
+++ b/apm-sniffer/apm-test-tools/src/main/java/org/apache/skywalking/apm/agent/test/tools/TracingSegmentRunner.java
@@ -55,7 +55,7 @@ protected Object createTest() throws Exception {
@Override
protected Statement withAfters(FrameworkMethod method, Object target, final Statement statement) {
- return new Statement() {
+ Statement st = new Statement() {
@Override
public void evaluate() throws Throwable {
if (field != null) {
@@ -89,5 +89,7 @@ public void afterFinished(IgnoredTracerContext tracerContext) {
}
}
};
+
+ return super.withAfters(method, target, st);
}
}
diff --git a/apm-sniffer/apm-toolkit-activation/apm-toolkit-kafka-activation/pom.xml b/apm-sniffer/apm-toolkit-activation/apm-toolkit-kafka-activation/pom.xml
index 5c7df0c206..a914b8d528 100644
--- a/apm-sniffer/apm-toolkit-activation/apm-toolkit-kafka-activation/pom.xml
+++ b/apm-sniffer/apm-toolkit-activation/apm-toolkit-kafka-activation/pom.xml
@@ -21,7 +21,7 @@
apm-toolkit-activation
org.apache.skywalking
- 9.3.0-SNAPSHOT
+ 9.7.0-SNAPSHOT
4.0.0
diff --git a/apm-sniffer/apm-toolkit-activation/apm-toolkit-log4j-1.x-activation/pom.xml b/apm-sniffer/apm-toolkit-activation/apm-toolkit-log4j-1.x-activation/pom.xml
index 1b937485b5..86e57d28bb 100644
--- a/apm-sniffer/apm-toolkit-activation/apm-toolkit-log4j-1.x-activation/pom.xml
+++ b/apm-sniffer/apm-toolkit-activation/apm-toolkit-log4j-1.x-activation/pom.xml
@@ -21,7 +21,7 @@
apm-toolkit-activation
org.apache.skywalking
- 9.3.0-SNAPSHOT
+ 9.7.0-SNAPSHOT
4.0.0
diff --git a/apm-sniffer/apm-toolkit-activation/apm-toolkit-log4j-2.x-activation/pom.xml b/apm-sniffer/apm-toolkit-activation/apm-toolkit-log4j-2.x-activation/pom.xml
index a4d7f78bbe..5e1a0fb598 100644
--- a/apm-sniffer/apm-toolkit-activation/apm-toolkit-log4j-2.x-activation/pom.xml
+++ b/apm-sniffer/apm-toolkit-activation/apm-toolkit-log4j-2.x-activation/pom.xml
@@ -21,7 +21,7 @@
apm-toolkit-activation
org.apache.skywalking
- 9.3.0-SNAPSHOT
+ 9.7.0-SNAPSHOT
4.0.0
diff --git a/apm-sniffer/apm-toolkit-activation/apm-toolkit-logback-1.x-activation/pom.xml b/apm-sniffer/apm-toolkit-activation/apm-toolkit-logback-1.x-activation/pom.xml
index 9134874b44..341faac073 100644
--- a/apm-sniffer/apm-toolkit-activation/apm-toolkit-logback-1.x-activation/pom.xml
+++ b/apm-sniffer/apm-toolkit-activation/apm-toolkit-logback-1.x-activation/pom.xml
@@ -21,7 +21,7 @@
apm-toolkit-activation
org.apache.skywalking
- 9.3.0-SNAPSHOT
+ 9.7.0-SNAPSHOT
4.0.0
diff --git a/apm-sniffer/apm-toolkit-activation/apm-toolkit-logging-common/pom.xml b/apm-sniffer/apm-toolkit-activation/apm-toolkit-logging-common/pom.xml
index 85659cfb98..ae19d88816 100644
--- a/apm-sniffer/apm-toolkit-activation/apm-toolkit-logging-common/pom.xml
+++ b/apm-sniffer/apm-toolkit-activation/apm-toolkit-logging-common/pom.xml
@@ -20,7 +20,7 @@
apm-toolkit-activation
org.apache.skywalking
- 9.3.0-SNAPSHOT
+ 9.7.0-SNAPSHOT
4.0.0
diff --git a/apm-sniffer/apm-toolkit-activation/apm-toolkit-meter-activation/pom.xml b/apm-sniffer/apm-toolkit-activation/apm-toolkit-meter-activation/pom.xml
index 30a272ff2c..4d260f63e5 100644
--- a/apm-sniffer/apm-toolkit-activation/apm-toolkit-meter-activation/pom.xml
+++ b/apm-sniffer/apm-toolkit-activation/apm-toolkit-meter-activation/pom.xml
@@ -21,7 +21,7 @@
apm-toolkit-activation
org.apache.skywalking
- 9.3.0-SNAPSHOT
+ 9.7.0-SNAPSHOT
4.0.0
diff --git a/apm-sniffer/apm-toolkit-activation/apm-toolkit-micrometer-activation/pom.xml b/apm-sniffer/apm-toolkit-activation/apm-toolkit-micrometer-activation/pom.xml
index d63725b992..7e9c7d103f 100644
--- a/apm-sniffer/apm-toolkit-activation/apm-toolkit-micrometer-activation/pom.xml
+++ b/apm-sniffer/apm-toolkit-activation/apm-toolkit-micrometer-activation/pom.xml
@@ -20,7 +20,7 @@
apm-toolkit-activation
org.apache.skywalking
- 9.3.0-SNAPSHOT
+ 9.7.0-SNAPSHOT
4.0.0
diff --git a/apm-sniffer/apm-toolkit-activation/apm-toolkit-micrometer-activation/src/test/java/org/apache/skywalking/apm/toolkit/activation/micrometer/MicrometerContextSnapshotThreadLocalAccessorInterceptorTest.java b/apm-sniffer/apm-toolkit-activation/apm-toolkit-micrometer-activation/src/test/java/org/apache/skywalking/apm/toolkit/activation/micrometer/MicrometerContextSnapshotThreadLocalAccessorInterceptorTest.java
index 3e3f66c844..258808f8f1 100644
--- a/apm-sniffer/apm-toolkit-activation/apm-toolkit-micrometer-activation/src/test/java/org/apache/skywalking/apm/toolkit/activation/micrometer/MicrometerContextSnapshotThreadLocalAccessorInterceptorTest.java
+++ b/apm-sniffer/apm-toolkit-activation/apm-toolkit-micrometer-activation/src/test/java/org/apache/skywalking/apm/toolkit/activation/micrometer/MicrometerContextSnapshotThreadLocalAccessorInterceptorTest.java
@@ -92,8 +92,6 @@ public void clear() {
@AfterClass
public static void clearAfterAll() {
// test from threadlocalaccessor test x 2 TODO: I have no idea what is going on
- ContextManager.stopSpan();
- ContextManager.stopSpan();
assertThat(ContextManager.isActive(), is(false));
}
@@ -103,6 +101,7 @@ public void testServiceFromPlugin() {
PluginBootService.class);
Assert.assertNotNull(service);
+ ContextManager.stopSpan();
}
@Test
@@ -110,6 +109,7 @@ public void testServiceOverrideFromPlugin() {
ContextManagerExtendService service = ServiceManager.INSTANCE.findService(ContextManagerExtendService.class);
Assert.assertTrue(service instanceof ContextManagerExtendOverrideService);
+ ContextManager.stopSpan();
}
@Test
diff --git a/apm-sniffer/apm-toolkit-activation/apm-toolkit-opentracing-activation/pom.xml b/apm-sniffer/apm-toolkit-activation/apm-toolkit-opentracing-activation/pom.xml
index d0484207c1..05dc1b4ac9 100644
--- a/apm-sniffer/apm-toolkit-activation/apm-toolkit-opentracing-activation/pom.xml
+++ b/apm-sniffer/apm-toolkit-activation/apm-toolkit-opentracing-activation/pom.xml
@@ -21,7 +21,7 @@
apm-toolkit-activation
org.apache.skywalking
- 9.3.0-SNAPSHOT
+ 9.7.0-SNAPSHOT
4.0.0
diff --git a/apm-sniffer/apm-toolkit-activation/apm-toolkit-trace-activation/pom.xml b/apm-sniffer/apm-toolkit-activation/apm-toolkit-trace-activation/pom.xml
index 56a268c4a1..f93d0a3397 100644
--- a/apm-sniffer/apm-toolkit-activation/apm-toolkit-trace-activation/pom.xml
+++ b/apm-sniffer/apm-toolkit-activation/apm-toolkit-trace-activation/pom.xml
@@ -21,7 +21,7 @@
apm-toolkit-activation
org.apache.skywalking
- 9.3.0-SNAPSHOT
+ 9.7.0-SNAPSHOT
4.0.0
diff --git a/apm-sniffer/apm-toolkit-activation/apm-toolkit-trace-activation/src/test/java/org/apache/skywalking/apm/toolkit/activation/trace/CallableOrRunnableInterceptorTest.java b/apm-sniffer/apm-toolkit-activation/apm-toolkit-trace-activation/src/test/java/org/apache/skywalking/apm/toolkit/activation/trace/CallableOrRunnableInterceptorTest.java
index 45e00baa73..3aacc88c67 100644
--- a/apm-sniffer/apm-toolkit-activation/apm-toolkit-trace-activation/src/test/java/org/apache/skywalking/apm/toolkit/activation/trace/CallableOrRunnableInterceptorTest.java
+++ b/apm-sniffer/apm-toolkit-activation/apm-toolkit-trace-activation/src/test/java/org/apache/skywalking/apm/toolkit/activation/trace/CallableOrRunnableInterceptorTest.java
@@ -22,7 +22,7 @@
import java.lang.reflect.Method;
import java.util.List;
import java.util.concurrent.Callable;
-import org.apache.skywalking.apm.agent.core.context.ContextSnapshot;
+import org.apache.skywalking.apm.agent.core.context.MockContextSnapshot;
import org.apache.skywalking.apm.agent.core.context.trace.AbstractTracingSpan;
import org.apache.skywalking.apm.agent.core.context.trace.TraceSegment;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
@@ -36,7 +36,6 @@
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
-import org.mockito.Mock;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
@@ -69,9 +68,6 @@ public void setSkyWalkingDynamicField(Object value) {
}
};
- @Mock
- private ContextSnapshot contextSnapshot;
-
private Object[] arguments;
private Method callMethod;
@@ -100,7 +96,7 @@ public void testOnConstructor() {
@Test
public void testCall() throws Throwable {
- enhancedInstance.setSkyWalkingDynamicField(contextSnapshot);
+ enhancedInstance.setSkyWalkingDynamicField(MockContextSnapshot.INSTANCE.mockContextSnapshot());
callableCallInterceptor.beforeMethod(enhancedInstance, callMethod, arguments, null, null);
callableCallInterceptor.afterMethod(enhancedInstance, callMethod, arguments, null, "result");
@@ -111,4 +107,16 @@ public void testCall() throws Throwable {
}
+ @Test
+ public void testCallWithIgnoreSnapshot() throws Throwable {
+
+ enhancedInstance.setSkyWalkingDynamicField(MockContextSnapshot.INSTANCE.mockIgnoreContextSnapshot());
+ callableCallInterceptor.beforeMethod(enhancedInstance, callMethod, arguments, null, null);
+ callableCallInterceptor.afterMethod(enhancedInstance, callMethod, arguments, null, "result");
+
+ assertThat(segmentStorage.getTraceSegments().size(), is(0));
+ assertThat(segmentStorage.getIgnoredTracerContexts().size(), is(1));
+
+ }
+
}
diff --git a/apm-sniffer/apm-toolkit-activation/apm-toolkit-webflux-activation/pom.xml b/apm-sniffer/apm-toolkit-activation/apm-toolkit-webflux-activation/pom.xml
index f56c2edf8f..d8832e24f5 100644
--- a/apm-sniffer/apm-toolkit-activation/apm-toolkit-webflux-activation/pom.xml
+++ b/apm-sniffer/apm-toolkit-activation/apm-toolkit-webflux-activation/pom.xml
@@ -21,7 +21,7 @@
apm-toolkit-activation
org.apache.skywalking
- 9.3.0-SNAPSHOT
+ 9.7.0-SNAPSHOT
4.0.0
diff --git a/apm-sniffer/apm-toolkit-activation/pom.xml b/apm-sniffer/apm-toolkit-activation/pom.xml
index f597ebabea..f6e3b542c5 100644
--- a/apm-sniffer/apm-toolkit-activation/pom.xml
+++ b/apm-sniffer/apm-toolkit-activation/pom.xml
@@ -21,7 +21,7 @@
java-agent-sniffer
org.apache.skywalking
- 9.3.0-SNAPSHOT
+ 9.7.0-SNAPSHOT
4.0.0
pom
diff --git a/apm-sniffer/bootstrap-plugins/CLAUDE.md b/apm-sniffer/bootstrap-plugins/CLAUDE.md
new file mode 100644
index 0000000000..51b4db99e7
--- /dev/null
+++ b/apm-sniffer/bootstrap-plugins/CLAUDE.md
@@ -0,0 +1,53 @@
+# CLAUDE.md - Bootstrap Plugin Development Guide
+
+This guide covers developing bootstrap-level plugins in `apm-sniffer/bootstrap-plugins/`.
+
+For general plugin development concepts (V2 API, tracing, class matching, testing), see `apm-sniffer/apm-sdk-plugin/CLAUDE.md`.
+
+## What Are Bootstrap Plugins?
+
+Bootstrap plugins instrument JDK core classes (rt.jar / java.base module) at the JVM bootstrap phase. They are loaded before application classes and can intercept fundamental JDK APIs.
+
+**Examples:**
+- `jdk-threading-plugin` - Thread pool context propagation
+- `jdk-http-plugin` - `HttpURLConnection` instrumentation
+- `jdk-httpclient-plugin` - JDK 11+ `HttpClient` instrumentation
+- `jdk-virtual-thread-executor-plugin` - JDK 21+ virtual thread support
+- `jdk-forkjoinpool-plugin` - `ForkJoinPool` instrumentation
+
+## Key Difference from SDK Plugins
+
+Bootstrap plugins **must** override `isBootstrapInstrumentation()`:
+```java
+@Override
+public boolean isBootstrapInstrumentation() {
+ return true;
+}
+```
+
+**WARNING**: Use bootstrap instrumentation only where absolutely necessary. It affects JDK core classes and has broader impact than SDK plugins.
+
+## Development Rules
+
+All general plugin development rules apply (see `apm-sdk-plugin/CLAUDE.md`), plus:
+
+1. **Use V2 API** for new bootstrap plugins, same as SDK plugins
+2. **Minimal scope**: Only intercept what is strictly necessary in JDK classes
+3. **Performance critical**: Bootstrap plugins run on core JDK paths - keep interceptor logic lightweight
+4. **Class loading awareness**: JDK core classes are loaded by the bootstrap classloader; be careful with class references that might not be visible at bootstrap level
+
+## Testing Bootstrap Plugins
+
+Bootstrap plugin test scenarios use `runningMode: with_bootstrap` in `configuration.yml`:
+```yaml
+type: jvm
+entryService: http://localhost:8080/case
+healthCheck: http://localhost:8080/health
+startScript: ./bin/startup.sh
+runningMode: with_bootstrap
+withPlugins: jdk-threading-plugin-*.jar
+```
+
+This tells the test framework to load the plugin at the bootstrap level instead of the normal plugin directory.
+
+See `apm-sdk-plugin/CLAUDE.md` for full test framework documentation.
diff --git a/apm-sniffer/bootstrap-plugins/jdk-forkjoinpool-plugin/pom.xml b/apm-sniffer/bootstrap-plugins/jdk-forkjoinpool-plugin/pom.xml
index 0f9790e758..5de97c5a33 100644
--- a/apm-sniffer/bootstrap-plugins/jdk-forkjoinpool-plugin/pom.xml
+++ b/apm-sniffer/bootstrap-plugins/jdk-forkjoinpool-plugin/pom.xml
@@ -20,7 +20,7 @@
org.apache.skywalking
bootstrap-plugins
- 9.3.0-SNAPSHOT
+ 9.7.0-SNAPSHOT
4.0.0
diff --git a/apm-sniffer/bootstrap-plugins/jdk-http-plugin/pom.xml b/apm-sniffer/bootstrap-plugins/jdk-http-plugin/pom.xml
index a1bcb92708..1692e684a6 100755
--- a/apm-sniffer/bootstrap-plugins/jdk-http-plugin/pom.xml
+++ b/apm-sniffer/bootstrap-plugins/jdk-http-plugin/pom.xml
@@ -20,7 +20,7 @@
org.apache.skywalking
bootstrap-plugins
- 9.3.0-SNAPSHOT
+ 9.7.0-SNAPSHOT
4.0.0
@@ -32,6 +32,8 @@
UTF-8
+
+
diff --git a/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-9.x-plugin/pom.xml b/apm-sniffer/bootstrap-plugins/jdk-httpclient-plugin/pom.xml
similarity index 69%
rename from apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-9.x-plugin/pom.xml
rename to apm-sniffer/bootstrap-plugins/jdk-httpclient-plugin/pom.xml
index 03f8740533..f537f685e6 100644
--- a/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-9.x-plugin/pom.xml
+++ b/apm-sniffer/bootstrap-plugins/jdk-httpclient-plugin/pom.xml
@@ -18,28 +18,29 @@
- jetty-plugins
+ bootstrap-plugins
org.apache.skywalking
- 9.3.0-SNAPSHOT
+ 9.7.0-SNAPSHOT
4.0.0
- apm-jetty-server-9.x-plugin
+ apm-jdk-httpclient-plugin
jar
- jetty-server-9.x-plugin
+ apm-jdk-httpclient-plugin
http://maven.apache.org
- 9.0.0.v20130308
+ UTF-8
+ 11
-
-
- org.eclipse.jetty
- jetty-server
- ${jetty-server.version}
- provided
-
-
-
+
+
+
+ maven-deploy-plugin
+
+
+
+
+
\ No newline at end of file
diff --git a/apm-sniffer/bootstrap-plugins/jdk-httpclient-plugin/src/main/java/org/apache/skywalking/apm/plugin/HttpClientSendAsyncInterceptor.java b/apm-sniffer/bootstrap-plugins/jdk-httpclient-plugin/src/main/java/org/apache/skywalking/apm/plugin/HttpClientSendAsyncInterceptor.java
new file mode 100644
index 0000000000..0661c4705f
--- /dev/null
+++ b/apm-sniffer/bootstrap-plugins/jdk-httpclient-plugin/src/main/java/org/apache/skywalking/apm/plugin/HttpClientSendAsyncInterceptor.java
@@ -0,0 +1,123 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin;
+
+import org.apache.skywalking.apm.agent.core.context.ContextCarrier;
+import org.apache.skywalking.apm.agent.core.context.ContextManager;
+import org.apache.skywalking.apm.agent.core.context.tag.Tags;
+import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan;
+import org.apache.skywalking.apm.agent.core.context.trace.SpanLayer;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
+import org.apache.skywalking.apm.network.trace.component.ComponentsDefine;
+
+import java.lang.reflect.Method;
+import java.net.URI;
+import java.net.http.HttpRequest;
+import java.net.http.HttpResponse;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.CompletableFuture;
+
+public class HttpClientSendAsyncInterceptor implements InstanceMethodsAroundInterceptor {
+
+ @Override
+ public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes, MethodInterceptResult result) throws Throwable {
+ HttpRequest request = (HttpRequest) allArguments[0];
+ URI uri = request.uri();
+
+ ContextCarrier contextCarrier = new ContextCarrier();
+ AbstractSpan span = ContextManager.createExitSpan(buildOperationName(request.method(), uri), contextCarrier, getPeer(uri));
+
+ if (request instanceof EnhancedInstance) {
+ ((EnhancedInstance) request).setSkyWalkingDynamicField(contextCarrier);
+ }
+
+ span.setComponent(ComponentsDefine.JDK_HTTP);
+ Tags.HTTP.METHOD.set(span, request.method());
+ Tags.URL.set(span, String.valueOf(uri));
+ SpanLayer.asHttp(span);
+ }
+
+ @Override
+ public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes, Object ret) throws Throwable {
+
+ if (ContextManager.isActive()) {
+ AbstractSpan span = ContextManager.activeSpan();
+ span.prepareForAsync();
+
+ if (ret != null) {
+ CompletableFuture> future = (CompletableFuture>) ret;
+ ret = future.whenComplete((response, throwable) -> {
+ try {
+ if (throwable != null) {
+ span.errorOccurred();
+ span.log(throwable);
+ return;
+ }
+ if (response instanceof HttpResponse) {
+ HttpResponse> httpResponse = (HttpResponse>) response;
+ int statusCode = httpResponse.statusCode();
+ Tags.HTTP_RESPONSE_STATUS_CODE.set(span, statusCode);
+ if (statusCode >= 400) {
+ span.errorOccurred();
+ }
+ }
+ } finally {
+ span.asyncFinish();
+ }
+ });
+ } else {
+ Map eventMap = new HashMap();
+ eventMap.put("error", "No response");
+ span.log(System.currentTimeMillis(), eventMap);
+ span.errorOccurred();
+ }
+ ContextManager.stopSpan();
+ }
+ return ret;
+ }
+
+ @Override
+ public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes, Throwable t) {
+ if (ContextManager.isActive()) {
+ ContextManager.activeSpan().log(t);
+ }
+ }
+
+ private String buildOperationName(String method, URI uri) {
+ String path = uri.getPath();
+ if (path == null || path.isEmpty()) {
+ path = "/";
+ }
+ return method + ":" + path;
+ }
+
+ private String getPeer(URI uri) {
+ String host = uri.getHost();
+ int port = uri.getPort();
+
+ if (port == -1) {
+ port = "https".equalsIgnoreCase(uri.getScheme()) ? 443 : 80;
+ }
+
+ return host + ":" + port;
+ }
+}
diff --git a/apm-sniffer/bootstrap-plugins/jdk-httpclient-plugin/src/main/java/org/apache/skywalking/apm/plugin/HttpClientSendInterceptor.java b/apm-sniffer/bootstrap-plugins/jdk-httpclient-plugin/src/main/java/org/apache/skywalking/apm/plugin/HttpClientSendInterceptor.java
new file mode 100644
index 0000000000..3a06f59ad9
--- /dev/null
+++ b/apm-sniffer/bootstrap-plugins/jdk-httpclient-plugin/src/main/java/org/apache/skywalking/apm/plugin/HttpClientSendInterceptor.java
@@ -0,0 +1,108 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin;
+
+import org.apache.skywalking.apm.agent.core.context.ContextCarrier;
+import org.apache.skywalking.apm.agent.core.context.ContextManager;
+import org.apache.skywalking.apm.agent.core.context.tag.Tags;
+import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan;
+import org.apache.skywalking.apm.agent.core.context.trace.SpanLayer;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
+import org.apache.skywalking.apm.network.trace.component.ComponentsDefine;
+
+import java.lang.reflect.Method;
+import java.net.URI;
+import java.net.http.HttpRequest;
+import java.net.http.HttpResponse;
+import java.util.HashMap;
+import java.util.Map;
+
+public class HttpClientSendInterceptor implements InstanceMethodsAroundInterceptor {
+
+ @Override
+ public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes, MethodInterceptResult result) throws Throwable {
+ HttpRequest request = (HttpRequest) allArguments[0];
+ URI uri = request.uri();
+
+ ContextCarrier contextCarrier = new ContextCarrier();
+ AbstractSpan span = ContextManager.createExitSpan(buildOperationName(request.method(), uri), contextCarrier, getPeer(uri));
+
+ if (request instanceof EnhancedInstance) {
+ ((EnhancedInstance) request).setSkyWalkingDynamicField(contextCarrier);
+ }
+
+ span.setComponent(ComponentsDefine.JDK_HTTP);
+ Tags.HTTP.METHOD.set(span, request.method());
+ Tags.URL.set(span, String.valueOf(uri));
+ SpanLayer.asHttp(span);
+ }
+
+ @Override
+ public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes, Object ret) throws Throwable {
+
+ if (ContextManager.isActive()) {
+ AbstractSpan span = ContextManager.activeSpan();
+ if (ret != null) {
+ HttpResponse> response = (HttpResponse>) ret;
+ int statusCode = response.statusCode();
+
+ Tags.HTTP_RESPONSE_STATUS_CODE.set(span, response.statusCode());
+ if (statusCode >= 400) {
+ span.errorOccurred();
+ }
+ } else {
+ Map eventMap = new HashMap();
+ eventMap.put("error", "No response");
+ span.log(System.currentTimeMillis(), eventMap);
+ span.errorOccurred();
+ }
+
+ ContextManager.stopSpan();
+ }
+ return ret;
+ }
+
+ @Override
+ public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes, Throwable t) {
+ if (ContextManager.isActive()) {
+ ContextManager.activeSpan().log(t);
+ }
+ }
+
+ private String buildOperationName(String method, URI uri) {
+ String path = uri.getPath();
+ if (path == null || path.isEmpty()) {
+ path = "/";
+ }
+ return method + ":" + path;
+ }
+
+ private String getPeer(URI uri) {
+ String host = uri.getHost();
+ int port = uri.getPort();
+
+ if (port == -1) {
+ port = "https".equalsIgnoreCase(uri.getScheme()) ? 443 : 80;
+ }
+
+ return host + ":" + port;
+ }
+}
diff --git a/apm-sniffer/bootstrap-plugins/jdk-httpclient-plugin/src/main/java/org/apache/skywalking/apm/plugin/HttpRequestHeadersInterceptor.java b/apm-sniffer/bootstrap-plugins/jdk-httpclient-plugin/src/main/java/org/apache/skywalking/apm/plugin/HttpRequestHeadersInterceptor.java
new file mode 100644
index 0000000000..a6dc76650f
--- /dev/null
+++ b/apm-sniffer/bootstrap-plugins/jdk-httpclient-plugin/src/main/java/org/apache/skywalking/apm/plugin/HttpRequestHeadersInterceptor.java
@@ -0,0 +1,62 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin;
+
+import org.apache.skywalking.apm.agent.core.context.CarrierItem;
+import org.apache.skywalking.apm.agent.core.context.ContextCarrier;
+import org.apache.skywalking.apm.agent.core.context.ContextManager;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
+
+import java.lang.reflect.Method;
+import java.net.http.HttpHeaders;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class HttpRequestHeadersInterceptor implements InstanceMethodsAroundInterceptor {
+
+ @Override
+ public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes, MethodInterceptResult result) throws Throwable {
+
+ }
+
+ @Override
+ public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes, Object ret) throws Throwable {
+
+ ContextCarrier contextCarrier = (ContextCarrier) objInst.getSkyWalkingDynamicField();
+ HttpHeaders originalHeaders = (HttpHeaders) ret;
+ final Map> headerMap = new HashMap<>(originalHeaders.map());
+ CarrierItem next = contextCarrier.items();
+ while (next.hasNext()) {
+ next = next.next();
+ headerMap.put(next.getHeadKey(), List.of(next.getHeadValue()));
+ }
+
+ return HttpHeaders.of(headerMap, (k, v) -> true);
+ }
+
+ @Override
+ public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes, Throwable t) {
+ if (ContextManager.isActive()) {
+ ContextManager.activeSpan().log(t);
+ }
+ }
+}
diff --git a/apm-sniffer/bootstrap-plugins/jdk-httpclient-plugin/src/main/java/org/apache/skywalking/apm/plugin/define/HttpClientInstrumentation.java b/apm-sniffer/bootstrap-plugins/jdk-httpclient-plugin/src/main/java/org/apache/skywalking/apm/plugin/define/HttpClientInstrumentation.java
new file mode 100644
index 0000000000..18f7cf298b
--- /dev/null
+++ b/apm-sniffer/bootstrap-plugins/jdk-httpclient-plugin/src/main/java/org/apache/skywalking/apm/plugin/define/HttpClientInstrumentation.java
@@ -0,0 +1,109 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.define;
+
+import net.bytebuddy.description.method.MethodDescription;
+import net.bytebuddy.matcher.ElementMatcher;
+import net.bytebuddy.matcher.ElementMatchers;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine;
+import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
+import org.apache.skywalking.apm.agent.core.plugin.match.HierarchyMatch;
+import org.apache.skywalking.apm.agent.core.plugin.match.IndirectMatch;
+import org.apache.skywalking.apm.agent.core.plugin.match.MultiClassNameMatch;
+import org.apache.skywalking.apm.agent.core.plugin.match.logical.LogicalMatchOperation;
+
+import static net.bytebuddy.matcher.ElementMatchers.named;
+
+public class HttpClientInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
+
+ private static final String ENHANCE_PARENT_CLASS = "java.net.http.HttpClient";
+
+ private static final String EXCLUDE_CLASS = "jdk.internal.net.http.HttpClientFacade";
+
+ private static final String INTERCEPT_SEND_METHOD = "send";
+
+ private static final String INTERCEPT_SEND_ASYNC_METHOD = "sendAsync";
+
+ private static final String INTERCEPT_SEND_HANDLE = "org.apache.skywalking.apm.plugin.HttpClientSendInterceptor";
+
+ private static final String INTERCEPT_SEND_ASYNC_HANDLE = "org.apache.skywalking.apm.plugin.HttpClientSendAsyncInterceptor";
+
+ @Override
+ public boolean isBootstrapInstrumentation() {
+ return true;
+ }
+
+ @Override
+ public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
+ return new ConstructorInterceptPoint[0];
+ }
+
+ @Override
+ protected ClassMatch enhanceClass() {
+ IndirectMatch parentType = HierarchyMatch.byHierarchyMatch(ENHANCE_PARENT_CLASS);
+ IndirectMatch excludeClass = LogicalMatchOperation.not(MultiClassNameMatch.byMultiClassMatch(EXCLUDE_CLASS));
+ return LogicalMatchOperation.and(parentType, excludeClass);
+ }
+
+ @Override
+ public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
+ return new InstanceMethodsInterceptPoint[]{
+ new InstanceMethodsInterceptPoint() {
+ @Override
+ public ElementMatcher getMethodsMatcher() {
+ return ElementMatchers.named(INTERCEPT_SEND_METHOD)
+ .and(ElementMatchers.takesArgument(0, named("java.net.http.HttpRequest")))
+ .and(ElementMatchers.takesArguments(2));
+ }
+
+ @Override
+ public String getMethodsInterceptor() {
+ return INTERCEPT_SEND_HANDLE;
+ }
+
+ @Override
+ public boolean isOverrideArgs() {
+ return false;
+ }
+ },
+ new InstanceMethodsInterceptPoint() {
+ @Override
+ public ElementMatcher getMethodsMatcher() {
+ return ElementMatchers.named(INTERCEPT_SEND_ASYNC_METHOD)
+ .and(ElementMatchers.takesArgument(0, named("java.net.http.HttpRequest")))
+ .and(ElementMatchers.takesArgument(1, named("java.net.http.HttpResponse$BodyHandler")))
+ .and(ElementMatchers.takesArgument(2, named("java.net.http.HttpResponse$PushPromiseHandler")))
+ .and(ElementMatchers.takesArguments(3));
+ }
+
+ @Override
+ public String getMethodsInterceptor() {
+ return INTERCEPT_SEND_ASYNC_HANDLE;
+ }
+
+ @Override
+ public boolean isOverrideArgs() {
+ return false;
+ }
+ },
+ };
+ }
+}
diff --git a/apm-sniffer/bootstrap-plugins/jdk-httpclient-plugin/src/main/java/org/apache/skywalking/apm/plugin/define/HttpRequestInstrumentation.java b/apm-sniffer/bootstrap-plugins/jdk-httpclient-plugin/src/main/java/org/apache/skywalking/apm/plugin/define/HttpRequestInstrumentation.java
new file mode 100644
index 0000000000..18d47b6923
--- /dev/null
+++ b/apm-sniffer/bootstrap-plugins/jdk-httpclient-plugin/src/main/java/org/apache/skywalking/apm/plugin/define/HttpRequestInstrumentation.java
@@ -0,0 +1,75 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.define;
+
+import net.bytebuddy.description.method.MethodDescription;
+import net.bytebuddy.matcher.ElementMatcher;
+import net.bytebuddy.matcher.ElementMatchers;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine;
+import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
+
+import static org.apache.skywalking.apm.agent.core.plugin.match.NameMatch.byName;
+
+public class HttpRequestInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
+
+ private static final String ENHANCE_CLASS = "jdk.internal.net.http.ImmutableHttpRequest";
+
+ private static final String INTERCEPT_HEADERS_METHOD = "headers";
+
+ private static final String INTERCEPT_HEADERS_HANDLE = "org.apache.skywalking.apm.plugin.HttpRequestHeadersInterceptor";
+
+ @Override
+ public boolean isBootstrapInstrumentation() {
+ return true;
+ }
+
+ @Override
+ public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
+ return new ConstructorInterceptPoint[0];
+ }
+
+ @Override
+ protected ClassMatch enhanceClass() {
+ return byName(ENHANCE_CLASS);
+ }
+
+ @Override
+ public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
+ return new InstanceMethodsInterceptPoint[]{
+ new InstanceMethodsInterceptPoint() {
+ @Override
+ public ElementMatcher getMethodsMatcher() {
+ return ElementMatchers.named(INTERCEPT_HEADERS_METHOD);
+ }
+
+ @Override
+ public String getMethodsInterceptor() {
+ return INTERCEPT_HEADERS_HANDLE;
+ }
+
+ @Override
+ public boolean isOverrideArgs() {
+ return true;
+ }
+ }
+ };
+ }
+}
diff --git a/apm-sniffer/bootstrap-plugins/jdk-httpclient-plugin/src/main/resources/skywalking-plugin.def b/apm-sniffer/bootstrap-plugins/jdk-httpclient-plugin/src/main/resources/skywalking-plugin.def
new file mode 100644
index 0000000000..e4d1ef2562
--- /dev/null
+++ b/apm-sniffer/bootstrap-plugins/jdk-httpclient-plugin/src/main/resources/skywalking-plugin.def
@@ -0,0 +1,18 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+jdk-httpclient-plugin=org.apache.skywalking.apm.plugin.define.HttpClientInstrumentation
+jdk-httpclient-plugin=org.apache.skywalking.apm.plugin.define.HttpRequestInstrumentation
\ No newline at end of file
diff --git a/apm-sniffer/bootstrap-plugins/jdk-threading-plugin/pom.xml b/apm-sniffer/bootstrap-plugins/jdk-threading-plugin/pom.xml
index 29efafb1ae..33dd7a3b4d 100755
--- a/apm-sniffer/bootstrap-plugins/jdk-threading-plugin/pom.xml
+++ b/apm-sniffer/bootstrap-plugins/jdk-threading-plugin/pom.xml
@@ -20,7 +20,7 @@
org.apache.skywalking
bootstrap-plugins
- 9.3.0-SNAPSHOT
+ 9.7.0-SNAPSHOT
4.0.0
diff --git a/apm-sniffer/bootstrap-plugins/jdk-threadpool-plugin/pom.xml b/apm-sniffer/bootstrap-plugins/jdk-threadpool-plugin/pom.xml
index 91799d8558..3da184c381 100644
--- a/apm-sniffer/bootstrap-plugins/jdk-threadpool-plugin/pom.xml
+++ b/apm-sniffer/bootstrap-plugins/jdk-threadpool-plugin/pom.xml
@@ -20,7 +20,7 @@
bootstrap-plugins
org.apache.skywalking
- 9.3.0-SNAPSHOT
+ 9.7.0-SNAPSHOT
4.0.0
diff --git a/apm-sniffer/bootstrap-plugins/jdk-threadpool-plugin/src/main/java/org/apache/skywalking/apm/plugin/AbstractThreadingPoolInterceptor.java b/apm-sniffer/bootstrap-plugins/jdk-threadpool-plugin/src/main/java/org/apache/skywalking/apm/plugin/AbstractThreadingPoolInterceptor.java
index 7239453074..152064960b 100644
--- a/apm-sniffer/bootstrap-plugins/jdk-threadpool-plugin/src/main/java/org/apache/skywalking/apm/plugin/AbstractThreadingPoolInterceptor.java
+++ b/apm-sniffer/bootstrap-plugins/jdk-threadpool-plugin/src/main/java/org/apache/skywalking/apm/plugin/AbstractThreadingPoolInterceptor.java
@@ -24,26 +24,16 @@
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
import java.lang.reflect.Method;
+import java.util.concurrent.ForkJoinTask;
public abstract class AbstractThreadingPoolInterceptor implements InstanceMethodsAroundInterceptor {
@Override
public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes, MethodInterceptResult result) throws Throwable {
- if (!ContextManager.isActive()) {
+ if (notToEnhance(allArguments)) {
return;
}
- if (allArguments == null || allArguments.length < 1) {
- return;
- }
-
- Object argument = allArguments[0];
-
- // Avoid duplicate enhancement, such as the case where it has already been enhanced by RunnableWrapper or CallableWrapper with toolkit.
- if (argument instanceof EnhancedInstance && ((EnhancedInstance) argument).getSkyWalkingDynamicField() instanceof ContextSnapshot) {
- return;
- }
-
- Object wrappedObject = wrap(argument);
+ Object wrappedObject = wrap(allArguments[0]);
if (wrappedObject != null) {
allArguments[0] = wrappedObject;
}
@@ -63,6 +53,27 @@ public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allA
@Override
public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes, Throwable t) {
+ if (notToEnhance(allArguments)) {
+ return;
+ }
+
ContextManager.activeSpan().log(t);
}
+
+ private boolean notToEnhance(Object[] allArguments) {
+ if (!ContextManager.isActive()) {
+ return true;
+ }
+
+ if (allArguments == null || allArguments.length < 1) {
+ return true;
+ }
+
+ Object argument = allArguments[0];
+
+ // Avoid duplicate enhancement, such as the case where it has already been enhanced by RunnableWrapper or CallableWrapper with toolkit.
+ return argument instanceof EnhancedInstance
+ && ((EnhancedInstance) argument).getSkyWalkingDynamicField() instanceof ContextSnapshot
+ && !(argument instanceof ForkJoinTask);
+ }
}
diff --git a/apm-sniffer/bootstrap-plugins/jdk-virtual-thread-executor-plugin/pom.xml b/apm-sniffer/bootstrap-plugins/jdk-virtual-thread-executor-plugin/pom.xml
new file mode 100644
index 0000000000..9a3eee820f
--- /dev/null
+++ b/apm-sniffer/bootstrap-plugins/jdk-virtual-thread-executor-plugin/pom.xml
@@ -0,0 +1,46 @@
+
+
+
+
+ bootstrap-plugins
+ org.apache.skywalking
+ 9.7.0-SNAPSHOT
+
+ 4.0.0
+
+ apm-jdk-virtual-thread-executor-plugin
+ jar
+
+ apm-jdk-virtual-thread-executor-plugin
+ http://maven.apache.org
+
+
+ UTF-8
+
+
+
+
+
+
+ maven-deploy-plugin
+
+
+
+
+
\ No newline at end of file
diff --git a/apm-sniffer/bootstrap-plugins/jdk-virtual-thread-executor-plugin/src/main/java/org/apache/skywalking/apm/plugin/ThreadPerTaskExecutorConstructInterceptor.java b/apm-sniffer/bootstrap-plugins/jdk-virtual-thread-executor-plugin/src/main/java/org/apache/skywalking/apm/plugin/ThreadPerTaskExecutorConstructInterceptor.java
new file mode 100644
index 0000000000..c8f18193f9
--- /dev/null
+++ b/apm-sniffer/bootstrap-plugins/jdk-virtual-thread-executor-plugin/src/main/java/org/apache/skywalking/apm/plugin/ThreadPerTaskExecutorConstructInterceptor.java
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin;
+
+import org.apache.skywalking.apm.agent.core.context.ContextManager;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceConstructorInterceptor;
+
+public class ThreadPerTaskExecutorConstructInterceptor implements InstanceConstructorInterceptor {
+
+ @Override
+ public void onConstruct(EnhancedInstance objInst, Object[] allArguments) throws Throwable {
+ if (ContextManager.isActive()) {
+ objInst.setSkyWalkingDynamicField(ContextManager.capture());
+ }
+ }
+}
diff --git a/apm-sniffer/bootstrap-plugins/jdk-virtual-thread-executor-plugin/src/main/java/org/apache/skywalking/apm/plugin/ThreadPerTaskExecutorRunInterceptor.java b/apm-sniffer/bootstrap-plugins/jdk-virtual-thread-executor-plugin/src/main/java/org/apache/skywalking/apm/plugin/ThreadPerTaskExecutorRunInterceptor.java
new file mode 100644
index 0000000000..9cd9289116
--- /dev/null
+++ b/apm-sniffer/bootstrap-plugins/jdk-virtual-thread-executor-plugin/src/main/java/org/apache/skywalking/apm/plugin/ThreadPerTaskExecutorRunInterceptor.java
@@ -0,0 +1,81 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin;
+
+import org.apache.skywalking.apm.agent.core.context.ContextManager;
+import org.apache.skywalking.apm.agent.core.context.ContextSnapshot;
+import org.apache.skywalking.apm.agent.core.context.tag.Tags;
+import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
+import org.apache.skywalking.apm.network.trace.component.ComponentsDefine;
+
+import java.lang.reflect.Method;
+
+public class ThreadPerTaskExecutorRunInterceptor implements InstanceMethodsAroundInterceptor {
+
+ @Override
+ public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes, MethodInterceptResult result) throws Throwable {
+ Object skyWalkingDynamicField = objInst.getSkyWalkingDynamicField();
+ if (skyWalkingDynamicField == null) {
+ return;
+ }
+
+ if (!(skyWalkingDynamicField instanceof ContextSnapshot)) {
+ return;
+ }
+
+ AbstractSpan span = ContextManager.createLocalSpan(getOperationName(objInst, method));
+ span.setComponent(ComponentsDefine.THREAD_PER_TASK_EXECUTOR);
+ setCarrierThread(span);
+
+ ContextSnapshot contextSnapshot = (ContextSnapshot) skyWalkingDynamicField;
+ ContextManager.continued(contextSnapshot);
+ }
+
+ @Override
+ public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes, Object ret) throws Throwable {
+ if (ContextManager.isActive()) {
+ ContextManager.stopSpan();
+ }
+ return ret;
+ }
+
+ @Override
+ public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes, Throwable t) {
+ if (ContextManager.isActive()) {
+ ContextManager.activeSpan().log(t);
+ }
+ }
+
+ private String getOperationName(EnhancedInstance objInst, Method method) {
+ return objInst.getClass().getName() + "." + method.getName();
+ }
+
+ private void setCarrierThread(AbstractSpan span) {
+ String threadInfo = Thread.currentThread().toString();
+ if (threadInfo.startsWith("VirtualThread")) {
+ String[] parts = threadInfo.split("@");
+ if (parts.length >= 1) {
+ Tags.THREAD_CARRIER.set(span, parts[1]);
+ }
+ }
+ }
+}
diff --git a/apm-sniffer/bootstrap-plugins/jdk-virtual-thread-executor-plugin/src/main/java/org/apache/skywalking/apm/plugin/define/ThreadPerTaskExecutorFutureInstrumentation.java b/apm-sniffer/bootstrap-plugins/jdk-virtual-thread-executor-plugin/src/main/java/org/apache/skywalking/apm/plugin/define/ThreadPerTaskExecutorFutureInstrumentation.java
new file mode 100644
index 0000000000..3ed5788a1e
--- /dev/null
+++ b/apm-sniffer/bootstrap-plugins/jdk-virtual-thread-executor-plugin/src/main/java/org/apache/skywalking/apm/plugin/define/ThreadPerTaskExecutorFutureInstrumentation.java
@@ -0,0 +1,90 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.define;
+
+import net.bytebuddy.description.method.MethodDescription;
+import net.bytebuddy.matcher.ElementMatcher;
+import net.bytebuddy.matcher.ElementMatchers;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine;
+import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
+import org.apache.skywalking.apm.agent.core.plugin.match.MultiClassNameMatch;
+
+import static net.bytebuddy.matcher.ElementMatchers.any;
+
+public class ThreadPerTaskExecutorFutureInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
+
+ private static final String ENHANCE_CLASS = "java.util.concurrent.ThreadPerTaskExecutor$ThreadBoundFuture";
+
+ private static final String INTERCEPT_RUN_METHOD = "run";
+
+ private static final String INTERCEPT_RUN_HANDLE = "org.apache.skywalking.apm.plugin.ThreadPerTaskExecutorRunInterceptor";
+
+ private static final String TASK_RUNNER_CONSTRUCT_METHOD_INTERCEPTOR = "org.apache.skywalking.apm.plugin.ThreadPerTaskExecutorConstructInterceptor";
+
+ @Override
+ public boolean isBootstrapInstrumentation() {
+ return true;
+ }
+
+ @Override
+ protected ClassMatch enhanceClass() {
+ return MultiClassNameMatch.byMultiClassMatch(ENHANCE_CLASS);
+ }
+
+ @Override
+ public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
+ return new ConstructorInterceptPoint[]{
+ new ConstructorInterceptPoint() {
+ @Override
+ public ElementMatcher getConstructorMatcher() {
+ return any();
+ }
+
+ @Override
+ public String getConstructorInterceptor() {
+ return TASK_RUNNER_CONSTRUCT_METHOD_INTERCEPTOR;
+ }
+ }
+ };
+ }
+
+ @Override
+ public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
+ return new InstanceMethodsInterceptPoint[]{
+ new InstanceMethodsInterceptPoint() {
+ @Override
+ public ElementMatcher getMethodsMatcher() {
+ return ElementMatchers.named(INTERCEPT_RUN_METHOD);
+ }
+
+ @Override
+ public String getMethodsInterceptor() {
+ return INTERCEPT_RUN_HANDLE;
+ }
+
+ @Override
+ public boolean isOverrideArgs() {
+ return true;
+ }
+ }
+ };
+ }
+}
diff --git a/apm-sniffer/bootstrap-plugins/jdk-virtual-thread-executor-plugin/src/main/java/org/apache/skywalking/apm/plugin/define/ThreadPerTaskExecutorTaskRunnerInstrumentation.java b/apm-sniffer/bootstrap-plugins/jdk-virtual-thread-executor-plugin/src/main/java/org/apache/skywalking/apm/plugin/define/ThreadPerTaskExecutorTaskRunnerInstrumentation.java
new file mode 100644
index 0000000000..9a0efd075f
--- /dev/null
+++ b/apm-sniffer/bootstrap-plugins/jdk-virtual-thread-executor-plugin/src/main/java/org/apache/skywalking/apm/plugin/define/ThreadPerTaskExecutorTaskRunnerInstrumentation.java
@@ -0,0 +1,90 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.define;
+
+import net.bytebuddy.description.method.MethodDescription;
+import net.bytebuddy.matcher.ElementMatcher;
+import net.bytebuddy.matcher.ElementMatchers;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine;
+import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
+import org.apache.skywalking.apm.agent.core.plugin.match.MultiClassNameMatch;
+
+import static net.bytebuddy.matcher.ElementMatchers.any;
+
+public class ThreadPerTaskExecutorTaskRunnerInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
+
+ private static final String ENHANCE_CLASS = "java.util.concurrent.ThreadPerTaskExecutor$TaskRunner";
+
+ private static final String INTERCEPT_RUN_METHOD = "run";
+
+ private static final String INTERCEPT_RUN_HANDLE = "org.apache.skywalking.apm.plugin.ThreadPerTaskExecutorRunInterceptor";
+
+ private static final String TASK_RUNNER_CONSTRUCT_METHOD_INTERCEPTOR = "org.apache.skywalking.apm.plugin.ThreadPerTaskExecutorConstructInterceptor";
+
+ @Override
+ public boolean isBootstrapInstrumentation() {
+ return true;
+ }
+
+ @Override
+ protected ClassMatch enhanceClass() {
+ return MultiClassNameMatch.byMultiClassMatch(ENHANCE_CLASS);
+ }
+
+ @Override
+ public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
+ return new ConstructorInterceptPoint[]{
+ new ConstructorInterceptPoint() {
+ @Override
+ public ElementMatcher getConstructorMatcher() {
+ return any();
+ }
+
+ @Override
+ public String getConstructorInterceptor() {
+ return TASK_RUNNER_CONSTRUCT_METHOD_INTERCEPTOR;
+ }
+ }
+ };
+ }
+
+ @Override
+ public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
+ return new InstanceMethodsInterceptPoint[]{
+ new InstanceMethodsInterceptPoint() {
+ @Override
+ public ElementMatcher getMethodsMatcher() {
+ return ElementMatchers.named(INTERCEPT_RUN_METHOD);
+ }
+
+ @Override
+ public String getMethodsInterceptor() {
+ return INTERCEPT_RUN_HANDLE;
+ }
+
+ @Override
+ public boolean isOverrideArgs() {
+ return true;
+ }
+ }
+ };
+ }
+}
diff --git a/apm-sniffer/bootstrap-plugins/jdk-virtual-thread-executor-plugin/src/main/resources/skywalking-plugin.def b/apm-sniffer/bootstrap-plugins/jdk-virtual-thread-executor-plugin/src/main/resources/skywalking-plugin.def
new file mode 100644
index 0000000000..3ab6a970a9
--- /dev/null
+++ b/apm-sniffer/bootstrap-plugins/jdk-virtual-thread-executor-plugin/src/main/resources/skywalking-plugin.def
@@ -0,0 +1,18 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+jdk-virtual-thread-executor-plugin=org.apache.skywalking.apm.plugin.define.ThreadPerTaskExecutorTaskRunnerInstrumentation
+jdk-virtual-thread-executor-plugin=org.apache.skywalking.apm.plugin.define.ThreadPerTaskExecutorFutureInstrumentation
\ No newline at end of file
diff --git a/apm-sniffer/bootstrap-plugins/pom.xml b/apm-sniffer/bootstrap-plugins/pom.xml
index bc540de6ab..fe3bf24930 100644
--- a/apm-sniffer/bootstrap-plugins/pom.xml
+++ b/apm-sniffer/bootstrap-plugins/pom.xml
@@ -21,7 +21,7 @@
java-agent-sniffer
org.apache.skywalking
- 9.3.0-SNAPSHOT
+ 9.7.0-SNAPSHOT
4.0.0
@@ -32,10 +32,7 @@
${shade.package}.${shade.net.bytebuddy.source}
UTF-8
-
- ${project.build.directory}${sdk.plugin.related.dir}/../../../../skywalking-agent
-
- ${agent.package.dest.dir}/bootstrap-plugins
+ ${maven.multiModuleProjectDirectory}/skywalking-agent/bootstrap-plugins
1.0b3
1.8.1
@@ -46,6 +43,8 @@
jdk-threading-plugin
jdk-threadpool-plugin
jdk-forkjoinpool-plugin
+ jdk-virtual-thread-executor-plugin
+ jdk-httpclient-plugin
diff --git a/apm-sniffer/bytebuddy-patch/pom.xml b/apm-sniffer/bytebuddy-patch/pom.xml
index e5ec1d0cda..460631dfc3 100644
--- a/apm-sniffer/bytebuddy-patch/pom.xml
+++ b/apm-sniffer/bytebuddy-patch/pom.xml
@@ -21,7 +21,7 @@
org.apache.skywalking
java-agent-sniffer
- 9.3.0-SNAPSHOT
+ 9.7.0-SNAPSHOT
4.0.0
diff --git a/apm-sniffer/bytebuddy-patch/src/main/java/net/bytebuddy/agent/builder/SWDescriptionStrategy.java b/apm-sniffer/bytebuddy-patch/src/main/java/net/bytebuddy/agent/builder/SWDescriptionStrategy.java
index 62e8a0606c..0d10a039bb 100644
--- a/apm-sniffer/bytebuddy-patch/src/main/java/net/bytebuddy/agent/builder/SWDescriptionStrategy.java
+++ b/apm-sniffer/bytebuddy-patch/src/main/java/net/bytebuddy/agent/builder/SWDescriptionStrategy.java
@@ -34,10 +34,12 @@
import java.io.Serializable;
import java.lang.annotation.Annotation;
import java.util.Arrays;
+import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.WeakHashMap;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
@@ -125,9 +127,16 @@ static class SWTypeDescriptionWrapper extends TypeDescription.AbstractBase imple
/**
* Original type cache.
- * classloader hashcode -> ( typeName -> type cache )
+ * ClassLoader -> (typeName -> TypeCache)
+ * Using WeakHashMap to automatically clean up cache when ClassLoader is garbage collected.
*/
- private static final Map> CLASS_LOADER_TYPE_CACHE = new ConcurrentHashMap<>();
+ private static final Map> CLASS_LOADER_TYPE_CACHE =
+ Collections.synchronizedMap(new WeakHashMap<>());
+
+ /**
+ * Bootstrap ClassLoader cache (null key cannot be stored in WeakHashMap)
+ */
+ private static final Map BOOTSTRAP_TYPE_CACHE = new ConcurrentHashMap<>();
private static final List IGNORED_INTERFACES = Arrays.asList(EnhancedInstance.class.getName());
@@ -153,10 +162,15 @@ public SWTypeDescriptionWrapper(TypeDescription delegate, String nameTrait, Clas
}
private TypeCache getTypeCache() {
- int classLoaderHashCode = classLoader != null ? classLoader.hashCode() : 0;
- Map typeCacheMap = CLASS_LOADER_TYPE_CACHE.computeIfAbsent(classLoaderHashCode, k -> new ConcurrentHashMap<>());
- TypeCache typeCache = typeCacheMap.computeIfAbsent(typeName, k -> new TypeCache(typeName));
- return typeCache;
+ if (classLoader == null) {
+ // Bootstrap ClassLoader - use separate cache since null key cannot be stored in WeakHashMap
+ return BOOTSTRAP_TYPE_CACHE.computeIfAbsent(typeName, k -> new TypeCache(typeName));
+ } else {
+ // Regular ClassLoader - use WeakHashMap for automatic cleanup
+ Map typeCacheMap = CLASS_LOADER_TYPE_CACHE.computeIfAbsent(
+ classLoader, k -> new ConcurrentHashMap<>());
+ return typeCacheMap.computeIfAbsent(typeName, k -> new TypeCache(typeName));
+ }
}
@Override
diff --git a/apm-sniffer/bytebuddy-patch/src/test/java/net/bytebuddy/agent/builder/SWDescriptionStrategyCacheTest.java b/apm-sniffer/bytebuddy-patch/src/test/java/net/bytebuddy/agent/builder/SWDescriptionStrategyCacheTest.java
new file mode 100644
index 0000000000..90f9e4a437
--- /dev/null
+++ b/apm-sniffer/bytebuddy-patch/src/test/java/net/bytebuddy/agent/builder/SWDescriptionStrategyCacheTest.java
@@ -0,0 +1,239 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package net.bytebuddy.agent.builder;
+
+import org.junit.Test;
+import org.junit.Assert;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.net.URLClassLoader;
+import java.net.URL;
+import java.util.Map;
+
+/**
+ * Tests the behavior of the WeakHashMap caching mechanism in SWDescriptionStrategy.
+ */
+public class SWDescriptionStrategyCacheTest {
+
+ @Test
+ public void testWeakHashMapCacheCleanup() throws Exception {
+ // Get static cache field
+ Field cacheField = SWDescriptionStrategy.SWTypeDescriptionWrapper.class
+ .getDeclaredField("CLASS_LOADER_TYPE_CACHE");
+ cacheField.setAccessible(true);
+ @SuppressWarnings("unchecked")
+ Map> cache =
+ (Map>) cacheField.get(null);
+
+ // Record initial cache size
+ int initialCacheSize = cache.size();
+
+ // Create test ClassLoader
+ URLClassLoader testClassLoader = new URLClassLoader(new URL[0], null);
+ String testTypeName = "com.test.DynamicClass";
+
+ // Create SWTypeDescriptionWrapper instance
+ SWDescriptionStrategy.SWTypeDescriptionWrapper wrapper =
+ new SWDescriptionStrategy.SWTypeDescriptionWrapper(
+ null, "test", testClassLoader, testTypeName);
+
+ // Call getTypeCache method via reflection to trigger caching
+ Method getTypeCacheMethod = wrapper.getClass()
+ .getDeclaredMethod("getTypeCache");
+ getTypeCacheMethod.setAccessible(true);
+ SWDescriptionStrategy.TypeCache typeCache =
+ (SWDescriptionStrategy.TypeCache) getTypeCacheMethod.invoke(wrapper);
+
+ // Verify that the ClassLoader exists in cache
+ Assert.assertTrue("Cache should contain the test ClassLoader",
+ cache.containsKey(testClassLoader));
+ Assert.assertNotNull("TypeCache should be created", typeCache);
+ Assert.assertEquals("Cache size should increase by 1",
+ initialCacheSize + 1, cache.size());
+
+ // Clear ClassLoader references, prepare for GC test
+ testClassLoader = null;
+ wrapper = null;
+ typeCache = null;
+
+ // Force garbage collection
+ System.gc();
+ Thread.sleep(100);
+ System.gc();
+ Thread.sleep(100);
+
+ // WeakHashMap should automatically clean up garbage collected ClassLoader entries
+ int attempts = 0;
+ int currentCacheSize = cache.size();
+ while (currentCacheSize > initialCacheSize && attempts < 20) {
+ System.gc();
+ Thread.sleep(50);
+ currentCacheSize = cache.size();
+ attempts++;
+ }
+
+ System.out.println("Cache size after GC: " + currentCacheSize +
+ " (initial: " + initialCacheSize + ", attempts: " + attempts + ")");
+
+ // Verify that WeakHashMap cleanup mechanism works properly
+ Assert.assertTrue("WeakHashMap should clean up entries or attempts should be reasonable",
+ currentCacheSize <= initialCacheSize + 1 && attempts < 20);
+ }
+
+ @Test
+ public void testBootstrapClassLoaderHandling() throws Exception {
+ // Get Bootstrap ClassLoader cache field
+ Field bootstrapCacheField = SWDescriptionStrategy.SWTypeDescriptionWrapper.class
+ .getDeclaredField("BOOTSTRAP_TYPE_CACHE");
+ bootstrapCacheField.setAccessible(true);
+ @SuppressWarnings("unchecked")
+ Map bootstrapCache =
+ (Map) bootstrapCacheField.get(null);
+
+ int initialBootstrapCacheSize = bootstrapCache.size();
+
+ // Test Bootstrap ClassLoader (null) handling
+ String testTypeName = "test.BootstrapClass";
+ SWDescriptionStrategy.SWTypeDescriptionWrapper wrapper =
+ new SWDescriptionStrategy.SWTypeDescriptionWrapper(
+ null, "test", null, testTypeName);
+
+ // Call getTypeCache method via reflection
+ Method getTypeCacheMethod = wrapper.getClass()
+ .getDeclaredMethod("getTypeCache");
+ getTypeCacheMethod.setAccessible(true);
+ SWDescriptionStrategy.TypeCache typeCache =
+ (SWDescriptionStrategy.TypeCache) getTypeCacheMethod.invoke(wrapper);
+
+ // Verify Bootstrap ClassLoader cache handling
+ Assert.assertNotNull("TypeCache should be created for bootstrap classloader", typeCache);
+ Assert.assertTrue("Bootstrap cache should contain the type",
+ bootstrapCache.containsKey(testTypeName));
+ Assert.assertEquals("Bootstrap cache size should increase by 1",
+ initialBootstrapCacheSize + 1, bootstrapCache.size());
+ }
+
+ @Test
+ public void testMultipleClassLoadersIndependentCache() throws Exception {
+ Field cacheField = SWDescriptionStrategy.SWTypeDescriptionWrapper.class
+ .getDeclaredField("CLASS_LOADER_TYPE_CACHE");
+ cacheField.setAccessible(true);
+ @SuppressWarnings("unchecked")
+ Map> cache =
+ (Map>) cacheField.get(null);
+
+ int initialCacheSize = cache.size();
+
+ // Create two different ClassLoaders
+ URLClassLoader classLoader1 = new URLClassLoader(new URL[0], null);
+ URLClassLoader classLoader2 = new URLClassLoader(new URL[0], null);
+ String testTypeName = "com.test.SameClassName";
+
+ // Create TypeCache with same class name for both ClassLoaders
+ SWDescriptionStrategy.SWTypeDescriptionWrapper wrapper1 =
+ new SWDescriptionStrategy.SWTypeDescriptionWrapper(
+ null, "test", classLoader1, testTypeName);
+ SWDescriptionStrategy.SWTypeDescriptionWrapper wrapper2 =
+ new SWDescriptionStrategy.SWTypeDescriptionWrapper(
+ null, "test", classLoader2, testTypeName);
+
+ // Call getTypeCache method via reflection
+ Method getTypeCacheMethod =
+ SWDescriptionStrategy.SWTypeDescriptionWrapper.class.getDeclaredMethod("getTypeCache");
+ getTypeCacheMethod.setAccessible(true);
+
+ SWDescriptionStrategy.TypeCache typeCache1 =
+ (SWDescriptionStrategy.TypeCache) getTypeCacheMethod.invoke(wrapper1);
+ SWDescriptionStrategy.TypeCache typeCache2 =
+ (SWDescriptionStrategy.TypeCache) getTypeCacheMethod.invoke(wrapper2);
+
+ // Verify that the two ClassLoaders have independent cache entries
+ Assert.assertNotNull("TypeCache1 should be created", typeCache1);
+ Assert.assertNotNull("TypeCache2 should be created", typeCache2);
+ Assert.assertNotSame("TypeCaches should be different instances", typeCache1, typeCache2);
+
+ // Verify cache structure
+ Assert.assertEquals("Cache should contain both classloaders",
+ initialCacheSize + 2, cache.size());
+ Assert.assertTrue("Cache should contain classloader1", cache.containsKey(classLoader1));
+ Assert.assertTrue("Cache should contain classloader2", cache.containsKey(classLoader2));
+
+ // Verify each ClassLoader has independent type cache
+ Map typeCacheMap1 = cache.get(classLoader1);
+ Map typeCacheMap2 = cache.get(classLoader2);
+
+ Assert.assertNotNull("ClassLoader1 should have type cache map", typeCacheMap1);
+ Assert.assertNotNull("ClassLoader2 should have type cache map", typeCacheMap2);
+ Assert.assertNotSame("Type cache maps should be different", typeCacheMap1, typeCacheMap2);
+
+ Assert.assertTrue("ClassLoader1 cache should contain the type",
+ typeCacheMap1.containsKey(testTypeName));
+ Assert.assertTrue("ClassLoader2 cache should contain the type",
+ typeCacheMap2.containsKey(testTypeName));
+ }
+
+ @Test
+ public void testConcurrentAccess() throws Exception {
+ // Test concurrent access scenario
+ final String testTypeName = "com.test.ConcurrentClass";
+ final int threadCount = 10;
+ final Thread[] threads = new Thread[threadCount];
+ final URLClassLoader[] classLoaders = new URLClassLoader[threadCount];
+ final SWDescriptionStrategy.TypeCache[] results = new SWDescriptionStrategy.TypeCache[threadCount];
+
+ // Create multiple threads to access cache simultaneously
+ for (int i = 0; i < threadCount; i++) {
+ final int index = i;
+ classLoaders[i] = new URLClassLoader(new URL[0], null);
+ threads[i] = new Thread(() -> {
+ try {
+ SWDescriptionStrategy.SWTypeDescriptionWrapper wrapper =
+ new SWDescriptionStrategy.SWTypeDescriptionWrapper(
+ null, "test", classLoaders[index], testTypeName);
+
+ Method getTypeCacheMethod = wrapper.getClass()
+ .getDeclaredMethod("getTypeCache");
+ getTypeCacheMethod.setAccessible(true);
+ results[index] = (SWDescriptionStrategy.TypeCache)
+ getTypeCacheMethod.invoke(wrapper);
+ } catch (Exception e) {
+ Assert.fail("Concurrent access should not throw exception: " + e.getMessage());
+ }
+ });
+ }
+
+ // Start all threads
+ for (Thread thread : threads) {
+ thread.start();
+ }
+
+ // Wait for all threads to complete
+ for (Thread thread : threads) {
+ thread.join(1000); // Wait at most 1 second
+ }
+
+ // Verify all results
+ for (int i = 0; i < threadCount; i++) {
+ Assert.assertNotNull("Result " + i + " should not be null", results[i]);
+ }
+
+ System.out.println("Concurrent access test completed successfully with " + threadCount + " threads");
+ }
+}
\ No newline at end of file
diff --git a/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-9.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/v9/server/Constants.java b/apm-sniffer/bytebuddy-patch/src/test/java/org/apache/skywalking/apm/agent/bytebuddy/biz/ChildBar.java
similarity index 77%
rename from apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-9.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/v9/server/Constants.java
rename to apm-sniffer/bytebuddy-patch/src/test/java/org/apache/skywalking/apm/agent/bytebuddy/biz/ChildBar.java
index e1e8d84d65..e7ac8d49ff 100644
--- a/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-9.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/v9/server/Constants.java
+++ b/apm-sniffer/bytebuddy-patch/src/test/java/org/apache/skywalking/apm/agent/bytebuddy/biz/ChildBar.java
@@ -6,7 +6,7 @@
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
@@ -14,11 +14,14 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*
- *
*/
-package org.apache.skywalking.apm.plugin.jetty.v9.server;
+package org.apache.skywalking.apm.agent.bytebuddy.biz;
+
+public class ChildBar extends ParentBar {
+
+ public String sayHelloChild() {
+ return "Joe";
+ }
-public class Constants {
- public static final String FORWARD_REQUEST_FLAG = "SW_FORWARD_REQUEST_FLAG";
}
diff --git a/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-11.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/v11/server/Constants.java b/apm-sniffer/bytebuddy-patch/src/test/java/org/apache/skywalking/apm/agent/bytebuddy/biz/ParentBar.java
similarity index 77%
rename from apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-11.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/v11/server/Constants.java
rename to apm-sniffer/bytebuddy-patch/src/test/java/org/apache/skywalking/apm/agent/bytebuddy/biz/ParentBar.java
index 156bb0517b..6113b4c41a 100644
--- a/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-11.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/v11/server/Constants.java
+++ b/apm-sniffer/bytebuddy-patch/src/test/java/org/apache/skywalking/apm/agent/bytebuddy/biz/ParentBar.java
@@ -6,7 +6,7 @@
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
@@ -14,11 +14,13 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*
- *
*/
-package org.apache.skywalking.apm.plugin.jetty.v11.server;
+package org.apache.skywalking.apm.agent.bytebuddy.biz;
+
+public class ParentBar {
-public class Constants {
- public static final String FORWARD_REQUEST_FLAG = "SW_FORWARD_REQUEST_FLAG";
+ public String sayHelloParent() {
+ return "Joe";
+ }
}
diff --git a/apm-sniffer/bytebuddy-patch/src/test/java/org/apache/skywalking/apm/agent/bytebuddy/cases/AbstractInterceptTest.java b/apm-sniffer/bytebuddy-patch/src/test/java/org/apache/skywalking/apm/agent/bytebuddy/cases/AbstractInterceptTest.java
index ba9cf4d372..627fc8888d 100644
--- a/apm-sniffer/bytebuddy-patch/src/test/java/org/apache/skywalking/apm/agent/bytebuddy/cases/AbstractInterceptTest.java
+++ b/apm-sniffer/bytebuddy-patch/src/test/java/org/apache/skywalking/apm/agent/bytebuddy/cases/AbstractInterceptTest.java
@@ -24,6 +24,7 @@
import net.bytebuddy.agent.builder.SWAgentBuilderDefault;
import net.bytebuddy.agent.builder.SWDescriptionStrategy;
import net.bytebuddy.agent.builder.SWNativeMethodStrategy;
+import net.bytebuddy.description.modifier.Visibility;
import net.bytebuddy.implementation.FieldAccessor;
import net.bytebuddy.implementation.MethodDelegation;
import net.bytebuddy.implementation.SWImplementationContextFactory;
@@ -38,6 +39,7 @@
import org.apache.skywalking.apm.agent.bytebuddy.SWAuxiliaryTypeNamingStrategy;
import org.apache.skywalking.apm.agent.bytebuddy.SWClassFileLocator;
import org.apache.skywalking.apm.agent.bytebuddy.biz.BizFoo;
+import org.apache.skywalking.apm.agent.bytebuddy.biz.ChildBar;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
import org.junit.Assert;
import org.junit.BeforeClass;
@@ -58,11 +60,15 @@
import static net.bytebuddy.jar.asm.Opcodes.ACC_PRIVATE;
import static net.bytebuddy.jar.asm.Opcodes.ACC_VOLATILE;
import static org.apache.skywalking.apm.agent.core.plugin.AbstractClassEnhancePluginDefine.CONTEXT_ATTR_NAME;
+import static org.apache.skywalking.apm.agent.core.plugin.AbstractClassEnhancePluginDefine.CONTEXT_GETTER_NAME;
+import static org.apache.skywalking.apm.agent.core.plugin.AbstractClassEnhancePluginDefine.CONTEXT_SETTER_NAME;
public class AbstractInterceptTest {
public static final String BIZ_FOO_CLASS_NAME = "org.apache.skywalking.apm.agent.bytebuddy.biz.BizFoo";
public static final String PROJECT_SERVICE_CLASS_NAME = "org.apache.skywalking.apm.agent.bytebuddy.biz.ProjectService";
public static final String DOC_SERVICE_CLASS_NAME = "org.apache.skywalking.apm.agent.bytebuddy.biz.DocService";
+ public static final String PARENT_BAR_CLASS_NAME = "org.apache.skywalking.apm.agent.bytebuddy.biz.ParentBar";
+ public static final String CHILD_BAR_CLASS_NAME = "org.apache.skywalking.apm.agent.bytebuddy.biz.ChildBar";
public static final String SAY_HELLO_METHOD = "sayHello";
public static final int BASE_INT_VALUE = 100;
public static final String CONSTRUCTOR_INTERCEPTOR_CLASS = "constructorInterceptorClass";
@@ -85,6 +91,20 @@ protected void failed(Throwable e, Description description) {
}
};
+ protected static void callBar(int round) {
+ Log.info("-------------");
+ Log.info("callChildBar: " + round);
+ // load target class
+ String strResultChild = new ChildBar().sayHelloChild();
+ Log.info("result: " + strResultChild);
+
+ String strResultParent = new ChildBar().sayHelloParent();
+ Log.info("result: " + strResultParent);
+
+ Assert.assertEquals("String value is unexpected", "John", strResultChild);
+ Assert.assertEquals("String value is unexpected", "John", strResultParent);
+ }
+
protected static void callBizFoo(int round) {
Log.info("-------------");
Log.info("callBizFoo: " + round);
@@ -115,7 +135,7 @@ protected static void checkConstructorInterceptor(String className, int round) {
protected static void checkInterface(Class testClass, Class interfaceCls) {
Assert.assertTrue("Check interface failure, the test class: " + testClass + " does not implement the expected interface: " + interfaceCls,
- EnhancedInstance.class.isAssignableFrom(BizFoo.class));
+ EnhancedInstance.class.isAssignableFrom(testClass));
}
protected static void checkErrors() {
@@ -195,6 +215,9 @@ protected void installInterface(String className) {
builder = builder.defineField(
CONTEXT_ATTR_NAME, Object.class, ACC_PRIVATE | ACC_VOLATILE)
.implement(EnhancedInstance.class)
+ .defineMethod(CONTEXT_GETTER_NAME, Object.class, Visibility.PUBLIC)
+ .intercept(FieldAccessor.ofField(CONTEXT_ATTR_NAME))
+ .defineMethod(CONTEXT_SETTER_NAME, void.class, Visibility.PUBLIC).withParameters(Object.class)
.intercept(FieldAccessor.ofField(CONTEXT_ATTR_NAME));
}
return builder;
@@ -223,7 +246,7 @@ protected void installTraceClassTransformer(String msg) {
ClassFileTransformer classFileTransformer = new ClassFileTransformer() {
@Override
public byte[] transform(ClassLoader loader, String className, Class> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
- if (className.endsWith("BizFoo") || className.endsWith("ProjectService") || className.endsWith("DocService")) {
+ if (className.endsWith("BizFoo") || className.endsWith("ProjectService") || className.endsWith("DocService") || className.endsWith("ChildBar") || className.endsWith("ParentBar")) {
Log.error(msg + className);
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
ClassReader cr = new ClassReader(classfileBuffer);
diff --git a/apm-sniffer/bytebuddy-patch/src/test/java/org/apache/skywalking/apm/agent/bytebuddy/cases/ReTransform4Test.java b/apm-sniffer/bytebuddy-patch/src/test/java/org/apache/skywalking/apm/agent/bytebuddy/cases/ReTransform4Test.java
new file mode 100644
index 0000000000..877dd416e7
--- /dev/null
+++ b/apm-sniffer/bytebuddy-patch/src/test/java/org/apache/skywalking/apm/agent/bytebuddy/cases/ReTransform4Test.java
@@ -0,0 +1,62 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.agent.bytebuddy.cases;
+
+import net.bytebuddy.agent.ByteBuddyAgent;
+import org.apache.skywalking.apm.agent.bytebuddy.biz.ChildBar;
+import org.apache.skywalking.apm.agent.bytebuddy.biz.ParentBar;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
+import org.junit.Test;
+
+import java.lang.instrument.Instrumentation;
+
+public class ReTransform4Test extends AbstractReTransformTest {
+
+ @Test
+ public void testInterceptConstructor() throws Exception {
+ Instrumentation instrumentation = ByteBuddyAgent.install();
+
+ // install transformer
+ installMethodInterceptor(PARENT_BAR_CLASS_NAME, "sayHelloParent", 1);
+ installMethodInterceptor(CHILD_BAR_CLASS_NAME, "sayHelloChild", 1);
+ // implement EnhancedInstance
+ installInterface(PARENT_BAR_CLASS_NAME);
+ installInterface(CHILD_BAR_CLASS_NAME);
+
+ // call target class
+ callBar(1);
+
+ // check interceptors
+ checkInterface(ParentBar.class, EnhancedInstance.class);
+ checkInterface(ChildBar.class, EnhancedInstance.class);
+ checkErrors();
+
+ installTraceClassTransformer("Trace class: ");
+
+ // do retransform
+ reTransform(instrumentation, ChildBar.class);
+
+ // check interceptors
+ checkInterface(ParentBar.class, EnhancedInstance.class);
+ checkInterface(ChildBar.class, EnhancedInstance.class);
+ checkErrors();
+ }
+
+}
+
diff --git a/apm-sniffer/config/agent.config b/apm-sniffer/config/agent.config
index 65b95a6fbd..b9101f1f1c 100755
--- a/apm-sniffer/config/agent.config
+++ b/apm-sniffer/config/agent.config
@@ -36,6 +36,9 @@ agent.authentication=${SW_AGENT_AUTHENTICATION:}
# The max number of TraceSegmentRef in a single span to keep memory cost estimatable.
agent.trace_segment_ref_limit_per_span=${SW_TRACE_SEGMENT_LIMIT:500}
+# The max number of logs in a single span to keep memory cost estimatable.
+agent.log_limit_per_span=${SW_LOG_LIMIT_PER_SPAN:500}
+
# The max amount of spans in a single segment.
# Through this config item, SkyWalking keep your application memory cost estimated.
agent.span_limit_per_segment=${SW_AGENT_SPAN_LIMIT:300}
@@ -164,6 +167,12 @@ profile.duration=${SW_AGENT_PROFILE_DURATION:10}
profile.dump_max_stack_depth=${SW_AGENT_PROFILE_DUMP_MAX_STACK_DEPTH:500}
# Snapshot transport to backend buffer size
profile.snapshot_transport_buffer_size=${SW_AGENT_PROFILE_SNAPSHOT_TRANSPORT_BUFFER_SIZE:4500}
+# If true, async profiler will be enabled when user creates a new async profiler task. If false, it will be disabled. The default value is true.
+asyncprofiler.active=${SW_AGENT_ASYNC_PROFILER_ACTIVE:true}
+# Max execution time(second) for the Async Profiler. The task will be stopped even if a longer time is specified. default 20min.
+asyncprofiler.max_duration=${SW_AGENT_ASYNC_PROFILER_MAX_DURATION:1200}
+# Path for the JFR outputs from the Async Profiler. If the parameter is not empty, the file will be created in the specified directory, otherwise the Files.createTemp method will be used to create the file.
+asyncprofiler.output_path=${SW_AGENT_ASYNC_PROFILER_OUTPUT_PATH:}
# If true, the agent collects and reports metrics to the backend.
meter.active=${SW_METER_ACTIVE:true}
# Report meters interval. The unit is second
@@ -209,8 +218,10 @@ plugin.jdkthreading.threading_class_prefixes=${SW_PLUGIN_JDKTHREADING_THREADING_
plugin.tomcat.collect_http_params=${SW_PLUGIN_TOMCAT_COLLECT_HTTP_PARAMS:false}
# This config item controls that whether the SpringMVC plugin should collect the parameters of the request, when your Spring application is based on Tomcat, consider only setting either `plugin.tomcat.collect_http_params` or `plugin.springmvc.collect_http_params`. Also, activate implicitly in the profiled trace.
plugin.springmvc.collect_http_params=${SW_PLUGIN_SPRINGMVC_COLLECT_HTTP_PARAMS:false}
-# This config item controls that whether the HttpClient plugin should collect the parameters of the request
+# This config item controls that whether the HttpClient plugin should collect the parameters of the request
plugin.httpclient.collect_http_params=${SW_PLUGIN_HTTPCLIENT_COLLECT_HTTP_PARAMS:false}
+# Comma-separated list of destination ports whose outbound HTTP requests will be completely skipped by the httpclient-4.x interceptor (no exit span created, no sw8 headers injected).
+plugin.httpclient.propagation_exclude_ports=${SW_PLUGIN_HTTPCLIENT_PROPAGATION_EXCLUDE_PORTS:}
# When `COLLECT_HTTP_PARAMS` is enabled, how many characters to keep and send to the OAP backend, use negative values to keep and send the complete parameters, NB. this config item is added for the sake of performance.
plugin.http.http_params_length_threshold=${SW_PLUGIN_HTTP_HTTP_PARAMS_LENGTH_THRESHOLD:1024}
# When `include_http_headers` declares header names, this threshold controls the length limitation of all header values. use negative values to keep and send the complete headers. Note. this config item is added for the sake of performance.
@@ -320,3 +331,43 @@ plugin.nettyhttp.supported_content_types_prefix=${SW_PLUGIN_NETTYHTTP_SUPPORTED_
plugin.rocketmqclient.collect_message_keys=${SW_PLUGIN_ROCKETMQCLIENT_COLLECT_MESSAGE_KEYS:false}
# If set to true, the tags of messages would be collected by the plugin for RocketMQ Java client.
plugin.rocketmqclient.collect_message_tags=${SW_PLUGIN_ROCKETMQCLIENT_COLLECT_MESSAGE_TAGS:false}
+# Define the max length of collected HTTP parameters. The default value(=0) means not collecting.
+plugin.solon.http_params_length_threshold=${SW_PLUGIN_SOLON_HTTP_PARAMS_LENGTH_THRESHOLD:0}
+# It controls what header data should be collected, values must be in lower case, if empty, no header data will be collected. default is empty.
+plugin.solon.include_http_headers=${SW_PLUGIN_SOLON_INCLUDE_HTTP_HEADERS:}
+# Define the max length of collected HTTP body. The default value(=0) means not collecting.
+plugin.solon.http_body_length_threshold=${SW_PLUGIN_SOLON_HTTP_BODY_LENGTH_THRESHOLD:0}
+# Specify which command should be converted to write operation
+plugin.caffeine.operation_mapping_write=${SW_PLUGIN_CAFFEINE_OPERATION_MAPPING_WRITE:put,putAll,remove,clear}
+# Specify which command should be converted to read operation
+plugin.caffeine.operation_mapping_read=${SW_PLUGIN_CAFFEINE_OPERATION_MAPPING_READ:getIfPresent,getAllPresent,computeIfAbsent}
+# Whether to collect the input messages of the GenAI request.
+plugin.springai.collect_input_messages=${SW_PLUGIN_SPRINGAI_COLLECT_INPUT_MESSAGES:false}
+# Whether to collect the output messages of the GenAI response.
+plugin.springai.collect_output_messages=${SW_PLUGIN_SPRINGAI_COLLECT_OUTPUT_MESSAGES:false}
+# The maximum characters of the collected prompt content.
+# If the content exceeds this limit, it will be truncated.
+# Use a negative value to represent no limit, but be aware this could cause OOM.
+plugin.springai.prompt_length_limit=${SW_PLUGIN_SPRINGAI_PROMPT_LENGTH_LIMIT:1024}
+# The maximum characters of the collected completion content.
+# If the content exceeds this limit, it will be truncated.
+# Use a negative value to represent no limit, but be aware this could cause OOM.
+plugin.springai.completion_length_limit=${SW_PLUGIN_SPRINGAI_COMPLETION_LENGTH_LIMIT:1024}
+# The threshold for token usage to trigger content collection.
+# When set to a positive value, prompt and completion will only be collected
+# if the total token usage of the request exceeds this threshold.
+# This requires collect_prompt or collect_completion to be enabled first.
+# Use a negative value to disable this threshold-based filtering (collect all).
+plugin.springai.content_collect_threshold_tokens=${SW_PLUGIN_SPRINGAI_CONTENT_COLLECT_THRESHOLD_TOKENS:-1}
+# Whether to collect the arguments (input parameters) of the tool/function call.
+plugin.springai.collect_tool_input=${SW_PLUGIN_SPRINGAI_COLLECT_TOOL_INPUT:false}
+# Whether to collect the execution result (output) of the tool/function call.
+plugin.springai.collect_tool_output=${SW_PLUGIN_SPRINGAI_COLLECT_TOOL_OUTPUT:false}
+# Whether to collect the query of the rag call.
+plugin.springai.collect_retrieval_query=${SW_PLUGIN_SPRINGAI_COLLECT_RETRIEVAL_QUERY:false}
+# The maximum characters of the collected rag query.
+# If the content exceeds this limit, it will be truncated.
+# Use a negative value to represent no limit, but be aware this could cause OOM.
+plugin.springai.retrieval_query_length_limit=${SW_PLUGIN_SPRINGAI_RETRIEVAL_QUERY_LENGTH_LIMIT:1024}
+# Whether to collect the documents of the rag call.
+plugin.springai.collect_retrieval_documents=${SW_PLUGIN_SPRINGAI_COLLECT_RETRIEVAL_DOCUMENTS:false}
\ No newline at end of file
diff --git a/apm-sniffer/expired-plugins/impala-jdbc-2.6.x-plugin/pom.xml b/apm-sniffer/expired-plugins/impala-jdbc-2.6.x-plugin/pom.xml
index 38b2880c74..5dfd4ed7ab 100644
--- a/apm-sniffer/expired-plugins/impala-jdbc-2.6.x-plugin/pom.xml
+++ b/apm-sniffer/expired-plugins/impala-jdbc-2.6.x-plugin/pom.xml
@@ -24,7 +24,7 @@
org.apache.skywalking
expired-plugins
- 9.3.0-SNAPSHOT
+ 9.7.0-SNAPSHOT
apm-impala-jdbc-2.6.x-plugin
diff --git a/apm-sniffer/expired-plugins/pom.xml b/apm-sniffer/expired-plugins/pom.xml
index 817506785a..4385464c61 100644
--- a/apm-sniffer/expired-plugins/pom.xml
+++ b/apm-sniffer/expired-plugins/pom.xml
@@ -21,7 +21,7 @@
java-agent-sniffer
org.apache.skywalking
- 9.3.0-SNAPSHOT
+ 9.7.0-SNAPSHOT
4.0.0
@@ -32,10 +32,7 @@
${shade.package}.${shade.net.bytebuddy.source}
UTF-8
-
- ${project.build.directory}${sdk.plugin.related.dir}/../../../../skywalking-agent
-
- ${agent.package.dest.dir}/expired-plugins
+ ${maven.multiModuleProjectDirectory}/skywalking-agent/expired-plugins
1.0b3
1.8.1
diff --git a/apm-sniffer/apm-sdk-plugin/tomcat-10x-plugin/pom.xml b/apm-sniffer/optional-plugins/caffeine-3.x-plugin/pom.xml
similarity index 73%
rename from apm-sniffer/apm-sdk-plugin/tomcat-10x-plugin/pom.xml
rename to apm-sniffer/optional-plugins/caffeine-3.x-plugin/pom.xml
index 48b7ce02ff..89d8d96b65 100644
--- a/apm-sniffer/apm-sdk-plugin/tomcat-10x-plugin/pom.xml
+++ b/apm-sniffer/optional-plugins/caffeine-3.x-plugin/pom.xml
@@ -18,28 +18,28 @@
-->
+ 4.0.0
- apm-sdk-plugin
org.apache.skywalking
- 9.3.0-SNAPSHOT
+ optional-plugins
+ 9.7.0-SNAPSHOT
- 4.0.0
- tomcat-10x-plugin
- 8.11.0
+ apm-caffeine-3.x-plugin
+ jar
+ caffeine-3.x-plugin
- 8
- 8
- 10.0.22
+ UTF-8
+ 3.1.8
+
- org.apache.tomcat.embed
- tomcat-embed-core
- ${tomcat.version}
+ com.github.ben-manes.caffeine
+ caffeine
+ ${caffeine.version}
provided
-
diff --git a/apm-sniffer/optional-plugins/caffeine-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/caffeine/v3/AbstractCaffeineInterceptor.java b/apm-sniffer/optional-plugins/caffeine-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/caffeine/v3/AbstractCaffeineInterceptor.java
new file mode 100644
index 0000000000..9c66cabd08
--- /dev/null
+++ b/apm-sniffer/optional-plugins/caffeine-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/caffeine/v3/AbstractCaffeineInterceptor.java
@@ -0,0 +1,71 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.caffeine.v3;
+
+import java.lang.reflect.Method;
+import org.apache.skywalking.apm.agent.core.context.ContextManager;
+import org.apache.skywalking.apm.agent.core.context.tag.Tags;
+import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan;
+import org.apache.skywalking.apm.agent.core.context.trace.SpanLayer;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
+import org.apache.skywalking.apm.network.trace.component.ComponentsDefine;
+
+import static org.apache.skywalking.apm.plugin.caffeine.v3.CaffeineOperationTransform.transformOperation;
+
+abstract public class AbstractCaffeineInterceptor implements InstanceMethodsAroundInterceptor {
+
+ protected AbstractSpan generateSpanInfo(String methodName) {
+ AbstractSpan span = ContextManager.createLocalSpan("Caffeine/" + methodName);
+ span.setComponent(ComponentsDefine.CAFFEINE);
+ Tags.CACHE_TYPE.set(span, ComponentsDefine.CAFFEINE.getName());
+ Tags.CACHE_CMD.set(span, methodName);
+ transformOperation(methodName).ifPresent(op -> Tags.CACHE_OP.set(span, op));
+ SpanLayer.asCache(span);
+ return span;
+ }
+
+ @Override
+ public void beforeMethod(final EnhancedInstance objInst,
+ final Method method,
+ final Object[] allArguments,
+ final Class>[] argumentsTypes,
+ final MethodInterceptResult result) throws Throwable {
+ }
+
+ @Override
+ public Object afterMethod(final EnhancedInstance objInst,
+ final Method method,
+ final Object[] allArguments,
+ final Class>[] argumentsTypes,
+ final Object ret) throws Throwable {
+ ContextManager.stopSpan();
+ return ret;
+ }
+
+ @Override
+ public void handleMethodException(final EnhancedInstance objInst,
+ final Method method,
+ final Object[] allArguments,
+ final Class>[] argumentsTypes,
+ final Throwable t) {
+ ContextManager.activeSpan().log(t);
+ }
+}
diff --git a/apm-sniffer/optional-plugins/caffeine-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/caffeine/v3/CaffeineIterableInterceptor.java b/apm-sniffer/optional-plugins/caffeine-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/caffeine/v3/CaffeineIterableInterceptor.java
new file mode 100644
index 0000000000..ef5860e46f
--- /dev/null
+++ b/apm-sniffer/optional-plugins/caffeine-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/caffeine/v3/CaffeineIterableInterceptor.java
@@ -0,0 +1,46 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.caffeine.v3;
+
+import java.lang.reflect.Method;
+import java.util.stream.Collectors;
+import java.util.stream.StreamSupport;
+import org.apache.skywalking.apm.agent.core.context.tag.Tags;
+import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
+
+public class CaffeineIterableInterceptor extends AbstractCaffeineInterceptor {
+
+ @Override
+ public void beforeMethod(final EnhancedInstance objInst,
+ final Method method,
+ final Object[] allArguments,
+ final Class>[] argumentsTypes,
+ final MethodInterceptResult result) throws Throwable {
+ AbstractSpan span = generateSpanInfo(method.getName());
+ if (allArguments != null && allArguments.length > 0) {
+ String keys = StreamSupport
+ .stream(((Iterable>) allArguments[0]).spliterator(), false)
+ .map(String::valueOf)
+ .collect(Collectors.joining(","));
+ Tags.CACHE_KEY.set(span, keys);
+ }
+ }
+}
diff --git a/apm-sniffer/optional-plugins/caffeine-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/caffeine/v3/CaffeineMapInterceptor.java b/apm-sniffer/optional-plugins/caffeine-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/caffeine/v3/CaffeineMapInterceptor.java
new file mode 100644
index 0000000000..98258bbb38
--- /dev/null
+++ b/apm-sniffer/optional-plugins/caffeine-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/caffeine/v3/CaffeineMapInterceptor.java
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.caffeine.v3;
+
+import java.lang.reflect.Method;
+import java.util.Map;
+import java.util.stream.Collectors;
+import org.apache.skywalking.apm.agent.core.context.tag.Tags;
+import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
+
+public class CaffeineMapInterceptor extends AbstractCaffeineInterceptor {
+
+ @Override
+ public void beforeMethod(final EnhancedInstance objInst,
+ final Method method,
+ final Object[] allArguments,
+ final Class>[] argumentsTypes,
+ final MethodInterceptResult result) throws Throwable {
+ AbstractSpan span = generateSpanInfo(method.getName());
+ if (allArguments != null && allArguments.length > 0) {
+ String keys = ((Map, ?>) allArguments[0])
+ .keySet().stream().map(String::valueOf)
+ .collect(Collectors.joining(","));
+ Tags.CACHE_KEY.set(span, keys);
+ }
+ }
+}
diff --git a/apm-sniffer/optional-plugins/caffeine-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/caffeine/v3/CaffeineOperationTransform.java b/apm-sniffer/optional-plugins/caffeine-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/caffeine/v3/CaffeineOperationTransform.java
new file mode 100644
index 0000000000..0f4a128a92
--- /dev/null
+++ b/apm-sniffer/optional-plugins/caffeine-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/caffeine/v3/CaffeineOperationTransform.java
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.caffeine.v3;
+
+import java.util.Optional;
+
+public class CaffeineOperationTransform {
+
+ public static Optional transformOperation(String cmd) {
+ if (CaffeinePluginConfig.Plugin.Caffeine.OPERATION_MAPPING_READ.contains(cmd)) {
+ return Optional.of("read");
+ }
+ if (CaffeinePluginConfig.Plugin.Caffeine.OPERATION_MAPPING_WRITE.contains(cmd)) {
+ return Optional.of("write");
+ }
+ return Optional.empty();
+ }
+}
diff --git a/apm-sniffer/optional-plugins/caffeine-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/caffeine/v3/CaffeinePluginConfig.java b/apm-sniffer/optional-plugins/caffeine-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/caffeine/v3/CaffeinePluginConfig.java
new file mode 100644
index 0000000000..f775668bee
--- /dev/null
+++ b/apm-sniffer/optional-plugins/caffeine-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/caffeine/v3/CaffeinePluginConfig.java
@@ -0,0 +1,50 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.caffeine.v3;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
+import org.apache.skywalking.apm.agent.core.boot.PluginConfig;
+
+/**
+ * Operation represent a cache span is "write" or "read" action , and "op"(operation) is tagged with key "cache.op"
+ * usually This config term define which command should be converted to write Operation .
+ *
+ * @see org.apache.skywalking.apm.agent.core.context.tag.Tags#CACHE_OP
+ * @see CaffeineOperationTransform#transformOperation(String)
+ */
+public class CaffeinePluginConfig {
+ public static class Plugin {
+ @PluginConfig(root = CaffeinePluginConfig.class)
+ public static class Caffeine {
+ public static Set OPERATION_MAPPING_WRITE = new HashSet<>(Arrays.asList(
+ "put",
+ "putAll",
+ "remove",
+ "clear"
+ ));
+ public static Set OPERATION_MAPPING_READ = new HashSet<>(Arrays.asList(
+ "getIfPresent",
+ "getAllPresent",
+ "computeIfAbsent"
+ ));
+ }
+ }
+}
\ No newline at end of file
diff --git a/apm-sniffer/optional-plugins/caffeine-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/caffeine/v3/CaffeineStringInterceptor.java b/apm-sniffer/optional-plugins/caffeine-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/caffeine/v3/CaffeineStringInterceptor.java
new file mode 100644
index 0000000000..82b34ca48d
--- /dev/null
+++ b/apm-sniffer/optional-plugins/caffeine-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/caffeine/v3/CaffeineStringInterceptor.java
@@ -0,0 +1,40 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.caffeine.v3;
+
+import java.lang.reflect.Method;
+import org.apache.skywalking.apm.agent.core.context.tag.Tags;
+import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
+
+public class CaffeineStringInterceptor extends AbstractCaffeineInterceptor {
+
+ @Override
+ public void beforeMethod(final EnhancedInstance objInst,
+ final Method method,
+ final Object[] allArguments,
+ final Class>[] argumentsTypes,
+ final MethodInterceptResult result) throws Throwable {
+ AbstractSpan span = generateSpanInfo(method.getName());
+ if (allArguments != null && allArguments.length > 0 && allArguments[0] instanceof String) {
+ Tags.CACHE_KEY.set(span, allArguments[0].toString());
+ }
+ }
+}
diff --git a/apm-sniffer/optional-plugins/caffeine-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/caffeine/v3/define/CaffeineInstrumentation.java b/apm-sniffer/optional-plugins/caffeine-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/caffeine/v3/define/CaffeineInstrumentation.java
new file mode 100644
index 0000000000..50e5b3751a
--- /dev/null
+++ b/apm-sniffer/optional-plugins/caffeine-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/caffeine/v3/define/CaffeineInstrumentation.java
@@ -0,0 +1,119 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.caffeine.v3.define;
+
+import java.util.Map;
+import net.bytebuddy.description.method.MethodDescription;
+import net.bytebuddy.matcher.ElementMatcher;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine;
+import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
+
+import static net.bytebuddy.matcher.ElementMatchers.named;
+import static net.bytebuddy.matcher.ElementMatchers.takesArgument;
+import static net.bytebuddy.matcher.ElementMatchers.takesArguments;
+import static org.apache.skywalking.apm.agent.core.plugin.match.MultiClassNameMatch.byMultiClassMatch;
+
+public class CaffeineInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
+
+ public static final String BOUNDED_LOCAL_INTERCEPT_CLASS = "com.github.benmanes.caffeine.cache.BoundedLocalCache";
+ public static final String UNBOUNDED_LOCAL_INTERCEPT_CLASS = "com.github.benmanes.caffeine.cache.UnboundedLocalCache";
+ public static final String CAFFEINE_ITERABLE_ENHANCE_CLASS = "org.apache.skywalking.apm.plugin.caffeine.v3.CaffeineIterableInterceptor";
+ public static final String CAFFEINE_MAP_ENHANCE_CLASS = "org.apache.skywalking.apm.plugin.caffeine.v3.CaffeineMapInterceptor";
+ public static final String CAFFEINE_STRING_ENHANCE_CLASS = "org.apache.skywalking.apm.plugin.caffeine.v3.CaffeineStringInterceptor";
+
+ // read/write operations
+ public static final String GET_IF_PRESENT_METHOD = "getIfPresent";
+ public static final String GET_ALL_PRESENT_METHOD = "getAllPresent";
+ public static final String COMPUTE_IF_ABSENT_METHOD = "computeIfAbsent";
+ public static final String PUT_METHOD = "put";
+ public static final String PUT_ALL_METHOD = "putAll";
+ public static final String REMOVE_METHOD = "remove";
+ public static final String CLEAR_METHOD = "clear";
+
+ @Override
+ protected ClassMatch enhanceClass() {
+ return byMultiClassMatch(BOUNDED_LOCAL_INTERCEPT_CLASS, UNBOUNDED_LOCAL_INTERCEPT_CLASS);
+ }
+
+ @Override
+ public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
+ return new ConstructorInterceptPoint[0];
+ }
+
+ @Override
+ public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
+ return new InstanceMethodsInterceptPoint[] {
+ new InstanceMethodsInterceptPoint() {
+ @Override
+ public ElementMatcher getMethodsMatcher() {
+ return named(GET_IF_PRESENT_METHOD)
+ .and(takesArguments(2))
+ .or(named(COMPUTE_IF_ABSENT_METHOD).and(takesArguments(4)))
+ .or(named(PUT_METHOD).and(takesArguments(2)))
+ .or(named(REMOVE_METHOD).and(takesArguments(1)))
+ .or(named(CLEAR_METHOD).and(takesArguments(0)));
+ }
+
+ @Override
+ public String getMethodsInterceptor() {
+ return CAFFEINE_STRING_ENHANCE_CLASS;
+ }
+
+ @Override
+ public boolean isOverrideArgs() {
+ return false;
+ }
+ },
+ new InstanceMethodsInterceptPoint() {
+ @Override
+ public ElementMatcher getMethodsMatcher() {
+ return named(GET_ALL_PRESENT_METHOD).and(takesArgument(0, Iterable.class));
+ }
+
+ @Override
+ public String getMethodsInterceptor() {
+ return CAFFEINE_ITERABLE_ENHANCE_CLASS;
+ }
+
+ @Override
+ public boolean isOverrideArgs() {
+ return false;
+ }
+ },
+ new InstanceMethodsInterceptPoint() {
+ @Override
+ public ElementMatcher getMethodsMatcher() {
+ return named(PUT_ALL_METHOD).and(takesArgument(0, Map.class));
+ }
+
+ @Override
+ public String getMethodsInterceptor() {
+ return CAFFEINE_MAP_ENHANCE_CLASS;
+ }
+
+ @Override
+ public boolean isOverrideArgs() {
+ return false;
+ }
+ }
+ };
+ }
+}
diff --git a/apm-sniffer/optional-plugins/caffeine-3.x-plugin/src/main/resources/skywalking-plugin.def b/apm-sniffer/optional-plugins/caffeine-3.x-plugin/src/main/resources/skywalking-plugin.def
new file mode 100644
index 0000000000..1edf1e3a0e
--- /dev/null
+++ b/apm-sniffer/optional-plugins/caffeine-3.x-plugin/src/main/resources/skywalking-plugin.def
@@ -0,0 +1,17 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+caffeine-3.x=org.apache.skywalking.apm.plugin.caffeine.v3.define.CaffeineInstrumentation
diff --git a/apm-sniffer/optional-plugins/caffeine-3.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/caffeine/v3/CaffeineInterceptorTest.java b/apm-sniffer/optional-plugins/caffeine-3.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/caffeine/v3/CaffeineInterceptorTest.java
new file mode 100644
index 0000000000..7642ae110d
--- /dev/null
+++ b/apm-sniffer/optional-plugins/caffeine-3.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/caffeine/v3/CaffeineInterceptorTest.java
@@ -0,0 +1,149 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.caffeine.v3;
+
+import com.github.benmanes.caffeine.cache.Expiry;
+import java.lang.reflect.Method;
+import java.util.List;
+import java.util.Map;
+import java.util.function.Function;
+import org.apache.skywalking.apm.agent.core.context.trace.TraceSegment;
+import org.apache.skywalking.apm.agent.test.tools.AgentServiceRule;
+import org.apache.skywalking.apm.agent.test.tools.SegmentStorage;
+import org.apache.skywalking.apm.agent.test.tools.SegmentStoragePoint;
+import org.apache.skywalking.apm.agent.test.tools.TracingSegmentRunner;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+
+import static org.hamcrest.CoreMatchers.is;
+
+@RunWith(TracingSegmentRunner.class)
+public class CaffeineInterceptorTest {
+
+ @SegmentStoragePoint
+ private SegmentStorage segmentStorage;
+
+ private CaffeineIterableInterceptor caffeineIterableInterceptor;
+ private CaffeineMapInterceptor caffeineMapInterceptor;
+ private CaffeineStringInterceptor caffeineStringInterceptor;
+ private Object[] operateObjectArguments;
+
+ private Exception exception;
+
+ private Method getAllPresentMethod;
+ private Method getIfPresentMethod;
+ private Method computeIfAbsentMethod;
+
+ private Method putMethod;
+ private Method putAllMethod;
+ private Method removeMethod;
+ private Method cleanMethod;
+
+ @Rule
+ public AgentServiceRule serviceRule = new AgentServiceRule();
+ @Rule
+ public MockitoRule rule = MockitoJUnit.rule();
+
+ @Before
+ public void setUp() throws Exception {
+ caffeineIterableInterceptor = new CaffeineIterableInterceptor();
+ caffeineMapInterceptor = new CaffeineMapInterceptor();
+ caffeineStringInterceptor = new CaffeineStringInterceptor();
+ exception = new Exception();
+ operateObjectArguments = new Object[] {"dataKey"};
+ Class> cache = Class.forName("com.github.benmanes.caffeine.cache.BoundedLocalCache");
+ getAllPresentMethod = cache.getDeclaredMethod("getAllPresent", Iterable.class);
+ getIfPresentMethod = cache.getDeclaredMethod("getIfPresent", Object.class, boolean.class);
+ computeIfAbsentMethod = cache.getDeclaredMethod(
+ "computeIfAbsent", Object.class, Function.class, boolean.class, boolean.class);
+ putMethod = cache.getDeclaredMethod("put", Object.class, Object.class, Expiry.class, boolean.class);
+ putAllMethod = cache.getDeclaredMethod("putAll", Map.class);
+ removeMethod = cache.getDeclaredMethod("remove", Object.class);
+ cleanMethod = cache.getDeclaredMethod("clear");
+ }
+
+ @Test
+ public void testGetAllPresentSuccess() throws Throwable {
+ caffeineIterableInterceptor.beforeMethod(null, getAllPresentMethod, null, null, null);
+ caffeineIterableInterceptor.handleMethodException(null, getAllPresentMethod, null, null, exception);
+ caffeineIterableInterceptor.afterMethod(null, getAllPresentMethod, null, null, null);
+ List traceSegments = segmentStorage.getTraceSegments();
+ Assert.assertThat(traceSegments.size(), is(1));
+ }
+
+ @Test
+ public void testGetIfPresentSuccess() throws Throwable {
+ caffeineStringInterceptor.beforeMethod(null, getIfPresentMethod, operateObjectArguments, null, null);
+ caffeineStringInterceptor.handleMethodException(
+ null, getIfPresentMethod, operateObjectArguments, null, exception);
+ caffeineStringInterceptor.afterMethod(null, getIfPresentMethod, operateObjectArguments, null, null);
+ List traceSegments = segmentStorage.getTraceSegments();
+ Assert.assertThat(traceSegments.size(), is(1));
+ }
+
+ @Test
+ public void testComputeIfAbsentMethodSuccess() throws Throwable {
+ caffeineStringInterceptor.beforeMethod(null, computeIfAbsentMethod, null, null, null);
+ caffeineStringInterceptor.handleMethodException(null, computeIfAbsentMethod, null, null, exception);
+ caffeineStringInterceptor.afterMethod(null, computeIfAbsentMethod, null, null, null);
+ List traceSegments = segmentStorage.getTraceSegments();
+ Assert.assertThat(traceSegments.size(), is(1));
+ }
+
+ @Test
+ public void testPutMethodSuccess() throws Throwable {
+ caffeineStringInterceptor.beforeMethod(null, putMethod, operateObjectArguments, null, null);
+ caffeineStringInterceptor.handleMethodException(null, putMethod, operateObjectArguments, null, exception);
+ caffeineStringInterceptor.afterMethod(null, putMethod, operateObjectArguments, null, null);
+ List traceSegments = segmentStorage.getTraceSegments();
+ Assert.assertThat(traceSegments.size(), is(1));
+ }
+
+ @Test
+ public void testPutAllMethodSuccess() throws Throwable {
+ caffeineMapInterceptor.beforeMethod(null, putAllMethod, null, null, null);
+ caffeineMapInterceptor.handleMethodException(null, putAllMethod, null, null, exception);
+ caffeineMapInterceptor.afterMethod(null, putAllMethod, null, null, null);
+ List traceSegments = segmentStorage.getTraceSegments();
+ Assert.assertThat(traceSegments.size(), is(1));
+ }
+
+ @Test
+ public void testRemoveMethodSuccess() throws Throwable {
+ caffeineStringInterceptor.beforeMethod(null, removeMethod, operateObjectArguments, null, null);
+ caffeineStringInterceptor.handleMethodException(null, removeMethod, operateObjectArguments, null, exception);
+ caffeineStringInterceptor.afterMethod(null, removeMethod, operateObjectArguments, null, null);
+ List traceSegments = segmentStorage.getTraceSegments();
+ Assert.assertThat(traceSegments.size(), is(1));
+ }
+
+ @Test
+ public void testClearMethodSuccess() throws Throwable {
+ caffeineStringInterceptor.beforeMethod(null, cleanMethod, null, null, null);
+ caffeineStringInterceptor.handleMethodException(null, cleanMethod, null, null, exception);
+ caffeineStringInterceptor.afterMethod(null, cleanMethod, null, null, null);
+ List traceSegments = segmentStorage.getTraceSegments();
+ Assert.assertThat(traceSegments.size(), is(1));
+ }
+}
diff --git a/apm-sniffer/optional-plugins/caffeine-3.x-plugin/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker b/apm-sniffer/optional-plugins/caffeine-3.x-plugin/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker
new file mode 100644
index 0000000000..1f0955d450
--- /dev/null
+++ b/apm-sniffer/optional-plugins/caffeine-3.x-plugin/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker
@@ -0,0 +1 @@
+mock-maker-inline
diff --git a/apm-sniffer/optional-plugins/customize-enhance-plugin/pom.xml b/apm-sniffer/optional-plugins/customize-enhance-plugin/pom.xml
index 2c9ee683f6..fb100e0d94 100644
--- a/apm-sniffer/optional-plugins/customize-enhance-plugin/pom.xml
+++ b/apm-sniffer/optional-plugins/customize-enhance-plugin/pom.xml
@@ -21,7 +21,7 @@
org.apache.skywalking
optional-plugins
- 9.3.0-SNAPSHOT
+ 9.7.0-SNAPSHOT
4.0.0
diff --git a/apm-sniffer/optional-plugins/customize-enhance-plugin/src/main/java/org/apache/skywalking/apm/plugin/customize/conf/CustomizeConfiguration.java b/apm-sniffer/optional-plugins/customize-enhance-plugin/src/main/java/org/apache/skywalking/apm/plugin/customize/conf/CustomizeConfiguration.java
index ba48a9280e..ba3dd5f843 100644
--- a/apm-sniffer/optional-plugins/customize-enhance-plugin/src/main/java/org/apache/skywalking/apm/plugin/customize/conf/CustomizeConfiguration.java
+++ b/apm-sniffer/optional-plugins/customize-enhance-plugin/src/main/java/org/apache/skywalking/apm/plugin/customize/conf/CustomizeConfiguration.java
@@ -27,6 +27,7 @@
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.locks.ReentrantLock;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
@@ -67,6 +68,8 @@ public enum CustomizeConfiguration {
private static final Map CONTEXT_ENHANCE_CLASSES = new HashMap<>();
private static final AtomicBoolean LOAD_FOR_CONFIGURATION = new AtomicBoolean(false);
+ private static volatile List> RESOLVED_FILE_CONFIGURATIONS;
+ private static final ReentrantLock RESOLVED_FILE_LOCK = new ReentrantLock();
/**
* The loadForEnhance method is resolver configuration file, and parse it
*/
@@ -107,13 +110,26 @@ public synchronized void loadForConfiguration() {
* @throws SAXException link {@link SAXException}
*/
private List> resolver() throws ParserConfigurationException, IOException, SAXException {
- List> customizeMethods = new ArrayList>();
- File file = new File(CustomizePluginConfig.Plugin.Customize.ENHANCE_FILE);
- if (file.exists() && file.isFile()) {
- NodeList classNodeList = resolverFileClassDesc(file);
- resolverClassNodeList(classNodeList, customizeMethods);
+ if (RESOLVED_FILE_CONFIGURATIONS != null) {
+ return RESOLVED_FILE_CONFIGURATIONS;
}
- return customizeMethods;
+
+ RESOLVED_FILE_LOCK.lock();
+ try {
+ if (RESOLVED_FILE_CONFIGURATIONS != null) {
+ return RESOLVED_FILE_CONFIGURATIONS;
+ }
+ List> customizeMethods = new ArrayList>();
+ File file = new File(CustomizePluginConfig.Plugin.Customize.ENHANCE_FILE);
+ if (file.exists() && file.isFile()) {
+ NodeList classNodeList = resolverFileClassDesc(file);
+ resolverClassNodeList(classNodeList, customizeMethods);
+ }
+ RESOLVED_FILE_CONFIGURATIONS = customizeMethods;
+ } finally {
+ RESOLVED_FILE_LOCK.unlock();
+ }
+ return RESOLVED_FILE_CONFIGURATIONS;
}
/**
diff --git a/apm-sniffer/optional-plugins/ehcache-2.x-plugin/pom.xml b/apm-sniffer/optional-plugins/ehcache-2.x-plugin/pom.xml
index 02c5ad33f5..60906ea1df 100644
--- a/apm-sniffer/optional-plugins/ehcache-2.x-plugin/pom.xml
+++ b/apm-sniffer/optional-plugins/ehcache-2.x-plugin/pom.xml
@@ -21,7 +21,7 @@
org.apache.skywalking
optional-plugins
- 9.3.0-SNAPSHOT
+ 9.7.0-SNAPSHOT
4.0.0
diff --git a/apm-sniffer/optional-plugins/fastjson-1.2.x-plugin/pom.xml b/apm-sniffer/optional-plugins/fastjson-1.2.x-plugin/pom.xml
index f0019fa5ec..fd47548245 100644
--- a/apm-sniffer/optional-plugins/fastjson-1.2.x-plugin/pom.xml
+++ b/apm-sniffer/optional-plugins/fastjson-1.2.x-plugin/pom.xml
@@ -22,7 +22,7 @@
org.apache.skywalking
optional-plugins
- 9.3.0-SNAPSHOT
+ 9.7.0-SNAPSHOT
apm-fastjson-1.x-plugin
diff --git a/apm-sniffer/optional-plugins/gson-2.8.x-plugin/pom.xml b/apm-sniffer/optional-plugins/gson-2.8.x-plugin/pom.xml
index 8211d2e4df..3cacbd71f0 100644
--- a/apm-sniffer/optional-plugins/gson-2.8.x-plugin/pom.xml
+++ b/apm-sniffer/optional-plugins/gson-2.8.x-plugin/pom.xml
@@ -22,7 +22,7 @@
org.apache.skywalking
optional-plugins
- 9.3.0-SNAPSHOT
+ 9.7.0-SNAPSHOT
apm-gson-2.x-plugin
diff --git a/apm-sniffer/optional-plugins/guava-cache-plugin/pom.xml b/apm-sniffer/optional-plugins/guava-cache-plugin/pom.xml
index 79cfd12796..4b678e32ed 100644
--- a/apm-sniffer/optional-plugins/guava-cache-plugin/pom.xml
+++ b/apm-sniffer/optional-plugins/guava-cache-plugin/pom.xml
@@ -21,7 +21,7 @@
org.apache.skywalking
optional-plugins
- 9.3.0-SNAPSHOT
+ 9.7.0-SNAPSHOT
apm-guava-cache-plugin
diff --git a/apm-sniffer/optional-plugins/jackson-2.x-plugin/pom.xml b/apm-sniffer/optional-plugins/jackson-2.x-plugin/pom.xml
index 75279981da..6cc5017d9c 100644
--- a/apm-sniffer/optional-plugins/jackson-2.x-plugin/pom.xml
+++ b/apm-sniffer/optional-plugins/jackson-2.x-plugin/pom.xml
@@ -22,7 +22,7 @@
org.apache.skywalking
optional-plugins
- 9.3.0-SNAPSHOT
+ 9.7.0-SNAPSHOT
apm-jackson-2.x-plugin
diff --git a/apm-sniffer/optional-plugins/kotlin-coroutine-plugin/pom.xml b/apm-sniffer/optional-plugins/kotlin-coroutine-plugin/pom.xml
index 6c34690e6e..ab831b6c1b 100644
--- a/apm-sniffer/optional-plugins/kotlin-coroutine-plugin/pom.xml
+++ b/apm-sniffer/optional-plugins/kotlin-coroutine-plugin/pom.xml
@@ -22,7 +22,7 @@
org.apache.skywalking
optional-plugins
- 9.3.0-SNAPSHOT
+ 9.7.0-SNAPSHOT
apm-kotlin-coroutine-plugin
diff --git a/apm-sniffer/optional-plugins/mybatis-3.x-plugin/pom.xml b/apm-sniffer/optional-plugins/mybatis-3.x-plugin/pom.xml
index b738e93ad5..7da71f0c1c 100644
--- a/apm-sniffer/optional-plugins/mybatis-3.x-plugin/pom.xml
+++ b/apm-sniffer/optional-plugins/mybatis-3.x-plugin/pom.xml
@@ -22,7 +22,7 @@
org.apache.skywalking
optional-plugins
- 9.3.0-SNAPSHOT
+ 9.7.0-SNAPSHOT
apm-mybatis-3.x-plugin
diff --git a/apm-sniffer/optional-plugins/nacos-client-2.x-plugin/pom.xml b/apm-sniffer/optional-plugins/nacos-client-2.x-plugin/pom.xml
index 6da357f801..7f5ea9441e 100644
--- a/apm-sniffer/optional-plugins/nacos-client-2.x-plugin/pom.xml
+++ b/apm-sniffer/optional-plugins/nacos-client-2.x-plugin/pom.xml
@@ -21,7 +21,7 @@
org.apache.skywalking
optional-plugins
- 9.3.0-SNAPSHOT
+ 9.7.0-SNAPSHOT
4.0.0
diff --git a/apm-sniffer/optional-plugins/netty-http-4.1.x-plugin/pom.xml b/apm-sniffer/optional-plugins/netty-http-4.1.x-plugin/pom.xml
index a135366369..b8313a57c7 100644
--- a/apm-sniffer/optional-plugins/netty-http-4.1.x-plugin/pom.xml
+++ b/apm-sniffer/optional-plugins/netty-http-4.1.x-plugin/pom.xml
@@ -21,7 +21,7 @@
org.apache.skywalking
optional-plugins
- 9.3.0-SNAPSHOT
+ 9.7.0-SNAPSHOT
4.0.0
@@ -30,14 +30,12 @@
UTF-8
- 4.1.51.Final
io.netty
netty-all
- ${netty.version}
provided
diff --git a/apm-sniffer/optional-plugins/netty-http-4.1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/netty/http/handler/NettyHttpRequestEncoderTracingHandler.java b/apm-sniffer/optional-plugins/netty-http-4.1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/netty/http/handler/NettyHttpRequestEncoderTracingHandler.java
index bb34adbaac..38c8518fb3 100644
--- a/apm-sniffer/optional-plugins/netty-http-4.1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/netty/http/handler/NettyHttpRequestEncoderTracingHandler.java
+++ b/apm-sniffer/optional-plugins/netty-http-4.1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/netty/http/handler/NettyHttpRequestEncoderTracingHandler.java
@@ -80,7 +80,6 @@ public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise)
InetSocketAddress address = (InetSocketAddress) ctx.channel().remoteAddress();
String peer = address.getHostString() + ":" + address.getPort();
String url = peer + uri;
- String method = request.method().toString();
ContextCarrier contextCarrier = new ContextCarrier();
AbstractSpan span = ContextManager.createExitSpan(NettyConstants.NETTY_HTTP_OPERATION_PREFIX + uri, contextCarrier, peer);
diff --git a/apm-sniffer/optional-plugins/optional-spring-plugins/mvc-annotation-6.x-plugin/pom.xml b/apm-sniffer/optional-plugins/optional-spring-plugins/mvc-annotation-6.x-plugin/pom.xml
index ed3daad261..a2399d0bc6 100644
--- a/apm-sniffer/optional-plugins/optional-spring-plugins/mvc-annotation-6.x-plugin/pom.xml
+++ b/apm-sniffer/optional-plugins/optional-spring-plugins/mvc-annotation-6.x-plugin/pom.xml
@@ -19,7 +19,7 @@
optional-spring-plugins
org.apache.skywalking
- 9.3.0-SNAPSHOT
+ 9.7.0-SNAPSHOT
4.0.0
diff --git a/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-2.0.x-plugin/pom.xml b/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-2.0.x-plugin/pom.xml
index c483e6b29d..b2963c4c23 100644
--- a/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-2.0.x-plugin/pom.xml
+++ b/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-2.0.x-plugin/pom.xml
@@ -23,7 +23,7 @@
org.apache.skywalking
optional-spring-cloud
- 9.3.0-SNAPSHOT
+ 9.7.0-SNAPSHOT
apm-spring-cloud-gateway-2.0.x-plugin
@@ -61,7 +61,6 @@
org.apache.maven.plugins
maven-shade-plugin
- 3.2.4
package
diff --git a/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-2.0.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/cloud/gateway/v20x/GatewayFilterInterceptor.java b/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-2.0.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/cloud/gateway/v20x/GatewayFilterInterceptor.java
new file mode 100644
index 0000000000..b5174773c3
--- /dev/null
+++ b/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-2.0.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/cloud/gateway/v20x/GatewayFilterInterceptor.java
@@ -0,0 +1,94 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.skywalking.apm.plugin.spring.cloud.gateway.v20x;
+
+import org.apache.skywalking.apm.agent.core.context.ContextManager;
+import org.apache.skywalking.apm.agent.core.context.ContextSnapshot;
+import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
+import org.springframework.web.server.ServerWebExchange;
+import org.springframework.web.server.ServerWebExchangeDecorator;
+import org.springframework.web.server.adapter.DefaultServerWebExchange;
+
+import java.lang.reflect.Method;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import static org.apache.skywalking.apm.network.trace.component.ComponentsDefine.SPRING_CLOUD_GATEWAY;
+
+public class GatewayFilterInterceptor implements InstanceMethodsAroundInterceptor {
+
+ private static final ThreadLocal STACK_DEEP = ThreadLocal.withInitial(() -> new AtomicInteger(0));
+
+ @Override
+ public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes,
+ MethodInterceptResult result) throws Throwable {
+ if (isEntry()) {
+ ServerWebExchange exchange = (ServerWebExchange) allArguments[0];
+
+ EnhancedInstance enhancedInstance = getInstance(exchange);
+
+ AbstractSpan span = ContextManager.createLocalSpan("SpringCloudGateway/GatewayFilter");
+ if (enhancedInstance != null && enhancedInstance.getSkyWalkingDynamicField() != null) {
+ ContextManager.continued((ContextSnapshot) enhancedInstance.getSkyWalkingDynamicField());
+ }
+ span.setComponent(SPRING_CLOUD_GATEWAY);
+ }
+ }
+
+ public static EnhancedInstance getInstance(Object o) {
+ EnhancedInstance instance = null;
+ if (o instanceof DefaultServerWebExchange) {
+ instance = (EnhancedInstance) o;
+ } else if (o instanceof ServerWebExchangeDecorator) {
+ ServerWebExchange delegate = ((ServerWebExchangeDecorator) o).getDelegate();
+ return getInstance(delegate);
+ }
+ return instance;
+ }
+
+ @Override
+ public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes,
+ Object ret) throws Throwable {
+ if (isExit()) {
+ if (ContextManager.isActive()) {
+ ContextManager.stopSpan();
+ }
+ }
+ return ret;
+ }
+
+ @Override
+ public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments,
+ Class>[] argumentsTypes, Throwable t) {
+ ContextManager.activeSpan().log(t);
+ }
+
+ private boolean isEntry() {
+ return STACK_DEEP.get().getAndIncrement() == 0;
+ }
+
+ private boolean isExit() {
+ boolean isExit = STACK_DEEP.get().decrementAndGet() == 0;
+ if (isExit) {
+ STACK_DEEP.remove();
+ }
+ return isExit;
+ }
+}
diff --git a/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-2.0.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/cloud/gateway/v20x/define/AbstractGateway200EnhancePluginDefine.java b/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-2.0.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/cloud/gateway/v20x/define/AbstractGateway200EnhancePluginDefine.java
index baeb619eca..e260b8813c 100644
--- a/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-2.0.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/cloud/gateway/v20x/define/AbstractGateway200EnhancePluginDefine.java
+++ b/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-2.0.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/cloud/gateway/v20x/define/AbstractGateway200EnhancePluginDefine.java
@@ -24,7 +24,7 @@ public abstract class AbstractGateway200EnhancePluginDefine extends ClassInstanc
@Override
protected String[] witnessClasses() {
return new String[] {
- "org.springframework.cloud.gateway.config.GatewayAutoConfiguration$1"
+ "org.springframework.cloud.gateway.config.GatewayAutoConfiguration"
};
}
}
diff --git a/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-2.0.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/cloud/gateway/v20x/define/AbstractGateway200EnhancePluginDefineV2.java b/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-2.0.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/cloud/gateway/v20x/define/AbstractGateway200EnhancePluginDefineV2.java
index 1f07c0ba89..c42e2df60d 100644
--- a/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-2.0.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/cloud/gateway/v20x/define/AbstractGateway200EnhancePluginDefineV2.java
+++ b/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-2.0.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/cloud/gateway/v20x/define/AbstractGateway200EnhancePluginDefineV2.java
@@ -24,7 +24,7 @@ public abstract class AbstractGateway200EnhancePluginDefineV2 extends ClassInsta
@Override
protected String[] witnessClasses() {
return new String[] {
- "org.springframework.cloud.gateway.config.GatewayAutoConfiguration$1"
+ "org.springframework.cloud.gateway.config.GatewayAutoConfiguration"
};
}
}
diff --git a/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-2.0.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/cloud/gateway/v20x/define/Constants.java b/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-2.0.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/cloud/gateway/v20x/define/Constants.java
index 450699c959..f20a1c22a6 100644
--- a/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-2.0.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/cloud/gateway/v20x/define/Constants.java
+++ b/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-2.0.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/cloud/gateway/v20x/define/Constants.java
@@ -29,4 +29,8 @@ public interface Constants {
// HttpClientRequest
String INTERCEPT_CLASS_HTTP_CLIENT_REQUEST = "reactor.ipc.netty.http.client.HttpClientRequest";
String HTTPCLIENT_REQUEST_HEADERS_INTERCEPTOR = "org.apache.skywalking.apm.plugin.spring.cloud.gateway.v20x.HttpclientRequestHeadersInterceptor";
+
+ // GatewayFilter
+ String INTERCEPT_CLASS_GATEWAY_FILTER = "org.springframework.cloud.gateway.filter.GatewayFilter";
+ String GATEWAY_FILTER_INTERCEPTOR = "org.apache.skywalking.apm.plugin.spring.cloud.gateway.v20x.GatewayFilterInterceptor";
}
diff --git a/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-2.0.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/cloud/gateway/v20x/define/DispatcherHandlerInstrumentation.java b/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-2.0.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/cloud/gateway/v20x/define/DispatcherHandlerInstrumentation.java
index be9f8668ab..1188ae1804 100644
--- a/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-2.0.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/cloud/gateway/v20x/define/DispatcherHandlerInstrumentation.java
+++ b/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-2.0.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/cloud/gateway/v20x/define/DispatcherHandlerInstrumentation.java
@@ -23,7 +23,7 @@ public class DispatcherHandlerInstrumentation extends org.apache.skywalking.apm.
@Override
protected String[] witnessClasses() {
return new String[] {
- "org.springframework.cloud.gateway.config.GatewayAutoConfiguration$1"
+ "org.springframework.cloud.gateway.config.GatewayAutoConfiguration"
};
}
}
diff --git a/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-2.0.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/cloud/gateway/v20x/define/GatewayFilterInstrumentation.java b/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-2.0.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/cloud/gateway/v20x/define/GatewayFilterInstrumentation.java
new file mode 100644
index 0000000000..5435af8a08
--- /dev/null
+++ b/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-2.0.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/cloud/gateway/v20x/define/GatewayFilterInstrumentation.java
@@ -0,0 +1,64 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.skywalking.apm.plugin.spring.cloud.gateway.v20x.define;
+
+import net.bytebuddy.description.method.MethodDescription;
+import net.bytebuddy.matcher.ElementMatcher;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
+import org.apache.skywalking.apm.agent.core.plugin.match.HierarchyMatch;
+
+import static net.bytebuddy.matcher.ElementMatchers.named;
+import static org.apache.skywalking.apm.agent.core.plugin.bytebuddy.ArgumentTypeNameMatch.takesArgumentWithType;
+
+public class GatewayFilterInstrumentation extends AbstractGateway200EnhancePluginDefine {
+
+ @Override
+ protected ClassMatch enhanceClass() {
+ return HierarchyMatch.byHierarchyMatch(Constants.INTERCEPT_CLASS_GATEWAY_FILTER);
+ }
+
+ @Override
+ public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
+ return new ConstructorInterceptPoint[0];
+ }
+
+ @Override
+ public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
+ return new InstanceMethodsInterceptPoint[] {
+ new InstanceMethodsInterceptPoint() {
+ @Override
+ public ElementMatcher getMethodsMatcher() {
+ return named("filter").and(
+ takesArgumentWithType(0, "org.springframework.web.server.ServerWebExchange"));
+ }
+
+ @Override
+ public String getMethodsInterceptor() {
+ return Constants.GATEWAY_FILTER_INTERCEPTOR;
+ }
+
+ @Override
+ public boolean isOverrideArgs() {
+ return false;
+ }
+ }
+ };
+ }
+}
diff --git a/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-2.0.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/cloud/gateway/v20x/define/ServerWebExchangeInstrumentation.java b/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-2.0.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/cloud/gateway/v20x/define/ServerWebExchangeInstrumentation.java
index 029172d69d..bb2af27b54 100644
--- a/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-2.0.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/cloud/gateway/v20x/define/ServerWebExchangeInstrumentation.java
+++ b/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-2.0.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/cloud/gateway/v20x/define/ServerWebExchangeInstrumentation.java
@@ -23,7 +23,7 @@ public class ServerWebExchangeInstrumentation extends org.apache.skywalking.apm.
@Override
protected String[] witnessClasses() {
return new String[] {
- "org.springframework.cloud.gateway.config.GatewayAutoConfiguration$1"
+ "org.springframework.cloud.gateway.config.GatewayAutoConfiguration"
};
}
}
diff --git a/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-2.0.x-plugin/src/main/resources/skywalking-plugin.def b/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-2.0.x-plugin/src/main/resources/skywalking-plugin.def
index 4bd0c3f419..0e4bf641bd 100644
--- a/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-2.0.x-plugin/src/main/resources/skywalking-plugin.def
+++ b/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-2.0.x-plugin/src/main/resources/skywalking-plugin.def
@@ -18,4 +18,5 @@ spring-cloud-gateway-2.0.x=org.apache.skywalking.apm.plugin.spring.cloud.gateway
spring-cloud-gateway-2.0.x=org.apache.skywalking.apm.plugin.spring.cloud.gateway.v20x.define.HttpClientInstrumentation
spring-cloud-gateway-2.0.x=org.apache.skywalking.apm.plugin.spring.cloud.gateway.v20x.define.HttpClientRequestInstrumentation
spring-cloud-gateway-2.0.x=org.apache.skywalking.apm.plugin.spring.cloud.gateway.v20x.define.ServerWebExchangeInstrumentation
-spring-cloud-gateway-2.0.x=org.apache.skywalking.apm.plugin.spring.cloud.gateway.v20x.define.DispatcherHandlerInstrumentation
\ No newline at end of file
+spring-cloud-gateway-2.0.x=org.apache.skywalking.apm.plugin.spring.cloud.gateway.v20x.define.DispatcherHandlerInstrumentation
+spring-cloud-gateway-2.0.x=org.apache.skywalking.apm.plugin.spring.cloud.gateway.v20x.define.GatewayFilterInstrumentation
\ No newline at end of file
diff --git a/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-2.0.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/spring/cloud/gateway/v20x/GatewayFilterInterceptorTest.java b/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-2.0.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/spring/cloud/gateway/v20x/GatewayFilterInterceptorTest.java
new file mode 100644
index 0000000000..3cd7bc8705
--- /dev/null
+++ b/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-2.0.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/spring/cloud/gateway/v20x/GatewayFilterInterceptorTest.java
@@ -0,0 +1,333 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.spring.cloud.gateway.v20x;
+
+import org.apache.skywalking.apm.agent.core.context.ContextManager;
+import org.apache.skywalking.apm.agent.core.context.ContextSnapshot;
+import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan;
+import org.apache.skywalking.apm.agent.core.context.trace.AbstractTracingSpan;
+import org.apache.skywalking.apm.agent.core.context.trace.SpanLayer;
+import org.apache.skywalking.apm.agent.core.context.trace.TraceSegment;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
+import org.apache.skywalking.apm.agent.test.helper.SegmentHelper;
+
+import org.apache.skywalking.apm.agent.test.tools.AgentServiceRule;
+import org.apache.skywalking.apm.agent.test.tools.SegmentStorage;
+import org.apache.skywalking.apm.agent.test.tools.SegmentStoragePoint;
+import org.apache.skywalking.apm.agent.test.tools.SpanAssert;
+import org.apache.skywalking.apm.agent.test.tools.TracingSegmentRunner;
+import org.apache.skywalking.apm.network.trace.component.ComponentsDefine;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.i18n.LocaleContext;
+import org.springframework.http.codec.multipart.Part;
+import org.springframework.http.server.reactive.ServerHttpRequest;
+import org.springframework.http.server.reactive.ServerHttpResponse;
+import org.springframework.util.MultiValueMap;
+import org.springframework.web.server.ServerWebExchange;
+import org.springframework.web.server.WebSession;
+import reactor.core.publisher.Mono;
+
+import java.security.Principal;
+import java.time.Instant;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.function.Function;
+
+@RunWith(TracingSegmentRunner.class)
+public class GatewayFilterInterceptorTest {
+
+ private static final String GATEWAY_FILTER_INTERCEPTOR_LOCAL_SPAN_OPERATION_NAME = "SpringCloudGateway/GatewayFilter";
+
+ private static class ServerWebExchangeEnhancedInstance implements ServerWebExchange, EnhancedInstance {
+ private ContextSnapshot snapshot;
+ Map attributes = new HashMap<>();
+
+ @Override
+ public Object getSkyWalkingDynamicField() {
+ return snapshot;
+ }
+
+ @Override
+ public void setSkyWalkingDynamicField(Object value) {
+ this.snapshot = (ContextSnapshot) value;
+ }
+
+ @Override
+ public ServerHttpRequest getRequest() {
+ return null;
+ }
+
+ @Override
+ public ServerHttpResponse getResponse() {
+ return null;
+ }
+
+ @Override
+ public Map getAttributes() {
+ return attributes;
+ }
+
+ @Override
+ public Mono getSession() {
+ return null;
+ }
+
+ @Override
+ public Mono getPrincipal() {
+ return null;
+ }
+
+ @Override
+ public Mono> getFormData() {
+ return null;
+ }
+
+ @Override
+ public Mono> getMultipartData() {
+ return null;
+ }
+
+ @Override
+ public LocaleContext getLocaleContext() {
+ return null;
+ }
+
+ @Override
+ public ApplicationContext getApplicationContext() {
+ return null;
+ }
+
+ @Override
+ public boolean isNotModified() {
+ return false;
+ }
+
+ @Override
+ public boolean checkNotModified(Instant instant) {
+ return false;
+ }
+
+ @Override
+ public boolean checkNotModified(String s) {
+ return false;
+ }
+
+ @Override
+ public boolean checkNotModified(String s, Instant instant) {
+ return false;
+ }
+
+ @Override
+ public String transformUrl(String s) {
+ return null;
+ }
+
+ @Override
+ public void addUrlTransformer(Function function) {
+
+ }
+
+ @Override
+ public String getLogPrefix() {
+ return null;
+ }
+ }
+
+ private final ServerWebExchangeEnhancedInstance enhancedInstance = new ServerWebExchangeEnhancedInstance();
+ private final GatewayFilterInterceptor interceptor = new GatewayFilterInterceptor();
+ @Rule
+ public AgentServiceRule serviceRule = new AgentServiceRule();
+ @Rule
+ public MockitoRule rule = MockitoJUnit.rule();
+
+ @SegmentStoragePoint
+ private SegmentStorage segmentStorage;
+
+ @Before
+ public void setUp() throws Exception {
+ }
+
+ private final ServerWebExchange exchange = new ServerWebExchange() {
+ Map attributes = new HashMap<>();
+ @Override
+ public ServerHttpRequest getRequest() {
+ return null;
+ }
+
+ @Override
+ public ServerHttpResponse getResponse() {
+ return null;
+ }
+
+ @Override
+ public Map getAttributes() {
+ return attributes;
+ }
+
+ @Override
+ public Mono getSession() {
+ return null;
+ }
+
+ @Override
+ public Mono getPrincipal() {
+ return null;
+ }
+
+ @Override
+ public Mono> getFormData() {
+ return null;
+ }
+
+ @Override
+ public Mono> getMultipartData() {
+ return null;
+ }
+
+ @Override
+ public LocaleContext getLocaleContext() {
+ return null;
+ }
+
+ @Override
+ public ApplicationContext getApplicationContext() {
+ return null;
+ }
+
+ @Override
+ public boolean isNotModified() {
+ return false;
+ }
+
+ @Override
+ public boolean checkNotModified(Instant instant) {
+ return false;
+ }
+
+ @Override
+ public boolean checkNotModified(String s) {
+ return false;
+ }
+
+ @Override
+ public boolean checkNotModified(String s, Instant instant) {
+ return false;
+ }
+
+ @Override
+ public String transformUrl(String s) {
+ return null;
+ }
+
+ @Override
+ public void addUrlTransformer(Function function) {
+
+ }
+
+ @Override
+ public String getLogPrefix() {
+ return null;
+ }
+ };
+
+ @Test
+ public void testInterceptOnlyOnce() throws Throwable {
+ interceptor.beforeMethod(null, null, new Object[]{exchange}, null, null);
+ Assert.assertTrue(ContextManager.isActive());
+ AbstractSpan activeSpan = ContextManager.activeSpan();
+ Assert.assertTrue(activeSpan instanceof AbstractTracingSpan);
+ Assert.assertEquals(activeSpan.getOperationName(), GATEWAY_FILTER_INTERCEPTOR_LOCAL_SPAN_OPERATION_NAME);
+
+ interceptor.afterMethod(null, null, null, null, null);
+ Assert.assertFalse(ContextManager.isActive());
+ final List traceSegments = segmentStorage.getTraceSegments();
+ Assert.assertEquals(traceSegments.size(), 1);
+ final List spans = SegmentHelper.getSpans(traceSegments.get(0));
+ Assert.assertNotNull(spans);
+ Assert.assertEquals(spans.size(), 1);
+ SpanAssert.assertComponent(spans.get(0), ComponentsDefine.SPRING_CLOUD_GATEWAY);
+
+ }
+
+ @Test
+ public void testNestedInterception() throws Throwable {
+ interceptor.beforeMethod(null, null, new Object[]{enhancedInstance}, null, null);
+ Assert.assertTrue(ContextManager.isActive());
+
+ interceptor.beforeMethod(null, null, new Object[]{enhancedInstance}, null, null);
+ Assert.assertTrue(ContextManager.isActive());
+
+ interceptor.afterMethod(null, null, null, null, null);
+ Assert.assertTrue(ContextManager.isActive());
+
+ interceptor.afterMethod(null, null, null, null, null);
+ Assert.assertFalse(ContextManager.isActive());
+
+ final List traceSegments = segmentStorage.getTraceSegments();
+ Assert.assertEquals(traceSegments.size(), 1);
+ final List spans = SegmentHelper.getSpans(traceSegments.get(0));
+ Assert.assertNotNull(spans);
+ Assert.assertEquals(spans.size(), 1);
+ SpanAssert.assertComponent(spans.get(0), ComponentsDefine.SPRING_CLOUD_GATEWAY);
+ }
+
+ @Test
+ public void testWithNullDynamicField() throws Throwable {
+ interceptor.beforeMethod(null, null, new Object[]{enhancedInstance}, null, null);
+ interceptor.afterMethod(null, null, null, null, null);
+ // no more need this, span was stopped at interceptor#afterMethod
+ // ContextManager.stopSpan();
+ final List traceSegments = segmentStorage.getTraceSegments();
+ Assert.assertEquals(traceSegments.size(), 1);
+ final List spans = SegmentHelper.getSpans(traceSegments.get(0));
+ Assert.assertNotNull(spans);
+ Assert.assertEquals(spans.size(), 1);
+ SpanAssert.assertComponent(spans.get(0), ComponentsDefine.SPRING_CLOUD_GATEWAY);
+ }
+
+ @Test
+ public void testWithContextSnapshot() throws Throwable {
+ final AbstractSpan entrySpan = ContextManager.createEntrySpan("/get", null);
+ SpanLayer.asHttp(entrySpan);
+ entrySpan.setComponent(ComponentsDefine.SPRING_WEBFLUX);
+ enhancedInstance.setSkyWalkingDynamicField(ContextManager.capture());
+ interceptor.beforeMethod(null, null, new Object[]{enhancedInstance}, null, null);
+ interceptor.afterMethod(null, null, null, null, null);
+ // no more need this, span was stopped at interceptor#afterMethod
+ // ContextManager.stopSpan();
+ ContextManager.stopSpan(entrySpan);
+ final List traceSegments = segmentStorage.getTraceSegments();
+ Assert.assertEquals(traceSegments.size(), 1);
+ final List spans = SegmentHelper.getSpans(traceSegments.get(0));
+ Assert.assertNotNull(spans);
+ Assert.assertEquals(spans.size(), 2);
+ SpanAssert.assertComponent(spans.get(0), ComponentsDefine.SPRING_CLOUD_GATEWAY);
+ SpanAssert.assertComponent(spans.get(1), ComponentsDefine.SPRING_WEBFLUX);
+ SpanAssert.assertLayer(spans.get(1), SpanLayer.HTTP);
+ }
+
+}
diff --git a/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-2.1.x-plugin/pom.xml b/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-2.1.x-plugin/pom.xml
index 9973fe43dc..c9a0dfb040 100644
--- a/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-2.1.x-plugin/pom.xml
+++ b/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-2.1.x-plugin/pom.xml
@@ -23,7 +23,7 @@
org.apache.skywalking
optional-spring-cloud
- 9.3.0-SNAPSHOT
+ 9.7.0-SNAPSHOT
apm-spring-cloud-gateway-2.1.x-plugin
@@ -61,7 +61,6 @@
org.apache.maven.plugins
maven-shade-plugin
- 3.2.4
package
diff --git a/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-2.1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/cloud/gateway/v21x/GatewayFilterInterceptor.java b/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-2.1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/cloud/gateway/v21x/GatewayFilterInterceptor.java
new file mode 100644
index 0000000000..18b93a08d1
--- /dev/null
+++ b/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-2.1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/cloud/gateway/v21x/GatewayFilterInterceptor.java
@@ -0,0 +1,94 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.skywalking.apm.plugin.spring.cloud.gateway.v21x;
+
+import org.apache.skywalking.apm.agent.core.context.ContextManager;
+import org.apache.skywalking.apm.agent.core.context.ContextSnapshot;
+import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
+import org.springframework.web.server.ServerWebExchange;
+import org.springframework.web.server.ServerWebExchangeDecorator;
+import org.springframework.web.server.adapter.DefaultServerWebExchange;
+
+import java.lang.reflect.Method;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import static org.apache.skywalking.apm.network.trace.component.ComponentsDefine.SPRING_CLOUD_GATEWAY;
+
+public class GatewayFilterInterceptor implements InstanceMethodsAroundInterceptor {
+
+ private static final ThreadLocal STACK_DEEP = ThreadLocal.withInitial(() -> new AtomicInteger(0));
+
+ @Override
+ public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes,
+ MethodInterceptResult result) throws Throwable {
+ if (isEntry()) {
+ ServerWebExchange exchange = (ServerWebExchange) allArguments[0];
+
+ EnhancedInstance enhancedInstance = getInstance(exchange);
+
+ AbstractSpan span = ContextManager.createLocalSpan("SpringCloudGateway/GatewayFilter");
+ if (enhancedInstance != null && enhancedInstance.getSkyWalkingDynamicField() != null) {
+ ContextManager.continued((ContextSnapshot) enhancedInstance.getSkyWalkingDynamicField());
+ }
+ span.setComponent(SPRING_CLOUD_GATEWAY);
+ }
+ }
+
+ public static EnhancedInstance getInstance(Object o) {
+ EnhancedInstance instance = null;
+ if (o instanceof DefaultServerWebExchange) {
+ instance = (EnhancedInstance) o;
+ } else if (o instanceof ServerWebExchangeDecorator) {
+ ServerWebExchange delegate = ((ServerWebExchangeDecorator) o).getDelegate();
+ return getInstance(delegate);
+ }
+ return instance;
+ }
+
+ @Override
+ public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes,
+ Object ret) throws Throwable {
+ if (isExit()) {
+ if (ContextManager.isActive()) {
+ ContextManager.stopSpan();
+ }
+ }
+ return ret;
+ }
+
+ @Override
+ public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments,
+ Class>[] argumentsTypes, Throwable t) {
+ ContextManager.activeSpan().log(t);
+ }
+
+ private boolean isEntry() {
+ return STACK_DEEP.get().getAndIncrement() == 0;
+ }
+
+ private boolean isExit() {
+ boolean isExit = STACK_DEEP.get().decrementAndGet() == 0;
+ if (isExit) {
+ STACK_DEEP.remove();
+ }
+ return isExit;
+ }
+}
diff --git a/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-2.1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/cloud/gateway/v21x/define/Constants.java b/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-2.1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/cloud/gateway/v21x/define/Constants.java
index 1dbb09ff16..5c88626779 100644
--- a/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-2.1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/cloud/gateway/v21x/define/Constants.java
+++ b/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-2.1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/cloud/gateway/v21x/define/Constants.java
@@ -33,4 +33,7 @@ public interface Constants {
String INTERCEPT_CLASS_TCP_CLIENT = "reactor.netty.tcp.TcpClient";
String TCP_CLIENT_CONSTRUCTOR_INTERCEPTOR = "org.apache.skywalking.apm.plugin.spring.cloud.gateway.v21x.TcpClientConstructorInterceptor";
+ // GatewayFilter
+ String INTERCEPT_CLASS_GATEWAY_FILTER = "org.springframework.cloud.gateway.filter.GatewayFilter";
+ String GATEWAY_FILTER_INTERCEPTOR = "org.apache.skywalking.apm.plugin.spring.cloud.gateway.v21x.GatewayFilterInterceptor";
}
diff --git a/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-2.1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/cloud/gateway/v21x/define/GatewayFilterInstrumentation.java b/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-2.1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/cloud/gateway/v21x/define/GatewayFilterInstrumentation.java
new file mode 100644
index 0000000000..1031478c4a
--- /dev/null
+++ b/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-2.1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/cloud/gateway/v21x/define/GatewayFilterInstrumentation.java
@@ -0,0 +1,64 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.skywalking.apm.plugin.spring.cloud.gateway.v21x.define;
+
+import net.bytebuddy.description.method.MethodDescription;
+import net.bytebuddy.matcher.ElementMatcher;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
+import org.apache.skywalking.apm.agent.core.plugin.match.HierarchyMatch;
+
+import static net.bytebuddy.matcher.ElementMatchers.named;
+import static org.apache.skywalking.apm.agent.core.plugin.bytebuddy.ArgumentTypeNameMatch.takesArgumentWithType;
+
+public class GatewayFilterInstrumentation extends AbstractGateway210EnhancePluginDefine {
+
+ @Override
+ protected ClassMatch enhanceClass() {
+ return HierarchyMatch.byHierarchyMatch(Constants.INTERCEPT_CLASS_GATEWAY_FILTER);
+ }
+
+ @Override
+ public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
+ return new ConstructorInterceptPoint[0];
+ }
+
+ @Override
+ public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
+ return new InstanceMethodsInterceptPoint[] {
+ new InstanceMethodsInterceptPoint() {
+ @Override
+ public ElementMatcher getMethodsMatcher() {
+ return named("filter").and(
+ takesArgumentWithType(0, "org.springframework.web.server.ServerWebExchange"));
+ }
+
+ @Override
+ public String getMethodsInterceptor() {
+ return Constants.GATEWAY_FILTER_INTERCEPTOR;
+ }
+
+ @Override
+ public boolean isOverrideArgs() {
+ return false;
+ }
+ }
+ };
+ }
+}
diff --git a/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-2.1.x-plugin/src/main/resources/skywalking-plugin.def b/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-2.1.x-plugin/src/main/resources/skywalking-plugin.def
index 9929db9240..8ce727bb5d 100644
--- a/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-2.1.x-plugin/src/main/resources/skywalking-plugin.def
+++ b/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-2.1.x-plugin/src/main/resources/skywalking-plugin.def
@@ -19,3 +19,4 @@ spring-cloud-gateway-2.1.x=org.apache.skywalking.apm.plugin.spring.cloud.gateway
spring-cloud-gateway-2.1.x=org.apache.skywalking.apm.plugin.spring.cloud.gateway.v21x.define.TcpClientInstrumentation
spring-cloud-gateway-2.1.x=org.apache.skywalking.apm.plugin.spring.cloud.gateway.v21x.define.ServerWebExchangeInstrumentation
spring-cloud-gateway-2.1.x=org.apache.skywalking.apm.plugin.spring.cloud.gateway.v21x.define.DispatcherHandlerInstrumentation
+spring-cloud-gateway-2.1.x=org.apache.skywalking.apm.plugin.spring.cloud.gateway.v21x.define.GatewayFilterInstrumentation
diff --git a/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-2.1.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/spring/cloud/gateway/v21x/GatewayFilterInterceptorTest.java b/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-2.1.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/spring/cloud/gateway/v21x/GatewayFilterInterceptorTest.java
new file mode 100644
index 0000000000..c2250e3beb
--- /dev/null
+++ b/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-2.1.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/spring/cloud/gateway/v21x/GatewayFilterInterceptorTest.java
@@ -0,0 +1,332 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.spring.cloud.gateway.v21x;
+
+import org.apache.skywalking.apm.agent.core.context.ContextManager;
+import org.apache.skywalking.apm.agent.core.context.ContextSnapshot;
+import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan;
+import org.apache.skywalking.apm.agent.core.context.trace.AbstractTracingSpan;
+import org.apache.skywalking.apm.agent.core.context.trace.SpanLayer;
+import org.apache.skywalking.apm.agent.core.context.trace.TraceSegment;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
+import org.apache.skywalking.apm.agent.test.helper.SegmentHelper;
+import org.apache.skywalking.apm.agent.test.tools.AgentServiceRule;
+import org.apache.skywalking.apm.agent.test.tools.SegmentStorage;
+import org.apache.skywalking.apm.agent.test.tools.SegmentStoragePoint;
+import org.apache.skywalking.apm.agent.test.tools.SpanAssert;
+import org.apache.skywalking.apm.agent.test.tools.TracingSegmentRunner;
+import org.apache.skywalking.apm.network.trace.component.ComponentsDefine;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.i18n.LocaleContext;
+import org.springframework.http.codec.multipart.Part;
+import org.springframework.http.server.reactive.ServerHttpRequest;
+import org.springframework.http.server.reactive.ServerHttpResponse;
+import org.springframework.util.MultiValueMap;
+import org.springframework.web.server.ServerWebExchange;
+import org.springframework.web.server.WebSession;
+import reactor.core.publisher.Mono;
+
+import java.security.Principal;
+import java.time.Instant;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.function.Function;
+
+@RunWith(TracingSegmentRunner.class)
+public class GatewayFilterInterceptorTest {
+
+ private static final String GATEWAY_FILTER_INTERCEPTOR_LOCAL_SPAN_OPERATION_NAME = "SpringCloudGateway/GatewayFilter";
+
+ private static class ServerWebExchangeEnhancedInstance implements ServerWebExchange, EnhancedInstance {
+ private ContextSnapshot snapshot;
+ Map attributes = new HashMap<>();
+
+ @Override
+ public Object getSkyWalkingDynamicField() {
+ return snapshot;
+ }
+
+ @Override
+ public void setSkyWalkingDynamicField(Object value) {
+ this.snapshot = (ContextSnapshot) value;
+ }
+
+ @Override
+ public ServerHttpRequest getRequest() {
+ return null;
+ }
+
+ @Override
+ public ServerHttpResponse getResponse() {
+ return null;
+ }
+
+ @Override
+ public Map getAttributes() {
+ return attributes;
+ }
+
+ @Override
+ public Mono getSession() {
+ return null;
+ }
+
+ @Override
+ public Mono getPrincipal() {
+ return null;
+ }
+
+ @Override
+ public Mono> getFormData() {
+ return null;
+ }
+
+ @Override
+ public Mono> getMultipartData() {
+ return null;
+ }
+
+ @Override
+ public LocaleContext getLocaleContext() {
+ return null;
+ }
+
+ @Override
+ public ApplicationContext getApplicationContext() {
+ return null;
+ }
+
+ @Override
+ public boolean isNotModified() {
+ return false;
+ }
+
+ @Override
+ public boolean checkNotModified(Instant instant) {
+ return false;
+ }
+
+ @Override
+ public boolean checkNotModified(String s) {
+ return false;
+ }
+
+ @Override
+ public boolean checkNotModified(String s, Instant instant) {
+ return false;
+ }
+
+ @Override
+ public String transformUrl(String s) {
+ return null;
+ }
+
+ @Override
+ public void addUrlTransformer(Function function) {
+
+ }
+
+ @Override
+ public String getLogPrefix() {
+ return null;
+ }
+ }
+
+ private final ServerWebExchangeEnhancedInstance enhancedInstance = new ServerWebExchangeEnhancedInstance();
+ private final GatewayFilterInterceptor interceptor = new GatewayFilterInterceptor();
+ @Rule
+ public AgentServiceRule serviceRule = new AgentServiceRule();
+ @Rule
+ public MockitoRule rule = MockitoJUnit.rule();
+
+ @SegmentStoragePoint
+ private SegmentStorage segmentStorage;
+
+ @Before
+ public void setUp() throws Exception {
+ }
+
+ private final ServerWebExchange exchange = new ServerWebExchange() {
+ Map attributes = new HashMap<>();
+ @Override
+ public ServerHttpRequest getRequest() {
+ return null;
+ }
+
+ @Override
+ public ServerHttpResponse getResponse() {
+ return null;
+ }
+
+ @Override
+ public Map getAttributes() {
+ return attributes;
+ }
+
+ @Override
+ public Mono getSession() {
+ return null;
+ }
+
+ @Override
+ public Mono getPrincipal() {
+ return null;
+ }
+
+ @Override
+ public Mono> getFormData() {
+ return null;
+ }
+
+ @Override
+ public Mono> getMultipartData() {
+ return null;
+ }
+
+ @Override
+ public LocaleContext getLocaleContext() {
+ return null;
+ }
+
+ @Override
+ public ApplicationContext getApplicationContext() {
+ return null;
+ }
+
+ @Override
+ public boolean isNotModified() {
+ return false;
+ }
+
+ @Override
+ public boolean checkNotModified(Instant instant) {
+ return false;
+ }
+
+ @Override
+ public boolean checkNotModified(String s) {
+ return false;
+ }
+
+ @Override
+ public boolean checkNotModified(String s, Instant instant) {
+ return false;
+ }
+
+ @Override
+ public String transformUrl(String s) {
+ return null;
+ }
+
+ @Override
+ public void addUrlTransformer(Function function) {
+
+ }
+
+ @Override
+ public String getLogPrefix() {
+ return null;
+ }
+ };
+
+ @Test
+ public void testInterceptOnlyOnce() throws Throwable {
+ interceptor.beforeMethod(null, null, new Object[]{exchange}, null, null);
+ Assert.assertTrue(ContextManager.isActive());
+ AbstractSpan activeSpan = ContextManager.activeSpan();
+ Assert.assertTrue(activeSpan instanceof AbstractTracingSpan);
+ Assert.assertEquals(activeSpan.getOperationName(), GATEWAY_FILTER_INTERCEPTOR_LOCAL_SPAN_OPERATION_NAME);
+
+ interceptor.afterMethod(null, null, null, null, null);
+ Assert.assertFalse(ContextManager.isActive());
+ final List traceSegments = segmentStorage.getTraceSegments();
+ Assert.assertEquals(traceSegments.size(), 1);
+ final List spans = SegmentHelper.getSpans(traceSegments.get(0));
+ Assert.assertNotNull(spans);
+ Assert.assertEquals(spans.size(), 1);
+ SpanAssert.assertComponent(spans.get(0), ComponentsDefine.SPRING_CLOUD_GATEWAY);
+
+ }
+
+ @Test
+ public void testNestedInterception() throws Throwable {
+ interceptor.beforeMethod(null, null, new Object[]{enhancedInstance}, null, null);
+ Assert.assertTrue(ContextManager.isActive());
+
+ interceptor.beforeMethod(null, null, new Object[]{enhancedInstance}, null, null);
+ Assert.assertTrue(ContextManager.isActive());
+
+ interceptor.afterMethod(null, null, null, null, null);
+ Assert.assertTrue(ContextManager.isActive());
+
+ interceptor.afterMethod(null, null, null, null, null);
+ Assert.assertFalse(ContextManager.isActive());
+
+ final List traceSegments = segmentStorage.getTraceSegments();
+ Assert.assertEquals(traceSegments.size(), 1);
+ final List spans = SegmentHelper.getSpans(traceSegments.get(0));
+ Assert.assertNotNull(spans);
+ Assert.assertEquals(spans.size(), 1);
+ SpanAssert.assertComponent(spans.get(0), ComponentsDefine.SPRING_CLOUD_GATEWAY);
+ }
+
+ @Test
+ public void testWithNullDynamicField() throws Throwable {
+ interceptor.beforeMethod(null, null, new Object[]{enhancedInstance}, null, null);
+ interceptor.afterMethod(null, null, null, null, null);
+ // no more need this, span was stopped at interceptor#afterMethod
+ // ContextManager.stopSpan();
+ final List traceSegments = segmentStorage.getTraceSegments();
+ Assert.assertEquals(traceSegments.size(), 1);
+ final List spans = SegmentHelper.getSpans(traceSegments.get(0));
+ Assert.assertNotNull(spans);
+ Assert.assertEquals(spans.size(), 1);
+ SpanAssert.assertComponent(spans.get(0), ComponentsDefine.SPRING_CLOUD_GATEWAY);
+ }
+
+ @Test
+ public void testWithContextSnapshot() throws Throwable {
+ final AbstractSpan entrySpan = ContextManager.createEntrySpan("/get", null);
+ SpanLayer.asHttp(entrySpan);
+ entrySpan.setComponent(ComponentsDefine.SPRING_WEBFLUX);
+ enhancedInstance.setSkyWalkingDynamicField(ContextManager.capture());
+ interceptor.beforeMethod(null, null, new Object[]{enhancedInstance}, null, null);
+ interceptor.afterMethod(null, null, null, null, null);
+ // no more need this, span was stopped at interceptor#afterMethod
+ // ContextManager.stopSpan();
+ ContextManager.stopSpan(entrySpan);
+ final List traceSegments = segmentStorage.getTraceSegments();
+ Assert.assertEquals(traceSegments.size(), 1);
+ final List spans = SegmentHelper.getSpans(traceSegments.get(0));
+ Assert.assertNotNull(spans);
+ Assert.assertEquals(spans.size(), 2);
+ SpanAssert.assertComponent(spans.get(0), ComponentsDefine.SPRING_CLOUD_GATEWAY);
+ SpanAssert.assertComponent(spans.get(1), ComponentsDefine.SPRING_WEBFLUX);
+ SpanAssert.assertLayer(spans.get(1), SpanLayer.HTTP);
+ }
+
+}
diff --git a/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-3.x-plugin/pom.xml b/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-3.x-plugin/pom.xml
index dae580784f..33180c560c 100644
--- a/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-3.x-plugin/pom.xml
+++ b/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-3.x-plugin/pom.xml
@@ -21,7 +21,7 @@
optional-spring-cloud
org.apache.skywalking
- 9.3.0-SNAPSHOT
+ 9.7.0-SNAPSHOT
4.0.0
@@ -52,7 +52,6 @@
org.apache.maven.plugins
maven-shade-plugin
- 3.2.4
package
diff --git a/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/cloud/gateway/v3x/GatewayFilterInterceptor.java b/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/cloud/gateway/v3x/GatewayFilterInterceptor.java
new file mode 100644
index 0000000000..133424539b
--- /dev/null
+++ b/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/cloud/gateway/v3x/GatewayFilterInterceptor.java
@@ -0,0 +1,94 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.skywalking.apm.plugin.spring.cloud.gateway.v3x;
+
+import org.apache.skywalking.apm.agent.core.context.ContextManager;
+import org.apache.skywalking.apm.agent.core.context.ContextSnapshot;
+import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
+import org.springframework.web.server.ServerWebExchange;
+import org.springframework.web.server.ServerWebExchangeDecorator;
+import org.springframework.web.server.adapter.DefaultServerWebExchange;
+
+import java.lang.reflect.Method;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import static org.apache.skywalking.apm.network.trace.component.ComponentsDefine.SPRING_CLOUD_GATEWAY;
+
+public class GatewayFilterInterceptor implements InstanceMethodsAroundInterceptor {
+
+ private static final ThreadLocal STACK_DEEP = ThreadLocal.withInitial(() -> new AtomicInteger(0));
+
+ @Override
+ public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes,
+ MethodInterceptResult result) throws Throwable {
+ if (isEntry()) {
+ ServerWebExchange exchange = (ServerWebExchange) allArguments[0];
+
+ EnhancedInstance enhancedInstance = getInstance(exchange);
+
+ AbstractSpan span = ContextManager.createLocalSpan("SpringCloudGateway/GatewayFilter");
+ if (enhancedInstance != null && enhancedInstance.getSkyWalkingDynamicField() != null) {
+ ContextManager.continued((ContextSnapshot) enhancedInstance.getSkyWalkingDynamicField());
+ }
+ span.setComponent(SPRING_CLOUD_GATEWAY);
+ }
+ }
+
+ public static EnhancedInstance getInstance(Object o) {
+ EnhancedInstance instance = null;
+ if (o instanceof DefaultServerWebExchange) {
+ instance = (EnhancedInstance) o;
+ } else if (o instanceof ServerWebExchangeDecorator) {
+ ServerWebExchange delegate = ((ServerWebExchangeDecorator) o).getDelegate();
+ return getInstance(delegate);
+ }
+ return instance;
+ }
+
+ @Override
+ public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes,
+ Object ret) throws Throwable {
+ if (isExit()) {
+ if (ContextManager.isActive()) {
+ ContextManager.stopSpan();
+ }
+ }
+ return ret;
+ }
+
+ @Override
+ public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments,
+ Class>[] argumentsTypes, Throwable t) {
+ ContextManager.activeSpan().log(t);
+ }
+
+ private boolean isEntry() {
+ return STACK_DEEP.get().getAndIncrement() == 0;
+ }
+
+ private boolean isExit() {
+ boolean isExit = STACK_DEEP.get().decrementAndGet() == 0;
+ if (isExit) {
+ STACK_DEEP.remove();
+ }
+ return isExit;
+ }
+}
diff --git a/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/cloud/gateway/v3x/define/GatewayFilterInstrumentation.java b/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/cloud/gateway/v3x/define/GatewayFilterInstrumentation.java
new file mode 100644
index 0000000000..4488516f19
--- /dev/null
+++ b/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/cloud/gateway/v3x/define/GatewayFilterInstrumentation.java
@@ -0,0 +1,67 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.skywalking.apm.plugin.spring.cloud.gateway.v3x.define;
+
+import net.bytebuddy.description.method.MethodDescription;
+import net.bytebuddy.matcher.ElementMatcher;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
+import org.apache.skywalking.apm.agent.core.plugin.match.HierarchyMatch;
+
+import static net.bytebuddy.matcher.ElementMatchers.named;
+import static org.apache.skywalking.apm.agent.core.plugin.bytebuddy.ArgumentTypeNameMatch.takesArgumentWithType;
+
+public class GatewayFilterInstrumentation extends AbstractGatewayV3EnhancePluginDefine {
+
+ private static final String INTERCEPT_CLASS_GATEWAY_FILTER = "org.springframework.cloud.gateway.filter.GatewayFilter";
+ private static final String GATEWAY_FILTER_INTERCEPTOR = "org.apache.skywalking.apm.plugin.spring.cloud.gateway.v3x.GatewayFilterInterceptor";
+
+ @Override
+ protected ClassMatch enhanceClass() {
+ return HierarchyMatch.byHierarchyMatch(INTERCEPT_CLASS_GATEWAY_FILTER);
+ }
+
+ @Override
+ public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
+ return new ConstructorInterceptPoint[0];
+ }
+
+ @Override
+ public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
+ return new InstanceMethodsInterceptPoint[] {
+ new InstanceMethodsInterceptPoint() {
+ @Override
+ public ElementMatcher getMethodsMatcher() {
+ return named("filter").and(
+ takesArgumentWithType(0, "org.springframework.web.server.ServerWebExchange"));
+ }
+
+ @Override
+ public String getMethodsInterceptor() {
+ return GATEWAY_FILTER_INTERCEPTOR;
+ }
+
+ @Override
+ public boolean isOverrideArgs() {
+ return false;
+ }
+ }
+ };
+ }
+}
diff --git a/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-3.x-plugin/src/main/resources/skywalking-plugin.def b/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-3.x-plugin/src/main/resources/skywalking-plugin.def
index ba4b480501..10525a931a 100644
--- a/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-3.x-plugin/src/main/resources/skywalking-plugin.def
+++ b/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-3.x-plugin/src/main/resources/skywalking-plugin.def
@@ -18,3 +18,4 @@ spring-cloud-gateway-3.x=org.apache.skywalking.apm.plugin.spring.cloud.gateway.v
spring-cloud-gateway-3.x=org.apache.skywalking.apm.plugin.spring.cloud.gateway.v3x.define.NettyRoutingFilterInstrumentation
spring-cloud-gateway-3.x=org.apache.skywalking.apm.plugin.spring.cloud.gateway.v3x.define.ServerWebExchangeInstrumentation
spring-cloud-gateway-3.x=org.apache.skywalking.apm.plugin.spring.cloud.gateway.v3x.define.DispatcherHandlerInstrumentation
+spring-cloud-gateway-3.x=org.apache.skywalking.apm.plugin.spring.cloud.gateway.v3x.define.GatewayFilterInstrumentation
diff --git a/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-3.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/spring/cloud/gateway/v3x/GatewayFilterInterceptorTest.java b/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-3.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/spring/cloud/gateway/v3x/GatewayFilterInterceptorTest.java
new file mode 100644
index 0000000000..db0e0e3174
--- /dev/null
+++ b/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-3.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/spring/cloud/gateway/v3x/GatewayFilterInterceptorTest.java
@@ -0,0 +1,332 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.spring.cloud.gateway.v3x;
+
+import org.apache.skywalking.apm.agent.core.context.ContextManager;
+import org.apache.skywalking.apm.agent.core.context.ContextSnapshot;
+import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan;
+import org.apache.skywalking.apm.agent.core.context.trace.AbstractTracingSpan;
+import org.apache.skywalking.apm.agent.core.context.trace.SpanLayer;
+import org.apache.skywalking.apm.agent.core.context.trace.TraceSegment;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
+import org.apache.skywalking.apm.agent.test.helper.SegmentHelper;
+import org.apache.skywalking.apm.agent.test.tools.AgentServiceRule;
+import org.apache.skywalking.apm.agent.test.tools.SegmentStorage;
+import org.apache.skywalking.apm.agent.test.tools.SegmentStoragePoint;
+import org.apache.skywalking.apm.agent.test.tools.SpanAssert;
+import org.apache.skywalking.apm.agent.test.tools.TracingSegmentRunner;
+import org.apache.skywalking.apm.network.trace.component.ComponentsDefine;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.i18n.LocaleContext;
+import org.springframework.http.codec.multipart.Part;
+import org.springframework.http.server.reactive.ServerHttpRequest;
+import org.springframework.http.server.reactive.ServerHttpResponse;
+import org.springframework.util.MultiValueMap;
+import org.springframework.web.server.ServerWebExchange;
+import org.springframework.web.server.WebSession;
+import reactor.core.publisher.Mono;
+
+import java.security.Principal;
+import java.time.Instant;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.function.Function;
+
+@RunWith(TracingSegmentRunner.class)
+public class GatewayFilterInterceptorTest {
+
+ private static final String GATEWAY_FILTER_INTERCEPTOR_LOCAL_SPAN_OPERATION_NAME = "SpringCloudGateway/GatewayFilter";
+
+ private static class ServerWebExchangeEnhancedInstance implements ServerWebExchange, EnhancedInstance {
+ private ContextSnapshot snapshot;
+ Map attributes = new HashMap<>();
+
+ @Override
+ public Object getSkyWalkingDynamicField() {
+ return snapshot;
+ }
+
+ @Override
+ public void setSkyWalkingDynamicField(Object value) {
+ this.snapshot = (ContextSnapshot) value;
+ }
+
+ @Override
+ public ServerHttpRequest getRequest() {
+ return null;
+ }
+
+ @Override
+ public ServerHttpResponse getResponse() {
+ return null;
+ }
+
+ @Override
+ public Map getAttributes() {
+ return attributes;
+ }
+
+ @Override
+ public Mono getSession() {
+ return null;
+ }
+
+ @Override
+ public Mono getPrincipal() {
+ return null;
+ }
+
+ @Override
+ public Mono> getFormData() {
+ return null;
+ }
+
+ @Override
+ public Mono> getMultipartData() {
+ return null;
+ }
+
+ @Override
+ public LocaleContext getLocaleContext() {
+ return null;
+ }
+
+ @Override
+ public ApplicationContext getApplicationContext() {
+ return null;
+ }
+
+ @Override
+ public boolean isNotModified() {
+ return false;
+ }
+
+ @Override
+ public boolean checkNotModified(Instant instant) {
+ return false;
+ }
+
+ @Override
+ public boolean checkNotModified(String s) {
+ return false;
+ }
+
+ @Override
+ public boolean checkNotModified(String s, Instant instant) {
+ return false;
+ }
+
+ @Override
+ public String transformUrl(String s) {
+ return null;
+ }
+
+ @Override
+ public void addUrlTransformer(Function function) {
+
+ }
+
+ @Override
+ public String getLogPrefix() {
+ return null;
+ }
+ }
+
+ private final ServerWebExchangeEnhancedInstance enhancedInstance = new ServerWebExchangeEnhancedInstance();
+ private final GatewayFilterInterceptor interceptor = new GatewayFilterInterceptor();
+ @Rule
+ public AgentServiceRule serviceRule = new AgentServiceRule();
+ @Rule
+ public MockitoRule rule = MockitoJUnit.rule();
+
+ @SegmentStoragePoint
+ private SegmentStorage segmentStorage;
+
+ @Before
+ public void setUp() throws Exception {
+ }
+
+ private final ServerWebExchange exchange = new ServerWebExchange() {
+ Map attributes = new HashMap<>();
+ @Override
+ public ServerHttpRequest getRequest() {
+ return null;
+ }
+
+ @Override
+ public ServerHttpResponse getResponse() {
+ return null;
+ }
+
+ @Override
+ public Map getAttributes() {
+ return attributes;
+ }
+
+ @Override
+ public Mono getSession() {
+ return null;
+ }
+
+ @Override
+ public Mono getPrincipal() {
+ return null;
+ }
+
+ @Override
+ public Mono> getFormData() {
+ return null;
+ }
+
+ @Override
+ public Mono> getMultipartData() {
+ return null;
+ }
+
+ @Override
+ public LocaleContext getLocaleContext() {
+ return null;
+ }
+
+ @Override
+ public ApplicationContext getApplicationContext() {
+ return null;
+ }
+
+ @Override
+ public boolean isNotModified() {
+ return false;
+ }
+
+ @Override
+ public boolean checkNotModified(Instant instant) {
+ return false;
+ }
+
+ @Override
+ public boolean checkNotModified(String s) {
+ return false;
+ }
+
+ @Override
+ public boolean checkNotModified(String s, Instant instant) {
+ return false;
+ }
+
+ @Override
+ public String transformUrl(String s) {
+ return null;
+ }
+
+ @Override
+ public void addUrlTransformer(Function function) {
+
+ }
+
+ @Override
+ public String getLogPrefix() {
+ return null;
+ }
+ };
+
+ @Test
+ public void testInterceptOnlyOnce() throws Throwable {
+ interceptor.beforeMethod(null, null, new Object[]{exchange}, null, null);
+ Assert.assertTrue(ContextManager.isActive());
+ AbstractSpan activeSpan = ContextManager.activeSpan();
+ Assert.assertTrue(activeSpan instanceof AbstractTracingSpan);
+ Assert.assertEquals(activeSpan.getOperationName(), GATEWAY_FILTER_INTERCEPTOR_LOCAL_SPAN_OPERATION_NAME);
+
+ interceptor.afterMethod(null, null, null, null, null);
+ Assert.assertFalse(ContextManager.isActive());
+ final List traceSegments = segmentStorage.getTraceSegments();
+ Assert.assertEquals(traceSegments.size(), 1);
+ final List spans = SegmentHelper.getSpans(traceSegments.get(0));
+ Assert.assertNotNull(spans);
+ Assert.assertEquals(spans.size(), 1);
+ SpanAssert.assertComponent(spans.get(0), ComponentsDefine.SPRING_CLOUD_GATEWAY);
+
+ }
+
+ @Test
+ public void testNestedInterception() throws Throwable {
+ interceptor.beforeMethod(null, null, new Object[]{enhancedInstance}, null, null);
+ Assert.assertTrue(ContextManager.isActive());
+
+ interceptor.beforeMethod(null, null, new Object[]{enhancedInstance}, null, null);
+ Assert.assertTrue(ContextManager.isActive());
+
+ interceptor.afterMethod(null, null, null, null, null);
+ Assert.assertTrue(ContextManager.isActive());
+
+ interceptor.afterMethod(null, null, null, null, null);
+ Assert.assertFalse(ContextManager.isActive());
+
+ final List traceSegments = segmentStorage.getTraceSegments();
+ Assert.assertEquals(traceSegments.size(), 1);
+ final List spans = SegmentHelper.getSpans(traceSegments.get(0));
+ Assert.assertNotNull(spans);
+ Assert.assertEquals(spans.size(), 1);
+ SpanAssert.assertComponent(spans.get(0), ComponentsDefine.SPRING_CLOUD_GATEWAY);
+ }
+
+ @Test
+ public void testWithNullDynamicField() throws Throwable {
+ interceptor.beforeMethod(null, null, new Object[]{enhancedInstance}, null, null);
+ interceptor.afterMethod(null, null, null, null, null);
+ // no more need this, span was stopped at interceptor#afterMethod
+ // ContextManager.stopSpan();
+ final List traceSegments = segmentStorage.getTraceSegments();
+ Assert.assertEquals(traceSegments.size(), 1);
+ final List spans = SegmentHelper.getSpans(traceSegments.get(0));
+ Assert.assertNotNull(spans);
+ Assert.assertEquals(spans.size(), 1);
+ SpanAssert.assertComponent(spans.get(0), ComponentsDefine.SPRING_CLOUD_GATEWAY);
+ }
+
+ @Test
+ public void testWithContextSnapshot() throws Throwable {
+ final AbstractSpan entrySpan = ContextManager.createEntrySpan("/get", null);
+ SpanLayer.asHttp(entrySpan);
+ entrySpan.setComponent(ComponentsDefine.SPRING_WEBFLUX);
+ enhancedInstance.setSkyWalkingDynamicField(ContextManager.capture());
+ interceptor.beforeMethod(null, null, new Object[]{enhancedInstance}, null, null);
+ interceptor.afterMethod(null, null, null, null, null);
+ // no more need this, span was stopped at interceptor#afterMethod
+ // ContextManager.stopSpan();
+ ContextManager.stopSpan(entrySpan);
+ final List traceSegments = segmentStorage.getTraceSegments();
+ Assert.assertEquals(traceSegments.size(), 1);
+ final List spans = SegmentHelper.getSpans(traceSegments.get(0));
+ Assert.assertNotNull(spans);
+ Assert.assertEquals(spans.size(), 2);
+ SpanAssert.assertComponent(spans.get(0), ComponentsDefine.SPRING_CLOUD_GATEWAY);
+ SpanAssert.assertComponent(spans.get(1), ComponentsDefine.SPRING_WEBFLUX);
+ SpanAssert.assertLayer(spans.get(1), SpanLayer.HTTP);
+ }
+
+}
diff --git a/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-4.x-plugin/pom.xml b/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-4.x-plugin/pom.xml
index 73ed729672..bcd6ffcca4 100644
--- a/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-4.x-plugin/pom.xml
+++ b/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-4.x-plugin/pom.xml
@@ -21,7 +21,7 @@
optional-spring-cloud
org.apache.skywalking
- 9.3.0-SNAPSHOT
+ 9.7.0-SNAPSHOT
4.0.0
@@ -52,7 +52,6 @@
org.apache.maven.plugins
maven-shade-plugin
- 3.2.4
package
diff --git a/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-4.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/cloud/gateway/v412x/GatewayFilterV412Interceptor.java b/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-4.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/cloud/gateway/v412x/GatewayFilterV412Interceptor.java
new file mode 100644
index 0000000000..c1a9ec505f
--- /dev/null
+++ b/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-4.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/cloud/gateway/v412x/GatewayFilterV412Interceptor.java
@@ -0,0 +1,94 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.skywalking.apm.plugin.spring.cloud.gateway.v412x;
+
+import org.apache.skywalking.apm.agent.core.context.ContextManager;
+import org.apache.skywalking.apm.agent.core.context.ContextSnapshot;
+import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
+import org.springframework.web.server.ServerWebExchange;
+import org.springframework.web.server.ServerWebExchangeDecorator;
+import org.springframework.web.server.adapter.DefaultServerWebExchange;
+
+import java.lang.reflect.Method;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import static org.apache.skywalking.apm.network.trace.component.ComponentsDefine.SPRING_CLOUD_GATEWAY;
+
+public class GatewayFilterV412Interceptor implements InstanceMethodsAroundInterceptor {
+
+ private static final ThreadLocal STACK_DEEP = ThreadLocal.withInitial(() -> new AtomicInteger(0));
+
+ @Override
+ public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes,
+ MethodInterceptResult result) throws Throwable {
+ if (isEntry()) {
+ ServerWebExchange exchange = (ServerWebExchange) allArguments[0];
+
+ EnhancedInstance enhancedInstance = getInstance(exchange);
+
+ AbstractSpan span = ContextManager.createLocalSpan("SpringCloudGateway/GatewayFilter");
+ if (enhancedInstance != null && enhancedInstance.getSkyWalkingDynamicField() != null) {
+ ContextManager.continued((ContextSnapshot) enhancedInstance.getSkyWalkingDynamicField());
+ }
+ span.setComponent(SPRING_CLOUD_GATEWAY);
+ }
+ }
+
+ public static EnhancedInstance getInstance(Object o) {
+ EnhancedInstance instance = null;
+ if (o instanceof DefaultServerWebExchange) {
+ instance = (EnhancedInstance) o;
+ } else if (o instanceof ServerWebExchangeDecorator) {
+ ServerWebExchange delegate = ((ServerWebExchangeDecorator) o).getDelegate();
+ return getInstance(delegate);
+ }
+ return instance;
+ }
+
+ @Override
+ public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes,
+ Object ret) throws Throwable {
+ if (isExit()) {
+ if (ContextManager.isActive()) {
+ ContextManager.stopSpan();
+ }
+ }
+ return ret;
+ }
+
+ @Override
+ public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments,
+ Class>[] argumentsTypes, Throwable t) {
+ ContextManager.activeSpan().log(t);
+ }
+
+ private boolean isEntry() {
+ return STACK_DEEP.get().getAndIncrement() == 0;
+ }
+
+ private boolean isExit() {
+ boolean isExit = STACK_DEEP.get().decrementAndGet() == 0;
+ if (isExit) {
+ STACK_DEEP.remove();
+ }
+ return isExit;
+ }
+}
diff --git a/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-4.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/cloud/gateway/v412x/HttpClientConnectDuplicateV412Interceptor.java b/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-4.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/cloud/gateway/v412x/HttpClientConnectDuplicateV412Interceptor.java
new file mode 100644
index 0000000000..5658134748
--- /dev/null
+++ b/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-4.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/cloud/gateway/v412x/HttpClientConnectDuplicateV412Interceptor.java
@@ -0,0 +1,50 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.skywalking.apm.plugin.spring.cloud.gateway.v412x;
+
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
+import org.apache.skywalking.apm.plugin.spring.cloud.gateway.v4x.define.EnhanceObjectCache;
+
+import java.lang.reflect.Method;
+
+public class HttpClientConnectDuplicateV412Interceptor implements InstanceMethodsAroundInterceptor {
+
+ @Override
+ public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes, MethodInterceptResult result) throws Throwable {
+
+ }
+
+ @Override
+ public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes, Object ret) throws Throwable {
+ if (objInst.getSkyWalkingDynamicField() != null) {
+ EnhanceObjectCache enhanceObjectCache = (EnhanceObjectCache) objInst.getSkyWalkingDynamicField();
+ if (ret instanceof EnhancedInstance) {
+ EnhancedInstance retEnhancedInstance = (EnhancedInstance) ret;
+ retEnhancedInstance.setSkyWalkingDynamicField(enhanceObjectCache);
+ }
+ }
+ return ret;
+ }
+
+ @Override
+ public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes, Throwable t) {
+
+ }
+}
diff --git a/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-4.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/cloud/gateway/v412x/HttpClientConnectRequestV412Interceptor.java b/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-4.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/cloud/gateway/v412x/HttpClientConnectRequestV412Interceptor.java
new file mode 100644
index 0000000000..f35f3551fb
--- /dev/null
+++ b/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-4.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/cloud/gateway/v412x/HttpClientConnectRequestV412Interceptor.java
@@ -0,0 +1,54 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.skywalking.apm.plugin.spring.cloud.gateway.v412x;
+
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
+import org.apache.skywalking.apm.plugin.spring.cloud.gateway.v4x.define.EnhanceObjectCache;
+
+import java.lang.reflect.Method;
+
+public class HttpClientConnectRequestV412Interceptor implements InstanceMethodsAroundInterceptor {
+
+ @Override
+ public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes, MethodInterceptResult result) throws Throwable {
+
+ }
+
+ @Override
+ public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes, Object ret) throws Throwable {
+ if (objInst.getSkyWalkingDynamicField() != null) {
+ if (ret instanceof EnhancedInstance) {
+ EnhancedInstance retEnhancedInstance = (EnhancedInstance) ret;
+ Object retSkyWalkingDynamicField = retEnhancedInstance.getSkyWalkingDynamicField();
+ if (retSkyWalkingDynamicField != null) {
+ EnhanceObjectCache retEnhanceObjectCache = (EnhanceObjectCache) retSkyWalkingDynamicField;
+ EnhanceObjectCache objEnhanceObjectCache = (EnhanceObjectCache) objInst.getSkyWalkingDynamicField();
+ retEnhanceObjectCache.setContextSnapshot(objEnhanceObjectCache.getContextSnapshot());
+ }
+ }
+ }
+ return ret;
+ }
+
+ @Override
+ public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes, Throwable t) {
+
+ }
+}
diff --git a/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-4.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/cloud/gateway/v412x/HttpClientFinalizerConstructorV412Interceptor.java b/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-4.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/cloud/gateway/v412x/HttpClientFinalizerConstructorV412Interceptor.java
new file mode 100644
index 0000000000..410baa61a7
--- /dev/null
+++ b/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-4.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/cloud/gateway/v412x/HttpClientFinalizerConstructorV412Interceptor.java
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.skywalking.apm.plugin.spring.cloud.gateway.v412x;
+
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceConstructorInterceptor;
+import org.apache.skywalking.apm.plugin.spring.cloud.gateway.v4x.define.EnhanceObjectCache;
+import reactor.netty.http.client.HttpClientConfig;
+
+/**
+ * Intercept the constructor and inject {@link EnhanceObjectCache}.
+ *
+ * The first constructor argument is {@link HttpClientConfig} class instance which can get the
+ * request uri string.
+ */
+public class HttpClientFinalizerConstructorV412Interceptor implements InstanceConstructorInterceptor {
+
+ @Override
+ public void onConstruct(EnhancedInstance objInst, Object[] allArguments) {
+ final HttpClientConfig httpClientConfig = (HttpClientConfig) allArguments[0];
+ if (httpClientConfig == null) {
+ return;
+ }
+ final EnhanceObjectCache enhanceObjectCache = new EnhanceObjectCache();
+ enhanceObjectCache.setUrl(httpClientConfig.uri());
+ objInst.setSkyWalkingDynamicField(enhanceObjectCache);
+ }
+}
diff --git a/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-4.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/cloud/gateway/v412x/HttpClientFinalizerResponseConnectionV412Interceptor.java b/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-4.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/cloud/gateway/v412x/HttpClientFinalizerResponseConnectionV412Interceptor.java
new file mode 100644
index 0000000000..7199c85744
--- /dev/null
+++ b/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-4.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/cloud/gateway/v412x/HttpClientFinalizerResponseConnectionV412Interceptor.java
@@ -0,0 +1,107 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.skywalking.apm.plugin.spring.cloud.gateway.v412x;
+
+import io.netty.handler.codec.http.HttpResponseStatus;
+import org.apache.skywalking.apm.agent.core.context.tag.Tags;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
+import org.apache.skywalking.apm.plugin.spring.cloud.gateway.v4x.define.EnhanceObjectCache;
+import org.reactivestreams.Publisher;
+import reactor.core.publisher.Flux;
+import reactor.core.publisher.SignalType;
+import reactor.netty.Connection;
+import reactor.netty.http.client.HttpClientResponse;
+
+import java.lang.reflect.Method;
+import java.util.function.BiFunction;
+
+/**
+ * This class intercept responseConnection method.
+ *
+ * After downstream service response, finish the span in the {@link EnhanceObjectCache}.
+ */
+public class HttpClientFinalizerResponseConnectionV412Interceptor implements InstanceMethodsAroundInterceptor {
+
+ @Override
+ public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes,
+ MethodInterceptResult result) {
+ BiFunction super HttpClientResponse, ? super Connection, ? extends Publisher> finalReceiver = (BiFunction super HttpClientResponse, ? super Connection, ? extends Publisher>) allArguments[0];
+ EnhanceObjectCache cache = (EnhanceObjectCache) objInst.getSkyWalkingDynamicField();
+ allArguments[0] = (BiFunction) (response, connection) -> {
+ Publisher publisher = finalReceiver.apply(response, connection);
+ if (cache == null) {
+ return publisher;
+ }
+ // receive the response.
+ if (cache.getSpan() != null) {
+ if (response.status().code() >= HttpResponseStatus.BAD_REQUEST.code()) {
+ cache.getSpan().errorOccurred();
+ }
+ Tags.HTTP_RESPONSE_STATUS_CODE.set(cache.getSpan(), response.status().code());
+ }
+
+ return publisher;
+ };
+ }
+
+ @Override
+ public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes,
+ Object ret) {
+ Flux> responseFlux = (Flux>) ret;
+
+ responseFlux = responseFlux
+ .doOnError(e -> {
+ EnhanceObjectCache cache = (EnhanceObjectCache) objInst.getSkyWalkingDynamicField();
+ if (cache == null) {
+ return;
+ }
+
+ if (cache.getSpan() != null) {
+ cache.getSpan().errorOccurred();
+ cache.getSpan().log(e);
+ }
+ })
+ .doFinally(signalType -> {
+ EnhanceObjectCache cache = (EnhanceObjectCache) objInst.getSkyWalkingDynamicField();
+ if (cache == null) {
+ return;
+ }
+ // do finally. Finish the span.
+ if (cache.getSpan() != null) {
+ if (signalType == SignalType.CANCEL) {
+ cache.getSpan().errorOccurred();
+ }
+ cache.getSpan().asyncFinish();
+ }
+
+ if (cache.getSpan1() != null) {
+ cache.getSpan1().asyncFinish();
+ }
+ });
+
+ return responseFlux;
+ }
+
+ @Override
+ public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments,
+ Class>[] argumentsTypes, Throwable t) {
+
+ }
+}
diff --git a/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-4.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/cloud/gateway/v412x/HttpClientFinalizerSendV412Interceptor.java b/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-4.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/cloud/gateway/v412x/HttpClientFinalizerSendV412Interceptor.java
new file mode 100644
index 0000000000..a1bc32f329
--- /dev/null
+++ b/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-4.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/cloud/gateway/v412x/HttpClientFinalizerSendV412Interceptor.java
@@ -0,0 +1,112 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.skywalking.apm.plugin.spring.cloud.gateway.v412x;
+
+import org.apache.skywalking.apm.agent.core.context.CarrierItem;
+import org.apache.skywalking.apm.agent.core.context.ContextCarrier;
+import org.apache.skywalking.apm.agent.core.context.ContextManager;
+import org.apache.skywalking.apm.agent.core.context.ContextSnapshot;
+import org.apache.skywalking.apm.agent.core.context.tag.Tags;
+import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan;
+import org.apache.skywalking.apm.agent.core.context.trace.SpanLayer;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
+import org.apache.skywalking.apm.plugin.spring.cloud.gateway.v4x.define.EnhanceObjectCache;
+import org.apache.skywalking.apm.util.StringUtil;
+import org.reactivestreams.Publisher;
+import reactor.netty.NettyOutbound;
+import reactor.netty.http.client.HttpClientRequest;
+
+import java.lang.reflect.Method;
+import java.net.URL;
+import java.util.function.BiFunction;
+
+import static org.apache.skywalking.apm.network.trace.component.ComponentsDefine.SPRING_CLOUD_GATEWAY;
+
+/**
+ * This class intercept send method.
+ *
+ * In before method, create a new BiFunction lambda expression for setting ContextCarrier to http header
+ * and replace the original lambda in argument
+ */
+public class HttpClientFinalizerSendV412Interceptor implements InstanceMethodsAroundInterceptor {
+
+ @Override
+ public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes,
+ MethodInterceptResult result) throws Throwable {
+ EnhanceObjectCache enhanceObjectCache = (EnhanceObjectCache) objInst.getSkyWalkingDynamicField();
+ if (enhanceObjectCache == null) {
+ return;
+ }
+ ContextSnapshot contextSnapshot = enhanceObjectCache.getContextSnapshot();
+ if (contextSnapshot == null) {
+ return;
+ }
+ AbstractSpan span = ContextManager.createLocalSpan("SpringCloudGateway/send");
+ ContextManager.continued(contextSnapshot);
+ span.setComponent(SPRING_CLOUD_GATEWAY);
+ span.prepareForAsync();
+
+ if (StringUtil.isNotEmpty(enhanceObjectCache.getUrl())) {
+ URL url = new URL(enhanceObjectCache.getUrl());
+
+ ContextCarrier contextCarrier = new ContextCarrier();
+ AbstractSpan abstractSpan = ContextManager.createExitSpan(
+ "SpringCloudGateway/sendRequest", contextCarrier, getPeer(url));
+ Tags.URL.set(abstractSpan, enhanceObjectCache.getUrl());
+ abstractSpan.prepareForAsync();
+ abstractSpan.setComponent(SPRING_CLOUD_GATEWAY);
+ abstractSpan.setLayer(SpanLayer.HTTP);
+ ContextManager.stopSpan(abstractSpan);
+
+ BiFunction super HttpClientRequest, ? super NettyOutbound, ? extends Publisher> finalSender = (BiFunction super HttpClientRequest, ? super NettyOutbound, ? extends Publisher>) allArguments[0];
+ allArguments[0] = (BiFunction>) (request, outbound) -> {
+ Publisher publisher = finalSender.apply(request, outbound);
+
+ CarrierItem next = contextCarrier.items();
+ while (next.hasNext()) {
+ next = next.next();
+ request.requestHeaders().remove(next.getHeadKey());
+ request.requestHeaders().set(next.getHeadKey(), next.getHeadValue());
+ }
+ return publisher;
+ };
+ enhanceObjectCache.setCacheSpan(abstractSpan);
+ }
+ ContextManager.stopSpan(span);
+ enhanceObjectCache.setSpan1(span);
+ }
+
+ private String getPeer(URL url) {
+ return url.getHost() + ":" + url.getPort();
+ }
+
+ @Override
+ public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes,
+ Object ret) {
+ ((EnhancedInstance) ret).setSkyWalkingDynamicField(objInst.getSkyWalkingDynamicField());
+ return ret;
+ }
+
+ @Override
+ public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments,
+ Class>[] argumentsTypes, Throwable t) {
+
+ }
+}
diff --git a/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-4.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/cloud/gateway/v412x/HttpClientFinalizerUriV412Interceptor.java b/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-4.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/cloud/gateway/v412x/HttpClientFinalizerUriV412Interceptor.java
new file mode 100644
index 0000000000..1d5c020210
--- /dev/null
+++ b/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-4.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/cloud/gateway/v412x/HttpClientFinalizerUriV412Interceptor.java
@@ -0,0 +1,57 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.skywalking.apm.plugin.spring.cloud.gateway.v412x;
+
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
+import org.apache.skywalking.apm.plugin.spring.cloud.gateway.v4x.define.EnhanceObjectCache;
+
+import java.lang.reflect.Method;
+
+/**
+ * This class intercept uri method to get the url of downstream service
+ */
+public class HttpClientFinalizerUriV412Interceptor implements InstanceMethodsAroundInterceptor {
+
+ @Override
+ public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes,
+ MethodInterceptResult result) throws Throwable {
+ }
+
+ @Override
+ public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes,
+ Object ret) throws Throwable {
+ if (ret instanceof EnhancedInstance) {
+ EnhanceObjectCache retEnhanceObjectCache = (EnhanceObjectCache) ((EnhancedInstance) ret).getSkyWalkingDynamicField();
+ if (retEnhanceObjectCache != null) {
+ retEnhanceObjectCache.setUrl(String.valueOf(allArguments[0]));
+ if (objInst.getSkyWalkingDynamicField() != null) {
+ EnhanceObjectCache objInstEnhanceObjectCache = (EnhanceObjectCache) objInst.getSkyWalkingDynamicField();
+ retEnhanceObjectCache.setContextSnapshot(objInstEnhanceObjectCache.getContextSnapshot());
+ }
+ }
+ }
+ return ret;
+ }
+
+ @Override
+ public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments,
+ Class>[] argumentsTypes, Throwable t) {
+ }
+}
diff --git a/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-4.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/cloud/gateway/v412x/NettyRoutingFilterV412Interceptor.java b/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-4.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/cloud/gateway/v412x/NettyRoutingFilterV412Interceptor.java
new file mode 100644
index 0000000000..1d6aa76da8
--- /dev/null
+++ b/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-4.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/cloud/gateway/v412x/NettyRoutingFilterV412Interceptor.java
@@ -0,0 +1,91 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.spring.cloud.gateway.v412x;
+
+import org.apache.skywalking.apm.agent.core.context.ContextManager;
+import org.apache.skywalking.apm.agent.core.context.ContextSnapshot;
+import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
+import org.springframework.web.server.ServerWebExchange;
+import org.springframework.web.server.ServerWebExchangeDecorator;
+
+import java.lang.reflect.Method;
+
+import static org.apache.skywalking.apm.network.trace.component.ComponentsDefine.SPRING_CLOUD_GATEWAY;
+
+public class NettyRoutingFilterV412Interceptor implements InstanceMethodsAroundInterceptor {
+
+ private static final String NETTY_ROUTING_FILTER_TRACED_ATTR = NettyRoutingFilterV412Interceptor.class.getName() + ".isTraced";
+
+ @Override
+ public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes,
+ MethodInterceptResult result) throws Throwable {
+ ServerWebExchange exchange = (ServerWebExchange) allArguments[0];
+ if (isTraced(exchange)) {
+ return;
+ }
+
+ setTracedStatus(exchange);
+
+ EnhancedInstance enhancedInstance = getInstance(allArguments[0]);
+
+ AbstractSpan span = ContextManager.createLocalSpan("SpringCloudGateway/RoutingFilter");
+ if (enhancedInstance != null && enhancedInstance.getSkyWalkingDynamicField() != null) {
+ ContextManager.continued((ContextSnapshot) enhancedInstance.getSkyWalkingDynamicField());
+ }
+ span.setComponent(SPRING_CLOUD_GATEWAY);
+ }
+
+ private static void setTracedStatus(ServerWebExchange exchange) {
+ exchange.getAttributes().put(NETTY_ROUTING_FILTER_TRACED_ATTR, true);
+ }
+
+ private static boolean isTraced(ServerWebExchange exchange) {
+ return exchange.getAttributeOrDefault(NETTY_ROUTING_FILTER_TRACED_ATTR, false);
+ }
+
+ private EnhancedInstance getInstance(Object o) {
+ EnhancedInstance instance = null;
+ if (o instanceof EnhancedInstance) {
+ instance = (EnhancedInstance) o;
+ } else if (o instanceof ServerWebExchangeDecorator) {
+ ServerWebExchange delegate = ((ServerWebExchangeDecorator) o).getDelegate();
+ return getInstance(delegate);
+ }
+ return instance;
+ }
+
+ @Override
+ public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes,
+ Object ret) throws Throwable {
+ if (ContextManager.isActive()) {
+ // if HttpClientFinalizerSendInterceptor does not invoke, we will stop the span there to avoid context leak.
+ ContextManager.stopSpan();
+ }
+ return ret;
+ }
+
+ @Override
+ public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments,
+ Class>[] argumentsTypes, Throwable t) {
+ ContextManager.activeSpan().log(t);
+ }
+}
diff --git a/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-4.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/cloud/gateway/v412x/NettyRoutingGetHttpClientV412Interceptor.java b/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-4.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/cloud/gateway/v412x/NettyRoutingGetHttpClientV412Interceptor.java
new file mode 100644
index 0000000000..282e6f5f17
--- /dev/null
+++ b/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-4.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/cloud/gateway/v412x/NettyRoutingGetHttpClientV412Interceptor.java
@@ -0,0 +1,55 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.spring.cloud.gateway.v412x;
+
+import org.apache.skywalking.apm.agent.core.context.ContextManager;
+import org.apache.skywalking.apm.agent.core.context.ContextSnapshot;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
+import org.apache.skywalking.apm.plugin.spring.cloud.gateway.v4x.define.EnhanceObjectCache;
+
+import java.lang.reflect.Method;
+
+public class NettyRoutingGetHttpClientV412Interceptor implements InstanceMethodsAroundInterceptor {
+
+ @Override
+ public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes, MethodInterceptResult result) throws Throwable {
+
+ }
+
+ @Override
+ public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes, Object ret) throws Throwable {
+ if (ret instanceof EnhancedInstance) {
+ if (ContextManager.isActive()) {
+ ContextSnapshot contextSnapshot = ContextManager.capture();
+ EnhanceObjectCache retEnhanceObjectCache = new EnhanceObjectCache();
+ retEnhanceObjectCache.setContextSnapshot(contextSnapshot);
+ EnhancedInstance retEnhancedInstance = (EnhancedInstance) ret;
+ retEnhancedInstance.setSkyWalkingDynamicField(retEnhanceObjectCache);
+ }
+ }
+ return ret;
+ }
+
+ @Override
+ public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes, Throwable t) {
+ }
+
+}
diff --git a/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-4.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/cloud/gateway/v412x/define/AbstractGatewayV412EnhancePluginDefine.java b/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-4.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/cloud/gateway/v412x/define/AbstractGatewayV412EnhancePluginDefine.java
new file mode 100644
index 0000000000..7cde134ef8
--- /dev/null
+++ b/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-4.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/cloud/gateway/v412x/define/AbstractGatewayV412EnhancePluginDefine.java
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.skywalking.apm.plugin.spring.cloud.gateway.v412x.define;
+
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine;
+
+/**
+ * This abstract class defines the witnessClasses() method,
+ * and other plugin define classes need to inherit from this class
+ */
+public abstract class AbstractGatewayV412EnhancePluginDefine extends ClassInstanceMethodsEnhancePluginDefine {
+
+ /**
+ * @since 4.0.0
+ */
+ @Override
+ protected String[] witnessClasses() {
+ return new String[]{"org.springframework.cloud.gateway.event.RouteDeletedEvent"};
+ }
+}
diff --git a/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-4.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/cloud/gateway/v412x/define/GatewayFilterV412Instrumentation.java b/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-4.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/cloud/gateway/v412x/define/GatewayFilterV412Instrumentation.java
new file mode 100644
index 0000000000..499502a07d
--- /dev/null
+++ b/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-4.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/cloud/gateway/v412x/define/GatewayFilterV412Instrumentation.java
@@ -0,0 +1,67 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.skywalking.apm.plugin.spring.cloud.gateway.v412x.define;
+
+import net.bytebuddy.description.method.MethodDescription;
+import net.bytebuddy.matcher.ElementMatcher;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
+import org.apache.skywalking.apm.agent.core.plugin.match.HierarchyMatch;
+
+import static net.bytebuddy.matcher.ElementMatchers.named;
+import static org.apache.skywalking.apm.agent.core.plugin.bytebuddy.ArgumentTypeNameMatch.takesArgumentWithType;
+
+public class GatewayFilterV412Instrumentation extends AbstractGatewayV412EnhancePluginDefine {
+
+ private static final String INTERCEPT_CLASS_GATEWAY_FILTER = "org.springframework.cloud.gateway.filter.GatewayFilter";
+ private static final String GATEWAY_FILTER_INTERCEPTOR = "org.apache.skywalking.apm.plugin.spring.cloud.gateway.v412x.GatewayFilterV412Interceptor";
+
+ @Override
+ protected ClassMatch enhanceClass() {
+ return HierarchyMatch.byHierarchyMatch(INTERCEPT_CLASS_GATEWAY_FILTER);
+ }
+
+ @Override
+ public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
+ return new ConstructorInterceptPoint[0];
+ }
+
+ @Override
+ public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
+ return new InstanceMethodsInterceptPoint[] {
+ new InstanceMethodsInterceptPoint() {
+ @Override
+ public ElementMatcher getMethodsMatcher() {
+ return named("filter").and(
+ takesArgumentWithType(0, "org.springframework.web.server.ServerWebExchange"));
+ }
+
+ @Override
+ public String getMethodsInterceptor() {
+ return GATEWAY_FILTER_INTERCEPTOR;
+ }
+
+ @Override
+ public boolean isOverrideArgs() {
+ return false;
+ }
+ }
+ };
+ }
+}
diff --git a/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-4.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/cloud/gateway/v412x/define/HttpClientConnectV412Instrumentation.java b/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-4.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/cloud/gateway/v412x/define/HttpClientConnectV412Instrumentation.java
new file mode 100644
index 0000000000..3d1bb3462b
--- /dev/null
+++ b/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-4.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/cloud/gateway/v412x/define/HttpClientConnectV412Instrumentation.java
@@ -0,0 +1,87 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.skywalking.apm.plugin.spring.cloud.gateway.v412x.define;
+
+import net.bytebuddy.description.method.MethodDescription;
+import net.bytebuddy.matcher.ElementMatcher;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
+
+import static net.bytebuddy.matcher.ElementMatchers.named;
+import static net.bytebuddy.matcher.ElementMatchers.returns;
+import static net.bytebuddy.matcher.ElementMatchers.takesNoArguments;
+import static org.apache.skywalking.apm.agent.core.plugin.bytebuddy.ArgumentTypeNameMatch.takesArgumentWithType;
+import static org.apache.skywalking.apm.agent.core.plugin.match.NameMatch.byName;
+
+public class HttpClientConnectV412Instrumentation extends AbstractGatewayV412EnhancePluginDefine {
+
+ private static final String ENHANCE_CLASS = "reactor.netty.http.client.HttpClientConnect";
+ private static final String HTTP_CLIENT_CONNECT_DUPLICATE_INTERCEPTOR = "org.apache.skywalking.apm.plugin.spring.cloud.gateway.v412x.HttpClientConnectDuplicateV412Interceptor";
+ private static final String HTTP_CLIENT_CONNECT_REQUEST_INTERCEPTOR = "org.apache.skywalking.apm.plugin.spring.cloud.gateway.v412x.HttpClientConnectRequestV412Interceptor";
+
+ @Override
+ protected ClassMatch enhanceClass() {
+ return byName(ENHANCE_CLASS);
+ }
+
+ @Override
+ public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
+ return new ConstructorInterceptPoint[0];
+ }
+
+ @Override
+ public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
+ return new InstanceMethodsInterceptPoint[]{
+ new InstanceMethodsInterceptPoint() {
+ @Override
+ public ElementMatcher getMethodsMatcher() {
+ return named("duplicate").and(takesNoArguments())
+ .and(returns(named("reactor.netty.http.client.HttpClient")));
+ }
+
+ @Override
+ public String getMethodsInterceptor() {
+ return HTTP_CLIENT_CONNECT_DUPLICATE_INTERCEPTOR;
+ }
+
+ @Override
+ public boolean isOverrideArgs() {
+ return false;
+ }
+ },
+ new InstanceMethodsInterceptPoint() {
+ @Override
+ public ElementMatcher getMethodsMatcher() {
+ return named("request").and(takesArgumentWithType(0, "io.netty.handler.codec.http.HttpMethod"))
+ .and(returns(named("reactor.netty.http.client.HttpClient$RequestSender")));
+ }
+
+ @Override
+ public String getMethodsInterceptor() {
+ return HTTP_CLIENT_CONNECT_REQUEST_INTERCEPTOR;
+ }
+
+ @Override
+ public boolean isOverrideArgs() {
+ return false;
+ }
+ }
+ };
+ }
+}
diff --git a/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-4.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/cloud/gateway/v412x/define/HttpClientFinalizerV412Instrumentation.java b/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-4.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/cloud/gateway/v412x/define/HttpClientFinalizerV412Instrumentation.java
new file mode 100644
index 0000000000..7a5b9b888e
--- /dev/null
+++ b/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-4.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/cloud/gateway/v412x/define/HttpClientFinalizerV412Instrumentation.java
@@ -0,0 +1,114 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.skywalking.apm.plugin.spring.cloud.gateway.v412x.define;
+
+import net.bytebuddy.description.method.MethodDescription;
+import net.bytebuddy.matcher.ElementMatcher;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
+
+import static net.bytebuddy.matcher.ElementMatchers.named;
+import static org.apache.skywalking.apm.agent.core.plugin.bytebuddy.ArgumentTypeNameMatch.takesArgumentWithType;
+import static org.apache.skywalking.apm.agent.core.plugin.match.NameMatch.byName;
+
+public class HttpClientFinalizerV412Instrumentation extends AbstractGatewayV412EnhancePluginDefine {
+
+ private static final String INTERCEPT_CLASS_HTTP_CLIENT_FINALIZER = "reactor.netty.http.client.HttpClientFinalizer";
+ private static final String CLIENT_FINALIZER_CONSTRUCTOR_INTERCEPTOR = "org.apache.skywalking.apm.plugin.spring.cloud.gateway.v412x.HttpClientFinalizerConstructorV412Interceptor";
+ private static final String CLIENT_FINALIZER_CONSTRUCTOR_ARGUMENT_TYPE = "reactor.netty.http.client.HttpClientConfig";
+ private static final String HTTP_CLIENT_FINALIZER_URI_INTERCEPTOR = "org.apache.skywalking.apm.plugin.spring.cloud.gateway.v412x.HttpClientFinalizerUriV412Interceptor";
+ private static final String HTTP_CLIENT_FINALIZER_SEND_INTERCEPTOR = "org.apache.skywalking.apm.plugin.spring.cloud.gateway.v412x.HttpClientFinalizerSendV412Interceptor";
+ private static final String HTTP_CLIENT_FINALIZER_RESPONSE_CONNECTION_INTERCEPTOR = "org.apache.skywalking.apm.plugin.spring.cloud.gateway.v412x.HttpClientFinalizerResponseConnectionV412Interceptor";
+
+ @Override
+ protected ClassMatch enhanceClass() {
+ return byName(INTERCEPT_CLASS_HTTP_CLIENT_FINALIZER);
+ }
+
+ @Override
+ public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
+ return new ConstructorInterceptPoint[]{
+ new ConstructorInterceptPoint() {
+ @Override
+ public ElementMatcher getConstructorMatcher() {
+ return takesArgumentWithType(0, CLIENT_FINALIZER_CONSTRUCTOR_ARGUMENT_TYPE);
+ }
+
+ @Override
+ public String getConstructorInterceptor() {
+ return CLIENT_FINALIZER_CONSTRUCTOR_INTERCEPTOR;
+ }
+ }
+ };
+ }
+
+ @Override
+ public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
+ return new InstanceMethodsInterceptPoint[]{
+ new InstanceMethodsInterceptPoint() {
+ @Override
+ public ElementMatcher getMethodsMatcher() {
+ return named("uri");
+ }
+
+ @Override
+ public String getMethodsInterceptor() {
+ return HTTP_CLIENT_FINALIZER_URI_INTERCEPTOR;
+ }
+
+ @Override
+ public boolean isOverrideArgs() {
+ return false;
+ }
+ },
+ new InstanceMethodsInterceptPoint() {
+ @Override
+ public ElementMatcher getMethodsMatcher() {
+ return named("send").and(takesArgumentWithType(0, "java.util.function.BiFunction"));
+ }
+
+ @Override
+ public String getMethodsInterceptor() {
+ return HTTP_CLIENT_FINALIZER_SEND_INTERCEPTOR;
+ }
+
+ @Override
+ public boolean isOverrideArgs() {
+ return true;
+ }
+ },
+ new InstanceMethodsInterceptPoint() {
+ @Override
+ public ElementMatcher getMethodsMatcher() {
+ return named("responseConnection");
+ }
+
+ @Override
+ public String getMethodsInterceptor() {
+ return HTTP_CLIENT_FINALIZER_RESPONSE_CONNECTION_INTERCEPTOR;
+ }
+
+ @Override
+ public boolean isOverrideArgs() {
+ return true;
+ }
+ }
+ };
+ }
+}
diff --git a/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-4.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/cloud/gateway/v412x/define/NettyRoutingFilterV412Instrumentation.java b/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-4.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/cloud/gateway/v412x/define/NettyRoutingFilterV412Instrumentation.java
new file mode 100644
index 0000000000..ca06147ba3
--- /dev/null
+++ b/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-4.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/cloud/gateway/v412x/define/NettyRoutingFilterV412Instrumentation.java
@@ -0,0 +1,89 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.spring.cloud.gateway.v412x.define;
+
+import net.bytebuddy.description.method.MethodDescription;
+import net.bytebuddy.matcher.ElementMatcher;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
+
+import static net.bytebuddy.matcher.ElementMatchers.named;
+import static net.bytebuddy.matcher.ElementMatchers.returns;
+import static org.apache.skywalking.apm.agent.core.plugin.bytebuddy.ArgumentTypeNameMatch.takesArgumentWithType;
+import static org.apache.skywalking.apm.agent.core.plugin.match.NameMatch.byName;
+
+public class NettyRoutingFilterV412Instrumentation extends AbstractGatewayV412EnhancePluginDefine {
+
+ private static final String INTERCEPT_CLASS_NETTY_ROUTING_FILTER = "org.springframework.cloud.gateway.filter.NettyRoutingFilter";
+ private static final String NETTY_ROUTING_FILTER_INTERCEPTOR = "org.apache.skywalking.apm.plugin.spring.cloud.gateway.v412x.NettyRoutingFilterV412Interceptor";
+ private static final String NETTY_ROUTING_GET_HTTP_CLIENT_INTERCEPTOR = "org.apache.skywalking.apm.plugin.spring.cloud.gateway.v412x.NettyRoutingGetHttpClientV412Interceptor";
+
+ @Override
+ protected ClassMatch enhanceClass() {
+ return byName(INTERCEPT_CLASS_NETTY_ROUTING_FILTER);
+ }
+
+ @Override
+ public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
+ return new ConstructorInterceptPoint[0];
+ }
+
+ @Override
+ public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
+ return new InstanceMethodsInterceptPoint[]{
+ new InstanceMethodsInterceptPoint() {
+ @Override
+ public ElementMatcher getMethodsMatcher() {
+ return named("filter").and(
+ takesArgumentWithType(0, "org.springframework.web.server.ServerWebExchange"));
+ }
+
+ @Override
+ public String getMethodsInterceptor() {
+ return NETTY_ROUTING_FILTER_INTERCEPTOR;
+ }
+
+ @Override
+ public boolean isOverrideArgs() {
+ return true;
+ }
+ },
+ new InstanceMethodsInterceptPoint() {
+ @Override
+ public ElementMatcher getMethodsMatcher() {
+ return named("getHttpClient")
+ .and(takesArgumentWithType(0, "org.springframework.cloud.gateway.route.Route"))
+ .and(takesArgumentWithType(1, "org.springframework.web.server.ServerWebExchange"))
+ .and(returns(named("reactor.netty.http.client.HttpClient")));
+ }
+
+ @Override
+ public String getMethodsInterceptor() {
+ return NETTY_ROUTING_GET_HTTP_CLIENT_INTERCEPTOR;
+ }
+
+ @Override
+ public boolean isOverrideArgs() {
+ return false;
+ }
+ }
+ };
+ }
+}
diff --git a/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-4.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/cloud/gateway/v4x/GatewayFilterInterceptor.java b/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-4.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/cloud/gateway/v4x/GatewayFilterInterceptor.java
new file mode 100644
index 0000000000..233eb24ea7
--- /dev/null
+++ b/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-4.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/cloud/gateway/v4x/GatewayFilterInterceptor.java
@@ -0,0 +1,94 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.skywalking.apm.plugin.spring.cloud.gateway.v4x;
+
+import org.apache.skywalking.apm.agent.core.context.ContextManager;
+import org.apache.skywalking.apm.agent.core.context.ContextSnapshot;
+import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
+import org.springframework.web.server.ServerWebExchange;
+import org.springframework.web.server.ServerWebExchangeDecorator;
+import org.springframework.web.server.adapter.DefaultServerWebExchange;
+
+import java.lang.reflect.Method;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import static org.apache.skywalking.apm.network.trace.component.ComponentsDefine.SPRING_CLOUD_GATEWAY;
+
+public class GatewayFilterInterceptor implements InstanceMethodsAroundInterceptor {
+
+ private static final ThreadLocal STACK_DEEP = ThreadLocal.withInitial(() -> new AtomicInteger(0));
+
+ @Override
+ public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes,
+ MethodInterceptResult result) throws Throwable {
+ if (isEntry()) {
+ ServerWebExchange exchange = (ServerWebExchange) allArguments[0];
+
+ EnhancedInstance enhancedInstance = getInstance(exchange);
+
+ AbstractSpan span = ContextManager.createLocalSpan("SpringCloudGateway/GatewayFilter");
+ if (enhancedInstance != null && enhancedInstance.getSkyWalkingDynamicField() != null) {
+ ContextManager.continued((ContextSnapshot) enhancedInstance.getSkyWalkingDynamicField());
+ }
+ span.setComponent(SPRING_CLOUD_GATEWAY);
+ }
+ }
+
+ public static EnhancedInstance getInstance(Object o) {
+ EnhancedInstance instance = null;
+ if (o instanceof DefaultServerWebExchange) {
+ instance = (EnhancedInstance) o;
+ } else if (o instanceof ServerWebExchangeDecorator) {
+ ServerWebExchange delegate = ((ServerWebExchangeDecorator) o).getDelegate();
+ return getInstance(delegate);
+ }
+ return instance;
+ }
+
+ @Override
+ public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes,
+ Object ret) throws Throwable {
+ if (isExit()) {
+ if (ContextManager.isActive()) {
+ ContextManager.stopSpan();
+ }
+ }
+ return ret;
+ }
+
+ @Override
+ public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments,
+ Class>[] argumentsTypes, Throwable t) {
+ ContextManager.activeSpan().log(t);
+ }
+
+ private boolean isEntry() {
+ return STACK_DEEP.get().getAndIncrement() == 0;
+ }
+
+ private boolean isExit() {
+ boolean isExit = STACK_DEEP.get().decrementAndGet() == 0;
+ if (isExit) {
+ STACK_DEEP.remove();
+ }
+ return isExit;
+ }
+}
diff --git a/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-4.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/cloud/gateway/v4x/define/AbstractGatewayV4EnhancePluginDefine.java b/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-4.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/cloud/gateway/v4x/define/AbstractGatewayV4EnhancePluginDefine.java
index 803097ba62..f40d8832d4 100644
--- a/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-4.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/cloud/gateway/v4x/define/AbstractGatewayV4EnhancePluginDefine.java
+++ b/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-4.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/cloud/gateway/v4x/define/AbstractGatewayV4EnhancePluginDefine.java
@@ -17,8 +17,15 @@
package org.apache.skywalking.apm.plugin.spring.cloud.gateway.v4x.define;
+import org.apache.skywalking.apm.agent.core.plugin.WitnessMethod;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine;
+import java.util.Collections;
+import java.util.List;
+
+import static net.bytebuddy.matcher.ElementMatchers.named;
+import static net.bytebuddy.matcher.ElementMatchers.returns;
+
/**
* This abstract class defines the witnessClasses() method,
* and other plugin define classes need to inherit from this class
@@ -32,4 +39,12 @@ public abstract class AbstractGatewayV4EnhancePluginDefine extends ClassInstance
protected String[] witnessClasses() {
return new String[]{"org.springframework.cloud.gateway.filter.factory.cache.LocalResponseCacheProperties"};
}
+
+ @Override
+ protected List witnessMethods() {
+ return Collections.singletonList(
+ new WitnessMethod("org.springframework.cloud.gateway.config.LocalResponseCacheAutoConfiguration",
+ named("responseCacheSizeWeigher").
+ and(returns(named("org.springframework.cloud.gateway.filter.factory.cache.ResponseCacheSizeWeigher")))));
+ }
}
diff --git a/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-4.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/cloud/gateway/v4x/define/EnhanceObjectCache.java b/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-4.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/cloud/gateway/v4x/define/EnhanceObjectCache.java
index 419d5118a2..335d5ab6cd 100644
--- a/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-4.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/cloud/gateway/v4x/define/EnhanceObjectCache.java
+++ b/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-4.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/cloud/gateway/v4x/define/EnhanceObjectCache.java
@@ -17,6 +17,7 @@
package org.apache.skywalking.apm.plugin.spring.cloud.gateway.v4x.define;
+import org.apache.skywalking.apm.agent.core.context.ContextSnapshot;
import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan;
/**
@@ -27,6 +28,7 @@ public class EnhanceObjectCache {
private String url;
private AbstractSpan span;
private AbstractSpan span1;
+ private ContextSnapshot contextSnapshot;
public String getUrl() {
return url;
@@ -51,4 +53,13 @@ public AbstractSpan getSpan1() {
public void setSpan1(final AbstractSpan span) {
span1 = span;
}
+
+ public ContextSnapshot getContextSnapshot() {
+ return contextSnapshot;
+ }
+
+ public void setContextSnapshot(final ContextSnapshot contextSnapshot) {
+ this.contextSnapshot = contextSnapshot;
+ }
+
}
diff --git a/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-4.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/cloud/gateway/v4x/define/GatewayFilterInstrumentation.java b/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-4.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/cloud/gateway/v4x/define/GatewayFilterInstrumentation.java
new file mode 100644
index 0000000000..e6bbde9c8a
--- /dev/null
+++ b/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-4.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/cloud/gateway/v4x/define/GatewayFilterInstrumentation.java
@@ -0,0 +1,67 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.skywalking.apm.plugin.spring.cloud.gateway.v4x.define;
+
+import net.bytebuddy.description.method.MethodDescription;
+import net.bytebuddy.matcher.ElementMatcher;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
+import org.apache.skywalking.apm.agent.core.plugin.match.HierarchyMatch;
+
+import static net.bytebuddy.matcher.ElementMatchers.named;
+import static org.apache.skywalking.apm.agent.core.plugin.bytebuddy.ArgumentTypeNameMatch.takesArgumentWithType;
+
+public class GatewayFilterInstrumentation extends AbstractGatewayV4EnhancePluginDefine {
+
+ private static final String INTERCEPT_CLASS_GATEWAY_FILTER = "org.springframework.cloud.gateway.filter.GatewayFilter";
+ private static final String GATEWAY_FILTER_INTERCEPTOR = "org.apache.skywalking.apm.plugin.spring.cloud.gateway.v4x.GatewayFilterInterceptor";
+
+ @Override
+ protected ClassMatch enhanceClass() {
+ return HierarchyMatch.byHierarchyMatch(INTERCEPT_CLASS_GATEWAY_FILTER);
+ }
+
+ @Override
+ public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
+ return new ConstructorInterceptPoint[0];
+ }
+
+ @Override
+ public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
+ return new InstanceMethodsInterceptPoint[] {
+ new InstanceMethodsInterceptPoint() {
+ @Override
+ public ElementMatcher getMethodsMatcher() {
+ return named("filter").and(
+ takesArgumentWithType(0, "org.springframework.web.server.ServerWebExchange"));
+ }
+
+ @Override
+ public String getMethodsInterceptor() {
+ return GATEWAY_FILTER_INTERCEPTOR;
+ }
+
+ @Override
+ public boolean isOverrideArgs() {
+ return false;
+ }
+ }
+ };
+ }
+}
diff --git a/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-4.x-plugin/src/main/resources/skywalking-plugin.def b/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-4.x-plugin/src/main/resources/skywalking-plugin.def
index 5cbcbfcdd8..bbb2bb4cf9 100644
--- a/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-4.x-plugin/src/main/resources/skywalking-plugin.def
+++ b/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-4.x-plugin/src/main/resources/skywalking-plugin.def
@@ -18,3 +18,8 @@ spring-cloud-gateway-4.x=org.apache.skywalking.apm.plugin.spring.cloud.gateway.v
spring-cloud-gateway-4.x=org.apache.skywalking.apm.plugin.spring.cloud.gateway.v4x.define.NettyRoutingFilterInstrumentation
spring-cloud-gateway-4.x=org.apache.skywalking.apm.plugin.spring.cloud.gateway.v4x.define.ServerWebExchangeInstrumentation
spring-cloud-gateway-4.x=org.apache.skywalking.apm.plugin.spring.cloud.gateway.v4x.define.DispatcherHandlerInstrumentation
+spring-cloud-gateway-4.x=org.apache.skywalking.apm.plugin.spring.cloud.gateway.v4x.define.GatewayFilterInstrumentation
+spring-cloud-gateway-4.x=org.apache.skywalking.apm.plugin.spring.cloud.gateway.v412x.define.HttpClientFinalizerV412Instrumentation
+spring-cloud-gateway-4.x=org.apache.skywalking.apm.plugin.spring.cloud.gateway.v412x.define.NettyRoutingFilterV412Instrumentation
+spring-cloud-gateway-4.x=org.apache.skywalking.apm.plugin.spring.cloud.gateway.v412x.define.GatewayFilterV412Instrumentation
+spring-cloud-gateway-4.x=org.apache.skywalking.apm.plugin.spring.cloud.gateway.v412x.define.HttpClientConnectV412Instrumentation
diff --git a/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-4.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/spring/cloud/gateway/v412x/GatewayFilterV412InterceptorTest.java b/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-4.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/spring/cloud/gateway/v412x/GatewayFilterV412InterceptorTest.java
new file mode 100644
index 0000000000..d8265ee075
--- /dev/null
+++ b/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-4.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/spring/cloud/gateway/v412x/GatewayFilterV412InterceptorTest.java
@@ -0,0 +1,332 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.spring.cloud.gateway.v412x;
+
+import org.apache.skywalking.apm.agent.core.context.ContextManager;
+import org.apache.skywalking.apm.agent.core.context.ContextSnapshot;
+import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan;
+import org.apache.skywalking.apm.agent.core.context.trace.AbstractTracingSpan;
+import org.apache.skywalking.apm.agent.core.context.trace.SpanLayer;
+import org.apache.skywalking.apm.agent.core.context.trace.TraceSegment;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
+import org.apache.skywalking.apm.agent.test.helper.SegmentHelper;
+import org.apache.skywalking.apm.agent.test.tools.AgentServiceRule;
+import org.apache.skywalking.apm.agent.test.tools.SegmentStorage;
+import org.apache.skywalking.apm.agent.test.tools.SegmentStoragePoint;
+import org.apache.skywalking.apm.agent.test.tools.SpanAssert;
+import org.apache.skywalking.apm.agent.test.tools.TracingSegmentRunner;
+import org.apache.skywalking.apm.network.trace.component.ComponentsDefine;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.i18n.LocaleContext;
+import org.springframework.http.codec.multipart.Part;
+import org.springframework.http.server.reactive.ServerHttpRequest;
+import org.springframework.http.server.reactive.ServerHttpResponse;
+import org.springframework.util.MultiValueMap;
+import org.springframework.web.server.ServerWebExchange;
+import org.springframework.web.server.WebSession;
+import reactor.core.publisher.Mono;
+
+import java.security.Principal;
+import java.time.Instant;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.function.Function;
+
+@RunWith(TracingSegmentRunner.class)
+public class GatewayFilterV412InterceptorTest {
+
+ private static final String GATEWAY_FILTER_INTERCEPTOR_LOCAL_SPAN_OPERATION_NAME = "SpringCloudGateway/GatewayFilter";
+
+ private static class ServerWebExchangeEnhancedInstance implements ServerWebExchange, EnhancedInstance {
+ private ContextSnapshot snapshot;
+ Map attributes = new HashMap<>();
+
+ @Override
+ public Object getSkyWalkingDynamicField() {
+ return snapshot;
+ }
+
+ @Override
+ public void setSkyWalkingDynamicField(Object value) {
+ this.snapshot = (ContextSnapshot) value;
+ }
+
+ @Override
+ public ServerHttpRequest getRequest() {
+ return null;
+ }
+
+ @Override
+ public ServerHttpResponse getResponse() {
+ return null;
+ }
+
+ @Override
+ public Map getAttributes() {
+ return attributes;
+ }
+
+ @Override
+ public Mono getSession() {
+ return null;
+ }
+
+ @Override
+ public Mono getPrincipal() {
+ return null;
+ }
+
+ @Override
+ public Mono> getFormData() {
+ return null;
+ }
+
+ @Override
+ public Mono> getMultipartData() {
+ return null;
+ }
+
+ @Override
+ public LocaleContext getLocaleContext() {
+ return null;
+ }
+
+ @Override
+ public ApplicationContext getApplicationContext() {
+ return null;
+ }
+
+ @Override
+ public boolean isNotModified() {
+ return false;
+ }
+
+ @Override
+ public boolean checkNotModified(Instant instant) {
+ return false;
+ }
+
+ @Override
+ public boolean checkNotModified(String s) {
+ return false;
+ }
+
+ @Override
+ public boolean checkNotModified(String s, Instant instant) {
+ return false;
+ }
+
+ @Override
+ public String transformUrl(String s) {
+ return null;
+ }
+
+ @Override
+ public void addUrlTransformer(Function function) {
+
+ }
+
+ @Override
+ public String getLogPrefix() {
+ return null;
+ }
+ }
+
+ private final ServerWebExchangeEnhancedInstance enhancedInstance = new ServerWebExchangeEnhancedInstance();
+ private final GatewayFilterV412Interceptor interceptor = new GatewayFilterV412Interceptor();
+ @Rule
+ public AgentServiceRule serviceRule = new AgentServiceRule();
+ @Rule
+ public MockitoRule rule = MockitoJUnit.rule();
+
+ @SegmentStoragePoint
+ private SegmentStorage segmentStorage;
+
+ @Before
+ public void setUp() throws Exception {
+ }
+
+ private final ServerWebExchange exchange = new ServerWebExchange() {
+ Map attributes = new HashMap<>();
+ @Override
+ public ServerHttpRequest getRequest() {
+ return null;
+ }
+
+ @Override
+ public ServerHttpResponse getResponse() {
+ return null;
+ }
+
+ @Override
+ public Map getAttributes() {
+ return attributes;
+ }
+
+ @Override
+ public Mono getSession() {
+ return null;
+ }
+
+ @Override
+ public Mono getPrincipal() {
+ return null;
+ }
+
+ @Override
+ public Mono> getFormData() {
+ return null;
+ }
+
+ @Override
+ public Mono> getMultipartData() {
+ return null;
+ }
+
+ @Override
+ public LocaleContext getLocaleContext() {
+ return null;
+ }
+
+ @Override
+ public ApplicationContext getApplicationContext() {
+ return null;
+ }
+
+ @Override
+ public boolean isNotModified() {
+ return false;
+ }
+
+ @Override
+ public boolean checkNotModified(Instant instant) {
+ return false;
+ }
+
+ @Override
+ public boolean checkNotModified(String s) {
+ return false;
+ }
+
+ @Override
+ public boolean checkNotModified(String s, Instant instant) {
+ return false;
+ }
+
+ @Override
+ public String transformUrl(String s) {
+ return null;
+ }
+
+ @Override
+ public void addUrlTransformer(Function function) {
+
+ }
+
+ @Override
+ public String getLogPrefix() {
+ return null;
+ }
+ };
+
+ @Test
+ public void testInterceptOnlyOnce() throws Throwable {
+ interceptor.beforeMethod(null, null, new Object[]{exchange}, null, null);
+ Assert.assertTrue(ContextManager.isActive());
+ AbstractSpan activeSpan = ContextManager.activeSpan();
+ Assert.assertTrue(activeSpan instanceof AbstractTracingSpan);
+ Assert.assertEquals(activeSpan.getOperationName(), GATEWAY_FILTER_INTERCEPTOR_LOCAL_SPAN_OPERATION_NAME);
+
+ interceptor.afterMethod(null, null, null, null, null);
+ Assert.assertFalse(ContextManager.isActive());
+ final List traceSegments = segmentStorage.getTraceSegments();
+ Assert.assertEquals(traceSegments.size(), 1);
+ final List spans = SegmentHelper.getSpans(traceSegments.get(0));
+ Assert.assertNotNull(spans);
+ Assert.assertEquals(spans.size(), 1);
+ SpanAssert.assertComponent(spans.get(0), ComponentsDefine.SPRING_CLOUD_GATEWAY);
+
+ }
+
+ @Test
+ public void testNestedInterception() throws Throwable {
+ interceptor.beforeMethod(null, null, new Object[]{enhancedInstance}, null, null);
+ Assert.assertTrue(ContextManager.isActive());
+
+ interceptor.beforeMethod(null, null, new Object[]{enhancedInstance}, null, null);
+ Assert.assertTrue(ContextManager.isActive());
+
+ interceptor.afterMethod(null, null, null, null, null);
+ Assert.assertTrue(ContextManager.isActive());
+
+ interceptor.afterMethod(null, null, null, null, null);
+ Assert.assertFalse(ContextManager.isActive());
+
+ final List traceSegments = segmentStorage.getTraceSegments();
+ Assert.assertEquals(traceSegments.size(), 1);
+ final List spans = SegmentHelper.getSpans(traceSegments.get(0));
+ Assert.assertNotNull(spans);
+ Assert.assertEquals(spans.size(), 1);
+ SpanAssert.assertComponent(spans.get(0), ComponentsDefine.SPRING_CLOUD_GATEWAY);
+ }
+
+ @Test
+ public void testWithNullDynamicField() throws Throwable {
+ interceptor.beforeMethod(null, null, new Object[]{enhancedInstance}, null, null);
+ interceptor.afterMethod(null, null, null, null, null);
+ // no more need this, span was stopped at interceptor#afterMethod
+ // ContextManager.stopSpan();
+ final List traceSegments = segmentStorage.getTraceSegments();
+ Assert.assertEquals(traceSegments.size(), 1);
+ final List spans = SegmentHelper.getSpans(traceSegments.get(0));
+ Assert.assertNotNull(spans);
+ Assert.assertEquals(spans.size(), 1);
+ SpanAssert.assertComponent(spans.get(0), ComponentsDefine.SPRING_CLOUD_GATEWAY);
+ }
+
+ @Test
+ public void testWithContextSnapshot() throws Throwable {
+ final AbstractSpan entrySpan = ContextManager.createEntrySpan("/get", null);
+ SpanLayer.asHttp(entrySpan);
+ entrySpan.setComponent(ComponentsDefine.SPRING_WEBFLUX);
+ enhancedInstance.setSkyWalkingDynamicField(ContextManager.capture());
+ interceptor.beforeMethod(null, null, new Object[]{enhancedInstance}, null, null);
+ interceptor.afterMethod(null, null, null, null, null);
+ // no more need this, span was stopped at interceptor#afterMethod
+ // ContextManager.stopSpan();
+ ContextManager.stopSpan(entrySpan);
+ final List traceSegments = segmentStorage.getTraceSegments();
+ Assert.assertEquals(traceSegments.size(), 1);
+ final List spans = SegmentHelper.getSpans(traceSegments.get(0));
+ Assert.assertNotNull(spans);
+ Assert.assertEquals(spans.size(), 2);
+ SpanAssert.assertComponent(spans.get(0), ComponentsDefine.SPRING_CLOUD_GATEWAY);
+ SpanAssert.assertComponent(spans.get(1), ComponentsDefine.SPRING_WEBFLUX);
+ SpanAssert.assertLayer(spans.get(1), SpanLayer.HTTP);
+ }
+
+}
diff --git a/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-4.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/spring/cloud/gateway/v412x/HttpClientConnectDuplicateV412InterceptorTest.java b/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-4.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/spring/cloud/gateway/v412x/HttpClientConnectDuplicateV412InterceptorTest.java
new file mode 100644
index 0000000000..8cf3e9d830
--- /dev/null
+++ b/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-4.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/spring/cloud/gateway/v412x/HttpClientConnectDuplicateV412InterceptorTest.java
@@ -0,0 +1,125 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.spring.cloud.gateway.v412x;
+
+import org.apache.skywalking.apm.agent.core.context.ContextManager;
+import org.apache.skywalking.apm.agent.core.context.ContextSnapshot;
+import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan;
+import org.apache.skywalking.apm.agent.core.context.trace.SpanLayer;
+import org.apache.skywalking.apm.agent.core.context.trace.TraceSegment;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
+import org.apache.skywalking.apm.agent.test.tools.AgentServiceRule;
+import org.apache.skywalking.apm.agent.test.tools.SegmentStorage;
+import org.apache.skywalking.apm.agent.test.tools.SegmentStoragePoint;
+import org.apache.skywalking.apm.agent.test.tools.TracingSegmentRunner;
+import org.apache.skywalking.apm.network.trace.component.ComponentsDefine;
+import org.apache.skywalking.apm.plugin.spring.cloud.gateway.v4x.define.EnhanceObjectCache;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+
+import java.util.List;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+@RunWith(TracingSegmentRunner.class)
+public class HttpClientConnectDuplicateV412InterceptorTest {
+
+ private final static String ENTRY_OPERATION_NAME = "/get";
+ private final HttpClientConnectDuplicateV412Interceptor duplicateInterceptor = new HttpClientConnectDuplicateV412Interceptor();
+ private final EnhancedInstance enhancedInstance = new EnhancedInstance() {
+ private EnhanceObjectCache enhanceObjectCache;
+
+ @Override
+ public Object getSkyWalkingDynamicField() {
+ return enhanceObjectCache;
+ }
+
+ @Override
+ public void setSkyWalkingDynamicField(Object value) {
+ this.enhanceObjectCache = (EnhanceObjectCache) value;
+ }
+ };
+ private final EnhancedInstance retEnhancedInstance = new EnhancedInstance() {
+ private EnhanceObjectCache enhanceObjectCache;
+ @Override
+ public Object getSkyWalkingDynamicField() {
+ return enhanceObjectCache;
+ }
+
+ @Override
+ public void setSkyWalkingDynamicField(Object value) {
+ this.enhanceObjectCache = (EnhanceObjectCache) value;
+ }
+ };
+
+ @Rule
+ public AgentServiceRule serviceRule = new AgentServiceRule();
+ @Rule
+ public MockitoRule rule = MockitoJUnit.rule();
+
+ @SegmentStoragePoint
+ private SegmentStorage segmentStorage;
+ private AbstractSpan entrySpan;
+
+ @Before
+ public void setUp() throws Exception {
+ entrySpan = ContextManager.createEntrySpan(ENTRY_OPERATION_NAME, null);
+ entrySpan.setLayer(SpanLayer.HTTP);
+ entrySpan.setComponent(ComponentsDefine.SPRING_WEBFLUX);
+ }
+
+ @Test
+ public void testWithDynamicFieldNull() throws Throwable {
+ enhancedInstance.setSkyWalkingDynamicField(null);
+ duplicateInterceptor.afterMethod(enhancedInstance, null, null, null, retEnhancedInstance);
+ assertNull(retEnhancedInstance.getSkyWalkingDynamicField());
+ final List traceSegments = segmentStorage.getTraceSegments();
+ assertEquals(traceSegments.size(), 0);
+ if (ContextManager.isActive()) {
+ ContextManager.stopSpan();
+ }
+ }
+
+ @Test
+ public void testWithDynamicFieldNotNull() throws Throwable {
+ ContextSnapshot contextSnapshot = ContextManager.capture();
+ EnhanceObjectCache enhanceObjectCache = new EnhanceObjectCache();
+ enhanceObjectCache.setContextSnapshot(contextSnapshot);
+ enhancedInstance.setSkyWalkingDynamicField(enhanceObjectCache);
+ duplicateInterceptor.afterMethod(enhancedInstance, null, null, null, retEnhancedInstance);
+ Object retEnhancedInstanceSkyWalkingDynamicField = retEnhancedInstance.getSkyWalkingDynamicField();
+ assertNotNull(retEnhancedInstanceSkyWalkingDynamicField);
+ assertTrue(retEnhancedInstanceSkyWalkingDynamicField instanceof EnhanceObjectCache);
+ EnhanceObjectCache retEnhanceObjectCache = (EnhanceObjectCache) retEnhancedInstanceSkyWalkingDynamicField;
+ assertNotNull(retEnhanceObjectCache.getContextSnapshot());
+ final List traceSegments = segmentStorage.getTraceSegments();
+ assertEquals(traceSegments.size(), 0);
+ if (ContextManager.isActive()) {
+ ContextManager.stopSpan();
+ }
+ }
+
+}
diff --git a/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-4.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/spring/cloud/gateway/v412x/HttpClientConnectRequestV412InterceptorTest.java b/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-4.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/spring/cloud/gateway/v412x/HttpClientConnectRequestV412InterceptorTest.java
new file mode 100644
index 0000000000..06668c1eb2
--- /dev/null
+++ b/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-4.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/spring/cloud/gateway/v412x/HttpClientConnectRequestV412InterceptorTest.java
@@ -0,0 +1,165 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.spring.cloud.gateway.v412x;
+
+import org.apache.skywalking.apm.agent.core.context.ContextManager;
+import org.apache.skywalking.apm.agent.core.context.ContextSnapshot;
+import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan;
+import org.apache.skywalking.apm.agent.core.context.trace.SpanLayer;
+import org.apache.skywalking.apm.agent.core.context.trace.TraceSegment;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
+import org.apache.skywalking.apm.agent.test.tools.AgentServiceRule;
+import org.apache.skywalking.apm.agent.test.tools.SegmentStorage;
+import org.apache.skywalking.apm.agent.test.tools.SegmentStoragePoint;
+import org.apache.skywalking.apm.agent.test.tools.TracingSegmentRunner;
+import org.apache.skywalking.apm.network.trace.component.ComponentsDefine;
+import org.apache.skywalking.apm.plugin.spring.cloud.gateway.v4x.define.EnhanceObjectCache;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+
+import java.util.List;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+@RunWith(TracingSegmentRunner.class)
+public class HttpClientConnectRequestV412InterceptorTest {
+ private final static String URI = "http://localhost:8080/get";
+ private final static String ENTRY_OPERATION_NAME = "/get";
+ private final HttpClientConnectRequestV412Interceptor requestInterceptor = new HttpClientConnectRequestV412Interceptor();
+ private final EnhancedInstance enhancedInstance = new EnhancedInstance() {
+ private EnhanceObjectCache enhanceObjectCache;
+
+ @Override
+ public Object getSkyWalkingDynamicField() {
+ return enhanceObjectCache;
+ }
+
+ @Override
+ public void setSkyWalkingDynamicField(Object value) {
+ this.enhanceObjectCache = (EnhanceObjectCache) value;
+ }
+ };
+ private final EnhancedInstance retEnhancedInstance = new EnhancedInstance() {
+ private EnhanceObjectCache enhanceObjectCache;
+ @Override
+ public Object getSkyWalkingDynamicField() {
+ return enhanceObjectCache;
+ }
+
+ @Override
+ public void setSkyWalkingDynamicField(Object value) {
+ this.enhanceObjectCache = (EnhanceObjectCache) value;
+ }
+ };
+
+ @Rule
+ public AgentServiceRule serviceRule = new AgentServiceRule();
+ @Rule
+ public MockitoRule rule = MockitoJUnit.rule();
+
+ @SegmentStoragePoint
+ private SegmentStorage segmentStorage;
+ private AbstractSpan entrySpan;
+
+ @Before
+ public void setUp() throws Exception {
+ entrySpan = ContextManager.createEntrySpan(ENTRY_OPERATION_NAME, null);
+ entrySpan.setLayer(SpanLayer.HTTP);
+ entrySpan.setComponent(ComponentsDefine.SPRING_WEBFLUX);
+ }
+
+ @Test
+ public void testWithDynamicFieldNull() throws Throwable {
+ enhancedInstance.setSkyWalkingDynamicField(null);
+ retEnhancedInstance.setSkyWalkingDynamicField(null);
+ requestInterceptor.afterMethod(enhancedInstance, null, null, null, retEnhancedInstance);
+ assertNull(retEnhancedInstance.getSkyWalkingDynamicField());
+ final List traceSegments = segmentStorage.getTraceSegments();
+ assertEquals(traceSegments.size(), 0);
+ if (ContextManager.isActive()) {
+ ContextManager.stopSpan();
+ }
+ }
+
+ @Test
+ public void testWithRetDynamicFieldNotNull() throws Throwable {
+ enhancedInstance.setSkyWalkingDynamicField(null);
+ EnhanceObjectCache retEnhanceObjectCache = new EnhanceObjectCache();
+ retEnhancedInstance.setSkyWalkingDynamicField(retEnhanceObjectCache);
+
+ requestInterceptor.afterMethod(enhancedInstance, null, null, null, retEnhancedInstance);
+ assertNotNull(retEnhancedInstance.getSkyWalkingDynamicField());
+ assertTrue(retEnhancedInstance.getSkyWalkingDynamicField() instanceof EnhanceObjectCache);
+ assertNull(((EnhanceObjectCache) retEnhancedInstance.getSkyWalkingDynamicField()).getContextSnapshot());
+ final List traceSegments = segmentStorage.getTraceSegments();
+ assertEquals(traceSegments.size(), 0);
+ if (ContextManager.isActive()) {
+ ContextManager.stopSpan();
+ }
+ }
+
+ @Test
+ public void testWithDynamicFieldNotNull() throws Throwable {
+ ContextSnapshot contextSnapshot = ContextManager.capture();
+ EnhanceObjectCache enhanceObjectCache = new EnhanceObjectCache();
+ enhanceObjectCache.setContextSnapshot(contextSnapshot);
+ enhancedInstance.setSkyWalkingDynamicField(enhanceObjectCache);
+
+ EnhanceObjectCache enhanceObjectCache2 = new EnhanceObjectCache();
+ enhanceObjectCache2.setUrl(URI);
+ retEnhancedInstance.setSkyWalkingDynamicField(enhanceObjectCache2);
+ requestInterceptor.afterMethod(enhancedInstance, null, null, null, retEnhancedInstance);
+ Object retEnhancedInstanceSkyWalkingDynamicField = retEnhancedInstance.getSkyWalkingDynamicField();
+ assertNotNull(retEnhancedInstanceSkyWalkingDynamicField);
+ assertTrue(retEnhancedInstanceSkyWalkingDynamicField instanceof EnhanceObjectCache);
+ EnhanceObjectCache retEnhanceObjectCache = (EnhanceObjectCache) retEnhancedInstanceSkyWalkingDynamicField;
+ assertNotNull(retEnhanceObjectCache.getContextSnapshot());
+ final List traceSegments = segmentStorage.getTraceSegments();
+ assertEquals(traceSegments.size(), 0);
+ if (ContextManager.isActive()) {
+ ContextManager.stopSpan();
+ }
+ }
+
+ @Test
+ public void testWithRetDynamicFieldNull() throws Throwable {
+ ContextSnapshot contextSnapshot = ContextManager.capture();
+ EnhanceObjectCache enhanceObjectCache = new EnhanceObjectCache();
+ enhanceObjectCache.setContextSnapshot(contextSnapshot);
+ enhancedInstance.setSkyWalkingDynamicField(enhanceObjectCache);
+ retEnhancedInstance.setSkyWalkingDynamicField(null);
+
+ requestInterceptor.afterMethod(enhancedInstance, null, null, null, retEnhancedInstance);
+ Object retEnhancedInstanceSkyWalkingDynamicField = retEnhancedInstance.getSkyWalkingDynamicField();
+ assertNull(retEnhancedInstanceSkyWalkingDynamicField);
+ final List traceSegments = segmentStorage.getTraceSegments();
+ assertEquals(traceSegments.size(), 0);
+ if (ContextManager.isActive()) {
+ ContextManager.stopSpan();
+ }
+ }
+
+}
diff --git a/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-4.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/spring/cloud/gateway/v412x/HttpClientFinalizerConstructorV412InterceptorTest.java b/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-4.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/spring/cloud/gateway/v412x/HttpClientFinalizerConstructorV412InterceptorTest.java
new file mode 100644
index 0000000000..a87a4e4979
--- /dev/null
+++ b/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-4.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/spring/cloud/gateway/v412x/HttpClientFinalizerConstructorV412InterceptorTest.java
@@ -0,0 +1,68 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.spring.cloud.gateway.v412x;
+
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
+import org.apache.skywalking.apm.plugin.spring.cloud.gateway.v4x.define.EnhanceObjectCache;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.junit.MockitoJUnitRunner;
+import reactor.netty.http.client.HttpClientConfig;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+@RunWith(MockitoJUnitRunner.class)
+public class HttpClientFinalizerConstructorV412InterceptorTest {
+
+ private static final String URI = "http://localhost:8080/get";
+ private final EnhancedInstance enhancedInstance = new EnhancedInstance() {
+ private EnhanceObjectCache enhanceObjectCache;
+
+ @Override
+ public Object getSkyWalkingDynamicField() {
+ return enhanceObjectCache;
+ }
+
+ @Override
+ public void setSkyWalkingDynamicField(Object value) {
+ this.enhanceObjectCache = (EnhanceObjectCache) value;
+ }
+ };
+ private HttpClientConfig httpClientConfig;
+ private HttpClientFinalizerConstructorV412Interceptor httpClientFinalizerConstructorInterceptor;
+
+ @Before
+ public void setUp() {
+ httpClientConfig = mock(HttpClientConfig.class);
+ when(httpClientConfig.uri()).thenReturn(URI);
+ httpClientFinalizerConstructorInterceptor = new HttpClientFinalizerConstructorV412Interceptor();
+ }
+
+ @Test
+ public void onConstruct() {
+ httpClientFinalizerConstructorInterceptor.onConstruct(enhancedInstance, new Object[]{httpClientConfig});
+ final EnhanceObjectCache enhanceCache = (EnhanceObjectCache) enhancedInstance.getSkyWalkingDynamicField();
+ assertNotNull(enhanceCache);
+ assertEquals(enhanceCache.getUrl(), URI);
+ }
+}
diff --git a/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-4.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/spring/cloud/gateway/v412x/HttpClientFinalizerUriV412InterceptorTest.java b/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-4.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/spring/cloud/gateway/v412x/HttpClientFinalizerUriV412InterceptorTest.java
new file mode 100644
index 0000000000..0cb079b299
--- /dev/null
+++ b/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-4.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/spring/cloud/gateway/v412x/HttpClientFinalizerUriV412InterceptorTest.java
@@ -0,0 +1,176 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.spring.cloud.gateway.v412x;
+
+import org.apache.skywalking.apm.agent.core.context.ContextManager;
+import org.apache.skywalking.apm.agent.core.context.ContextSnapshot;
+import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan;
+import org.apache.skywalking.apm.agent.core.context.trace.SpanLayer;
+import org.apache.skywalking.apm.agent.core.context.trace.TraceSegment;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
+import org.apache.skywalking.apm.agent.test.tools.AgentServiceRule;
+import org.apache.skywalking.apm.agent.test.tools.SegmentStorage;
+import org.apache.skywalking.apm.agent.test.tools.SegmentStoragePoint;
+import org.apache.skywalking.apm.agent.test.tools.TracingSegmentRunner;
+import org.apache.skywalking.apm.network.trace.component.ComponentsDefine;
+import org.apache.skywalking.apm.plugin.spring.cloud.gateway.v4x.define.EnhanceObjectCache;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+
+import java.util.List;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+@RunWith(TracingSegmentRunner.class)
+public class HttpClientFinalizerUriV412InterceptorTest {
+
+ private final static String URI = "http://localhost:8080/get";
+ private final static String ENTRY_OPERATION_NAME = "/get";
+ private final HttpClientFinalizerUriV412Interceptor uriInterceptor = new HttpClientFinalizerUriV412Interceptor();
+ private final EnhancedInstance enhancedInstance = new EnhancedInstance() {
+ private EnhanceObjectCache enhanceObjectCache;
+
+ @Override
+ public Object getSkyWalkingDynamicField() {
+ return enhanceObjectCache;
+ }
+
+ @Override
+ public void setSkyWalkingDynamicField(Object value) {
+ this.enhanceObjectCache = (EnhanceObjectCache) value;
+ }
+ };
+ private final EnhancedInstance retEnhancedInstance = new EnhancedInstance() {
+ private EnhanceObjectCache enhanceObjectCache;
+ @Override
+ public Object getSkyWalkingDynamicField() {
+ return enhanceObjectCache;
+ }
+
+ @Override
+ public void setSkyWalkingDynamicField(Object value) {
+ this.enhanceObjectCache = (EnhanceObjectCache) value;
+ }
+ };
+
+ @Rule
+ public AgentServiceRule serviceRule = new AgentServiceRule();
+ @Rule
+ public MockitoRule rule = MockitoJUnit.rule();
+
+ @SegmentStoragePoint
+ private SegmentStorage segmentStorage;
+ private AbstractSpan entrySpan;
+
+ @Before
+ public void setUp() throws Exception {
+ entrySpan = ContextManager.createEntrySpan(ENTRY_OPERATION_NAME, null);
+ entrySpan.setLayer(SpanLayer.HTTP);
+ entrySpan.setComponent(ComponentsDefine.SPRING_WEBFLUX);
+ }
+
+ @Test
+ public void testWithDynamicFieldNull() throws Throwable {
+ enhancedInstance.setSkyWalkingDynamicField(null);
+ retEnhancedInstance.setSkyWalkingDynamicField(null);
+ uriInterceptor.afterMethod(enhancedInstance, null, null, null, retEnhancedInstance);
+ assertNull(retEnhancedInstance.getSkyWalkingDynamicField());
+ final List traceSegments = segmentStorage.getTraceSegments();
+ assertEquals(traceSegments.size(), 0);
+ if (ContextManager.isActive()) {
+ ContextManager.stopSpan();
+ }
+ }
+
+ @Test
+ public void testWithRetDynamicFieldNotNull() throws Throwable {
+ enhancedInstance.setSkyWalkingDynamicField(null);
+ EnhanceObjectCache enhanceObjectCache2 = new EnhanceObjectCache();
+ retEnhancedInstance.setSkyWalkingDynamicField(enhanceObjectCache2);
+
+ uriInterceptor.afterMethod(enhancedInstance, null, new Object[]{URI}, null, retEnhancedInstance);
+ Object retEnhancedInstanceSkyWalkingDynamicField = retEnhancedInstance.getSkyWalkingDynamicField();
+ assertNotNull(retEnhancedInstanceSkyWalkingDynamicField);
+ assertTrue(retEnhancedInstanceSkyWalkingDynamicField instanceof EnhanceObjectCache);
+ EnhanceObjectCache retEnhanceObjectCache = (EnhanceObjectCache) retEnhancedInstanceSkyWalkingDynamicField;
+ assertNull(retEnhanceObjectCache.getContextSnapshot());
+ assertNotNull(retEnhanceObjectCache.getUrl());
+ assertEquals(URI, retEnhanceObjectCache.getUrl());
+ final List traceSegments = segmentStorage.getTraceSegments();
+ assertEquals(traceSegments.size(), 0);
+ if (ContextManager.isActive()) {
+ ContextManager.stopSpan();
+ }
+ }
+
+ @Test
+ public void testWithDynamicFieldNotNull() throws Throwable {
+ ContextSnapshot contextSnapshot = ContextManager.capture();
+ EnhanceObjectCache enhanceObjectCache = new EnhanceObjectCache();
+ enhanceObjectCache.setContextSnapshot(contextSnapshot);
+ enhancedInstance.setSkyWalkingDynamicField(enhanceObjectCache);
+ EnhanceObjectCache enhanceObjectCache2 = new EnhanceObjectCache();
+ retEnhancedInstance.setSkyWalkingDynamicField(enhanceObjectCache2);
+
+ uriInterceptor.afterMethod(enhancedInstance, null, new Object[]{URI}, null, retEnhancedInstance);
+ Object retEnhancedInstanceSkyWalkingDynamicField = retEnhancedInstance.getSkyWalkingDynamicField();
+ assertNotNull(retEnhancedInstanceSkyWalkingDynamicField);
+ assertTrue(retEnhancedInstanceSkyWalkingDynamicField instanceof EnhanceObjectCache);
+ EnhanceObjectCache retEnhanceObjectCache = (EnhanceObjectCache) retEnhancedInstanceSkyWalkingDynamicField;
+ assertNotNull(retEnhanceObjectCache.getContextSnapshot());
+ assertTrue(contextSnapshot == retEnhanceObjectCache.getContextSnapshot());
+ assertNotNull(retEnhanceObjectCache.getUrl());
+ assertEquals(URI, retEnhanceObjectCache.getUrl());
+ final List traceSegments = segmentStorage.getTraceSegments();
+ assertEquals(traceSegments.size(), 0);
+ if (ContextManager.isActive()) {
+ ContextManager.stopSpan();
+ }
+ }
+
+ @Test
+ public void testWithRetDynamicFieldNull() throws Throwable {
+ ContextSnapshot contextSnapshot = ContextManager.capture();
+ EnhanceObjectCache enhanceObjectCache = new EnhanceObjectCache();
+ enhanceObjectCache.setContextSnapshot(contextSnapshot);
+ enhancedInstance.setSkyWalkingDynamicField(enhanceObjectCache);
+ retEnhancedInstance.setSkyWalkingDynamicField(null);
+
+ uriInterceptor.afterMethod(enhancedInstance, null, new Object[]{URI}, null, retEnhancedInstance);
+ Object retEnhancedInstanceSkyWalkingDynamicField = retEnhancedInstance.getSkyWalkingDynamicField();
+ assertNull(retEnhancedInstanceSkyWalkingDynamicField);
+ assertNotNull(enhancedInstance.getSkyWalkingDynamicField());
+ assertTrue(enhancedInstance.getSkyWalkingDynamicField() instanceof EnhanceObjectCache);
+ EnhanceObjectCache objInstObjectCache = (EnhanceObjectCache) enhancedInstance.getSkyWalkingDynamicField();
+ assertTrue(contextSnapshot == objInstObjectCache.getContextSnapshot());
+ assertNull(objInstObjectCache.getUrl());
+ final List traceSegments = segmentStorage.getTraceSegments();
+ assertEquals(traceSegments.size(), 0);
+ if (ContextManager.isActive()) {
+ ContextManager.stopSpan();
+ }
+ }
+}
diff --git a/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-4.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/spring/cloud/gateway/v412x/HttpClientFinalizerV412InterceptorTest.java b/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-4.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/spring/cloud/gateway/v412x/HttpClientFinalizerV412InterceptorTest.java
new file mode 100644
index 0000000000..8018013db0
--- /dev/null
+++ b/apm-sniffer/optional-plugins/optional-spring-plugins/optional-spring-cloud/gateway-4.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/spring/cloud/gateway/v412x/HttpClientFinalizerV412InterceptorTest.java
@@ -0,0 +1,204 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.spring.cloud.gateway.v412x;
+
+import io.netty.handler.codec.http.HttpResponseStatus;
+import org.apache.skywalking.apm.agent.core.context.ContextManager;
+import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan;
+import org.apache.skywalking.apm.agent.core.context.trace.AbstractTracingSpan;
+import org.apache.skywalking.apm.agent.core.context.trace.SpanLayer;
+import org.apache.skywalking.apm.agent.core.context.trace.TraceSegment;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
+import org.apache.skywalking.apm.agent.test.helper.SegmentHelper;
+import org.apache.skywalking.apm.agent.test.tools.AgentServiceRule;
+import org.apache.skywalking.apm.agent.test.tools.SegmentStorage;
+import org.apache.skywalking.apm.agent.test.tools.SegmentStoragePoint;
+import org.apache.skywalking.apm.agent.test.tools.SpanAssert;
+import org.apache.skywalking.apm.agent.test.tools.TracingSegmentRunner;
+import org.apache.skywalking.apm.network.trace.component.ComponentsDefine;
+import org.apache.skywalking.apm.plugin.spring.cloud.gateway.v4x.define.EnhanceObjectCache;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+import org.reactivestreams.Publisher;
+import reactor.core.publisher.Flux;
+import reactor.netty.Connection;
+import reactor.netty.NettyOutbound;
+import reactor.netty.http.client.HttpClientRequest;
+import reactor.netty.http.client.HttpClientResponse;
+
+import java.util.List;
+import java.util.function.BiFunction;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+@RunWith(TracingSegmentRunner.class)
+public class HttpClientFinalizerV412InterceptorTest {
+
+ private final static String URI = "http://localhost:8080/get";
+ private final static String ENTRY_OPERATION_NAME = "/get";
+ private final HttpClientFinalizerSendV412Interceptor sendInterceptor = new HttpClientFinalizerSendV412Interceptor();
+ private final HttpClientFinalizerResponseConnectionV412Interceptor responseConnectionInterceptor = new HttpClientFinalizerResponseConnectionV412Interceptor();
+ private final BiFunction super HttpClientRequest, ? super NettyOutbound, ? extends Publisher> originalSendBiFunction = (httpClientRequest, nettyOutbound) -> (Publisher) s -> {
+ };
+ private final BiFunction super HttpClientResponse, ? super Connection, ? extends Publisher> originalResponseConnectionBiFunction = (httpClientResponse, connection) -> (Publisher) s -> {
+ };
+ private final EnhancedInstance enhancedInstance = new EnhancedInstance() {
+ private EnhanceObjectCache enhanceObjectCache;
+
+ @Override
+ public Object getSkyWalkingDynamicField() {
+ return enhanceObjectCache;
+ }
+
+ @Override
+ public void setSkyWalkingDynamicField(Object value) {
+ this.enhanceObjectCache = (EnhanceObjectCache) value;
+ }
+ };
+ @Rule
+ public AgentServiceRule serviceRule = new AgentServiceRule();
+ @Rule
+ public MockitoRule rule = MockitoJUnit.rule();
+
+ private HttpClientResponse mockResponse;
+ private HttpClientRequest mockRequest;
+ @SegmentStoragePoint
+ private SegmentStorage segmentStorage;
+ private AbstractSpan entrySpan;
+
+ @Before
+ public void setUp() throws Exception {
+ entrySpan = ContextManager.createEntrySpan(ENTRY_OPERATION_NAME, null);
+ entrySpan.setLayer(SpanLayer.HTTP);
+ entrySpan.setComponent(ComponentsDefine.SPRING_WEBFLUX);
+ mockRequest = new MockClientRequest();
+ mockResponse = new MockClientResponse();
+ final EnhanceObjectCache enhanceObjectCache = new EnhanceObjectCache();
+ enhanceObjectCache.setUrl(URI);
+ enhanceObjectCache.setContextSnapshot(ContextManager.capture());
+ enhancedInstance.setSkyWalkingDynamicField(enhanceObjectCache);
+ }
+
+ @Test
+ public void testWithDynamicFieldNull() throws Throwable {
+ enhancedInstance.setSkyWalkingDynamicField(null);
+ executeSendRequest();
+ stopEntrySpan();
+ final List traceSegments = segmentStorage.getTraceSegments();
+ assertEquals(1, traceSegments.size());
+ }
+
+ @Test
+ public void testWithContextSnapshotNull() throws Throwable {
+ EnhanceObjectCache objectCache = (EnhanceObjectCache) enhancedInstance.getSkyWalkingDynamicField();
+ objectCache.setContextSnapshot(null);
+ executeSendRequest();
+ stopEntrySpan();
+ final List traceSegments = segmentStorage.getTraceSegments();
+ assertEquals(1, traceSegments.size());
+ }
+
+ @Test
+ public void testWithEmptyUri() throws Throwable {
+ final EnhanceObjectCache objectCache = (EnhanceObjectCache) enhancedInstance.getSkyWalkingDynamicField();
+ objectCache.setUrl("");
+ executeSendRequest();
+ stopEntrySpan();
+ final List traceSegments = segmentStorage.getTraceSegments();
+ assertEquals(1, traceSegments.size());
+ final List