This is an automated email from the ASF dual-hosted git repository.
wu-sheng pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/skywalking-java.git
The following commit(s) were added to refs/heads/main by this push:
new 67c9afa00c Add mixed-classpath scenario and Tomcat http.headers
collection (#814)
67c9afa00c is described below
commit 67c9afa00cde91fb5fae6cc5a7d34d88e2579b7e
Author: 吴晟 Wu Sheng <[email protected]>
AuthorDate: Tue Jul 7 15:13:21 2026 +0800
Add mixed-classpath scenario and Tomcat http.headers collection (#814)
Two related follow-ups to the #812 servlet-commons unification, both about
HTTP
request-tag collection on the Tomcat/servlet path.
1. spring-6.x-mixed-servlet-scenario — an end-to-end repro of the #13938
field
condition: a Jakarta Spring 6 WAR that ALSO carries
javax.servlet-api:4.0.1 at
compile scope, so both javax.servlet.* (from WEB-INF/lib) and
jakarta.servlet.*
(from the Tomcat 10.1 container) are loadable in the deployed webapp at
once. The
scenario asserts http.headers and http.params are still collected on the
jakarta
entry span, proving servlet-commons' runtime instanceof dispatch
resolves the live
request under a mixed classpath — previously only covered by the
HttpRequestWrappersTest unit test. One version by design (the resolution
is
version-independent; version compatibility is already covered by
spring-6.x-scenario).
2. Tomcat http.headers — http.headers was emitted only by the Spring MVC
plugin, so
plugin.http.include_http_headers was a no-op for plain servlet apps
served by the
Tomcat plugin. Add INCLUDE_HTTP_HEADERS + HTTP_HEADERS_LENGTH_THRESHOLD
to
TomcatPluginConfig.Plugin.Http — the shared plugin.http.* namespace
already used by
the Spring MVC and HttpClient plugins, so no new config key and no
agent.config
change — and collect the configured request headers in
TomcatInvokeInterceptor,
guarded no-op when the config is empty. Proven on the dedicated Tomcat
scenarios,
where the Tomcat plugin owns the entry span: tomcat-9x (javax, Tomcat 9)
and
tomcat-10x (jakarta, Tomcat 10) now carry a mock_header header and a q1
query param
on their internal self-call and assert http.headers + http.params, which
also fills
the previously-missing jakarta http.params coverage.
---
.github/workflows/plugins-jdk17-test.1.yaml | 1 +
CHANGES.md | 1 +
.../apm/plugin/tomcat/TomcatInvokeInterceptor.java | 28 ++
.../apm/plugin/tomcat/TomcatPluginConfig.java | 14 +
.../config/expectedData.yaml | 379 +++++++++++++++++++++
.../configuration.yml | 8 +-
.../spring-6.x-mixed-servlet-scenario/pom.xml | 143 ++++++++
.../skywalking/apm/testcase/entity/User.java | 53 +++
.../testcase/implinterface/TestCaseController.java | 35 ++
.../testcase/implinterface/TestCaseInterface.java | 31 ++
.../apm/testcase/inherit/ChildController.java | 28 ++
.../apm/testcase/inherit/ParentController.java | 32 ++
.../apm/testcase/restapi/RestCaseController.java | 77 +++++
.../resttemplate/RestTemplateController.java | 85 +++++
.../apm/testcase/spring3/CaseController.java | 41 +++
.../spring3/component/TestComponentBean.java | 29 ++
.../testcase/spring3/dao/TestRepositoryBean.java | 29 ++
.../testcase/spring3/service/TestServiceBean.java | 38 +++
.../src/main/resources/log4j2.xml | 30 ++
.../src/main/webapp/WEB-INF/spring-mvc-servlet.xml | 30 ++
.../src/main/webapp/WEB-INF/web.xml | 35 ++
.../support-version.list} | 8 +-
.../tomcat-10x-scenario/config/expectedData.yaml | 4 +-
.../tomcat-10x-scenario/configuration.yml | 2 +
.../apm/testcase/tomcat10x/CaseServlet.java | 5 +-
.../tomcat-9x-scenario/config/expectedData.yaml | 4 +-
.../scenarios/tomcat-9x-scenario/configuration.yml | 2 +
.../apm/testcase/tomcat9x/CaseServlet.java | 5 +-
28 files changed, 1168 insertions(+), 9 deletions(-)
diff --git a/.github/workflows/plugins-jdk17-test.1.yaml
b/.github/workflows/plugins-jdk17-test.1.yaml
index e4f7144dfd..7738b85f44 100644
--- a/.github/workflows/plugins-jdk17-test.1.yaml
+++ b/.github/workflows/plugins-jdk17-test.1.yaml
@@ -71,6 +71,7 @@ jobs:
matrix:
case:
- spring-6.x-scenario
+ - spring-6.x-mixed-servlet-scenario
- spring-boot-3.x-scenario
- struts2.7-scenario
- resteasy-6.x-scenario
diff --git a/CHANGES.md b/CHANGES.md
index 48310efdab..4daf294f74 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -6,6 +6,7 @@ Release Notes.
------------------
* Fix `plugin.http.include_http_headers` not working on Spring Boot 3.x /
Jakarta EE (apache/skywalking#13938).
+* Support `plugin.http.include_http_headers` in the Tomcat plugin, collecting
the configured request headers as the `http.headers` tag on Tomcat entry spans
(e.g. RESTEasy on Tomcat), consistent with the Spring MVC plugin. Honors the
shared `plugin.http.http_headers_length_threshold`.
* Unify the Tomcat plugins into a single `tomcat` plugin (Tomcat 7 - 10) and
the Jetty server plugins into a single `jetty-server` plugin (Jetty 9 - 11),
each supporting both `javax.servlet` and `jakarta.servlet`. Breaking change:
plugin names `tomcat-7.x/8.x` and `tomcat-10.x` are replaced by `tomcat`, and
`jetty-server-9.x` and `jetty-server-11.x` by `jetty-server`; update
`plugin.exclude_plugins` if you reference the old names.
* Add a Jetty 12 server plugin (`jetty-server-12.x`). Jetty 12 removed the
`HttpChannel` handle target and moved request handling to the async
`Server#handle(Request, Response, Callback)` core API, so it needs a separate
plugin from the merged `jetty-server`.
* Add a Struts 7 plugin (`struts2-7.x`) for Jakarta Struts, whose
`DefaultActionInvocation` moved to `org.apache.struts2`.
diff --git
a/apm-sniffer/apm-sdk-plugin/tomcat-plugin/src/main/java/org/apache/skywalking/apm/plugin/tomcat/TomcatInvokeInterceptor.java
b/apm-sniffer/apm-sdk-plugin/tomcat-plugin/src/main/java/org/apache/skywalking/apm/plugin/tomcat/TomcatInvokeInterceptor.java
index 9cb009199a..8208a2a4c6 100644
---
a/apm-sniffer/apm-sdk-plugin/tomcat-plugin/src/main/java/org/apache/skywalking/apm/plugin/tomcat/TomcatInvokeInterceptor.java
+++
b/apm-sniffer/apm-sdk-plugin/tomcat-plugin/src/main/java/org/apache/skywalking/apm/plugin/tomcat/TomcatInvokeInterceptor.java
@@ -37,8 +37,11 @@ import org.apache.skywalking.apm.util.StringUtil;
import org.apache.tomcat.util.http.Parameters;
import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
public class TomcatInvokeInterceptor implements
InstanceMethodsAroundInterceptor {
@@ -64,6 +67,10 @@ public class TomcatInvokeInterceptor implements
InstanceMethodsAroundInterceptor
if (TomcatPluginConfig.Plugin.Tomcat.COLLECT_HTTP_PARAMS) {
collectHttpParam(request, span);
}
+
+ if
(!CollectionUtil.isEmpty(TomcatPluginConfig.Plugin.Http.INCLUDE_HTTP_HEADERS)) {
+ collectHttpHeaders(request, span);
+ }
}
@Override
@@ -115,4 +122,25 @@ public class TomcatInvokeInterceptor implements
InstanceMethodsAroundInterceptor
Tags.HTTP.PARAMS.set(span, tagValue);
}
}
+
+ private void collectHttpHeaders(Request request, AbstractSpan span) {
+ final List<String> headersList = new
ArrayList<>(TomcatPluginConfig.Plugin.Http.INCLUDE_HTTP_HEADERS.size());
+ TomcatPluginConfig.Plugin.Http.INCLUDE_HTTP_HEADERS.stream()
+ .filter(headerName -> request.getHeaders(headerName) != null)
+ .forEach(headerName -> {
+ Enumeration<String> headerValues =
request.getHeaders(headerName);
+ List<String> valueList = Collections.list(headerValues);
+ if (!CollectionUtil.isEmpty(valueList)) {
+ headersList.add(headerName + "=" + valueList);
+ }
+ });
+
+ if (!headersList.isEmpty()) {
+ String tagValue = String.join("\n", headersList);
+ tagValue =
TomcatPluginConfig.Plugin.Http.HTTP_HEADERS_LENGTH_THRESHOLD > 0 ?
+ StringUtil.cut(tagValue,
TomcatPluginConfig.Plugin.Http.HTTP_HEADERS_LENGTH_THRESHOLD) :
+ tagValue;
+ Tags.HTTP.HEADERS.set(span, tagValue);
+ }
+ }
}
diff --git
a/apm-sniffer/apm-sdk-plugin/tomcat-plugin/src/main/java/org/apache/skywalking/apm/plugin/tomcat/TomcatPluginConfig.java
b/apm-sniffer/apm-sdk-plugin/tomcat-plugin/src/main/java/org/apache/skywalking/apm/plugin/tomcat/TomcatPluginConfig.java
index 0a1d713cf9..8a99337863 100644
---
a/apm-sniffer/apm-sdk-plugin/tomcat-plugin/src/main/java/org/apache/skywalking/apm/plugin/tomcat/TomcatPluginConfig.java
+++
b/apm-sniffer/apm-sdk-plugin/tomcat-plugin/src/main/java/org/apache/skywalking/apm/plugin/tomcat/TomcatPluginConfig.java
@@ -18,6 +18,7 @@
package org.apache.skywalking.apm.plugin.tomcat;
+import java.util.List;
import org.apache.skywalking.apm.agent.core.boot.PluginConfig;
public class TomcatPluginConfig {
@@ -38,6 +39,19 @@ public class TomcatPluginConfig {
* for the sake of performance
*/
public static int HTTP_PARAMS_LENGTH_THRESHOLD = 1024;
+
+ /**
+ * When {@link Http#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.
+ */
+ public static int HTTP_HEADERS_LENGTH_THRESHOLD = 2048;
+
+ /**
+ * It controls what header data should be collected, this is for
security purpose, values must be in lower
+ * case. Shares the {@code plugin.http.include_http_headers}
config key with the other HTTP server plugins.
+ */
+ public static List<String> INCLUDE_HTTP_HEADERS;
}
}
}
diff --git
a/test/plugin/scenarios/spring-6.x-mixed-servlet-scenario/config/expectedData.yaml
b/test/plugin/scenarios/spring-6.x-mixed-servlet-scenario/config/expectedData.yaml
new file mode 100644
index 0000000000..992a34dafd
--- /dev/null
+++
b/test/plugin/scenarios/spring-6.x-mixed-servlet-scenario/config/expectedData.yaml
@@ -0,0 +1,379 @@
+# 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.
+segmentItems:
+- serviceName: spring-6.x-mixed-servlet-scenario
+ segmentSize: ge 10
+ segments:
+ - segmentId: not null
+ spans:
+ - operationName: HEAD:/healthCheck
+ parentSpanId: -1
+ spanId: 0
+ spanLayer: Http
+ startTime: nq 0
+ endTime: nq 0
+ componentId: 14
+ isError: false
+ spanType: Entry
+ peer: ''
+ tags:
+ - {key: url, value:
'http://localhost:8080/spring-6.x-mixed-servlet-scenario/healthCheck'}
+ - {key: http.method, value: HEAD}
+ - {key: http.status_code, value: '200'}
+ skipAnalysis: 'false'
+ - segmentId: not null
+ spans:
+ - operationName:
test.apache.skywalking.apm.testcase.spring3.component.TestComponentBean.componentMethod
+ parentSpanId: 1
+ spanId: 2
+ spanLayer: Unknown
+ startTime: nq 0
+ endTime: nq 0
+ componentId: 93
+ isError: false
+ spanType: Local
+ peer: ''
+ skipAnalysis: 'false'
+ - operationName:
test.apache.skywalking.apm.testcase.spring3.dao.TestRepositoryBean.doSomeStuff
+ parentSpanId: 1
+ spanId: 3
+ spanLayer: Unknown
+ startTime: nq 0
+ endTime: nq 0
+ componentId: 93
+ isError: false
+ spanType: Local
+ peer: ''
+ skipAnalysis: 'false'
+ - operationName:
test.apache.skywalking.apm.testcase.spring3.service.TestServiceBean.doSomeBusiness
+ parentSpanId: 0
+ spanId: 1
+ spanLayer: Unknown
+ startTime: nq 0
+ endTime: nq 0
+ componentId: 93
+ isError: false
+ spanType: Local
+ peer: ''
+ skipAnalysis: 'false'
+ - operationName: GET:/case/spring3
+ parentSpanId: -1
+ spanId: 0
+ spanLayer: Http
+ startTime: nq 0
+ endTime: nq 0
+ componentId: 14
+ isError: false
+ spanType: Entry
+ peer: ''
+ tags:
+ - {key: url, value:
'http://localhost:8080/spring-6.x-mixed-servlet-scenario/case/spring3'}
+ - {key: http.method, value: GET}
+ - {key: http.headers, value: 'mock_header=[mock_value]'}
+ - {key: http.status_code, value: '200'}
+ refs:
+ - {parentEndpoint: GET:/case/resttemplate, networkAddress:
'localhost:8080', refType: CrossProcess,
+ parentSpanId: 1, parentTraceSegmentId: not null,
parentServiceInstance: not
+ null, parentService: spring-6.x-mixed-servlet-scenario, traceId: not
null}
+ skipAnalysis: 'false'
+ - segmentId: not null
+ spans:
+ - operationName: 'POST:/create/'
+ parentSpanId: -1
+ spanId: 0
+ spanLayer: Http
+ startTime: nq 0
+ endTime: nq 0
+ componentId: 14
+ isError: false
+ spanType: Entry
+ peer: ''
+ tags:
+ - {key: url, value:
'http://localhost:8080/spring-6.x-mixed-servlet-scenario/create/'}
+ - {key: http.method, value: POST}
+ - {key: http.status_code, value: '201'}
+ refs:
+ - {parentEndpoint: GET:/case/resttemplate, networkAddress:
'localhost:8080', refType: CrossProcess,
+ parentSpanId: 2, parentTraceSegmentId: not null,
parentServiceInstance: not
+ null, parentService: spring-6.x-mixed-servlet-scenario, traceId: not
null}
+ skipAnalysis: 'false'
+ - segmentId: not null
+ spans:
+ - operationName: 'GET:/get/{id}'
+ parentSpanId: -1
+ spanId: 0
+ spanLayer: Http
+ startTime: nq 0
+ endTime: nq 0
+ componentId: 14
+ isError: false
+ spanType: Entry
+ peer: ''
+ tags:
+ - {key: url, value:
'http://localhost:8080/spring-6.x-mixed-servlet-scenario/get/1'}
+ - {key: http.method, value: GET}
+ - {key: http.status_code, value: '200'}
+ refs:
+ - {parentEndpoint: GET:/case/resttemplate, networkAddress:
'localhost:8080', refType: CrossProcess,
+ parentSpanId: 3, parentTraceSegmentId: not null,
parentServiceInstance: not
+ null, parentService: spring-6.x-mixed-servlet-scenario, traceId: not
null}
+ skipAnalysis: 'false'
+ - segmentId: not null
+ spans:
+ - operationName: 'PUT:/update/{id}'
+ parentSpanId: -1
+ spanId: 0
+ spanLayer: Http
+ startTime: nq 0
+ endTime: nq 0
+ componentId: 14
+ isError: false
+ spanType: Entry
+ peer: ''
+ tags:
+ - {key: url, value:
'http://localhost:8080/spring-6.x-mixed-servlet-scenario/update/1'}
+ - {key: http.method, value: PUT}
+ - {key: http.status_code, value: '200'}
+ refs:
+ - {parentEndpoint: GET:/case/resttemplate, networkAddress:
'localhost:8080', refType: CrossProcess,
+ parentSpanId: 4, parentTraceSegmentId: not null,
parentServiceInstance: not
+ null, parentService: spring-6.x-mixed-servlet-scenario, traceId: not
null}
+ skipAnalysis: 'false'
+ - segmentId: not null
+ spans:
+ - operationName: 'DELETE:/delete/{id}'
+ parentSpanId: -1
+ spanId: 0
+ spanLayer: Http
+ startTime: nq 0
+ endTime: nq 0
+ componentId: 14
+ isError: false
+ spanType: Entry
+ peer: ''
+ tags:
+ - {key: url, value:
'http://localhost:8080/spring-6.x-mixed-servlet-scenario/delete/1'}
+ - {key: http.method, value: DELETE}
+ - {key: http.status_code, value: '204'}
+ refs:
+ - {parentEndpoint: GET:/case/resttemplate, networkAddress:
'localhost:8080', refType: CrossProcess,
+ parentSpanId: 5, parentTraceSegmentId: not null,
parentServiceInstance: not
+ null, parentService: spring-6.x-mixed-servlet-scenario, traceId: not
null}
+ skipAnalysis: 'false'
+ - segmentId: not null
+ spans:
+ - operationName: GET:/inherit/child/test
+ parentSpanId: -1
+ spanId: 0
+ spanLayer: Http
+ startTime: nq 0
+ endTime: nq 0
+ componentId: 14
+ isError: false
+ spanType: Entry
+ peer: ''
+ tags:
+ - {key: url, value:
'http://localhost:8080/spring-6.x-mixed-servlet-scenario/inherit/child/test'}
+ - {key: http.method, value: GET}
+ - {key: http.status_code, value: '200'}
+ refs:
+ - {parentEndpoint: GET:/case/resttemplate, networkAddress:
'localhost:8080', refType: CrossProcess,
+ parentSpanId: 6, parentTraceSegmentId: not null,
parentServiceInstance: not
+ null, parentService: spring-6.x-mixed-servlet-scenario, traceId: not
null}
+ skipAnalysis: 'false'
+ - segmentId: not null
+ spans:
+ - operationName: GET:/impl/requestmapping
+ parentSpanId: -1
+ spanId: 0
+ spanLayer: Http
+ startTime: nq 0
+ endTime: nq 0
+ componentId: 14
+ isError: false
+ spanType: Entry
+ peer: ''
+ tags:
+ - {key: url, value:
'http://localhost:8080/spring-6.x-mixed-servlet-scenario/impl/requestmapping'}
+ - {key: http.method, value: GET}
+ - {key: http.status_code, value: '200'}
+ refs:
+ - {parentEndpoint: GET:/case/resttemplate, networkAddress:
'localhost:8080', refType: CrossProcess,
+ parentSpanId: 7, parentTraceSegmentId: not null,
parentServiceInstance: not
+ null, parentService: spring-6.x-mixed-servlet-scenario, traceId: not
null}
+ skipAnalysis: 'false'
+ - segmentId: not null
+ spans:
+ - operationName: 'GET:/impl/restmapping'
+ parentSpanId: -1
+ spanId: 0
+ spanLayer: Http
+ startTime: nq 0
+ endTime: nq 0
+ componentId: 14
+ isError: false
+ spanType: Entry
+ peer: ''
+ tags:
+ - {key: url, value:
'http://localhost:8080/spring-6.x-mixed-servlet-scenario/impl/restmapping'}
+ - {key: http.method, value: GET}
+ - {key: http.status_code, value: '200'}
+ refs:
+ - {parentEndpoint: GET:/case/resttemplate, networkAddress:
'localhost:8080', refType: CrossProcess,
+ parentSpanId: 8, parentTraceSegmentId: not null,
parentServiceInstance: not
+ null, parentService: spring-6.x-mixed-servlet-scenario, traceId: not
null}
+ skipAnalysis: 'false'
+ - segmentId: not null
+ spans:
+ - operationName: /spring-6.x-mixed-servlet-scenario/case/spring3
+ parentSpanId: 0
+ spanId: 1
+ spanLayer: Http
+ startTime: nq 0
+ endTime: nq 0
+ componentId: 12
+ isError: false
+ spanType: Exit
+ peer: localhost:8080
+ tags:
+ - {key: http.method, value: GET}
+ - {key: url, value:
'http://localhost:8080/spring-6.x-mixed-servlet-scenario/case/spring3'}
+ - {key: http.status_code, value: '200'}
+ skipAnalysis: 'false'
+ - operationName: /spring-6.x-mixed-servlet-scenario/create/
+ parentSpanId: 0
+ spanId: 2
+ spanLayer: Http
+ startTime: nq 0
+ endTime: nq 0
+ componentId: 13
+ isError: false
+ spanType: Exit
+ peer: localhost:8080
+ tags:
+ - {key: url, value:
'http://localhost:8080/spring-6.x-mixed-servlet-scenario/create/'}
+ - {key: http.method, value: POST}
+ - {key: http.status_code, value: '201'}
+ skipAnalysis: 'false'
+ - operationName: /spring-6.x-mixed-servlet-scenario/get/1
+ parentSpanId: 0
+ spanId: 3
+ spanLayer: Http
+ startTime: nq 0
+ endTime: nq 0
+ componentId: 13
+ isError: false
+ spanType: Exit
+ peer: localhost:8080
+ tags:
+ - {key: url, value:
'http://localhost:8080/spring-6.x-mixed-servlet-scenario/get/1'}
+ - {key: http.method, value: GET}
+ - {key: http.status_code, value: '200'}
+ skipAnalysis: 'false'
+ - operationName: /spring-6.x-mixed-servlet-scenario/update/1
+ parentSpanId: 0
+ spanId: 4
+ spanLayer: Http
+ startTime: nq 0
+ endTime: nq 0
+ componentId: 13
+ isError: false
+ spanType: Exit
+ peer: localhost:8080
+ tags:
+ - {key: url, value:
'http://localhost:8080/spring-6.x-mixed-servlet-scenario/update/1'}
+ - {key: http.method, value: PUT}
+ - {key: http.status_code, value: '200'}
+ skipAnalysis: 'false'
+ - operationName: /spring-6.x-mixed-servlet-scenario/delete/1
+ parentSpanId: 0
+ spanId: 5
+ spanLayer: Http
+ startTime: nq 0
+ endTime: nq 0
+ componentId: 13
+ isError: false
+ spanType: Exit
+ peer: localhost:8080
+ tags:
+ - {key: url, value:
'http://localhost:8080/spring-6.x-mixed-servlet-scenario/delete/1'}
+ - {key: http.method, value: DELETE}
+ - {key: http.status_code, value: '204'}
+ skipAnalysis: 'false'
+ - operationName: /spring-6.x-mixed-servlet-scenario/inherit/child/test
+ parentSpanId: 0
+ spanId: 6
+ spanLayer: Http
+ startTime: nq 0
+ endTime: nq 0
+ componentId: 12
+ isError: false
+ spanType: Exit
+ peer: localhost:8080
+ tags:
+ - {key: http.method, value: GET}
+ - {key: url, value:
'http://localhost:8080/spring-6.x-mixed-servlet-scenario/inherit/child/test'}
+ - {key: http.status_code, value: '200'}
+ skipAnalysis: 'false'
+ - operationName: /spring-6.x-mixed-servlet-scenario/impl/requestmapping
+ parentSpanId: 0
+ spanId: 7
+ spanLayer: Http
+ startTime: nq 0
+ endTime: nq 0
+ componentId: 12
+ isError: false
+ spanType: Exit
+ peer: localhost:8080
+ tags:
+ - {key: http.method, value: GET}
+ - {key: url, value:
'http://localhost:8080/spring-6.x-mixed-servlet-scenario/impl/requestmapping'}
+ - {key: http.status_code, value: '200'}
+ skipAnalysis: 'false'
+ - operationName: /spring-6.x-mixed-servlet-scenario/impl/restmapping
+ parentSpanId: 0
+ spanId: 8
+ spanLayer: Http
+ startTime: nq 0
+ endTime: nq 0
+ componentId: 12
+ isError: false
+ spanType: Exit
+ peer: localhost:8080
+ tags:
+ - {key: http.method, value: GET}
+ - {key: url, value:
'http://localhost:8080/spring-6.x-mixed-servlet-scenario/impl/restmapping'}
+ - {key: http.status_code, value: '200'}
+ skipAnalysis: 'false'
+ - operationName: GET:/case/resttemplate
+ parentSpanId: -1
+ spanId: 0
+ spanLayer: Http
+ startTime: nq 0
+ endTime: nq 0
+ componentId: 14
+ isError: false
+ spanType: Entry
+ peer: ''
+ tags:
+ - {key: url, value:
'http://localhost:8080/spring-6.x-mixed-servlet-scenario/case/resttemplate'}
+ - {key: http.method, value: GET}
+ - key: http.params
+ value: |-
+ q1=[v1]
+ chinese=[中文]
+ - {key: http.status_code, value: '200'}
+ skipAnalysis: 'false'
diff --git a/test/plugin/scenarios/tomcat-10x-scenario/configuration.yml
b/test/plugin/scenarios/spring-6.x-mixed-servlet-scenario/configuration.yml
similarity index 63%
copy from test/plugin/scenarios/tomcat-10x-scenario/configuration.yml
copy to
test/plugin/scenarios/spring-6.x-mixed-servlet-scenario/configuration.yml
index fac58bdfd1..8ca8d8b42b 100644
--- a/test/plugin/scenarios/tomcat-10x-scenario/configuration.yml
+++ b/test/plugin/scenarios/spring-6.x-mixed-servlet-scenario/configuration.yml
@@ -15,5 +15,9 @@
# limitations under the License.
type: tomcat
-entryService:
http://localhost:8080/tomcat-10x-scenario/case/tomcat-10x-scenario
-healthCheck: http://localhost:8080/tomcat-10x-scenario/case/healthCheck
+entryService:
'"http://localhost:8080/spring-6.x-mixed-servlet-scenario/case/resttemplate?q1=v1&chinese=%e4%b8%ad%e6%96%87"'
+healthCheck:
http://localhost:8080/spring-6.x-mixed-servlet-scenario/healthCheck
+runningMode: with_optional
+withPlugins: apm-spring-annotation-plugin-*.jar;apm-*-6.x-plugin-*.jar
+environment:
+ - CATALINA_OPTS="-Dskywalking.plugin.http.include_http_headers=mock_header
-Dskywalking.plugin.springmvc.collect_http_params=true"
diff --git a/test/plugin/scenarios/spring-6.x-mixed-servlet-scenario/pom.xml
b/test/plugin/scenarios/spring-6.x-mixed-servlet-scenario/pom.xml
new file mode 100644
index 0000000000..4cd3b19779
--- /dev/null
+++ b/test/plugin/scenarios/spring-6.x-mixed-servlet-scenario/pom.xml
@@ -0,0 +1,143 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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.
+ ~
+ -->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <groupId>org.apache.skywalking</groupId>
+ <artifactId>spring-6.x-mixed-servlet-scenario</artifactId>
+ <version>5.0.0</version>
+
+ <packaging>war</packaging>
+
+ <properties>
+ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+ <compiler.version>17</compiler.version>
+ <maven-compiler-plugin.version>3.11.0</maven-compiler-plugin.version>
+ <test.framework.version>6.0.0</test.framework.version>
+ <test.framework>spring</test.framework>
+ </properties>
+
+ <name>skywalking-spring-6.x-mixed-servlet-scenario</name>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.springframework</groupId>
+ <artifactId>spring-context</artifactId>
+ <version>${test.framework.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.springframework</groupId>
+ <artifactId>spring-aop</artifactId>
+ <version>${test.framework.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.springframework</groupId>
+ <artifactId>spring-webmvc</artifactId>
+ <version>${test.framework.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.springframework</groupId>
+ <artifactId>spring-web</artifactId>
+ <version>${test.framework.version}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>com.fasterxml.jackson.core</groupId>
+ <artifactId>jackson-databind</artifactId>
+ <version>2.14.3</version>
+ </dependency>
+
+ <dependency>
+ <groupId>com.google.code.gson</groupId>
+ <artifactId>gson</artifactId>
+ <version>2.9.1</version>
+ </dependency>
+
+ <dependency>
+ <groupId>com.squareup.okhttp3</groupId>
+ <artifactId>okhttp</artifactId>
+ <version>4.10.0</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.logging.log4j</groupId>
+ <artifactId>log4j-api</artifactId>
+ <version>2.19.0</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.logging.log4j</groupId>
+ <artifactId>log4j-core</artifactId>
+ <version>2.19.0</version>
+ </dependency>
+
+ <dependency>
+ <groupId>jakarta.servlet</groupId>
+ <artifactId>jakarta.servlet-api</artifactId>
+ <version>6.0.0</version>
+ </dependency>
+ <!--
+ The point of this scenario (issue #13938): a Jakarta Spring 6 app
that ALSO carries the
+ legacy javax.servlet-api transitively. At 'compile' scope this jar
lands in WEB-INF/lib,
+ so both javax.servlet.* and jakarta.servlet.* are loadable in the
deployed webapp at once
+ (jakarta from Tomcat 10.1's container libs, javax from WEB-INF/lib -
Tomcat only skips the
+ jakarta copy, not javax). servlet-commons' runtime instanceof
dispatch must still resolve
+ the live jakarta request and collect http.headers / http.params. Do
NOT change the scope
+ to provided - that would remove the mixed classpath and defeat the
test.
+ -->
+ <dependency>
+ <groupId>javax.servlet</groupId>
+ <artifactId>javax.servlet-api</artifactId>
+ <version>4.0.1</version>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <finalName>spring-6.x-mixed-servlet-scenario</finalName>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-war-plugin</artifactId>
+ <version>3.3.1</version>
+ </plugin>
+ <plugin>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <version>${maven-compiler-plugin.version}</version>
+ <configuration>
+ <parameters>true</parameters>
+ <source>${compiler.version}</source>
+ <target>${compiler.version}</target>
+ <encoding>${project.build.sourceEncoding}</encoding>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+
+ <pluginRepositories>
+ <pluginRepository>
+ <id>spring-snapshots</id>
+ <url>https://repo.spring.io/snapshot</url>
+ </pluginRepository>
+ <pluginRepository>
+ <id>spring-milestones</id>
+ <url>https://repo.spring.io/milestone</url>
+ </pluginRepository>
+ </pluginRepositories>
+</project>
\ No newline at end of file
diff --git
a/test/plugin/scenarios/spring-6.x-mixed-servlet-scenario/src/main/java/test/apache/skywalking/apm/testcase/entity/User.java
b/test/plugin/scenarios/spring-6.x-mixed-servlet-scenario/src/main/java/test/apache/skywalking/apm/testcase/entity/User.java
new file mode 100644
index 0000000000..e7fb1871e5
--- /dev/null
+++
b/test/plugin/scenarios/spring-6.x-mixed-servlet-scenario/src/main/java/test/apache/skywalking/apm/testcase/entity/User.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 test.apache.skywalking.apm.testcase.entity;
+
+public class User {
+
+ private int id;
+ private String userName;
+
+ public User(int id) {
+ this.id = id;
+ }
+
+ public User(int id, String userName) {
+ this.id = id;
+ this.userName = userName;
+ }
+
+ public User() {
+ }
+
+ public String getUserName() {
+ return userName;
+ }
+
+ public void setUserName(String userName) {
+ this.userName = userName;
+ }
+
+ public int getId() {
+ return id;
+ }
+
+ public void setId(int id) {
+ this.id = id;
+ }
+}
diff --git
a/test/plugin/scenarios/spring-6.x-mixed-servlet-scenario/src/main/java/test/apache/skywalking/apm/testcase/implinterface/TestCaseController.java
b/test/plugin/scenarios/spring-6.x-mixed-servlet-scenario/src/main/java/test/apache/skywalking/apm/testcase/implinterface/TestCaseController.java
new file mode 100644
index 0000000000..7a95a9318a
--- /dev/null
+++
b/test/plugin/scenarios/spring-6.x-mixed-servlet-scenario/src/main/java/test/apache/skywalking/apm/testcase/implinterface/TestCaseController.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 test.apache.skywalking.apm.testcase.implinterface;
+
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+public class TestCaseController implements TestCaseInterface {
+
+ @Override
+ public String implRequestMappingAnnotationTestCase() {
+ return "implRequestMappingAnnotationTestCase";
+ }
+
+ @Override
+ public String implRestAnnotationTestCase() {
+ return "implRestAnnotationTestCase";
+ }
+}
diff --git
a/test/plugin/scenarios/spring-6.x-mixed-servlet-scenario/src/main/java/test/apache/skywalking/apm/testcase/implinterface/TestCaseInterface.java
b/test/plugin/scenarios/spring-6.x-mixed-servlet-scenario/src/main/java/test/apache/skywalking/apm/testcase/implinterface/TestCaseInterface.java
new file mode 100644
index 0000000000..4fea97b7b1
--- /dev/null
+++
b/test/plugin/scenarios/spring-6.x-mixed-servlet-scenario/src/main/java/test/apache/skywalking/apm/testcase/implinterface/TestCaseInterface.java
@@ -0,0 +1,31 @@
+/*
+ * 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 test.apache.skywalking.apm.testcase.implinterface;
+
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+
+@RequestMapping("/impl")
+public interface TestCaseInterface {
+ @RequestMapping(path = "/requestmapping")
+ String implRequestMappingAnnotationTestCase();
+
+ @GetMapping("/restmapping")
+ String implRestAnnotationTestCase();
+}
diff --git
a/test/plugin/scenarios/spring-6.x-mixed-servlet-scenario/src/main/java/test/apache/skywalking/apm/testcase/inherit/ChildController.java
b/test/plugin/scenarios/spring-6.x-mixed-servlet-scenario/src/main/java/test/apache/skywalking/apm/testcase/inherit/ChildController.java
new file mode 100644
index 0000000000..27ddf54c76
--- /dev/null
+++
b/test/plugin/scenarios/spring-6.x-mixed-servlet-scenario/src/main/java/test/apache/skywalking/apm/testcase/inherit/ChildController.java
@@ -0,0 +1,28 @@
+/*
+ * 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 test.apache.skywalking.apm.testcase.inherit;
+
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+@RequestMapping("/inherit/child")
+public class ChildController extends ParentController {
+
+}
diff --git
a/test/plugin/scenarios/spring-6.x-mixed-servlet-scenario/src/main/java/test/apache/skywalking/apm/testcase/inherit/ParentController.java
b/test/plugin/scenarios/spring-6.x-mixed-servlet-scenario/src/main/java/test/apache/skywalking/apm/testcase/inherit/ParentController.java
new file mode 100644
index 0000000000..16b928100d
--- /dev/null
+++
b/test/plugin/scenarios/spring-6.x-mixed-servlet-scenario/src/main/java/test/apache/skywalking/apm/testcase/inherit/ParentController.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 test.apache.skywalking.apm.testcase.inherit;
+
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+@RequestMapping("/inherit/parent")
+public class ParentController {
+
+ @RequestMapping("test")
+ public String test(Integer param) {
+ return "parent-a" + param;
+ }
+}
diff --git
a/test/plugin/scenarios/spring-6.x-mixed-servlet-scenario/src/main/java/test/apache/skywalking/apm/testcase/restapi/RestCaseController.java
b/test/plugin/scenarios/spring-6.x-mixed-servlet-scenario/src/main/java/test/apache/skywalking/apm/testcase/restapi/RestCaseController.java
new file mode 100644
index 0000000000..6792ecb712
--- /dev/null
+++
b/test/plugin/scenarios/spring-6.x-mixed-servlet-scenario/src/main/java/test/apache/skywalking/apm/testcase/restapi/RestCaseController.java
@@ -0,0 +1,77 @@
+/*
+ * 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 test.apache.skywalking.apm.testcase.restapi;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.ResponseBody;
+import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.util.UriComponentsBuilder;
+import test.apache.skywalking.apm.testcase.entity.User;
+
+@RestController
+public class RestCaseController {
+
+ private static final Map<Integer, User> USERS = new
ConcurrentHashMap<Integer, User>();
+
+ @GetMapping(value = "/get/{id}")
+ @ResponseBody
+ private ResponseEntity<User> getUser(@PathVariable("id") int id) throws
InterruptedException {
+ User currentUser = new User(id, "a");
+ return ResponseEntity.ok(currentUser);
+ }
+
+ @PostMapping(value = "/create/")
+ @ResponseBody
+ public ResponseEntity<Void> createUser(@RequestBody User user,
+ UriComponentsBuilder ucBuilder) throws InterruptedException {
+ USERS.put(user.getId(), user);
+ HttpHeaders headers = new HttpHeaders();
+
headers.setLocation(ucBuilder.path("/get/{id}").buildAndExpand(user.getId()).toUri());
+ return new ResponseEntity<Void>(headers, HttpStatus.CREATED);
+ }
+
+ @PutMapping(value = "/update/{id}")
+ @ResponseBody
+ public ResponseEntity<User> updateUser(@PathVariable("id") int id,
+ @RequestBody User user) throws InterruptedException {
+ User currentUser = new User(id, user.getUserName());
+ return ResponseEntity.ok(currentUser);
+ }
+
+ @DeleteMapping(value = "/delete/{id}")
+ @ResponseBody
+ public ResponseEntity<Void> deleteUser(@PathVariable("id") int id) throws
InterruptedException {
+ User currentUser = USERS.get(id);
+ if (currentUser == null) {
+ return ResponseEntity.noContent().build();
+ }
+ USERS.remove(id);
+ return ResponseEntity.noContent().build();
+ }
+}
diff --git
a/test/plugin/scenarios/spring-6.x-mixed-servlet-scenario/src/main/java/test/apache/skywalking/apm/testcase/resttemplate/RestTemplateController.java
b/test/plugin/scenarios/spring-6.x-mixed-servlet-scenario/src/main/java/test/apache/skywalking/apm/testcase/resttemplate/RestTemplateController.java
new file mode 100644
index 0000000000..62b93ac01a
--- /dev/null
+++
b/test/plugin/scenarios/spring-6.x-mixed-servlet-scenario/src/main/java/test/apache/skywalking/apm/testcase/resttemplate/RestTemplateController.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 test.apache.skywalking.apm.testcase.resttemplate;
+
+import java.io.IOException;
+import okhttp3.OkHttpClient;
+import okhttp3.Request;
+import okhttp3.Response;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.springframework.http.HttpEntity;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.ResponseBody;
+import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.client.RestTemplate;
+import test.apache.skywalking.apm.testcase.entity.User;
+
+@RestController
+public class RestTemplateController {
+
+ private static final String SUCCESS = "Success";
+
+ private static final Logger LOGGER =
LogManager.getLogger(RestTemplateController.class);
+
+ private static final String URL =
"http://localhost:8080/spring-6.x-mixed-servlet-scenario";
+
+ @RequestMapping("/case/resttemplate")
+ @ResponseBody
+ public String restTemplate() throws IOException {
+ Request request = new Request.Builder().header("mock_header",
"mock_value").url(URL + "/case/spring3").build();
+ Response response = new OkHttpClient().newCall(request).execute();
+ LOGGER.info(response.toString());
+
+ // Create user
+ HttpEntity<User> userEntity = new HttpEntity<>(new User(1, "a"));
+ new RestTemplate().postForEntity(URL + "/create/", userEntity,
Void.class);
+
+ // Find User
+ new RestTemplate().getForEntity(URL + "/get/{id}", User.class, 1);
+
+ //Modify user
+ HttpEntity<User> updateUserEntity = new HttpEntity<>(new User(1, "b"));
+ new RestTemplate().put(URL + "/update/{id}", updateUserEntity,
userEntity.getBody().getId(), 1);
+
+ //Delete user
+ new RestTemplate().delete(URL + "/delete/{id}", 1);
+
+ Request inheritRequest = new Request.Builder().url(URL +
"/inherit/child/test").build();
+ response = new OkHttpClient().newCall(inheritRequest).execute();
+ LOGGER.info(response.toString());
+
+ Request implRequestMappingRequest = new Request.Builder().url(URL +
"/impl/requestmapping").build();
+ response = new
OkHttpClient().newCall(implRequestMappingRequest).execute();
+ LOGGER.info(response.toString());
+
+ Request implRestMappingRequest = new Request.Builder().url(URL +
"/impl/restmapping").build();
+ response = new
OkHttpClient().newCall(implRestMappingRequest).execute();
+ LOGGER.info(response.toString());
+
+ return SUCCESS;
+ }
+
+ @RequestMapping("/healthCheck")
+ @ResponseBody
+ public String healthCheck() {
+ return SUCCESS;
+ }
+
+}
diff --git
a/test/plugin/scenarios/spring-6.x-mixed-servlet-scenario/src/main/java/test/apache/skywalking/apm/testcase/spring3/CaseController.java
b/test/plugin/scenarios/spring-6.x-mixed-servlet-scenario/src/main/java/test/apache/skywalking/apm/testcase/spring3/CaseController.java
new file mode 100644
index 0000000000..501c691579
--- /dev/null
+++
b/test/plugin/scenarios/spring-6.x-mixed-servlet-scenario/src/main/java/test/apache/skywalking/apm/testcase/spring3/CaseController.java
@@ -0,0 +1,41 @@
+/*
+ * 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 test.apache.skywalking.apm.testcase.spring3;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.ResponseBody;
+import test.apache.skywalking.apm.testcase.spring3.service.TestServiceBean;
+
+@Controller
+public class CaseController {
+
+ private static final String SUCCESS = "Success";
+
+ @Autowired
+ private TestServiceBean testServiceBean;
+
+ @RequestMapping(value = "/case/spring3")
+ @ResponseBody
+ public String updateUser() {
+ testServiceBean.doSomeBusiness("test");
+ return SUCCESS;
+ }
+}
diff --git
a/test/plugin/scenarios/spring-6.x-mixed-servlet-scenario/src/main/java/test/apache/skywalking/apm/testcase/spring3/component/TestComponentBean.java
b/test/plugin/scenarios/spring-6.x-mixed-servlet-scenario/src/main/java/test/apache/skywalking/apm/testcase/spring3/component/TestComponentBean.java
new file mode 100644
index 0000000000..274aaf490e
--- /dev/null
+++
b/test/plugin/scenarios/spring-6.x-mixed-servlet-scenario/src/main/java/test/apache/skywalking/apm/testcase/spring3/component/TestComponentBean.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 test.apache.skywalking.apm.testcase.spring3.component;
+
+import org.springframework.stereotype.Component;
+
+@Component
+public class TestComponentBean {
+
+ public String componentMethod(String name) {
+ return name + "-" + "dealWith-component";
+ }
+}
diff --git
a/test/plugin/scenarios/spring-6.x-mixed-servlet-scenario/src/main/java/test/apache/skywalking/apm/testcase/spring3/dao/TestRepositoryBean.java
b/test/plugin/scenarios/spring-6.x-mixed-servlet-scenario/src/main/java/test/apache/skywalking/apm/testcase/spring3/dao/TestRepositoryBean.java
new file mode 100644
index 0000000000..84f871ef55
--- /dev/null
+++
b/test/plugin/scenarios/spring-6.x-mixed-servlet-scenario/src/main/java/test/apache/skywalking/apm/testcase/spring3/dao/TestRepositoryBean.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 test.apache.skywalking.apm.testcase.spring3.dao;
+
+import org.springframework.stereotype.Repository;
+
+@Repository
+public class TestRepositoryBean {
+
+ public String doSomeStuff(String name) {
+ return name + "-dealWithRepository";
+ }
+}
diff --git
a/test/plugin/scenarios/spring-6.x-mixed-servlet-scenario/src/main/java/test/apache/skywalking/apm/testcase/spring3/service/TestServiceBean.java
b/test/plugin/scenarios/spring-6.x-mixed-servlet-scenario/src/main/java/test/apache/skywalking/apm/testcase/spring3/service/TestServiceBean.java
new file mode 100644
index 0000000000..811fe11648
--- /dev/null
+++
b/test/plugin/scenarios/spring-6.x-mixed-servlet-scenario/src/main/java/test/apache/skywalking/apm/testcase/spring3/service/TestServiceBean.java
@@ -0,0 +1,38 @@
+/*
+ * 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 test.apache.skywalking.apm.testcase.spring3.service;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import test.apache.skywalking.apm.testcase.spring3.dao.TestRepositoryBean;
+import test.apache.skywalking.apm.testcase.spring3.component.TestComponentBean;
+
+@Service
+public class TestServiceBean {
+ @Autowired
+ private TestComponentBean componentBean;
+
+ @Autowired
+ private TestRepositoryBean repositoryBean;
+
+ public void doSomeBusiness(String name) {
+ componentBean.componentMethod(name);
+ repositoryBean.doSomeStuff(name);
+ }
+}
diff --git
a/test/plugin/scenarios/spring-6.x-mixed-servlet-scenario/src/main/resources/log4j2.xml
b/test/plugin/scenarios/spring-6.x-mixed-servlet-scenario/src/main/resources/log4j2.xml
new file mode 100644
index 0000000000..b5cda5ae8a
--- /dev/null
+++
b/test/plugin/scenarios/spring-6.x-mixed-servlet-scenario/src/main/resources/log4j2.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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.
+ ~
+ -->
+<Configuration status="WARN">
+ <Appenders>
+ <Console name="Console" target="SYSTEM_ERR">
+ <PatternLayout charset="UTF-8" pattern="[%d{yyyy-MM-dd
HH:mm:ss:SSS}] [%p] - %l - %m%n"/>
+ </Console>
+ </Appenders>
+ <Loggers>
+ <Root level="WARN">
+ <AppenderRef ref="Console"/>
+ </Root>
+ </Loggers>
+</Configuration>
diff --git
a/test/plugin/scenarios/spring-6.x-mixed-servlet-scenario/src/main/webapp/WEB-INF/spring-mvc-servlet.xml
b/test/plugin/scenarios/spring-6.x-mixed-servlet-scenario/src/main/webapp/WEB-INF/spring-mvc-servlet.xml
new file mode 100644
index 0000000000..b8a2885d3e
--- /dev/null
+++
b/test/plugin/scenarios/spring-6.x-mixed-servlet-scenario/src/main/webapp/WEB-INF/spring-mvc-servlet.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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.
+ ~
+ -->
+
+<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:mvc="http://www.springframework.org/schema/mvc"
+ xsi:schemaLocation="http://www.springframework.org/schema/beans
+
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
+ http://www.springframework.org/schema/context
+
http://www.springframework.org/schema/context/spring-context-3.0.xsd
+ http://www.springframework.org/schema/mvc
+
http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">
+ <context:component-scan
base-package="test.apache.skywalking.apm.testcase"/>
+ <mvc:annotation-driven/>
+</beans>
\ No newline at end of file
diff --git
a/test/plugin/scenarios/spring-6.x-mixed-servlet-scenario/src/main/webapp/WEB-INF/web.xml
b/test/plugin/scenarios/spring-6.x-mixed-servlet-scenario/src/main/webapp/WEB-INF/web.xml
new file mode 100644
index 0000000000..e64a37771f
--- /dev/null
+++
b/test/plugin/scenarios/spring-6.x-mixed-servlet-scenario/src/main/webapp/WEB-INF/web.xml
@@ -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.
+ ~
+ -->
+
+<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
+ http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
+ version="3.1">
+ <display-name>skywalking-spring-6.x-mixed-servlet-scenario</display-name>
+
+ <servlet>
+ <servlet-name>spring-mvc</servlet-name>
+
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
+ <load-on-startup>1</load-on-startup>
+ </servlet>
+ <servlet-mapping>
+ <servlet-name>spring-mvc</servlet-name>
+ <url-pattern>/</url-pattern>
+ </servlet-mapping>
+</web-app>
diff --git a/test/plugin/scenarios/tomcat-10x-scenario/configuration.yml
b/test/plugin/scenarios/spring-6.x-mixed-servlet-scenario/support-version.list
similarity index 69%
copy from test/plugin/scenarios/tomcat-10x-scenario/configuration.yml
copy to
test/plugin/scenarios/spring-6.x-mixed-servlet-scenario/support-version.list
index fac58bdfd1..845ea5eb10 100644
--- a/test/plugin/scenarios/tomcat-10x-scenario/configuration.yml
+++
b/test/plugin/scenarios/spring-6.x-mixed-servlet-scenario/support-version.list
@@ -14,6 +14,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-type: tomcat
-entryService:
http://localhost:8080/tomcat-10x-scenario/case/tomcat-10x-scenario
-healthCheck: http://localhost:8080/tomcat-10x-scenario/case/healthCheck
+# Single version by design: this scenario tests the mixed javax+jakarta
CLASSPATH
+# condition (issue #13938), which is resolved by servlet-commons' runtime
instanceof
+# dispatch and is independent of the Spring version. Version compatibility
across
+# 6.0/6.1/6.2 is already covered by spring-6.x-scenario. Do NOT expand this
list.
+6.2.19
diff --git a/test/plugin/scenarios/tomcat-10x-scenario/config/expectedData.yaml
b/test/plugin/scenarios/tomcat-10x-scenario/config/expectedData.yaml
index dc03590cdd..030fc841ae 100644
--- a/test/plugin/scenarios/tomcat-10x-scenario/config/expectedData.yaml
+++ b/test/plugin/scenarios/tomcat-10x-scenario/config/expectedData.yaml
@@ -34,6 +34,8 @@ segmentItems:
tags:
- {key: url, value:
'http://localhost:8080/tomcat-10x-scenario/case/tomcat-10x-scenario'}
- {key: http.method, value: POST}
+ - {key: http.params, value: 'q1=[v1]'}
+ - {key: http.headers, value: 'mock_header=[mock_value]'}
- {key: http.status_code, value: "200"}
refs:
- {parentEndpoint: 'GET:/tomcat-10x-scenario/case/tomcat-10x-scenario',
networkAddress: 'localhost:8080',
@@ -55,7 +57,7 @@ segmentItems:
peer: localhost:8080
skipAnalysis: false
tags:
- - {key: url, value:
'http://localhost:8080/tomcat-10x-scenario/case/tomcat-10x-scenario'}
+ - {key: url, value:
'http://localhost:8080/tomcat-10x-scenario/case/tomcat-10x-scenario?q1=v1'}
- {key: http.method, value: POST}
- {key: http.status_code, value: "200"}
- operationName: GET:/tomcat-10x-scenario/case/tomcat-10x-scenario
diff --git a/test/plugin/scenarios/tomcat-10x-scenario/configuration.yml
b/test/plugin/scenarios/tomcat-10x-scenario/configuration.yml
index fac58bdfd1..f28e57d9e7 100644
--- a/test/plugin/scenarios/tomcat-10x-scenario/configuration.yml
+++ b/test/plugin/scenarios/tomcat-10x-scenario/configuration.yml
@@ -17,3 +17,5 @@
type: tomcat
entryService:
http://localhost:8080/tomcat-10x-scenario/case/tomcat-10x-scenario
healthCheck: http://localhost:8080/tomcat-10x-scenario/case/healthCheck
+environment:
+ - CATALINA_OPTS="-Dskywalking.plugin.http.include_http_headers=mock_header
-Dskywalking.plugin.tomcat.collect_http_params=true"
diff --git
a/test/plugin/scenarios/tomcat-10x-scenario/src/main/java/org/apache/skywalking/apm/testcase/tomcat10x/CaseServlet.java
b/test/plugin/scenarios/tomcat-10x-scenario/src/main/java/org/apache/skywalking/apm/testcase/tomcat10x/CaseServlet.java
index 441f4e0e0b..78da65ec8a 100644
---
a/test/plugin/scenarios/tomcat-10x-scenario/src/main/java/org/apache/skywalking/apm/testcase/tomcat10x/CaseServlet.java
+++
b/test/plugin/scenarios/tomcat-10x-scenario/src/main/java/org/apache/skywalking/apm/testcase/tomcat10x/CaseServlet.java
@@ -37,7 +37,10 @@ public class CaseServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
- HttpPost httpPost = new
HttpPost("http://localhost:8080/tomcat-10x-scenario/case/tomcat-10x-scenario");
+ // Carry a query param and a header so the receiving Tomcat entry
span (doPost) exercises
+ // the tomcat-plugin's http.params + http.headers collection (see
configuration.yml).
+ HttpPost httpPost = new
HttpPost("http://localhost:8080/tomcat-10x-scenario/case/tomcat-10x-scenario?q1=v1");
+ httpPost.setHeader("mock_header", "mock_value");
ResponseHandler<String> responseHandler = response -> {
HttpEntity entity = response.getEntity();
return entity != null ? EntityUtils.toString(entity) : null;
diff --git a/test/plugin/scenarios/tomcat-9x-scenario/config/expectedData.yaml
b/test/plugin/scenarios/tomcat-9x-scenario/config/expectedData.yaml
index 10bd8bee30..2737cc9ca5 100644
--- a/test/plugin/scenarios/tomcat-9x-scenario/config/expectedData.yaml
+++ b/test/plugin/scenarios/tomcat-9x-scenario/config/expectedData.yaml
@@ -34,6 +34,8 @@ segmentItems:
tags:
- {key: url, value:
'http://localhost:8080/tomcat-9x-scenario/case/tomcat-9x-scenario'}
- {key: http.method, value: POST}
+ - {key: http.params, value: 'q1=[v1]'}
+ - {key: http.headers, value: 'mock_header=[mock_value]'}
- {key: http.status_code, value: "200"}
refs:
- {parentEndpoint: 'GET:/tomcat-9x-scenario/case/tomcat-9x-scenario',
networkAddress: 'localhost:8080',
@@ -55,7 +57,7 @@ segmentItems:
peer: localhost:8080
skipAnalysis: false
tags:
- - {key: url, value:
'http://localhost:8080/tomcat-9x-scenario/case/tomcat-9x-scenario'}
+ - {key: url, value:
'http://localhost:8080/tomcat-9x-scenario/case/tomcat-9x-scenario?q1=v1'}
- {key: http.method, value: POST}
- {key: http.status_code, value: "200"}
- operationName: GET:/tomcat-9x-scenario/case/tomcat-9x-scenario
diff --git a/test/plugin/scenarios/tomcat-9x-scenario/configuration.yml
b/test/plugin/scenarios/tomcat-9x-scenario/configuration.yml
index 523a817486..b345aba8f7 100644
--- a/test/plugin/scenarios/tomcat-9x-scenario/configuration.yml
+++ b/test/plugin/scenarios/tomcat-9x-scenario/configuration.yml
@@ -17,3 +17,5 @@
type: tomcat
entryService: http://localhost:8080/tomcat-9x-scenario/case/tomcat-9x-scenario
healthCheck: http://localhost:8080/tomcat-9x-scenario/case/healthCheck
+environment:
+ - CATALINA_OPTS="-Dskywalking.plugin.http.include_http_headers=mock_header
-Dskywalking.plugin.tomcat.collect_http_params=true"
diff --git
a/test/plugin/scenarios/tomcat-9x-scenario/src/main/java/org/apache/skywalking/apm/testcase/tomcat9x/CaseServlet.java
b/test/plugin/scenarios/tomcat-9x-scenario/src/main/java/org/apache/skywalking/apm/testcase/tomcat9x/CaseServlet.java
index 9b47be8639..e9dc5969c9 100644
---
a/test/plugin/scenarios/tomcat-9x-scenario/src/main/java/org/apache/skywalking/apm/testcase/tomcat9x/CaseServlet.java
+++
b/test/plugin/scenarios/tomcat-9x-scenario/src/main/java/org/apache/skywalking/apm/testcase/tomcat9x/CaseServlet.java
@@ -37,7 +37,10 @@ public class CaseServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
- HttpPost httpPost = new
HttpPost("http://localhost:8080/tomcat-9x-scenario/case/tomcat-9x-scenario");
+ // Carry a query param and a header so the receiving Tomcat entry
span (doPost) exercises
+ // the tomcat-plugin's http.params + http.headers collection (see
configuration.yml).
+ HttpPost httpPost = new
HttpPost("http://localhost:8080/tomcat-9x-scenario/case/tomcat-9x-scenario?q1=v1");
+ httpPost.setHeader("mock_header", "mock_value");
ResponseHandler<String> responseHandler = response -> {
HttpEntity entity = response.getEntity();
return entity != null ? EntityUtils.toString(entity) : null;