Support collecting http parameters (#4162)
Plugins of Tomcat, Spring MVC, Armeria are supported for now
This commit is contained in:
parent
4012545ed4
commit
f52f7f466a
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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"));
|
||||
}
|
||||
}
|
||||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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/
|
||||
|
||||
|
|
|
|||
|
|
@ -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" :
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
|
|
|
|||
|
|
@ -38,6 +38,8 @@ public interface IConfiguration {
|
|||
|
||||
String startScript();
|
||||
|
||||
String catalinaOpts();
|
||||
|
||||
String entryService();
|
||||
|
||||
String dockerImageName();
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 &
|
||||
|
|
@ -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=[中文]
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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=[中文]
|
||||
|
|
@ -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"
|
||||
|
|
@ -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}'
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
Loading…
Reference in New Issue