diff --git a/CHANGES.md b/CHANGES.md index 163c07732baf9ef9f08fb71a0d3d8898e3254415..7fff1356c1e641c001f97bfa8331f37894915931 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -7,6 +7,7 @@ Release Notes. #### Project #### Java Agent +* Make HttpClient 3.x, 4.x, and HttpAsyncClient 3.x plugins to support collecting HTTP parameters. * Make the Feign plugin to support Java 14 * Make the okhttp3 plugin to support Java 14 diff --git a/apm-sniffer/apm-sdk-plugin/httpClient-4.x-plugin/pom.xml b/apm-sniffer/apm-sdk-plugin/httpClient-4.x-plugin/pom.xml index 307cb28351cadb96c959f65c6d2c5ca9b2fe9cdf..5fd641b5fec552f2b75da1068c91d8615ad1c6ac 100644 --- a/apm-sniffer/apm-sdk-plugin/httpClient-4.x-plugin/pom.xml +++ b/apm-sniffer/apm-sdk-plugin/httpClient-4.x-plugin/pom.xml @@ -45,6 +45,12 @@ provided + + org.apache.skywalking + apm-httpclient-commons + ${project.version} + provided + junit diff --git a/apm-sniffer/apm-sdk-plugin/httpClient-4.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/httpClient/v4/HttpClientExecuteInterceptor.java b/apm-sniffer/apm-sdk-plugin/httpClient-4.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/httpClient/v4/HttpClientExecuteInterceptor.java index d84f862665f3afa5111e5645966195245fc91a6b..38edb702df74d8e604aa8c16726a79ceab6ac419 100644 --- a/apm-sniffer/apm-sdk-plugin/httpClient-4.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/httpClient/v4/HttpClientExecuteInterceptor.java +++ b/apm-sniffer/apm-sdk-plugin/httpClient-4.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/httpClient/v4/HttpClientExecuteInterceptor.java @@ -20,11 +20,14 @@ package org.apache.skywalking.apm.plugin.httpClient.v4; import java.lang.reflect.Method; import java.net.MalformedURLException; +import java.net.URI; import java.net.URL; + import org.apache.http.HttpHost; import org.apache.http.HttpRequest; import org.apache.http.HttpResponse; import org.apache.http.StatusLine; +import org.apache.http.client.methods.HttpUriRequest; 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; @@ -35,12 +38,14 @@ import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedI 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.httpclient.HttpClientPluginConfig; +import org.apache.skywalking.apm.util.StringUtil; public class HttpClientExecuteInterceptor implements InstanceMethodsAroundInterceptor { @Override public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class[] argumentsTypes, - MethodInterceptResult result) throws Throwable { + MethodInterceptResult result) throws Throwable { if (allArguments[0] == null || allArguments[1] == null) { // illegal args, can't trace. ignore. return; @@ -66,11 +71,14 @@ public class HttpClientExecuteInterceptor implements InstanceMethodsAroundInterc next = next.next(); httpRequest.setHeader(next.getHeadKey(), next.getHeadValue()); } + if (HttpClientPluginConfig.Plugin.HttpClient.COLLECT_HTTP_PARAMS) { + collectHttpParam(httpRequest, span); + } } @Override public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class[] argumentsTypes, - Object ret) throws Throwable { + Object ret) throws Throwable { if (allArguments[0] == null || allArguments[1] == null) { return ret; } @@ -85,6 +93,11 @@ public class HttpClientExecuteInterceptor implements InstanceMethodsAroundInterc span.errorOccurred(); Tags.STATUS_CODE.set(span, Integer.toString(statusCode)); } + HttpRequest httpRequest = (HttpRequest) allArguments[1]; + // Active HTTP parameter collection automatically in the profiling context. + if (!HttpClientPluginConfig.Plugin.HttpClient.COLLECT_HTTP_PARAMS && span.isProfiling()) { + collectHttpParam(httpRequest, span); + } } } @@ -94,7 +107,7 @@ public class HttpClientExecuteInterceptor implements InstanceMethodsAroundInterc @Override public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments, - Class[] argumentsTypes, Throwable t) { + Class[] argumentsTypes, Throwable t) { AbstractSpan activeSpan = ContextManager.activeSpan(); activeSpan.log(t); } @@ -132,4 +145,17 @@ public class HttpClientExecuteInterceptor implements InstanceMethodsAroundInterc int port = httpHost.getPort(); return port > 0 ? port : "https".equals(httpHost.getSchemeName().toLowerCase()) ? 443 : 80; } + + private void collectHttpParam(HttpRequest httpRequest, AbstractSpan span) { + if (httpRequest instanceof HttpUriRequest) { + URI uri = ((HttpUriRequest) httpRequest).getURI(); + String tagValue = uri.getQuery(); + if (StringUtil.isNotEmpty(tagValue)) { + tagValue = HttpClientPluginConfig.Plugin.Http.HTTP_PARAMS_LENGTH_THRESHOLD > 0 ? + StringUtil.cut(tagValue, HttpClientPluginConfig.Plugin.Http.HTTP_PARAMS_LENGTH_THRESHOLD) : + tagValue; + Tags.HTTP.PARAMS.set(span, tagValue); + } + } + } } diff --git a/apm-sniffer/apm-sdk-plugin/httpClient-4.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/httpClient/v4/HttpClientExecuteInterceptorTest.java b/apm-sniffer/apm-sdk-plugin/httpClient-4.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/httpClient/v4/HttpClientExecuteInterceptorTest.java index 7270989837ebd9235df6917f1d4fbcfee68d1bef..4e139e735ae6431d5a0fe40c626722fb484f7927 100644 --- a/apm-sniffer/apm-sdk-plugin/httpClient-4.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/httpClient/v4/HttpClientExecuteInterceptorTest.java +++ b/apm-sniffer/apm-sdk-plugin/httpClient-4.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/httpClient/v4/HttpClientExecuteInterceptorTest.java @@ -18,13 +18,14 @@ package org.apache.skywalking.apm.plugin.httpClient.v4; +import java.net.URI; import java.util.List; import org.apache.http.HttpHost; -import org.apache.http.HttpRequest; 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.AbstractTracingSpan; import org.apache.skywalking.apm.agent.core.context.trace.LogDataEntity; @@ -37,6 +38,7 @@ 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.hamcrest.CoreMatchers; import org.junit.Assert; import org.junit.Before; @@ -72,7 +74,7 @@ public class HttpClientExecuteInterceptorTest { @Mock private HttpHost httpHost; @Mock - private HttpRequest request; + private HttpGet request; @Mock private HttpResponse httpResponse; @Mock @@ -89,6 +91,7 @@ public class HttpClientExecuteInterceptorTest { ServiceManager.INSTANCE.boot(); httpClientExecuteInterceptor = new HttpClientExecuteInterceptor(); + HttpClientPluginConfig.Plugin.HttpClient.COLLECT_HTTP_PARAMS = true; PowerMockito.mock(HttpHost.class); when(statusLine.getStatusCode()).thenReturn(200); @@ -112,6 +115,7 @@ public class HttpClientExecuteInterceptorTest { } }); when(httpHost.getPort()).thenReturn(8080); + when(request.getURI()).thenReturn(new URI("http://127.0.0.1:8080/test-web/test?a=1&b=test")); allArguments = new Object[] { httpHost, @@ -149,8 +153,8 @@ public class HttpClientExecuteInterceptorTest { assertThat(spans.size(), is(1)); List tags = SpanHelper.getTags(spans.get(0)); - assertThat(tags.size(), is(3)); - assertThat(tags.get(2).getValue(), is("500")); + assertThat(tags.size(), is(4)); + assertThat(tags.get(3).getValue(), is("500")); assertHttpSpan(spans.get(0)); assertThat(SpanHelper.getErrorOccurred(spans.get(0)), is(true)); @@ -223,6 +227,7 @@ public class HttpClientExecuteInterceptorTest { List tags = SpanHelper.getTags(span); assertThat(tags.get(0).getValue(), is("http://127.0.0.1:8080/test-web/test")); assertThat(tags.get(1).getValue(), is("GET")); + assertThat(tags.get(2).getValue(), is("a=1&b=test")); assertThat(span.isExit(), is(true)); } 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 356cfdb3d2e0f125e9982d769f1ca50a8d798abf..46c97f5e7dc233f5189caba30a41d44f16718bcc 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 @@ -42,5 +42,11 @@ ${apache-httpasyncclient.version} provided + + org.apache.skywalking + apm-httpclient-commons + ${project.version} + provided + diff --git a/apm-sniffer/apm-sdk-plugin/httpasyncclient-4.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/httpasyncclient/v4/HttpAsyncRequestExecutorInterceptor.java b/apm-sniffer/apm-sdk-plugin/httpasyncclient-4.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/httpasyncclient/v4/HttpAsyncRequestExecutorInterceptor.java index 0df1d23fbef15f21fae4e6f151f0e49b5c5f3516..f89409eac979eca325a7e2d781c7441c1ef03cd4 100644 --- a/apm-sniffer/apm-sdk-plugin/httpasyncclient-4.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/httpasyncclient/v4/HttpAsyncRequestExecutorInterceptor.java +++ b/apm-sniffer/apm-sdk-plugin/httpasyncclient-4.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/httpasyncclient/v4/HttpAsyncRequestExecutorInterceptor.java @@ -32,8 +32,11 @@ import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedI 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.httpclient.HttpClientPluginConfig; +import org.apache.skywalking.apm.util.StringUtil; import java.lang.reflect.Method; +import java.net.URI; import java.net.URL; import static org.apache.skywalking.apm.plugin.httpasyncclient.v4.SessionRequestCompleteInterceptor.CONTEXT_LOCAL; @@ -69,6 +72,9 @@ public class HttpAsyncRequestExecutorInterceptor implements InstanceMethodsAroun next = next.next(); requestWrapper.setHeader(next.getHeadKey(), next.getHeadValue()); } + if (HttpClientPluginConfig.Plugin.HttpClient.COLLECT_HTTP_PARAMS) { + collectHttpParam(requestWrapper.getURI(), span); + } } @Override @@ -82,4 +88,17 @@ public class HttpAsyncRequestExecutorInterceptor implements InstanceMethodsAroun Class[] argumentsTypes, Throwable t) { } + + private void collectHttpParam(URI uri, AbstractSpan span) { + if (uri == null) { + return; + } + String tagValue = uri.getQuery(); + if (StringUtil.isNotEmpty(tagValue)) { + tagValue = HttpClientPluginConfig.Plugin.Http.HTTP_PARAMS_LENGTH_THRESHOLD > 0 ? + StringUtil.cut(tagValue, HttpClientPluginConfig.Plugin.Http.HTTP_PARAMS_LENGTH_THRESHOLD) : + tagValue; + Tags.HTTP.PARAMS.set(span, tagValue); + } + } } diff --git a/apm-sniffer/apm-sdk-plugin/httpasyncclient-4.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/httpasyncclient/v4/HttpAsyncClientInterceptorTest.java b/apm-sniffer/apm-sdk-plugin/httpasyncclient-4.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/httpasyncclient/v4/HttpAsyncClientInterceptorTest.java index d2efaa13a406659b26c746a13b1d1e9ea6c2f5e5..ed306300b28b5a809318bedac5a75bfc4fbd60f7 100644 --- a/apm-sniffer/apm-sdk-plugin/httpasyncclient-4.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/httpasyncclient/v4/HttpAsyncClientInterceptorTest.java +++ b/apm-sniffer/apm-sdk-plugin/httpasyncclient-4.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/httpasyncclient/v4/HttpAsyncClientInterceptorTest.java @@ -17,6 +17,7 @@ package org.apache.skywalking.apm.plugin.httpasyncclient.v4; +import java.net.URI; import java.util.List; import org.apache.http.HttpHost; import org.apache.http.HttpResponse; @@ -47,6 +48,7 @@ import org.apache.skywalking.apm.agent.test.tools.SegmentStoragePoint; import org.apache.skywalking.apm.agent.test.tools.TracingSegmentRunner; import org.apache.skywalking.apm.plugin.httpasyncclient.v4.wrapper.FutureCallbackWrapper; import org.apache.skywalking.apm.plugin.httpasyncclient.v4.wrapper.HttpAsyncResponseConsumerWrapper; +import org.apache.skywalking.apm.plugin.httpclient.HttpClientPluginConfig; import org.junit.Assert; import org.junit.Before; import org.junit.Rule; @@ -119,6 +121,7 @@ public class HttpAsyncClientInterceptorTest { httpContext.setAttribute(HttpClientContext.HTTP_REQUEST, requestWrapper); httpContext.setAttribute(HttpClientContext.HTTP_TARGET_HOST, httpHost); CONTEXT_LOCAL.set(httpContext); + HttpClientPluginConfig.Plugin.HttpClient.COLLECT_HTTP_PARAMS = true; when(httpHost.getHostName()).thenReturn("127.0.0.1"); when(httpHost.getSchemeName()).thenReturn("http"); @@ -158,6 +161,7 @@ public class HttpAsyncClientInterceptorTest { when(requestWrapper.getRequestLine()).thenReturn(requestLine); when(requestWrapper.getOriginal()).thenReturn(new HttpGet("http://localhost:8081/original/test")); + when(requestWrapper.getURI()).thenReturn(new URI("http://localhost:8081/original/test?a=1&b=test")); when(httpHost.getPort()).thenReturn(8080); enhancedInstance = new EnhancedInstance() { @@ -266,6 +270,7 @@ public class HttpAsyncClientInterceptorTest { List tags = SpanHelper.getTags(span); assertThat(tags.get(0).getValue(), is("http://localhost:8081/original/test")); assertThat(tags.get(1).getValue(), is("GET")); + assertThat(tags.get(2).getValue(), is("a=1&b=test")); assertThat(span.isExit(), is(true)); } 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 322f71faa37a32a86842648f3ae4d2ce9546ffbc..65895f1e869fb2030a6c79a68565cfd296a27ca9 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 @@ -44,5 +44,11 @@ ${commons-httpclient.version} provided + + org.apache.skywalking + apm-httpclient-commons + ${project.version} + provided + diff --git a/apm-sniffer/apm-sdk-plugin/httpclient-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/httpclient/v3/HttpClientExecuteInterceptor.java b/apm-sniffer/apm-sdk-plugin/httpclient-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/httpclient/v3/HttpClientExecuteInterceptor.java index a2a4312ef71ca21c5d9e4818f00d351fd46f8490..b23990cbaf9b19823abfbd16989bb4aa4de3e2b2 100644 --- a/apm-sniffer/apm-sdk-plugin/httpclient-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/httpclient/v3/HttpClientExecuteInterceptor.java +++ b/apm-sniffer/apm-sdk-plugin/httpclient-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/httpclient/v3/HttpClientExecuteInterceptor.java @@ -20,8 +20,6 @@ package org.apache.skywalking.apm.plugin.httpclient.v3; import java.lang.reflect.Method; -import org.apache.commons.httpclient.HostConfiguration; -import org.apache.commons.httpclient.HttpClient; import org.apache.commons.httpclient.HttpMethod; import org.apache.commons.httpclient.URI; import org.apache.commons.httpclient.URIException; @@ -35,21 +33,19 @@ import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedI 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.httpclient.HttpClientPluginConfig; +import org.apache.skywalking.apm.util.StringUtil; public class HttpClientExecuteInterceptor implements InstanceMethodsAroundInterceptor { @Override public void beforeMethod(final EnhancedInstance objInst, final Method method, final Object[] allArguments, - final Class[] argumentsTypes, final MethodInterceptResult result) throws Throwable { - - final HttpClient client = (HttpClient) objInst; - - HostConfiguration hostConfiguration = (HostConfiguration) allArguments[0]; - if (hostConfiguration == null) { - hostConfiguration = client.getHostConfiguration(); - } + final Class[] argumentsTypes, final MethodInterceptResult result) throws Throwable { final HttpMethod httpMethod = (HttpMethod) allArguments[1]; + if (httpMethod == null) { + return; + } final String remotePeer = httpMethod.getURI().getHost() + ":" + httpMethod.getURI().getPort(); final URI uri = httpMethod.getURI(); @@ -67,12 +63,15 @@ public class HttpClientExecuteInterceptor implements InstanceMethodsAroundInterc next = next.next(); httpMethod.setRequestHeader(next.getHeadKey(), next.getHeadValue()); } + + if (HttpClientPluginConfig.Plugin.HttpClient.COLLECT_HTTP_PARAMS) { + collectHttpParam(httpMethod, span); + } } @Override public Object afterMethod(final EnhancedInstance objInst, final Method method, final Object[] allArguments, - final Class[] argumentsTypes, final Object ret) { - + final Class[] argumentsTypes, final Object ret) { if (ret != null) { final int statusCode = (Integer) ret; final AbstractSpan span = ContextManager.activeSpan(); @@ -80,15 +79,22 @@ public class HttpClientExecuteInterceptor implements InstanceMethodsAroundInterc span.errorOccurred(); Tags.STATUS_CODE.set(span, Integer.toString(statusCode)); } + final HttpMethod httpMethod = (HttpMethod) allArguments[1]; + if (httpMethod == null) { + return ret; + } + // Active HTTP parameter collection automatically in the profiling context. + if (!HttpClientPluginConfig.Plugin.HttpClient.COLLECT_HTTP_PARAMS && span.isProfiling()) { + collectHttpParam(httpMethod, span); + } } - ContextManager.stopSpan(); return ret; } @Override public void handleMethodException(final EnhancedInstance objInst, final Method method, final Object[] allArguments, - final Class[] argumentsTypes, final Throwable t) { + final Class[] argumentsTypes, final Throwable t) { ContextManager.activeSpan().log(t); } @@ -97,4 +103,13 @@ public class HttpClientExecuteInterceptor implements InstanceMethodsAroundInterc return requestPath != null && requestPath.length() > 0 ? requestPath : "/"; } + private void collectHttpParam(HttpMethod httpMethod, AbstractSpan span) { + String tagValue = httpMethod.getQueryString(); + if (StringUtil.isNotEmpty(tagValue)) { + tagValue = HttpClientPluginConfig.Plugin.Http.HTTP_PARAMS_LENGTH_THRESHOLD > 0 ? + StringUtil.cut(tagValue, HttpClientPluginConfig.Plugin.Http.HTTP_PARAMS_LENGTH_THRESHOLD) : + tagValue; + Tags.HTTP.PARAMS.set(span, tagValue); + } + } } diff --git a/apm-sniffer/apm-sdk-plugin/httpclient-commons/pom.xml b/apm-sniffer/apm-sdk-plugin/httpclient-commons/pom.xml new file mode 100644 index 0000000000000000000000000000000000000000..28daa0c383da6a67688bd94c9a68182c0dbb7606 --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/httpclient-commons/pom.xml @@ -0,0 +1,40 @@ + + + + + 4.0.0 + + apm-sdk-plugin + org.apache.skywalking + 8.3.0-SNAPSHOT + + + apm-httpclient-commons + + UTF-8 + + + + + + maven-deploy-plugin + + + + 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 new file mode 100644 index 0000000000000000000000000000000000000000..9a4a94cdb1340d83735d41e86ab9d027c0a1a2a9 --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/httpclient-commons/src/main/java/org/apache/skywalking/apm/plugin/httpclient/HttpClientPluginConfig.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.httpclient; + +import org.apache.skywalking.apm.agent.core.boot.PluginConfig; + +public class HttpClientPluginConfig { + public static class Plugin { + @PluginConfig(root = HttpClientPluginConfig.class) + 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; + } + + @PluginConfig(root = HttpClientPluginConfig.class) + public static class Http { + /** + * When either {@link HttpClient#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 + */ + public static int HTTP_PARAMS_LENGTH_THRESHOLD = 1024; + } + } +} diff --git a/apm-sniffer/apm-sdk-plugin/pom.xml b/apm-sniffer/apm-sdk-plugin/pom.xml index 907123207fbb6e30ad482df633f4e501c69a107b..679672300b79ca42eb6ee15485a770bb66a3fdc3 100644 --- a/apm-sniffer/apm-sdk-plugin/pom.xml +++ b/apm-sniffer/apm-sdk-plugin/pom.xml @@ -101,6 +101,7 @@ graphql-plugin xxl-job-2.x-plugin thrift-plugin + httpclient-commons pom diff --git a/docs/en/setup/service-agent/java-agent/README.md b/docs/en/setup/service-agent/java-agent/README.md index 44750dbdc8ba390c9b3e13008f47ce9b23e38b92..a752a2b9d0868584cff2e2246903dfe35a7fa6b8 100755 --- a/docs/en/setup/service-agent/java-agent/README.md +++ b/docs/en/setup/service-agent/java-agent/README.md @@ -133,6 +133,7 @@ property key | Description | Default | `plugin.jdkthreading.threading_class_prefixes` | Threading classes (`java.lang.Runnable` and `java.util.concurrent.Callable`) and their subclasses, including anonymous inner classes whose name match any one of the `THREADING_CLASS_PREFIXES` (splitted by `,`) will be instrumented, make sure to only specify as narrow prefixes as what you're expecting to instrument, (`java.` and `javax.` will be ignored due to safety issues) | Not set | `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.httpclient.collect_http_params`| This config item controls that whether the HttpClient plugin should collect the parameters of the request | `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.http.http_headers_length_threshold`| 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. | `2048` | `plugin.http.include_http_headers`| Set the header names, which should be collected by the plugin. Header name must follow `javax.servlet.http` definition. Multiple names should be split by comma. | ``(No header would be collected) | diff --git a/test/plugin/scenarios/httpclient-3.x-scenario/config/expectedData.yaml b/test/plugin/scenarios/httpclient-3.x-scenario/config/expectedData.yaml index 890791b19b03001da2afe289618877af20cda499..bef00d4f50e229cc3a4c0833ee05ebd7426a6526 100644 --- a/test/plugin/scenarios/httpclient-3.x-scenario/config/expectedData.yaml +++ b/test/plugin/scenarios/httpclient-3.x-scenario/config/expectedData.yaml @@ -33,6 +33,10 @@ segmentItems: tags: - {key: url, value: 'http://localhost:8080/httpclient-3.x-scenario/case/context-propagate'} - {key: http.method, value: GET} + - key: http.params + value: |- + q1=[v1] + chinese=[中文] refs: - {parentEndpoint: /httpclient-3.x-scenario/case/httpclient, networkAddress: 'localhost:8080', refType: CrossProcess, parentSpanId: 1, parentTraceSegmentId: not null, parentServiceInstance: not @@ -52,8 +56,9 @@ segmentItems: spanType: Exit peer: localhost:8080 tags: - - {key: url, value: 'http://localhost:8080/httpclient-3.x-scenario/case/context-propagate'} + - {key: url, value: 'http://localhost:8080/httpclient-3.x-scenario/case/context-propagate?q1=v1&chinese=%e4%b8%ad%e6%96%87'} - {key: http.method, value: GET} + - {key: http.params, value: q1=v1&chinese=%e4%b8%ad%e6%96%87} skipAnalysis: 'false' - operationName: /httpclient-3.x-scenario/case/httpclient operationId: 0 diff --git a/test/plugin/scenarios/httpclient-3.x-scenario/configuration.yml b/test/plugin/scenarios/httpclient-3.x-scenario/configuration.yml index 278d9ca09095980c2c8da93543b6675786ed3690..1008dfe8df024c64ce9ce667ef997a54cf1ba1d7 100644 --- a/test/plugin/scenarios/httpclient-3.x-scenario/configuration.yml +++ b/test/plugin/scenarios/httpclient-3.x-scenario/configuration.yml @@ -18,4 +18,4 @@ type: tomcat entryService: '"http://localhost:8080/httpclient-3.x-scenario/case/httpclient?q1=v1&chinese=%e4%b8%ad%e6%96%87"' healthCheck: http://localhost:8080/httpclient-3.x-scenario/healthCheck environment: - - CATALINA_OPTS="-Dskywalking.plugin.tomcat.collect_http_params=true" + - CATALINA_OPTS="-Dskywalking.plugin.tomcat.collect_http_params=true -Dskywalking.plugin.httpclient.collect_http_params=true" diff --git a/test/plugin/scenarios/httpclient-3.x-scenario/src/main/java/org/apache/skywalking/apm/testcase/httpclient/CaseServlet.java b/test/plugin/scenarios/httpclient-3.x-scenario/src/main/java/org/apache/skywalking/apm/testcase/httpclient/CaseServlet.java index c903c7a93817de9a0ebe96435573f18d1a0df751..1f11dddec20dda807146d3606f7eee202456c33c 100644 --- a/test/plugin/scenarios/httpclient-3.x-scenario/src/main/java/org/apache/skywalking/apm/testcase/httpclient/CaseServlet.java +++ b/test/plugin/scenarios/httpclient-3.x-scenario/src/main/java/org/apache/skywalking/apm/testcase/httpclient/CaseServlet.java @@ -35,7 +35,7 @@ public class CaseServlet extends HttpServlet { MultiThreadedHttpConnectionManager httpConnectionManager = new MultiThreadedHttpConnectionManager(); HttpClient client = new HttpClient(httpConnectionManager); - HttpMethod httpGet = new GetMethod("http://localhost:8080" + req.getContextPath() + "/case/context-propagate"); + HttpMethod httpGet = new GetMethod("http://localhost:8080" + req.getContextPath() + "/case/context-propagate?q1=v1&chinese=%e4%b8%ad%e6%96%87"); int statusCode = client.executeMethod(httpGet); try (PrintWriter printWriter = resp.getWriter()) {