This is an automated email from the ASF dual-hosted git repository.

wusheng pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/skywalking.git


The following commit(s) were added to refs/heads/master by this push:
     new dd6f439  support collecting feign params (#5235)
dd6f439 is described below

commit dd6f439df1c9d722dccb45eae4e040609a65ca12
Author: zshit <[email protected]>
AuthorDate: Thu Aug 6 13:09:31 2020 +0800

    support collecting feign params (#5235)
---
 .../apm/agent/core/context/tag/Tags.java           |  2 +
 .../http/v9/DefaultHttpClientInterceptor.java      | 32 +++++++++++++++
 .../plugin/feign/http/v9/FeignPluginConfig.java    | 45 ++++++++++++++++++++++
 docs/en/setup/service-agent/java-agent/README.md   |  3 ++
 .../plugin/scenarios/feign-scenario/bin/startup.sh |  4 +-
 .../feign-scenario/config/expectedData.yaml        | 43 ++++++++++++++++++++-
 .../testcase/feign/controller/CaseController.java  |  1 +
 .../testcase/feign/controller/RestController.java  |  8 ++++
 .../apm/testcase/feign/controller/RestRequest.java |  5 +++
 9 files changed, 139 insertions(+), 4 deletions(-)

diff --git 
a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/tag/Tags.java
 
b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/tag/Tags.java
index 7ddb592..5795277 100644
--- 
a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/tag/Tags.java
+++ 
b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/tag/Tags.java
@@ -81,6 +81,8 @@ public final class Tags {
         public static final StringTag METHOD = new StringTag(10, 
"http.method");
 
         public static final StringTag PARAMS = new StringTag(11, 
"http.params", true);
+
+        public static final StringTag BODY = new StringTag(13, "http.body");
     }
 
     public static final StringTag LOGIC_ENDPOINT = new StringTag(12, "x-le");
diff --git 
a/apm-sniffer/apm-sdk-plugin/feign-default-http-9.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/feign/http/v9/DefaultHttpClientInterceptor.java
 
b/apm-sniffer/apm-sdk-plugin/feign-default-http-9.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/feign/http/v9/DefaultHttpClientInterceptor.java
index bb87886..6bd87ac 100644
--- 
a/apm-sniffer/apm-sdk-plugin/feign-default-http-9.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/feign/http/v9/DefaultHttpClientInterceptor.java
+++ 
b/apm-sniffer/apm-sdk-plugin/feign-default-http-9.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/feign/http/v9/DefaultHttpClientInterceptor.java
@@ -20,6 +20,7 @@ package org.apache.skywalking.apm.plugin.feign.http.v9;
 
 import feign.Request;
 import feign.Response;
+import java.util.Iterator;
 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;
@@ -41,12 +42,17 @@ import java.util.LinkedHashMap;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
+import org.apache.skywalking.apm.util.StringUtil;
+
+import static feign.Util.valuesOrEmpty;
 
 /**
  * {@link DefaultHttpClientInterceptor} intercept the default implementation 
of http calls by the Feign.
  */
 public class DefaultHttpClientInterceptor implements 
InstanceMethodsAroundInterceptor {
 
+    private static final String CONTENT_TYPE_HEADER = "Content-Type";
+
     /**
      * Get the {@link feign.Request} from {@link EnhancedInstance}, then 
create {@link AbstractSpan} and set host, port,
      * kind, component, url from {@link feign.Request}. Through the reflection 
of the way, set the http header of
@@ -82,6 +88,21 @@ public class DefaultHttpClientInterceptor implements 
InstanceMethodsAroundInterc
         Tags.URL.set(span, request.url());
         SpanLayer.asHttp(span);
 
+        if (FeignPluginConfig.Plugin.Feign.COLLECT_REQUEST_BODY) {
+            boolean needCollectHttpBody = false;
+            Iterator<String> stringIterator = valuesOrEmpty(request.headers(), 
CONTENT_TYPE_HEADER).iterator();
+            String contentTypeHeaderValue = stringIterator.hasNext() ? 
stringIterator.next() : "";
+            for (String contentType : 
FeignPluginConfig.Plugin.Feign.SUPPORTED_CONTENT_TYPES_PREFIX.split(",")) {
+                if (contentTypeHeaderValue.startsWith(contentType)) {
+                    needCollectHttpBody = true;
+                    break;
+                }
+            }
+            if (needCollectHttpBody) {
+                collectHttpBody(request, span);
+            }
+        }
+
         Field headersField = Request.class.getDeclaredField("headers");
         Field modifiersField = Field.class.getDeclaredField("modifiers");
         modifiersField.setAccessible(true);
@@ -101,6 +122,17 @@ public class DefaultHttpClientInterceptor implements 
InstanceMethodsAroundInterc
         headersField.set(request, Collections.unmodifiableMap(headers));
     }
 
+    private void collectHttpBody(final Request request, final AbstractSpan 
span) {
+        if (request.body() == null || request.charset() == null) {
+            return;
+        }
+        String tagValue = new String(request.body(), request.charset());
+        tagValue = FeignPluginConfig.Plugin.Feign.FILTER_LENGTH_LIMIT > 0 ?
+            StringUtil.cut(tagValue, 
FeignPluginConfig.Plugin.Feign.FILTER_LENGTH_LIMIT) : tagValue;
+
+        Tags.HTTP.BODY.set(span, tagValue);
+    }
+
     /**
      * Get the status code from {@link Response}, when status code greater 
than 400, it means there was some errors in
      * the server. Finish the {@link AbstractSpan}.
diff --git 
a/apm-sniffer/apm-sdk-plugin/feign-default-http-9.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/feign/http/v9/FeignPluginConfig.java
 
b/apm-sniffer/apm-sdk-plugin/feign-default-http-9.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/feign/http/v9/FeignPluginConfig.java
new file mode 100644
index 0000000..e728f76
--- /dev/null
+++ 
b/apm-sniffer/apm-sdk-plugin/feign-default-http-9.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/feign/http/v9/FeignPluginConfig.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.feign.http.v9;
+
+import org.apache.skywalking.apm.agent.core.boot.PluginConfig;
+
+public class FeignPluginConfig {
+    public static class Plugin {
+        @PluginConfig(root = FeignPluginConfig.class)
+        public static class Feign {
+            /**
+             * This config item controls that whether the Feign plugin should 
collect the http body of the request.
+             */
+            public static boolean COLLECT_REQUEST_BODY = false;
+
+            /**
+             * When either {@link Plugin.Feign#COLLECT_REQUEST_BODY} is 
enabled, how many characters to keep and send to the OAP
+             * backend, use negative values to keep and send the complete body.
+             */
+            public static int FILTER_LENGTH_LIMIT = 1024;
+
+            /**
+             * When either {@link Plugin.Feign#COLLECT_REQUEST_BODY} is 
enabled and content-type start with SUPPORTED_CONTENT_TYPES_PREFIX, collect the 
body of the request
+             */
+            public static String SUPPORTED_CONTENT_TYPES_PREFIX = 
"application/json,text/";
+        }
+    }
+}
+
diff --git a/docs/en/setup/service-agent/java-agent/README.md 
b/docs/en/setup/service-agent/java-agent/README.md
index ba122cc..3a1783d 100755
--- a/docs/en/setup/service-agent/java-agent/README.md
+++ b/docs/en/setup/service-agent/java-agent/README.md
@@ -131,6 +131,9 @@ property key | Description | Default |
 `plugin.tomcat.collect_http_params`| This config item controls that whether 
the Tomcat plugin should collect the parameters of the request. Also, activate 
implicitly in the profiled trace. | `false` |
 `plugin.springmvc.collect_http_params`| 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. | `false` |
 `plugin.http.http_params_length_threshold`| 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.  | `1024` |
+`plugin.feign.collect_request_body`| This config item controls that whether 
the Feign plugin should collect the http body of the request. | `false` |
+`plugin.feign.filter_length_limit`| When `COLLECT_REQUEST_BODY` is enabled, 
how many characters to keep and send to the OAP backend, use negative values to 
keep and send the complete body.  | `1024` |
+`plugin.feign.supported_content_types_prefix`| When `COLLECT_REQUEST_BODY` is 
enabled and content-type start with SUPPORTED_CONTENT_TYPES_PREFIX, collect the 
body of the request , multiple paths should be separated by `,`  | 
`application/json,text/` |
 `plugin.influxdb.trace_influxql`|If true, trace all the influxql(query and 
write) in InfluxDB access, default is true.|`true`|
 `correlation.element_max_number`|Max element count of the correlation 
context.|`3`|
 `correlation.value_max_length`|Max value length of correlation context 
element.|`128`|
diff --git a/test/plugin/scenarios/feign-scenario/bin/startup.sh 
b/test/plugin/scenarios/feign-scenario/bin/startup.sh
index 671bec9..6ae5fbb 100644
--- a/test/plugin/scenarios/feign-scenario/bin/startup.sh
+++ b/test/plugin/scenarios/feign-scenario/bin/startup.sh
@@ -17,5 +17,5 @@
 # limitations under the License.
 
 home="$(cd "$(dirname $0)"; pwd)"
-
-java -jar ${agent_opts} ${home}/../libs/feign-scenario.jar &
\ No newline at end of file
+java -jar ${agent_opts} -Dskywalking.plugin.feign.collect_request_body=true \
+-Dskywalking.plugin.feign.supported_content_types_prefix='application/json,text/'
 ${home}/../libs/feign-scenario.jar &
\ No newline at end of file
diff --git a/test/plugin/scenarios/feign-scenario/config/expectedData.yaml 
b/test/plugin/scenarios/feign-scenario/config/expectedData.yaml
index 6015330..d56703b 100644
--- a/test/plugin/scenarios/feign-scenario/config/expectedData.yaml
+++ b/test/plugin/scenarios/feign-scenario/config/expectedData.yaml
@@ -82,6 +82,27 @@ segmentItems:
       skipAnalysis: 'false'
   - segmentId: not null
     spans:
+      - operationName: /feign-scenario/modify/1
+        operationId: 0
+        parentSpanId: -1
+        spanId: 0
+        spanLayer: Http
+        startTime: nq 0
+        endTime: nq 0
+        componentId: 1
+        isError: false
+        spanType: Entry
+        peer: ''
+        tags:
+          - {key: url, value: 'http://localhost:8080/feign-scenario/modify/1'}
+          - {key: http.method, value: PUT}
+        refs:
+          - {parentEndpoint: /feign-scenario/case/feign-scenario, 
networkAddress: 'localhost:8080',
+             refType: CrossProcess, parentSpanId: 4, parentTraceSegmentId: not 
null, parentServiceInstance: not
+                                                                               
        null, parentService: feign-scenario, traceId: not null}
+        skipAnalysis: 'false'
+  - segmentId: not null
+    spans:
     - operationName: /feign-scenario/delete/1
       operationId: 0
       parentSpanId: -1
@@ -98,7 +119,7 @@ segmentItems:
       - {key: http.method, value: DELETE}
       refs:
       - {parentEndpoint: /feign-scenario/case/feign-scenario, networkAddress: 
'localhost:8080',
-        refType: CrossProcess, parentSpanId: 4, parentTraceSegmentId: not 
null, parentServiceInstance: not
+        refType: CrossProcess, parentSpanId: 5, parentTraceSegmentId: not 
null, parentServiceInstance: not
           null, parentService: feign-scenario, traceId: not null}
       skipAnalysis: 'false'
   - segmentId: not null
@@ -117,6 +138,7 @@ segmentItems:
       tags:
       - {key: http.method, value: POST}
       - {key: url, value: 'http://localhost:8080/feign-scenario/create/'}
+      - {key: http.body, value: '{"id": "1", "userName": "test"}'}
       skipAnalysis: 'false'
     - operationName: /feign-scenario/get/{id}
       operationId: 0
@@ -147,8 +169,9 @@ segmentItems:
       tags:
       - {key: http.method, value: PUT}
       - {key: url, value: 'http://localhost:8080/feign-scenario/update/1'}
+      - {key: http.body, value: '{"id": "1", "userName": "testA"}'}
       skipAnalysis: 'false'
-    - operationName: /feign-scenario/delete/{id}
+    - operationName: /feign-scenario/modify/{id}
       operationId: 0
       parentSpanId: 0
       spanId: 4
@@ -160,6 +183,22 @@ segmentItems:
       spanType: Exit
       peer: localhost:8080
       tags:
+        - {key: http.method, value: PUT}
+        - {key: url, value: 'http://localhost:8080/feign-scenario/modify/1'}
+        - {key: http.body, value: testA}
+      skipAnalysis: 'false'
+    - operationName: /feign-scenario/delete/{id}
+      operationId: 0
+      parentSpanId: 0
+      spanId: 5
+      spanLayer: Http
+      startTime: nq 0
+      endTime: nq 0
+      componentId: 11
+      isError: false
+      spanType: Exit
+      peer: localhost:8080
+      tags:
       - {key: http.method, value: DELETE}
       - {key: url, value: 'http://localhost:8080/feign-scenario/delete/1'}
       skipAnalysis: 'false'
diff --git 
a/test/plugin/scenarios/feign-scenario/src/main/java/org/apache/skywalking/apm/testcase/feign/controller/CaseController.java
 
b/test/plugin/scenarios/feign-scenario/src/main/java/org/apache/skywalking/apm/testcase/feign/controller/CaseController.java
index fe30ff9..82d2b37 100644
--- 
a/test/plugin/scenarios/feign-scenario/src/main/java/org/apache/skywalking/apm/testcase/feign/controller/CaseController.java
+++ 
b/test/plugin/scenarios/feign-scenario/src/main/java/org/apache/skywalking/apm/testcase/feign/controller/CaseController.java
@@ -45,6 +45,7 @@ public class CaseController {
         User user = request.getById(1);
         logger.info("find Id{} user. User name is {} ", user.getId(), 
user.getUserName());
         request.updateUser(1, "testA");
+        request.modifyUser(1, "testA");
         request.deleteUser(1);
         return "success";
     }
diff --git 
a/test/plugin/scenarios/feign-scenario/src/main/java/org/apache/skywalking/apm/testcase/feign/controller/RestController.java
 
b/test/plugin/scenarios/feign-scenario/src/main/java/org/apache/skywalking/apm/testcase/feign/controller/RestController.java
index f3bdcb0..2165e11 100644
--- 
a/test/plugin/scenarios/feign-scenario/src/main/java/org/apache/skywalking/apm/testcase/feign/controller/RestController.java
+++ 
b/test/plugin/scenarios/feign-scenario/src/main/java/org/apache/skywalking/apm/testcase/feign/controller/RestController.java
@@ -64,6 +64,14 @@ public class RestController {
         return ResponseEntity.ok(currentUser);
     }
 
+    @PutMapping(value = "/modify/{id}")
+    @ResponseBody
+    public ResponseEntity<User> modify(@PathVariable("id") int id,
+                                           @RequestBody String userName) 
throws InterruptedException {
+        User currentUser = new User(id, userName);
+        return ResponseEntity.ok(currentUser);
+    }
+
     @DeleteMapping(value = "/delete/{id}")
     @ResponseBody
     public ResponseEntity<User> deleteUser(@PathVariable("id") int id) throws 
InterruptedException {
diff --git 
a/test/plugin/scenarios/feign-scenario/src/main/java/org/apache/skywalking/apm/testcase/feign/controller/RestRequest.java
 
b/test/plugin/scenarios/feign-scenario/src/main/java/org/apache/skywalking/apm/testcase/feign/controller/RestRequest.java
index 04596f7..30fe0a1 100644
--- 
a/test/plugin/scenarios/feign-scenario/src/main/java/org/apache/skywalking/apm/testcase/feign/controller/RestRequest.java
+++ 
b/test/plugin/scenarios/feign-scenario/src/main/java/org/apache/skywalking/apm/testcase/feign/controller/RestRequest.java
@@ -43,6 +43,11 @@ public interface RestRequest {
     @Body("%7B\"id\": \"{id}\", \"userName\": \"{userName}\"%7D")
     User updateUser(@Param("id") int id, @Param("userName") String userName);
 
+    @RequestLine("PUT /modify/{id}")
+    @Headers("Content-Type: text/plain")
+    @Body("{userName}")
+    User modifyUser(@Param("id") int id, @Param("userName") String userName);
+
     @RequestLine("DELETE /delete/{id}")
     void deleteUser(@Param("id") int id);
 

Reply via email to