未验证 提交 a3241f0a 编写于 作者: wu-sheng's avatar wu-sheng 提交者: GitHub

Support op group name in agent config core. (#3299)

* Support op group name in agent config core.

* Provide core API for operation name grouping, rest template plugin update, and doc update.

* Fix doc

* Fix test case.

* Fix missing changes.

* add shuyun to powered-by.md (#3341)

* add shuyun to powered-by.md

* update powered-by.md

* Remove static method.
上级 1cc4a517
...@@ -23,12 +23,12 @@ import java.lang.reflect.Field; ...@@ -23,12 +23,12 @@ import java.lang.reflect.Field;
import java.lang.reflect.Modifier; import java.lang.reflect.Modifier;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Properties; import java.util.Properties;
import java.util.logging.Logger; import java.util.logging.Logger;
/** /**
* Init a class's static fields by a {@link Properties}, * Init a class's static fields by a {@link Properties}, including static fields and static inner classes.
* including static fields and static inner classes.
* <p> * <p>
* Created by wusheng on 2017/1/9. * Created by wusheng on 2017/1/9.
*/ */
...@@ -44,21 +44,39 @@ public class ConfigInitializer { ...@@ -44,21 +44,39 @@ public class ConfigInitializer {
for (Field field : recentConfigType.getFields()) { for (Field field : recentConfigType.getFields()) {
if (Modifier.isPublic(field.getModifiers()) && Modifier.isStatic(field.getModifiers())) { if (Modifier.isPublic(field.getModifiers()) && Modifier.isStatic(field.getModifiers())) {
String configKey = (parentDesc + "." + field.getName()).toLowerCase(); String configKey = (parentDesc + "." + field.getName()).toLowerCase();
String value = properties.getProperty(configKey); /**
if (value != null) { * Map config format is, config_key[map_key]=map_value
Class<?> type = field.getType(); * Such as plugin.opgroup.resttemplate.rule[abc]=/url/path
if (type.equals(int.class)) */
field.set(null, Integer.valueOf(value)); if (field.getType().equals(Map.class)) {
else if (type.equals(String.class)) Map map = (Map)field.get(null);
field.set(null, value); for (Object key : properties.keySet()) {
else if (type.equals(long.class)) String stringKey = key.toString();
field.set(null, Long.valueOf(value)); if (stringKey.startsWith(configKey + "[") && stringKey.endsWith("]")) {
else if (type.equals(boolean.class)) String itemKey = stringKey.substring(configKey.length() + 1, stringKey.length() - 1);
field.set(null, Boolean.valueOf(value)); map.put(itemKey, properties.getProperty(stringKey));
else if (type.equals(List.class)) }
field.set(null, convert2List(value)); }
else if (type.isEnum()) } else {
field.set(null, Enum.valueOf((Class<Enum>)type, value.toUpperCase())); /**
* Others typical field type
*/
String value = properties.getProperty(configKey);
if (value != null) {
Class<?> type = field.getType();
if (type.equals(int.class))
field.set(null, Integer.valueOf(value));
else if (type.equals(String.class))
field.set(null, value);
else if (type.equals(long.class))
field.set(null, Long.valueOf(value));
else if (type.equals(boolean.class))
field.set(null, Boolean.valueOf(value));
else if (type.equals(List.class))
field.set(null, convert2List(value));
else if (type.isEnum())
field.set(null, Enum.valueOf((Class<Enum>)type, value.toUpperCase()));
}
} }
} }
} }
......
...@@ -19,14 +19,13 @@ ...@@ -19,14 +19,13 @@
package org.apache.skywalking.apm.agent.core.conf; package org.apache.skywalking.apm.agent.core.conf;
import java.util.HashMap;
import java.util.Map;
import org.apache.skywalking.apm.agent.core.context.trace.TraceSegment; import org.apache.skywalking.apm.agent.core.context.trace.TraceSegment;
import org.apache.skywalking.apm.agent.core.logging.core.LogLevel; import org.apache.skywalking.apm.agent.core.logging.core.LogLevel;
import org.apache.skywalking.apm.agent.core.logging.core.LogOutput; import org.apache.skywalking.apm.agent.core.logging.core.LogOutput;
import org.apache.skywalking.apm.agent.core.logging.core.WriterFactory; import org.apache.skywalking.apm.agent.core.logging.core.WriterFactory;
import java.util.HashMap;
import java.util.Map;
/** /**
* This is the core config in sniffer agent. * This is the core config in sniffer agent.
* *
...@@ -41,14 +40,14 @@ public class Config { ...@@ -41,14 +40,14 @@ public class Config {
public static String NAMESPACE = ""; public static String NAMESPACE = "";
/** /**
* Service name is showed in skywalking-ui. Suggestion: set a unique name for each service, * Service name is showed in skywalking-ui. Suggestion: set a unique name for each service, service instance
* service instance nodes share the same code * nodes share the same code
*/ */
public static String SERVICE_NAME = ""; public static String SERVICE_NAME = "";
/** /**
* Authentication active is based on backend setting, see application.yml for more details. * Authentication active is based on backend setting, see application.yml for more details. For most scenarios,
* For most scenarios, this needs backend extensions, only basic match auth provided in default implementation. * this needs backend extensions, only basic match auth provided in default implementation.
*/ */
public static String AUTHENTICATION = ""; public static String AUTHENTICATION = "";
...@@ -70,8 +69,8 @@ public class Config { ...@@ -70,8 +69,8 @@ public class Config {
public static int SPAN_LIMIT_PER_SEGMENT = 300; public static int SPAN_LIMIT_PER_SEGMENT = 300;
/** /**
* If true, skywalking agent will save all instrumented classes files in `/debugging` folder. * If true, skywalking agent will save all instrumented classes files in `/debugging` folder. Skywalking team
* Skywalking team may ask for these files in order to resolve compatible problem. * may ask for these files in order to resolve compatible problem.
*/ */
public static boolean IS_OPEN_DEBUGGING_CLASS = false; public static boolean IS_OPEN_DEBUGGING_CLASS = false;
...@@ -96,16 +95,14 @@ public class Config { ...@@ -96,16 +95,14 @@ public class Config {
public static int CAUSE_EXCEPTION_DEPTH = 5; public static int CAUSE_EXCEPTION_DEPTH = 5;
/** /**
* How long should the agent wait (in minute) * How long should the agent wait (in minute) before re-registering to the OAP server after receiving reset
* before re-registering to the OAP server * command
* after receiving reset command
*/ */
public static int COOL_DOWN_THRESHOLD = 10; public static int COOL_DOWN_THRESHOLD = 10;
/** /**
* Force reconnection period of grpc, based on grpc_channel_check_interval. * Force reconnection period of grpc, based on grpc_channel_check_interval. If count of check grpc channel
* If count of check grpc channel status more than this number. * status more than this number. The channel check will call channel.getState(true) to requestConnection.
* The channel check will call channel.getState(true) to requestConnection.
*/ */
public static long FORCE_RECONNECTION_PERIOD = 1; public static long FORCE_RECONNECTION_PERIOD = 1;
} }
...@@ -177,19 +174,13 @@ public class Config { ...@@ -177,19 +174,13 @@ public class Config {
public static LogOutput OUTPUT = LogOutput.FILE; public static LogOutput OUTPUT = LogOutput.FILE;
/** /**
* The log patten. Default is "%level %timestamp %thread %class : %msg %throwable". * The log patten. Default is "%level %timestamp %thread %class : %msg %throwable". Each conversion specifiers
* Each conversion specifiers starts with a percent sign '%' and fis followed by conversion word. * starts with a percent sign '%' and fis followed by conversion word. There are some default conversion
* There are some default conversion specifiers: * specifiers: %thread = ThreadName %level = LogLevel {@link LogLevel} %timestamp = The now() who format is
* %thread = ThreadName * 'yyyy-MM-dd HH:mm:ss:SSS' %class = SimpleName of TargetClass %msg = Message of user input %throwable =
* %level = LogLevel {@link LogLevel} * Throwable of user input %agent_name = ServiceName of Agent {@link Agent#SERVICE_NAME}
* %timestamp = The now() who format is 'yyyy-MM-dd HH:mm:ss:SSS'
* %class = SimpleName of TargetClass
* %msg = Message of user input
* %throwable = Throwable of user input
* %agent_name = ServiceName of Agent {@link Agent#SERVICE_NAME}
* *
* @see org.apache.skywalking.apm.agent.core.logging.core.PatternLogger#DEFAULT_CONVERTER_MAP * @see org.apache.skywalking.apm.agent.core.logging.core.PatternLogger#DEFAULT_CONVERTER_MAP
*
*/ */
public static String PATTERN = "%level %timestamp %thread %class : %msg %throwable"; public static String PATTERN = "%level %timestamp %thread %class : %msg %throwable";
} }
...@@ -203,7 +194,8 @@ public class Config { ...@@ -203,7 +194,8 @@ public class Config {
public static class MongoDB { public static class MongoDB {
/** /**
* If true, trace all the parameters in MongoDB access, default is false. Only trace the operation, not include parameters. * If true, trace all the parameters in MongoDB access, default is false. Only trace the operation, not
* include parameters.
*/ */
public static boolean TRACE_PARAM = false; public static boolean TRACE_PARAM = false;
} }
...@@ -230,27 +222,29 @@ public class Config { ...@@ -230,27 +222,29 @@ public class Config {
public static class SpringMVC { public static class SpringMVC {
/** /**
* If true, the fully qualified method name will be used as the endpoint name instead of the request URL, default is false. * If true, the fully qualified method name will be used as the endpoint name instead of the request URL,
* default is false.
*/ */
public static boolean USE_QUALIFIED_NAME_AS_ENDPOINT_NAME = false; public static boolean USE_QUALIFIED_NAME_AS_ENDPOINT_NAME = false;
} }
public static class Toolkit { public static class Toolkit {
/** /**
* If true, the fully qualified method name will be used as the operation name instead of the given operation name, default is false. * If true, the fully qualified method name will be used as the operation name instead of the given
* operation name, default is false.
*/ */
public static boolean USE_QUALIFIED_NAME_AS_OPERATION_NAME = false; public static boolean USE_QUALIFIED_NAME_AS_OPERATION_NAME = false;
} }
public static class MySQL { public static class MySQL {
/** /**
* If set to true, the parameters of the sql (typically {@link java.sql.PreparedStatement}) * If set to true, the parameters of the sql (typically {@link java.sql.PreparedStatement}) would be
* would be collected. * collected.
*/ */
public static boolean TRACE_SQL_PARAMETERS = false; public static boolean TRACE_SQL_PARAMETERS = false;
/** /**
* For the sake of performance, SkyWalking won't save the entire parameters string into the tag, * For the sake of performance, SkyWalking won't save the entire parameters string into the tag, but only
* but only the first {@code SQL_PARAMETERS_MAX_LENGTH} characters. * the first {@code SQL_PARAMETERS_MAX_LENGTH} characters.
* *
* Set a negative number to save the complete parameter string to the tag. * Set a negative number to save the complete parameter string to the tag.
*/ */
...@@ -259,7 +253,8 @@ public class Config { ...@@ -259,7 +253,8 @@ public class Config {
public static class SolrJ { public static class SolrJ {
/** /**
* If true, trace all the query parameters(include deleteByIds and deleteByQuery) in Solr query request, default is false. * If true, trace all the query parameters(include deleteByIds and deleteByQuery) in Solr query request,
* default is false.
*/ */
public static boolean TRACE_STATEMENT = false; public static boolean TRACE_STATEMENT = false;
...@@ -269,5 +264,16 @@ public class Config { ...@@ -269,5 +264,16 @@ public class Config {
public static boolean TRACE_OPS_PARAMS = false; public static boolean TRACE_OPS_PARAMS = false;
} }
/**
* Operation name group rules
*/
public static class OPGroup {
/**
* Rules for RestTemplate plugin
*/
public static class RestTemplate implements OPGroupDefinition {
public static Map<String, String> RULE = new HashMap<String, String>();
}
}
} }
} }
/*
* 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.conf;
/**
* @author wusheng
*/
public interface OPGroupDefinition {
}
/*
* 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.context;
import java.lang.reflect.Field;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.apache.skywalking.apm.agent.core.boot.BootService;
import org.apache.skywalking.apm.agent.core.boot.DefaultImplementor;
import org.apache.skywalking.apm.agent.core.conf.Config;
import org.apache.skywalking.apm.agent.core.conf.OPGroupDefinition;
import org.apache.skywalking.apm.util.StringFormatGroup;
/**
* Support operation name format by config. Every plugin could declare its own rule to avoid performance concerns.
*
* Right now, the rule is REGEX based, it definitely has much space to optimize, because basically, only `*` is required
* to be supported.
*
* @author wusheng
*/
@DefaultImplementor
public class OperationNameFormatService implements BootService {
private static final Map<Class, StringFormatGroup> RULES = new ConcurrentHashMap<Class, StringFormatGroup>();
@Override public void prepare() throws Throwable {
for (Class<?> ruleName : Config.Plugin.OPGroup.class.getClasses()) {
if (!OPGroupDefinition.class.isAssignableFrom(ruleName)) {
continue;
}
StringFormatGroup formatGroup = RULES.get(ruleName);
if (formatGroup == null) {
formatGroup = new StringFormatGroup();
RULES.put(ruleName, formatGroup);
}
for (Field ruleNameField : ruleName.getFields()) {
if (ruleNameField.getType().equals(Map.class)) {
Map<String, String> rule = (Map<String, String>)ruleNameField.get(null);
for (Map.Entry<String, String> entry : rule.entrySet()) {
formatGroup.addRule(entry.getKey(), entry.getValue());
}
}
}
}
}
@Override public void boot() throws Throwable {
}
@Override public void onComplete() throws Throwable {
}
@Override public void shutdown() throws Throwable {
}
/**
* Format the operation name based on group rules
*
* @param definition in the Config
* @param opName represents the operation name literal string
* @return format string if rule matched or the given opName
*/
public String formatOperationName(Class<? extends OPGroupDefinition> definition, String opName) {
StringFormatGroup formatGroup = RULES.get(definition);
if (formatGroup == null) {
return opName;
} else {
return formatGroup.format(opName).getName();
}
}
}
...@@ -25,3 +25,4 @@ org.apache.skywalking.apm.agent.core.remote.ServiceAndEndpointRegisterClient ...@@ -25,3 +25,4 @@ org.apache.skywalking.apm.agent.core.remote.ServiceAndEndpointRegisterClient
org.apache.skywalking.apm.agent.core.context.ContextManagerExtendService org.apache.skywalking.apm.agent.core.context.ContextManagerExtendService
org.apache.skywalking.apm.agent.core.commands.CommandService org.apache.skywalking.apm.agent.core.commands.CommandService
org.apache.skywalking.apm.agent.core.commands.CommandExecutorService org.apache.skywalking.apm.agent.core.commands.CommandExecutorService
org.apache.skywalking.apm.agent.core.context.OperationNameFormatService
...@@ -55,7 +55,7 @@ public class ServiceManagerTest { ...@@ -55,7 +55,7 @@ public class ServiceManagerTest {
public void testServiceDependencies() throws Exception { public void testServiceDependencies() throws Exception {
HashMap<Class, BootService> registryService = getFieldValue(ServiceManager.INSTANCE, "bootedServices"); HashMap<Class, BootService> registryService = getFieldValue(ServiceManager.INSTANCE, "bootedServices");
assertThat(registryService.size(), is(9)); assertThat(registryService.size(), is(10));
assertTraceSegmentServiceClient(ServiceManager.INSTANCE.findService(TraceSegmentServiceClient.class)); assertTraceSegmentServiceClient(ServiceManager.INSTANCE.findService(TraceSegmentServiceClient.class));
assertContextManager(ServiceManager.INSTANCE.findService(ContextManager.class)); assertContextManager(ServiceManager.INSTANCE.findService(ContextManager.class));
......
...@@ -20,7 +20,6 @@ ...@@ -20,7 +20,6 @@
package org.apache.skywalking.apm.plugin.spring.resttemplate.async; package org.apache.skywalking.apm.plugin.spring.resttemplate.async;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.net.URI;
import org.apache.skywalking.apm.agent.core.context.ContextManager; import org.apache.skywalking.apm.agent.core.context.ContextManager;
import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan; import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance; import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
...@@ -33,7 +32,7 @@ public class FutureGetInterceptor implements InstanceMethodsAroundInterceptor { ...@@ -33,7 +32,7 @@ public class FutureGetInterceptor implements InstanceMethodsAroundInterceptor {
public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes, public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes,
MethodInterceptResult result) throws Throwable { MethodInterceptResult result) throws Throwable {
Object[] cacheValues = (Object[])objInst.getSkyWalkingDynamicField(); Object[] cacheValues = (Object[])objInst.getSkyWalkingDynamicField();
ContextManager.createLocalSpan("future/get:" + ((URI)cacheValues[0]).getPath()); ContextManager.createLocalSpan("future/get:" + cacheValues[0]);
} }
@Override @Override
......
...@@ -20,9 +20,12 @@ package org.apache.skywalking.apm.plugin.spring.resttemplate.async; ...@@ -20,9 +20,12 @@ package org.apache.skywalking.apm.plugin.spring.resttemplate.async;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.net.URI; import java.net.URI;
import org.apache.skywalking.apm.agent.core.boot.ServiceManager;
import org.apache.skywalking.apm.agent.core.conf.Config;
import org.apache.skywalking.apm.agent.core.context.ContextCarrier; import org.apache.skywalking.apm.agent.core.context.ContextCarrier;
import org.apache.skywalking.apm.agent.core.context.ContextManager; import org.apache.skywalking.apm.agent.core.context.ContextManager;
import org.apache.skywalking.apm.agent.core.context.ContextSnapshot; import org.apache.skywalking.apm.agent.core.context.ContextSnapshot;
import org.apache.skywalking.apm.agent.core.context.OperationNameFormatService;
import org.apache.skywalking.apm.agent.core.context.tag.Tags; import org.apache.skywalking.apm.agent.core.context.tag.Tags;
import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan; import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan;
import org.apache.skywalking.apm.agent.core.context.trace.SpanLayer; import org.apache.skywalking.apm.agent.core.context.trace.SpanLayer;
...@@ -34,6 +37,7 @@ import org.apache.skywalking.apm.plugin.spring.commons.EnhanceCacheObjects; ...@@ -34,6 +37,7 @@ import org.apache.skywalking.apm.plugin.spring.commons.EnhanceCacheObjects;
import org.springframework.http.HttpMethod; import org.springframework.http.HttpMethod;
public class RestExecuteInterceptor implements InstanceMethodsAroundInterceptor { public class RestExecuteInterceptor implements InstanceMethodsAroundInterceptor {
private OperationNameFormatService nameFormatService;
@Override @Override
public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes, public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes,
...@@ -42,15 +46,23 @@ public class RestExecuteInterceptor implements InstanceMethodsAroundInterceptor ...@@ -42,15 +46,23 @@ public class RestExecuteInterceptor implements InstanceMethodsAroundInterceptor
final HttpMethod httpMethod = (HttpMethod)allArguments[1]; final HttpMethod httpMethod = (HttpMethod)allArguments[1];
final ContextCarrier contextCarrier = new ContextCarrier(); final ContextCarrier contextCarrier = new ContextCarrier();
if (nameFormatService == null) {
nameFormatService = ServiceManager.INSTANCE.findService(OperationNameFormatService.class);
}
String remotePeer = requestURL.getHost() + ":" + (requestURL.getPort() > 0 ? requestURL.getPort() : "https".equalsIgnoreCase(requestURL.getScheme()) ? 443 : 80); String remotePeer = requestURL.getHost() + ":" + (requestURL.getPort() > 0 ? requestURL.getPort() : "https".equalsIgnoreCase(requestURL.getScheme()) ? 443 : 80);
AbstractSpan span = ContextManager.createExitSpan(requestURL.getPath(), contextCarrier, remotePeer);
String formatURIPath = nameFormatService.formatOperationName(Config.Plugin.OPGroup.RestTemplate.class, requestURL.getPath());
AbstractSpan span = ContextManager.createExitSpan(
formatURIPath,
contextCarrier, remotePeer);
span.setComponent(ComponentsDefine.SPRING_REST_TEMPLATE); span.setComponent(ComponentsDefine.SPRING_REST_TEMPLATE);
Tags.URL.set(span, requestURL.getScheme() + "://" + requestURL.getHost() + ":" + requestURL.getPort() + requestURL.getPath()); Tags.URL.set(span, requestURL.getScheme() + "://" + requestURL.getHost() + ":" + requestURL.getPort() + requestURL.getPath());
Tags.HTTP.METHOD.set(span, httpMethod.toString()); Tags.HTTP.METHOD.set(span, httpMethod.toString());
SpanLayer.asHttp(span); SpanLayer.asHttp(span);
Object[] cacheValues = new Object[3]; Object[] cacheValues = new Object[3];
cacheValues[0] = requestURL; cacheValues[0] = formatURIPath;
cacheValues[1] = contextCarrier; cacheValues[1] = contextCarrier;
objInst.setSkyWalkingDynamicField(cacheValues); objInst.setSkyWalkingDynamicField(cacheValues);
} }
...@@ -61,8 +73,8 @@ public class RestExecuteInterceptor implements InstanceMethodsAroundInterceptor ...@@ -61,8 +73,8 @@ public class RestExecuteInterceptor implements InstanceMethodsAroundInterceptor
Object[] cacheValues = (Object[])objInst.getSkyWalkingDynamicField(); Object[] cacheValues = (Object[])objInst.getSkyWalkingDynamicField();
cacheValues[2] = ContextManager.capture(); cacheValues[2] = ContextManager.capture();
if (ret != null) { if (ret != null) {
URI uri = (URI)cacheValues[0]; String uri = (String)cacheValues[0];
((EnhancedInstance)ret).setSkyWalkingDynamicField(new EnhanceCacheObjects(uri.getPath(), ComponentsDefine.SPRING_REST_TEMPLATE, SpanLayer.HTTP, (ContextSnapshot)cacheValues[2])); ((EnhancedInstance)ret).setSkyWalkingDynamicField(new EnhanceCacheObjects(uri, ComponentsDefine.SPRING_REST_TEMPLATE, SpanLayer.HTTP, (ContextSnapshot)cacheValues[2]));
} }
ContextManager.stopSpan(); ContextManager.stopSpan();
return ret; return ret;
......
...@@ -20,7 +20,10 @@ package org.apache.skywalking.apm.plugin.spring.resttemplate.sync; ...@@ -20,7 +20,10 @@ package org.apache.skywalking.apm.plugin.spring.resttemplate.sync;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.net.URI; import java.net.URI;
import org.apache.skywalking.apm.agent.core.boot.ServiceManager;
import org.apache.skywalking.apm.agent.core.conf.Config;
import org.apache.skywalking.apm.agent.core.context.ContextCarrier; import org.apache.skywalking.apm.agent.core.context.ContextCarrier;
import org.apache.skywalking.apm.agent.core.context.OperationNameFormatService;
import org.apache.skywalking.apm.agent.core.context.tag.Tags; import org.apache.skywalking.apm.agent.core.context.tag.Tags;
import org.apache.skywalking.apm.agent.core.context.trace.SpanLayer; 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.EnhancedInstance;
...@@ -32,6 +35,7 @@ import org.apache.skywalking.apm.network.trace.component.ComponentsDefine; ...@@ -32,6 +35,7 @@ import org.apache.skywalking.apm.network.trace.component.ComponentsDefine;
import org.springframework.http.HttpMethod; import org.springframework.http.HttpMethod;
public class RestExecuteInterceptor implements InstanceMethodsAroundInterceptor { public class RestExecuteInterceptor implements InstanceMethodsAroundInterceptor {
private OperationNameFormatService nameFormatService;
@Override @Override
public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes, public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes,
...@@ -40,8 +44,13 @@ public class RestExecuteInterceptor implements InstanceMethodsAroundInterceptor ...@@ -40,8 +44,13 @@ public class RestExecuteInterceptor implements InstanceMethodsAroundInterceptor
final HttpMethod httpMethod = (HttpMethod)allArguments[1]; final HttpMethod httpMethod = (HttpMethod)allArguments[1];
final ContextCarrier contextCarrier = new ContextCarrier(); final ContextCarrier contextCarrier = new ContextCarrier();
if (nameFormatService == null) {
nameFormatService = ServiceManager.INSTANCE.findService(OperationNameFormatService.class);
}
String remotePeer = requestURL.getHost() + ":" + (requestURL.getPort() > 0 ? requestURL.getPort() : "https".equalsIgnoreCase(requestURL.getScheme()) ? 443 : 80); String remotePeer = requestURL.getHost() + ":" + (requestURL.getPort() > 0 ? requestURL.getPort() : "https".equalsIgnoreCase(requestURL.getScheme()) ? 443 : 80);
AbstractSpan span = ContextManager.createExitSpan(requestURL.getPath(), contextCarrier, remotePeer); String formatURIPath = nameFormatService.formatOperationName(Config.Plugin.OPGroup.RestTemplate.class, requestURL.getPath());
AbstractSpan span = ContextManager.createExitSpan(formatURIPath, contextCarrier, remotePeer);
span.setComponent(ComponentsDefine.SPRING_REST_TEMPLATE); span.setComponent(ComponentsDefine.SPRING_REST_TEMPLATE);
Tags.URL.set(span, requestURL.getScheme() + "://" + requestURL.getHost() + ":" + requestURL.getPort() + requestURL.getPath()); Tags.URL.set(span, requestURL.getScheme() + "://" + requestURL.getHost() + ":" + requestURL.getPort() + requestURL.getPath());
......
...@@ -100,6 +100,7 @@ property key | Description | Default | ...@@ -100,6 +100,7 @@ property key | Description | Default |
`plugin.mysql.sql_parameters_max_length`|If set to positive number, the `db.sql.parameters` would be truncated to this length, otherwise it would be completely saved, which may cause performance problem.|`512`| `plugin.mysql.sql_parameters_max_length`|If set to positive number, the `db.sql.parameters` would be truncated to this length, otherwise it would be completely saved, which may cause performance problem.|`512`|
`plugin.solrj.trace_statement`|If true, trace all the query parameters(include deleteByIds and deleteByQuery) in Solr query request, default is false.|`false`| `plugin.solrj.trace_statement`|If true, trace all the query parameters(include deleteByIds and deleteByQuery) in Solr query request, default is false.|`false`|
`plugin.solrj.trace_ops_params`|If true, trace all the operation parameters in Solr request, default is false.|`false`| `plugin.solrj.trace_ops_params`|If true, trace all the operation parameters in Solr request, default is false.|`false`|
`plugin.opgroup.*`|Support operation name customize group rules in different plugins. Read [Group rule supported plugins](op_name_group_rule.md)|Not set|
## Optional Plugins ## Optional Plugins
Java agent plugins are all pluggable. Optional plugins could be provided in `optional-plugins` folder under agent or 3rd party repositories. Java agent plugins are all pluggable. Optional plugins could be provided in `optional-plugins` folder under agent or 3rd party repositories.
......
# Operation Name Group Rule
Operation Name in auto instrumentation agent is unpredictable, some time, target application carries parameter in it, due to the parameter included in URI mostly.
Those operation name are also as known endpoint name in most cases.
Such as /api/checkTicket/tk/{userToken}.
We solved most of these cases, by leverage the parameter pattern path in framework, such as SpringMVC, Webflux, etc.
But it is undetected in RPC client side, such as HTTP restful client.
In this case, we have to ask the users to set the group rule manually.
All rules are supported to set through agent.config, system properties and system env, like other agent settings.
- Config format, `plugin.opgroup.`plugin name`.rule[`rule name`]`=pattern regex expression
Multiple configuration items for a single plugin with different keys are supports, such as
1. plugin.opgroup.resttemplate.rule[/rule1]=/path1
1. plugin.opgroup.resttemplate.rule[/rule2]=/path2
1. plugin.opgroup.resttemplate.rule[/rule2]=/path3
We have following plugins supporting operation name group.
| Plugin | Config Key | Example |
|:----:|:-----:|:----|
|RestTemplate| plugin.opgroup.resttemplate.rule | plugin.opgroup.resttemplate.rule[/user/auth/{token}]=`\/user\/auth\/.*` |
...@@ -68,6 +68,7 @@ or providing commercial products including Apache SkyWalking. ...@@ -68,6 +68,7 @@ or providing commercial products including Apache SkyWalking.
1. Rongjinbao. 深圳融金宝互联网金融服务有限公司. http://www.rjb777.com 1. Rongjinbao. 深圳融金宝互联网金融服务有限公司. http://www.rjb777.com
1. Shouqi Limousine & chauffeur Group 首约科技(北京)有限公司. https://www.01zhuanche.com/ 1. Shouqi Limousine & chauffeur Group 首约科技(北京)有限公司. https://www.01zhuanche.com/
1. shuaibaoshop.com 宁波鲸灵网络科技有限公司 http://www.shuaibaoshop.com/ 1. shuaibaoshop.com 宁波鲸灵网络科技有限公司 http://www.shuaibaoshop.com/
1. shuyun.com 杭州数云信息技术有限公司 http://www.shuyun.com/
1. Sijibao.com 司机宝 https://www.sijibao.com/ 1. Sijibao.com 司机宝 https://www.sijibao.com/
1. Sinolink Securities Co.,Ltd. 国金证券佣金宝 http://www.yongjinbao.com.cn/ 1. Sinolink Securities Co.,Ltd. 国金证券佣金宝 http://www.yongjinbao.com.cn/
1. Source++ https://sourceplusplus.com 1. Source++ https://sourceplusplus.com
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册