Support collecting http parameters (#4162)

Plugins of Tomcat, Spring MVC, Armeria are supported for now
This commit is contained in:
kezhenxu94 2020-01-03 07:51:26 +08:00 committed by GitHub
parent 4012545ed4
commit f52f7f466a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 143 additions and 12 deletions

View File

@ -353,5 +353,19 @@ public class Config {
*/
public static String THREADING_CLASS_PREFIXES = "";
}
public static class Http {
/**
* This config item controls that whether the plugins related to HTTP should
* collect the parameters of the request.
*/
public static boolean COLLECT_HTTP_PARAMS = false;
/**
* When {@link #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;
}
}
}

View File

@ -76,5 +76,7 @@ public final class Tags {
public static final class HTTP {
public static final StringTag METHOD = new StringTag(10, "http.method");
public static final StringTag PARAMS = new StringTag(11, "http.params");
}
}

View File

@ -0,0 +1,40 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.skywalking.apm.agent.core.util;
import java.util.Arrays;
import java.util.Map;
import java.util.stream.Collectors;
/**
* Some utility methods for collections.
* Reinvent the wheels because importing third-party libs just for some methods is not worthwhile in agent side
*
* @author kezhenxu94
* @since 7.0.0
*/
public final class CollectionUtil {
public static String toString(final Map<String, String[]> map) {
return map
.entrySet()
.stream()
.map(entry -> entry.getKey() + "=" + Arrays.toString(entry.getValue()))
.collect(Collectors.joining("\n"));
}
}

View File

@ -19,6 +19,7 @@
package org.apache.skywalking.apm.plugin.spring.mvc.commons.interceptor;
import java.lang.reflect.Method;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.skywalking.apm.agent.core.conf.Config;
@ -31,11 +32,13 @@ import org.apache.skywalking.apm.agent.core.context.trace.SpanLayer;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
import org.apache.skywalking.apm.agent.core.util.CollectionUtil;
import org.apache.skywalking.apm.agent.core.util.MethodUtil;
import org.apache.skywalking.apm.network.trace.component.ComponentsDefine;
import org.apache.skywalking.apm.plugin.spring.mvc.commons.EnhanceRequireObjectCache;
import org.apache.skywalking.apm.plugin.spring.mvc.commons.exception.IllegalMethodStackDepthException;
import org.apache.skywalking.apm.plugin.spring.mvc.commons.exception.ServletResponseNotFoundException;
import org.apache.skywalking.apm.util.StringUtil;
import static org.apache.skywalking.apm.plugin.spring.mvc.commons.Constants.CONTROLLER_METHOD_STACK_DEPTH;
import static org.apache.skywalking.apm.plugin.spring.mvc.commons.Constants.FORWARD_REQUEST_FLAG;
@ -104,6 +107,17 @@ public abstract class AbstractMethodInterceptor implements InstanceMethodsAround
span.setComponent(ComponentsDefine.SPRING_MVC_ANNOTATION);
SpanLayer.asHttp(span);
if (Config.Plugin.Http.COLLECT_HTTP_PARAMS) {
final Map<String, String[]> parameterMap = request.getParameterMap();
if (parameterMap != null && !parameterMap.isEmpty()) {
String tagValue = CollectionUtil.toString(parameterMap);
tagValue = Config.Plugin.Http.HTTP_PARAMS_LENGTH_THRESHOLD > 0
? StringUtil.cut(tagValue, Config.Plugin.Http.HTTP_PARAMS_LENGTH_THRESHOLD)
: tagValue;
Tags.HTTP.PARAMS.set(span, tagValue);
}
}
stackDepth = new StackDepth();
ContextManager.getRuntimeContext().put(CONTROLLER_METHOD_STACK_DEPTH, stackDepth);
} else {

View File

@ -19,9 +19,15 @@
package org.apache.skywalking.apm.plugin.tomcat78x;
import java.lang.reflect.Method;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import org.apache.catalina.connector.Request;
import org.apache.skywalking.apm.agent.core.conf.Config;
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;
@ -32,8 +38,11 @@ import org.apache.skywalking.apm.agent.core.context.trace.TraceSegment;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
import org.apache.skywalking.apm.agent.core.util.CollectionUtil;
import org.apache.skywalking.apm.agent.core.util.MethodUtil;
import org.apache.skywalking.apm.network.trace.component.ComponentsDefine;
import org.apache.skywalking.apm.util.StringUtil;
import org.apache.tomcat.util.http.Parameters;
/**
* {@link TomcatInvokeInterceptor} fetch the serialized context data by using {@link
@ -63,7 +72,7 @@ public class TomcatInvokeInterceptor implements InstanceMethodsAroundInterceptor
*/
@Override public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments,
Class<?>[] argumentsTypes, MethodInterceptResult result) throws Throwable {
HttpServletRequest request = (HttpServletRequest)allArguments[0];
Request request = (Request) allArguments[0];
ContextCarrier contextCarrier = new ContextCarrier();
CarrierItem next = contextCarrier.items();
@ -78,6 +87,23 @@ public class TomcatInvokeInterceptor implements InstanceMethodsAroundInterceptor
span.setComponent(ComponentsDefine.TOMCAT);
SpanLayer.asHttp(span);
if (Config.Plugin.Http.COLLECT_HTTP_PARAMS) {
final Map<String, String[]> parameterMap = new HashMap<>();
final org.apache.coyote.Request coyoteRequest = request.getCoyoteRequest();
final Parameters parameters = coyoteRequest.getParameters();
for (final Enumeration<String> names = parameters.getParameterNames(); names.hasMoreElements(); ) {
final String name = names.nextElement();
parameterMap.put(name, parameters.getParameterValues(name));
}
if (!parameterMap.isEmpty()) {
String tagValue = CollectionUtil.toString(parameterMap);
tagValue = Config.Plugin.Http.HTTP_PARAMS_LENGTH_THRESHOLD > 0
? StringUtil.cut(tagValue, Config.Plugin.Http.HTTP_PARAMS_LENGTH_THRESHOLD)
: tagValue;
Tags.HTTP.PARAMS.set(span, tagValue);
}
}
}
@Override public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments,

View File

@ -19,8 +19,9 @@
package org.apache.skywalking.apm.plugin.tomcat78x;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.catalina.connector.Request;
import org.apache.skywalking.apm.agent.core.conf.Config;
import org.apache.skywalking.apm.agent.core.context.SW3CarrierItem;
import org.apache.skywalking.apm.agent.core.context.trace.AbstractTracingSpan;
@ -66,7 +67,7 @@ public class TomcatInvokeInterceptorTest {
public AgentServiceRule serviceRule = new AgentServiceRule();
@Mock
private HttpServletRequest request;
private Request request;
@Mock
private HttpServletResponse response;
@Mock

View File

@ -118,6 +118,8 @@ property key | Description | Default |
`plugin.opgroup.*`|Support operation name customize group rules in different plugins. Read [Group rule supported plugins](op_name_group_rule.md)|Not set|
`plugin.springtransaction.simplify_transaction_definition_name`|If true, the transaction definition name will be simplified.|false|
`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.http.collect_http_params`| This config item controls that whether the plugins related to HTTP should collect the parameters of the request. The name `plugin.http.collect_http_params` is rather general, but it doesn't guarantee that all http plugins should be under its control, unless the plugin itself takes this config item into consideration, such as Tomcat, Spring MVC, and Armeria plugin. | `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` |
## Optional Plugins
Java agent plugins are all pluggable. Optional plugins could be provided in `optional-plugins` folder under agent or 3rd party repositories.

View File

@ -18,6 +18,8 @@ FROM tomcat:8.5.42-jdk8-openjdk
MAINTAINER zhangxin@apache.org
WORKDIR /usr/local/skywalking/tools
ENV CATALINA_OPTS ""
COPY run.sh /
COPY catalina.sh /usr/local/tomcat/bin/

View File

@ -25,6 +25,8 @@ import org.yaml.snakeyaml.Yaml;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.util.Collections;
import java.util.List;
public class ConfigurationImpl implements IConfiguration {
private CaseConfiguration configuration;
@ -97,6 +99,12 @@ public class ConfigurationImpl implements IConfiguration {
return this.configuration.getStartScript();
}
@Override
public String catalinaOpts() {
List<String> environment = this.configuration.getEnvironment() != null ? this.configuration.getEnvironment() : Collections.emptyList();
return environment.stream().filter(it -> it.startsWith("CATALINA_OPTS=")).findFirst().orElse("").replaceAll("^CATALINA_OPTS=", "");
}
@Override public String dockerImageName() {
switch (this.configuration.getType().toLowerCase()) {
case "tomcat" :

View File

@ -45,6 +45,7 @@ public class DockerContainerRunningGenerator extends AbstractRunningGenerator {
root.put("scenario_version", configuration.scenarioVersion());
root.put("health_check", configuration.healthCheck());
root.put("start_script", configuration.startScript());
root.put("catalina_opts", configuration.catalinaOpts());
root.put("entry_service", configuration.entryService());
root.put("test_framework", configuration.testFramework());
root.put("docker_image_name", configuration.dockerImageName());

View File

@ -38,6 +38,8 @@ public interface IConfiguration {
String startScript();
String catalinaOpts();
String entryService();
String dockerImageName();

View File

@ -24,8 +24,11 @@ docker run \
<#if start_script??>
--env SCENARIO_START_SCRIPT=${start_script} \
</#if>
--env SCENARIO_ENTRY_SERVICE=${entry_service} \
--env SCENARIO_ENTRY_SERVICE=${entry_service} \
--env SCENARIO_HEALTH_CHECK_URL=${health_check} \
<#if catalina_opts??>
--env CATALINA_OPTS=${catalina_opts} \
</#if>
-v ${agent_home}:/usr/local/skywalking/scenario/agent \
-v ${scenario_home}:/usr/local/skywalking/scenario \
${docker_image_name}:${docker_image_version} 1>${scenario_home}/logs/container.log

View File

@ -18,4 +18,4 @@
home="$(cd "$(dirname $0)"; pwd)"
java -jar ${agent_opts} ${home}/../libs/armeria-0.96minus-scenario.jar &
java -jar -Dskywalking.plugin.http.collect_http_params=true ${agent_opts} ${home}/../libs/armeria-0.96minus-scenario.jar &

View File

@ -82,4 +82,8 @@ segmentItems:
peerId: 0
tags:
- {key: url, value: 'http://localhost:8080/greet/skywalking'}
- {key: http.method, value: GET}
- {key: http.method, value: GET}
- key: http.params
value: |-
q1=[v1]
chinese=[中文]

View File

@ -15,7 +15,7 @@
# limitations under the License.
type: jvm
entryService: http://localhost:8080/greet/skywalking
entryService: '"http://localhost:8080/greet/skywalking?q1=v1&chinese=%e4%b8%ad%e6%96%87"'
healthCheck: http://localhost:8080/healthCheck
startScript: ./bin/startup.sh
framework: Armeria

View File

@ -83,4 +83,8 @@ segmentItems:
peerId: 0
tags:
- {key: url, value: 'http://localhost:8080/httpclient-3.x-scenario/case/httpclient'}
- {key: http.method, value: GET}
- {key: http.method, value: GET}
- key: http.params
value: |-
q1=[v1]
chinese=[中文]

View File

@ -15,6 +15,8 @@
# limitations under the License.
type: tomcat
entryService: http://localhost:8080/httpclient-3.x-scenario/case/httpclient
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
framework: httpclient
environment:
- CATALINA_OPTS="-Dskywalking.plugin.http.collect_http_params=true"

View File

@ -274,6 +274,10 @@ segmentItems:
tags:
- {key: url, value: 'http://localhost:8080/spring-3.1.x-scenario/case/resttemplate'}
- {key: http.method, value: GET}
- key: http.params
value: |-
q1=[v1]
chinese=[中文]
- segmentId: not null
spans:
- operationName: '{PUT}/update/{id}'

View File

@ -15,8 +15,10 @@
# limitations under the License.
type: tomcat
entryService: http://localhost:8080/spring-3.1.x-scenario/case/resttemplate
entryService: '"http://localhost:8080/spring-3.1.x-scenario/case/resttemplate?q1=v1&chinese=%e4%b8%ad%e6%96%87"'
healthCheck: http://localhost:8080/spring-3.1.x-scenario/healthCheck
runningMode: with_optional
withPlugins: apm-spring-annotation-plugin-*.jar
framework: spring
framework: spring
environment:
- CATALINA_OPTS="-Dskywalking.plugin.http.collect_http_params=true"