diff --git a/assembly.xml b/assembly.xml index b7d32b8e..bf83bfa0 100644 --- a/assembly.xml +++ b/assembly.xml @@ -53,6 +53,13 @@ **/** + + chaosblade-exec-spi/target/classes + + + **/** + + diff --git a/chaosblade-exec-common/pom.xml b/chaosblade-exec-common/pom.xml index 474bf426..c76c3f3d 100644 --- a/chaosblade-exec-common/pom.xml +++ b/chaosblade-exec-common/pom.xml @@ -29,6 +29,11 @@ + + com.alibaba.chaosblade + chaosblade-exec-spi + ${project.version} + org.projectlombok lombok diff --git a/chaosblade-exec-common/src/main/java/com/alibaba/chaosblade/exec/common/aop/matcher/busi/BusinessParamMatcher.java b/chaosblade-exec-common/src/main/java/com/alibaba/chaosblade/exec/common/aop/matcher/busi/BusinessParamMatcher.java new file mode 100644 index 00000000..b091565f --- /dev/null +++ b/chaosblade-exec-common/src/main/java/com/alibaba/chaosblade/exec/common/aop/matcher/busi/BusinessParamMatcher.java @@ -0,0 +1,41 @@ +package com.alibaba.chaosblade.exec.common.aop.matcher.busi; + +import com.alibaba.chaosblade.exec.common.aop.CustomMatcher; +import com.alibaba.chaosblade.exec.common.util.BusinessParamUtil; + +import java.util.List; +import java.util.Map; + +/** + * @author wufunc@gmail.com + */ +public class BusinessParamMatcher implements CustomMatcher { + private static final BusinessParamMatcher INSTANCE = new BusinessParamMatcher(); + + private BusinessParamMatcher() { + } + + public static BusinessParamMatcher getInstance() { + return INSTANCE; + } + + @Override + public boolean match(String commandValue, Object originValue) { + Map businessData = (Map) originValue; + List businessParams = BusinessParamUtil.parseFromJsonStr(commandValue); + for (BusinessParamUtil.BusinessParam businessParam : businessParams) { + if (!businessData.containsKey(businessParam.getKey())) { + return false; + } + if (!businessData.get(businessParam.getKey()).equals(businessParam.getValue())) { + return false; + } + } + return true; + } + + @Override + public boolean regexMatch(String commandValue, Object originValue) { + return false; + } +} diff --git a/chaosblade-exec-common/src/main/java/com/alibaba/chaosblade/exec/common/center/DefaultSPIServiceManager.java b/chaosblade-exec-common/src/main/java/com/alibaba/chaosblade/exec/common/center/DefaultSPIServiceManager.java new file mode 100644 index 00000000..f0ebc805 --- /dev/null +++ b/chaosblade-exec-common/src/main/java/com/alibaba/chaosblade/exec/common/center/DefaultSPIServiceManager.java @@ -0,0 +1,51 @@ +package com.alibaba.chaosblade.exec.common.center; + + +import java.util.*; + +public class DefaultSPIServiceManager implements SPIServiceManager { + private static Map> spiMap; + + static { + spiMap = new HashMap>(); + } + + @Override + public void load() { + + } + @Override + public List getServices(String className, ClassLoader classLoader) { + if (spiMap.containsKey(className)) { + return spiMap.get(className); + } + synchronized (this) { + if (spiMap.containsKey(className)) { + return spiMap.get(className); + } + List services = loadService(className, classLoader); + spiMap.put(className, services); + return services; + } + } + + public List loadService(String className, ClassLoader classLoader) { + Class clazz; + try { + clazz = classLoader.loadClass(className); + } catch (ClassNotFoundException e) { + return Collections.EMPTY_LIST; + } + ServiceLoader serviceLoader = ServiceLoader.load(clazz, classLoader); + List objects = new ArrayList(); + for (Object object : serviceLoader) { + objects.add(object); + } + return objects; + } + + @Override + public void unload() { + spiMap.clear(); + } +} diff --git a/chaosblade-exec-common/src/main/java/com/alibaba/chaosblade/exec/common/center/ManagerFactory.java b/chaosblade-exec-common/src/main/java/com/alibaba/chaosblade/exec/common/center/ManagerFactory.java index c65ca336..4eef7e4d 100644 --- a/chaosblade-exec-common/src/main/java/com/alibaba/chaosblade/exec/common/center/ManagerFactory.java +++ b/chaosblade-exec-common/src/main/java/com/alibaba/chaosblade/exec/common/center/ManagerFactory.java @@ -34,6 +34,8 @@ public class ManagerFactory { */ private static ListenerManager listenerManager = new DefaultListenerManager(); + private static SPIServiceManager spiServiceManager = new DefaultSPIServiceManager(); + public static StatusManager getStatusManager() { return statusManager; } @@ -46,10 +48,15 @@ public static ListenerManager getListenerManager() { return listenerManager; } + public static SPIServiceManager spiServiceManager() { + return spiServiceManager; + } + public static void load() { modelSpecManager.load(); listenerManager.load(); statusManager.load(); + spiServiceManager.load(); } /** @@ -59,5 +66,6 @@ public static void unload() { statusManager.unload(); modelSpecManager.unload(); listenerManager.unload(); + spiServiceManager.unload(); } } diff --git a/chaosblade-exec-common/src/main/java/com/alibaba/chaosblade/exec/common/center/SPIServiceManager.java b/chaosblade-exec-common/src/main/java/com/alibaba/chaosblade/exec/common/center/SPIServiceManager.java new file mode 100644 index 00000000..4181bab8 --- /dev/null +++ b/chaosblade-exec-common/src/main/java/com/alibaba/chaosblade/exec/common/center/SPIServiceManager.java @@ -0,0 +1,7 @@ +package com.alibaba.chaosblade.exec.common.center; + +import java.util.List; + +public interface SPIServiceManager extends ManagerService{ + List getServices(String className, ClassLoader classLoader); +} diff --git a/chaosblade-exec-common/src/main/java/com/alibaba/chaosblade/exec/common/constant/ModelConstant.java b/chaosblade-exec-common/src/main/java/com/alibaba/chaosblade/exec/common/constant/ModelConstant.java index 1812b548..02b9edb3 100644 --- a/chaosblade-exec-common/src/main/java/com/alibaba/chaosblade/exec/common/constant/ModelConstant.java +++ b/chaosblade-exec-common/src/main/java/com/alibaba/chaosblade/exec/common/constant/ModelConstant.java @@ -22,6 +22,10 @@ public interface ModelConstant { String JVM_TARGET = "jvm"; + String HTTP_TARGET = "http"; + + String HTTP_URL_MATCHER_NAME = "uri"; + /** * The name of effect percent matcher */ @@ -36,4 +40,9 @@ public interface ModelConstant { * The flag of regex pattern */ String REGEX_PATTERN_FLAG = "regex-pattern"; + + /** + * the flag of buisness params + */ + String BUSINESS_PARAMS = "b-params"; } diff --git a/chaosblade-exec-common/src/main/java/com/alibaba/chaosblade/exec/common/context/GlobalContext.java b/chaosblade-exec-common/src/main/java/com/alibaba/chaosblade/exec/common/context/GlobalContext.java index f86ebe79..685f3b64 100644 --- a/chaosblade-exec-common/src/main/java/com/alibaba/chaosblade/exec/common/context/GlobalContext.java +++ b/chaosblade-exec-common/src/main/java/com/alibaba/chaosblade/exec/common/context/GlobalContext.java @@ -54,4 +54,8 @@ public Object get(String key) { public Object remove(String key) { return contextMap.remove(key); } + + public boolean containsKey(String key){ + return contextMap.containsKey(key); + } } diff --git a/chaosblade-exec-common/src/main/java/com/alibaba/chaosblade/exec/common/context/ThreadLocalContext.java b/chaosblade-exec-common/src/main/java/com/alibaba/chaosblade/exec/common/context/ThreadLocalContext.java index d7626ddf..126c7a92 100644 --- a/chaosblade-exec-common/src/main/java/com/alibaba/chaosblade/exec/common/context/ThreadLocalContext.java +++ b/chaosblade-exec-common/src/main/java/com/alibaba/chaosblade/exec/common/context/ThreadLocalContext.java @@ -1,22 +1,45 @@ package com.alibaba.chaosblade.exec.common.context; +import java.util.Map; + /** * @author shizhi.zhu@qunar.com */ public class ThreadLocalContext { private static ThreadLocalContext DEFAULT = new ThreadLocalContext(); - private InheritableThreadLocal local = new InheritableThreadLocal(); + private InheritableThreadLocal local = new InheritableThreadLocal(); public static ThreadLocalContext getInstance() { return DEFAULT; } - public void set(Object value) { + public void set(Content value) { local.set(value); } - public Object get() { + public Content get() { return local.get(); } + + public static class Content{ + private StackTraceElement[] stackTraceElements; + private Map> businessData; + + public StackTraceElement[] getStackTraceElements() { + return stackTraceElements; + } + + public void setStackTraceElements(StackTraceElement[] stackTraceElements) { + this.stackTraceElements = stackTraceElements; + } + + public Map> getBusinessData() { + return businessData; + } + + public void settValue(Map> businessData) { + this.businessData = businessData; + } + } } diff --git a/chaosblade-exec-common/src/main/java/com/alibaba/chaosblade/exec/common/injection/Injector.java b/chaosblade-exec-common/src/main/java/com/alibaba/chaosblade/exec/common/injection/Injector.java index 0fca17b6..cc5003e9 100644 --- a/chaosblade-exec-common/src/main/java/com/alibaba/chaosblade/exec/common/injection/Injector.java +++ b/chaosblade-exec-common/src/main/java/com/alibaba/chaosblade/exec/common/injection/Injector.java @@ -28,6 +28,7 @@ import com.alibaba.chaosblade.exec.common.model.action.returnv.UnsupportedReturnTypeException; import com.alibaba.chaosblade.exec.common.model.matcher.MatcherModel; import com.alibaba.chaosblade.exec.common.util.JsonUtil; +import com.alibaba.chaosblade.exec.common.util.ModelUtil; import com.alibaba.chaosblade.exec.common.util.StringUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -163,9 +164,13 @@ private static boolean compare(Model model, EnhancerModel enhancerModel) { continue; } } - return false; } + // business param match + if (keyName.equals(ModelConstant.BUSINESS_PARAMS)) { + Map> expMap = (Map>) value; + value = expMap.get(ModelUtil.getIdentifier(model)); + } // custom match if (keyName.endsWith(ModelConstant.REGEX_PATTERN_FLAG) ? customMatcher.regexMatch(String.valueOf(entry.getValue()), value) : customMatcher.match(String.valueOf(entry.getValue()), value)) { continue; diff --git a/chaosblade-exec-common/src/main/java/com/alibaba/chaosblade/exec/common/model/matcher/BusinessParamsMatcherSpec.java b/chaosblade-exec-common/src/main/java/com/alibaba/chaosblade/exec/common/model/matcher/BusinessParamsMatcherSpec.java new file mode 100644 index 00000000..42d29760 --- /dev/null +++ b/chaosblade-exec-common/src/main/java/com/alibaba/chaosblade/exec/common/model/matcher/BusinessParamsMatcherSpec.java @@ -0,0 +1,42 @@ +package com.alibaba.chaosblade.exec.common.model.matcher; + +import com.alibaba.chaosblade.exec.common.aop.PredicateResult; +import com.alibaba.chaosblade.exec.common.constant.ModelConstant; +import com.alibaba.chaosblade.exec.common.util.BusinessParamUtil; + +import java.util.List; + +/** + * @author wufunc@gmail.com + */ +public class BusinessParamsMatcherSpec extends BasePredicateMatcherSpec { + @Override + public String getName() { + return ModelConstant.BUSINESS_PARAMS; + } + + @Override + public String getDesc() { + return "business parmas"; + } + + @Override + public boolean noArgs() { + return false; + } + + @Override + public boolean required() { + return false; + } + + @Override + public PredicateResult predicate(MatcherModel matcherModel) { + String bParam = matcherModel.get(ModelConstant.BUSINESS_PARAMS); + List params = BusinessParamUtil.parseFromJsonStr(bParam); + if (params == null || params.isEmpty()) { + return PredicateResult.fail(getName() + " illegal json"); + } + return PredicateResult.success(); + } +} diff --git a/chaosblade-exec-common/src/main/java/com/alibaba/chaosblade/exec/common/util/BusinessParamUtil.java b/chaosblade-exec-common/src/main/java/com/alibaba/chaosblade/exec/common/util/BusinessParamUtil.java new file mode 100644 index 00000000..29fb07a5 --- /dev/null +++ b/chaosblade-exec-common/src/main/java/com/alibaba/chaosblade/exec/common/util/BusinessParamUtil.java @@ -0,0 +1,174 @@ +package com.alibaba.chaosblade.exec.common.util; + +import com.alibaba.chaosblade.exec.common.center.ManagerFactory; +import com.alibaba.chaosblade.exec.common.center.StatusMetric; +import com.alibaba.chaosblade.exec.common.constant.ModelConstant; +import com.alibaba.chaosblade.exec.common.context.GlobalContext; +import com.alibaba.chaosblade.exec.common.model.Model; +import com.alibaba.chaosblade.exec.spi.BusinessDataGetter; +import com.fasterxml.jackson.databind.JsonNode; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.*; + +/** + * @author wufunc@gmail.com + */ +public class BusinessParamUtil { + private static final Logger LOGGER = LoggerFactory.getLogger(BusinessParamUtil.class); + private static GlobalContext businessParamContent = new GlobalContext(3600, 100000); + + private static Map> getAndParse(String target) throws Exception { + Map> paramsMap = new HashMap>(); + List statusMetrics = ManagerFactory.getStatusManager().getExpByTarget( + target); + for (StatusMetric statusMetric : statusMetrics) { + Model model = statusMetric.getModel(); + String flag = model.getMatcher().get(ModelConstant.BUSINESS_PARAMS); + List businessParams = parseFromJsonStr(flag); + paramsMap.put(ModelUtil.getIdentifier(model), businessParams); + } + return paramsMap; + } + + public static List parseFromJsonStr(String str) { + try { + if (!StringUtil.isBlank(str)) { + if (businessParamContent.containsKey(str)) { + return (List) businessParamContent.get(str); + } + List businessParams = Arrays.asList(JsonUtil.reader().readValue(str, BusinessParam[].class)); + businessParamContent.put(str, businessParams); + return businessParams; + } + } catch (Exception exp) { + LOGGER.warn("{} is not illegal json ", ModelConstant.BUSINESS_PARAMS); + } + return Collections.EMPTY_LIST; + } + + public static Map> getAndParse(String target, BusinessDataGetter dataGetter) throws Exception { + Map> businessParams = getAndParse(target); + Map> result = new HashMap>(); + for (Map.Entry> entry : businessParams.entrySet()) { + result.put(entry.getKey(), new HashMap()); + for (BusinessParam businessParam : entry.getValue()) { + String value = ""; + if (businessParam.getMode().equals(mode.rpc.getValue())) { + value = getValueFromRpc(businessParam, dataGetter); + } else { + value = getValueFromSPI(businessParam, dataGetter); + } + if (!StringUtils.isEmpty(value)) { + result.get(entry.getKey()).put(businessParam.getKey(), value); + } + } + } + return result; + } + + private static String getValueFromSPI(BusinessParam businessParam, BusinessDataGetter dataGetter) { + List objects = ManagerFactory.spiServiceManager().getServices(BusinessDataGetter.class.getName(), Thread.currentThread().getContextClassLoader()); + if (objects == null || objects.isEmpty()) { + return null; + } + for (Object object : objects) { + String tmpValue = null; + try { + tmpValue = ReflectUtil.invokeMethod(object, "get", new Object[]{businessParam.getKey()}, true); + } catch (Exception e) { + LOGGER.warn("get business value from spi class error,class :{}", object.getClass().getName(), e); + } + if (!StringUtils.isEmpty(tmpValue)) { + return tmpValue; + } + } + return null; + } + + private static String getValueFromRpc(BusinessParam businessParam, BusinessDataGetter dataGetter) { + String value = ""; + try { + if (businessParam.hasMultiLevelKey()) { + String json = dataGetter.get(businessParam.getFirstLevelKey()); + if (StringUtils.isEmpty(json)) { + return null; + } + JsonNode jsonNode = JsonUtil.reader().readTree(json); + JsonNode nodeResult = jsonNode.findValue(businessParam.getJsonPath()); + if ((nodeResult != null)) { + value = nodeResult.asText(); + } + } else { + value = dataGetter.get(businessParam.getKey()); + } + } catch (Exception e) { + LOGGER.warn("get business data from rpc error", e); + } + return value; + } + + public static class BusinessParam { + private String key; + private String value; + private String mode = BusinessParamUtil.mode.rpc.getValue(); + + public String getFirstLevelKey() { + if (hasMultiLevelKey()) { + return key.substring(0, key.indexOf(".")); + } else { + return key; + } + } + + public boolean hasMultiLevelKey() { + if (key.contains(".")) { + return true; + } else { + return false; + } + } + + public String getJsonPath() { + return key.substring(key.indexOf(".") + 1, key.length()); + } + + public String getKey() { + return key; + } + + public void setKey(String key) { + this.key = key; + } + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } + + public String getMode() { + return mode; + } + + public void setMode(String mode) { + this.mode = mode; + } + } + + private enum mode { + spi("spi"), rpc("rpc"); + private String value; + + mode(String value) { + this.value = value; + } + + public String getValue() { + return value; + } + } +} diff --git a/chaosblade-exec-plugin/chaosblade-exec-plugin-dubbo/pom.xml b/chaosblade-exec-plugin/chaosblade-exec-plugin-dubbo/pom.xml index 67547790..c1fe6d4a 100644 --- a/chaosblade-exec-plugin/chaosblade-exec-plugin-dubbo/pom.xml +++ b/chaosblade-exec-plugin/chaosblade-exec-plugin-dubbo/pom.xml @@ -38,6 +38,14 @@ + + + com.alibaba.chaosblade + chaosblade-exec-spi + 1.4.0 + compile + + diff --git a/chaosblade-exec-plugin/chaosblade-exec-plugin-dubbo/src/main/java/com/alibaba/chaosblade/exec/plugin/dubbo/DubboEnhancer.java b/chaosblade-exec-plugin/chaosblade-exec-plugin-dubbo/src/main/java/com/alibaba/chaosblade/exec/plugin/dubbo/DubboEnhancer.java index 53ca24c5..006e0ef1 100644 --- a/chaosblade-exec-plugin/chaosblade-exec-plugin-dubbo/src/main/java/com/alibaba/chaosblade/exec/plugin/dubbo/DubboEnhancer.java +++ b/chaosblade-exec-plugin/chaosblade-exec-plugin-dubbo/src/main/java/com/alibaba/chaosblade/exec/plugin/dubbo/DubboEnhancer.java @@ -17,13 +17,15 @@ package com.alibaba.chaosblade.exec.plugin.dubbo; import java.lang.reflect.Method; +import java.util.Map; import com.alibaba.chaosblade.exec.common.aop.BeforeEnhancer; import com.alibaba.chaosblade.exec.common.aop.EnhancerModel; +import com.alibaba.chaosblade.exec.common.aop.matcher.busi.BusinessParamMatcher; +import com.alibaba.chaosblade.exec.common.constant.ModelConstant; import com.alibaba.chaosblade.exec.common.model.action.delay.TimeoutExecutor; import com.alibaba.chaosblade.exec.common.model.matcher.MatcherModel; -import com.alibaba.chaosblade.exec.common.util.JsonUtil; -import com.alibaba.chaosblade.exec.common.util.ReflectUtil; +import com.alibaba.chaosblade.exec.common.util.*; import com.alibaba.chaosblade.exec.plugin.dubbo.model.DubboThreadPoolFullExecutor; import org.slf4j.Logger; @@ -41,19 +43,22 @@ public abstract class DubboEnhancer extends BeforeEnhancer { public static final String GET_SERVICE_KEY = "getServiceKey"; public static final String GET_METHOD_NAME = "getMethodName"; public static final String GET_ARGUMENTS = "getArguments"; + public static final String GET_ATTACHMENTS = "getAttachments"; public static final String GENERIC = "generic"; public static final String SPLIT_TOKEN = ":"; public static final String GROUP_SEP = "/"; public static final String GET_INVOKER = "getInvoker"; public static final String RECEIVED_METHOD = "received"; + + public static final int INVALID_POS = -1; private static final Logger LOGGER = LoggerFactory.getLogger(DubboEnhancer.class); @Override public EnhancerModel doBeforeAdvice(ClassLoader classLoader, String className, Object object, Method method, Object[] - methodArguments) - throws Exception { + methodArguments) + throws Exception { if (method.getName().equals(RECEIVED_METHOD)) { // received method for thread pool experiment DubboThreadPoolFullExecutor.INSTANCE.setWrappedChannelHandler(object); @@ -70,14 +75,13 @@ public EnhancerModel doBeforeAdvice(ClassLoader classLoader, String className, O LOGGER.warn("Url is null, can not get necessary values."); return null; } - String appName = ReflectUtil.invokeMethod(url, GET_PARAMETER, new Object[] {APPLICATION_KEY}, false); String methodName = null; - String provideGeneric = ReflectUtil.invokeMethod(url, GET_PARAMETER, new Object[] {GENERIC}, false); + String provideGeneric = ReflectUtil.invokeMethod(url, GET_PARAMETER, new Object[]{GENERIC}, false); boolean consumerGeneric = isConsumerGeneric(object, invocation); if (Boolean.valueOf(provideGeneric) || consumerGeneric) { Object[] arguments = ReflectUtil.invokeMethod(invocation, GET_ARGUMENTS, new Object[0], false); if (arguments.length > 1 && arguments[0] instanceof String) { - methodName = (String)arguments[0]; + methodName = (String) arguments[0]; } LOGGER.debug("generic is true, methodName:{}", methodName); } else { @@ -88,28 +92,33 @@ public EnhancerModel doBeforeAdvice(ClassLoader classLoader, String className, O LOGGER.warn("methodName is null, can not get necessary values."); return null; } - String[] serviceAndVersionGroup = getServiceNameWithVersionGroup(invocation, url); MatcherModel matcherModel = new MatcherModel(); + String appName = ReflectUtil.invokeMethod(url, GET_PARAMETER, new Object[]{APPLICATION_KEY}, false); matcherModel.add(DubboConstant.APP_KEY, appName); matcherModel.add(DubboConstant.SERVICE_KEY, serviceAndVersionGroup[0]); matcherModel.add(DubboConstant.VERSION_KEY, serviceAndVersionGroup[1]); if (2 < serviceAndVersionGroup.length && - null != serviceAndVersionGroup[2]) { + null != serviceAndVersionGroup[2]) { matcherModel.add(DubboConstant.GROUP_KEY, serviceAndVersionGroup[2]); } matcherModel.add(DubboConstant.METHOD_KEY, methodName); int timeout = getTimeout(methodName, object, invocation); matcherModel.add(DubboConstant.TIMEOUT_KEY, timeout + ""); - if (LOGGER.isDebugEnabled()) { LOGGER.debug("dubbo matchers: {}", JsonUtil.writer().writeValueAsString(matcherModel)); } - EnhancerModel enhancerModel = new EnhancerModel(classLoader, matcherModel); enhancerModel.setTimeoutExecutor(createTimeoutExecutor(classLoader, timeout, className)); - + try { + Map> businessParams = getBusinessParams(invocation); + if (businessParams != null) { + enhancerModel.addCustomMatcher(ModelConstant.BUSINESS_PARAMS, businessParams, BusinessParamMatcher.getInstance()); + } + } catch (Exception e) { + LOGGER.warn("Getting business params occurs exception,return null", e); + } postDoBeforeAdvice(enhancerModel); return enhancerModel; } @@ -119,7 +128,7 @@ protected boolean isConsumerGeneric(Object object, Object invocation) throws Exc Class type = ReflectUtil.getSuperclassFieldValue(object, "type", false); String clazz = type.getName(); return methodName.contains("$invoke") && (clazz.equalsIgnoreCase("org.apache.dubbo.rpc.service.GenericService") - || clazz.equalsIgnoreCase("com.alibaba.dubbo.rpc.service.GenericService")); + || clazz.equalsIgnoreCase("com.alibaba.dubbo.rpc.service.GenericService")); } protected abstract void postDoBeforeAdvice(EnhancerModel enhancerModel); @@ -148,9 +157,9 @@ public String[] getServiceNameWithVersionGroup(Object invocation, Object url) th String[] serviceAndVersion = serviceKey.split(SPLIT_TOKEN); if (serviceAndVersion.length == 1) { - return new String[] {serviceAndVersion[0], DEFAULT_VERSION, group}; + return new String[]{serviceAndVersion[0], DEFAULT_VERSION, group}; } - return new String[] {serviceAndVersion[0], serviceAndVersion[1], group}; + return new String[]{serviceAndVersion[0], serviceAndVersion[1], group}; } } @@ -194,4 +203,14 @@ protected abstract TimeoutExecutor createTimeoutExecutor(ClassLoader classLoader protected boolean isThan2700Version(String className) { return className.startsWith("org.apache"); } + + /** + * Get b-params + * + * @param invocation + * @return + * @throws Exception + */ + protected abstract Map> getBusinessParams(Object invocation) throws Exception; + } diff --git a/chaosblade-exec-plugin/chaosblade-exec-plugin-dubbo/src/main/java/com/alibaba/chaosblade/exec/plugin/dubbo/consumer/DubboConsumerEnhancer.java b/chaosblade-exec-plugin/chaosblade-exec-plugin-dubbo/src/main/java/com/alibaba/chaosblade/exec/plugin/dubbo/consumer/DubboConsumerEnhancer.java index c397e547..7116d3df 100644 --- a/chaosblade-exec-plugin/chaosblade-exec-plugin-dubbo/src/main/java/com/alibaba/chaosblade/exec/plugin/dubbo/consumer/DubboConsumerEnhancer.java +++ b/chaosblade-exec-plugin/chaosblade-exec-plugin-dubbo/src/main/java/com/alibaba/chaosblade/exec/plugin/dubbo/consumer/DubboConsumerEnhancer.java @@ -17,20 +17,26 @@ package com.alibaba.chaosblade.exec.plugin.dubbo.consumer; import java.lang.reflect.Constructor; +import java.lang.reflect.Method; import java.util.List; +import java.util.Map; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.alibaba.chaosblade.exec.common.aop.EnhancerModel; +import com.alibaba.chaosblade.exec.common.aop.matcher.busi.BusinessParamMatcher; +import com.alibaba.chaosblade.exec.common.constant.ModelConstant; import com.alibaba.chaosblade.exec.common.model.action.delay.BaseTimeoutExecutor; import com.alibaba.chaosblade.exec.common.model.action.delay.TimeoutExecutor; +import com.alibaba.chaosblade.exec.common.util.BusinessParamUtil; import com.alibaba.chaosblade.exec.common.util.FlagUtil; import com.alibaba.chaosblade.exec.common.util.ReflectUtil; import com.alibaba.chaosblade.exec.common.util.StringUtils; import com.alibaba.chaosblade.exec.plugin.dubbo.DubboConstant; import com.alibaba.chaosblade.exec.plugin.dubbo.DubboEnhancer; import com.alibaba.chaosblade.exec.plugin.dubbo.model.CallPointMatcher; +import com.alibaba.chaosblade.exec.spi.BusinessDataGetter; /** * @author Changjun Xiao @@ -105,6 +111,16 @@ protected Object getUrl(Object instance, Object invocation) throws Exception { } return ReflectUtil.invokeMethod(instance, GET_URL, new Object[0], false); } + @Override + protected Map> getBusinessParams(final Object invocation) throws Exception { + return BusinessParamUtil.getAndParse(DubboConstant.TARGET_NAME, new BusinessDataGetter() { + @Override + public String get(String key) throws Exception { + Map attachments = ReflectUtil.invokeMethod(invocation, GET_ATTACHMENTS, new Object[0], false); + return attachments.get(key); + } + }); + } @Override protected void postDoBeforeAdvice(EnhancerModel enhancerModel) { diff --git a/chaosblade-exec-plugin/chaosblade-exec-plugin-dubbo/src/main/java/com/alibaba/chaosblade/exec/plugin/dubbo/model/DubboModelSpec.java b/chaosblade-exec-plugin/chaosblade-exec-plugin-dubbo/src/main/java/com/alibaba/chaosblade/exec/plugin/dubbo/model/DubboModelSpec.java index f472468b..c492c176 100644 --- a/chaosblade-exec-plugin/chaosblade-exec-plugin-dubbo/src/main/java/com/alibaba/chaosblade/exec/plugin/dubbo/model/DubboModelSpec.java +++ b/chaosblade-exec-plugin/chaosblade-exec-plugin-dubbo/src/main/java/com/alibaba/chaosblade/exec/plugin/dubbo/model/DubboModelSpec.java @@ -31,6 +31,7 @@ import com.alibaba.chaosblade.exec.common.model.action.threadpool.ThreadPoolFullActionSpec; import com.alibaba.chaosblade.exec.common.model.handler.PreCreateInjectionModelHandler; import com.alibaba.chaosblade.exec.common.model.handler.PreDestroyInjectionModelHandler; +import com.alibaba.chaosblade.exec.common.model.matcher.BusinessParamsMatcherSpec; import com.alibaba.chaosblade.exec.common.model.matcher.MatcherModel; import com.alibaba.chaosblade.exec.common.model.matcher.MatcherSpec; import com.alibaba.chaosblade.exec.common.plugin.MethodNameMatcherSpec; @@ -89,6 +90,7 @@ protected List createNewMatcherSpecs() { matcherSpecs.add(new MethodNameMatcherSpec()); matcherSpecs.add(new GroupMatcherSpec()); matcherSpecs.add(new CallPointMatcherSpec()); + matcherSpecs.add(new BusinessParamsMatcherSpec()); return matcherSpecs; } diff --git a/chaosblade-exec-plugin/chaosblade-exec-plugin-dubbo/src/main/java/com/alibaba/chaosblade/exec/plugin/dubbo/provider/DubboProviderEnhancer.java b/chaosblade-exec-plugin/chaosblade-exec-plugin-dubbo/src/main/java/com/alibaba/chaosblade/exec/plugin/dubbo/provider/DubboProviderEnhancer.java index bd0736c4..fc8c6182 100644 --- a/chaosblade-exec-plugin/chaosblade-exec-plugin-dubbo/src/main/java/com/alibaba/chaosblade/exec/plugin/dubbo/provider/DubboProviderEnhancer.java +++ b/chaosblade-exec-plugin/chaosblade-exec-plugin-dubbo/src/main/java/com/alibaba/chaosblade/exec/plugin/dubbo/provider/DubboProviderEnhancer.java @@ -22,6 +22,8 @@ import com.alibaba.chaosblade.exec.plugin.dubbo.DubboConstant; import com.alibaba.chaosblade.exec.plugin.dubbo.DubboEnhancer; +import java.util.Map; + /** * @author Changjun Xiao */ @@ -38,6 +40,11 @@ protected TimeoutExecutor createTimeoutExecutor(ClassLoader classLoader, long ti return null; } + @Override + protected Map> getBusinessParams(Object invocation) throws Exception { + return null; + } + @Override protected void postDoBeforeAdvice(EnhancerModel enhancerModel) { enhancerModel.addMatcher(DubboConstant.PROVIDER_KEY, "true"); diff --git a/chaosblade-exec-plugin/chaosblade-exec-plugin-http/src/main/java/com/alibaba/chaosblade/exec/plugin/http/HttpConstant.java b/chaosblade-exec-plugin/chaosblade-exec-plugin-http/src/main/java/com/alibaba/chaosblade/exec/plugin/http/HttpConstant.java index c7609aba..b487dd5b 100644 --- a/chaosblade-exec-plugin/chaosblade-exec-plugin-http/src/main/java/com/alibaba/chaosblade/exec/plugin/http/HttpConstant.java +++ b/chaosblade-exec-plugin/chaosblade-exec-plugin-http/src/main/java/com/alibaba/chaosblade/exec/plugin/http/HttpConstant.java @@ -16,7 +16,7 @@ public class HttpConstant { public static final String HTTPCLIENT4 = "httpclient4"; public static final String HTTPCLIENT3 = "httpclient3"; public static final String OKHTTP3 = "okhttp3"; - public static final String ASYNC_HTTP_CLIENT = "asyncHttpClient"; + public static final String ASYNC_HTTP_TARGET_NAME = "asyncHttpClient"; public static final String getURI = "getURI"; public static final String CALL_POINT_KEY = "call-point"; @@ -25,4 +25,10 @@ public class HttpConstant { public static final int DEFAULT_TIMEOUT = 60000; public static final String REQUEST_ID = "c_request_id"; + + public static final String REST_TARGET_NAME = "rest"; + public static final String HTTPCLIENT3_TARGET_NAME = "httpclient3"; + public static final String HTTPCLIENT4_TARGET_NAME = "httpclient4"; + public static final String OKHTTP3_TARGET_NAME = "okhttp3"; + } diff --git a/chaosblade-exec-plugin/chaosblade-exec-plugin-http/src/main/java/com/alibaba/chaosblade/exec/plugin/http/HttpEnhancer.java b/chaosblade-exec-plugin/chaosblade-exec-plugin-http/src/main/java/com/alibaba/chaosblade/exec/plugin/http/HttpEnhancer.java index ca262ddc..2a717a4a 100644 --- a/chaosblade-exec-plugin/chaosblade-exec-plugin-http/src/main/java/com/alibaba/chaosblade/exec/plugin/http/HttpEnhancer.java +++ b/chaosblade-exec-plugin/chaosblade-exec-plugin-http/src/main/java/com/alibaba/chaosblade/exec/plugin/http/HttpEnhancer.java @@ -18,7 +18,10 @@ import java.lang.reflect.Method; import java.net.SocketTimeoutException; +import java.util.Map; +import com.alibaba.chaosblade.exec.common.aop.matcher.busi.BusinessParamMatcher; +import com.alibaba.chaosblade.exec.common.constant.ModelConstant; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -59,9 +62,27 @@ public EnhancerModel doBeforeAdvice(ClassLoader classLoader, String className, O enhancerModel.addCustomMatcher(HttpConstant.CALL_POINT_KEY, stackTrace, CallPointMatcher.getInstance()); } enhancerModel.setTimeoutExecutor(createTimeoutExecutor(classLoader, timeout, className)); + try { + Map> businessParams = getBusinessParams(className, object, method, methodArguments); + if (businessParams != null) { + enhancerModel.addCustomMatcher(ModelConstant.BUSINESS_PARAMS, businessParams, BusinessParamMatcher.getInstance()); + } + } catch (Exception e) { + LOGGER.warn("Getting business params occurs exception", e); + } return enhancerModel; } + /** + * Get b-params + * + * @param instance + * @param methodArguments + * @return + * @throws Exception + */ + protected abstract Map> getBusinessParams(String className, Object instance, Method method, Object[] methodArguments) throws Exception; + protected boolean shouldAddCallPoint() { return FlagUtil.hasFlag("http", HttpConstant.CALL_POINT_KEY); } @@ -72,6 +93,7 @@ protected boolean shouldAddCallPoint() { * @param instance * @return */ + protected abstract int getTimeout(Object instance, Object[] methodArguments); /** diff --git a/chaosblade-exec-plugin/chaosblade-exec-plugin-http/src/main/java/com/alibaba/chaosblade/exec/plugin/http/asynchttpclient/AsyncHttpClientEnhancerWrapper.java b/chaosblade-exec-plugin/chaosblade-exec-plugin-http/src/main/java/com/alibaba/chaosblade/exec/plugin/http/asynchttpclient/AsyncHttpClientEnhancerWrapper.java index 7c0dcc39..d3a9b1ea 100644 --- a/chaosblade-exec-plugin/chaosblade-exec-plugin-http/src/main/java/com/alibaba/chaosblade/exec/plugin/http/asynchttpclient/AsyncHttpClientEnhancerWrapper.java +++ b/chaosblade-exec-plugin/chaosblade-exec-plugin-http/src/main/java/com/alibaba/chaosblade/exec/plugin/http/asynchttpclient/AsyncHttpClientEnhancerWrapper.java @@ -25,11 +25,11 @@ public AsyncHttpClientEnhancerWrapper() { @Override public EnhancerModel doBeforeAdvice(ClassLoader classLoader, String className, Object object, Method method, - Object[] methodArguments) throws Exception { + Object[] methodArguments) throws Exception { Enhancer enhancer = container.get(className, method.getName()); if (enhancer != null) { if (enhancer instanceof BeforeEnhancer) { - BeforeEnhancer beforeEnhancer = (BeforeEnhancer)enhancer; + BeforeEnhancer beforeEnhancer = (BeforeEnhancer) enhancer; return beforeEnhancer.doBeforeAdvice(classLoader, className, object, method, methodArguments); } } diff --git a/chaosblade-exec-plugin/chaosblade-exec-plugin-http/src/main/java/com/alibaba/chaosblade/exec/plugin/http/asynchttpclient/AsyncHttpClientHandlerEnhancer.java b/chaosblade-exec-plugin/chaosblade-exec-plugin-http/src/main/java/com/alibaba/chaosblade/exec/plugin/http/asynchttpclient/AsyncHttpClientHandlerEnhancer.java index 31148c77..e9ba94fa 100644 --- a/chaosblade-exec-plugin/chaosblade-exec-plugin-http/src/main/java/com/alibaba/chaosblade/exec/plugin/http/asynchttpclient/AsyncHttpClientHandlerEnhancer.java +++ b/chaosblade-exec-plugin/chaosblade-exec-plugin-http/src/main/java/com/alibaba/chaosblade/exec/plugin/http/asynchttpclient/AsyncHttpClientHandlerEnhancer.java @@ -2,7 +2,9 @@ import static com.alibaba.chaosblade.exec.plugin.http.HttpConstant.DEFAULT_TIMEOUT; +import java.lang.reflect.Method; import java.net.SocketTimeoutException; +import java.util.Map; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -31,13 +33,19 @@ public class AsyncHttpClientHandlerEnhancer extends HttpEnhancer { @Override protected void postDoBeforeAdvice(EnhancerModel enhancerModel) { - enhancerModel.addMatcher(HttpConstant.ASYNC_HTTP_CLIENT, "true"); + ThreadLocalContext.Content content = ThreadLocalContext.getInstance().get(); + enhancerModel.addMatcher(HttpConstant.ASYNC_HTTP_TARGET_NAME, "true"); if (FlagUtil.hasFlag("http", HttpConstant.CALL_POINT_KEY)) { - Object value = ThreadLocalContext.getInstance().get(); - if (value != null) { - enhancerModel.addCustomMatcher(HttpConstant.CALL_POINT_KEY, value, CallPointMatcher.getInstance()); - } + enhancerModel.addCustomMatcher(HttpConstant.CALL_POINT_KEY, content.getStackTraceElements(), CallPointMatcher.getInstance()); } + } + + @Override + protected Map> getBusinessParams(String className, Object instance, Method method, Object[] methodArguments) throws Exception { + ThreadLocalContext.Content content = ThreadLocalContext.getInstance().get(); + if (content == null) { + return null; } + return content.getBusinessData(); } @Override @@ -66,7 +74,7 @@ protected int getTimeout(Object instance, Object[] methodArguments) { } return DEFAULT_TIMEOUT; } - + @Override protected TimeoutExecutor createTimeoutExecutor(ClassLoader classLoader, final long timeout, String className) { return new TimeoutExecutor() { @Override diff --git a/chaosblade-exec-plugin/chaosblade-exec-plugin-http/src/main/java/com/alibaba/chaosblade/exec/plugin/http/asynchttpclient/AsyncHttpClientPlugin.java b/chaosblade-exec-plugin/chaosblade-exec-plugin-http/src/main/java/com/alibaba/chaosblade/exec/plugin/http/asynchttpclient/AsyncHttpClientPlugin.java index d46e4560..91e7198d 100644 --- a/chaosblade-exec-plugin/chaosblade-exec-plugin-http/src/main/java/com/alibaba/chaosblade/exec/plugin/http/asynchttpclient/AsyncHttpClientPlugin.java +++ b/chaosblade-exec-plugin/chaosblade-exec-plugin-http/src/main/java/com/alibaba/chaosblade/exec/plugin/http/asynchttpclient/AsyncHttpClientPlugin.java @@ -11,7 +11,7 @@ public class AsyncHttpClientPlugin extends HttpPlugin { @Override public String getName() { - return HttpConstant.ASYNC_HTTP_CLIENT; + return HttpConstant.ASYNC_HTTP_TARGET_NAME; } @Override diff --git a/chaosblade-exec-plugin/chaosblade-exec-plugin-http/src/main/java/com/alibaba/chaosblade/exec/plugin/http/asynchttpclient/HttpProtocolEnhancer.java b/chaosblade-exec-plugin/chaosblade-exec-plugin-http/src/main/java/com/alibaba/chaosblade/exec/plugin/http/asynchttpclient/HttpProtocolEnhancer.java index b9f22bcc..e2d4527e 100644 --- a/chaosblade-exec-plugin/chaosblade-exec-plugin-http/src/main/java/com/alibaba/chaosblade/exec/plugin/http/asynchttpclient/HttpProtocolEnhancer.java +++ b/chaosblade-exec-plugin/chaosblade-exec-plugin-http/src/main/java/com/alibaba/chaosblade/exec/plugin/http/asynchttpclient/HttpProtocolEnhancer.java @@ -2,7 +2,12 @@ import java.lang.reflect.Method; import java.util.List; +import java.util.Map; +import com.alibaba.chaosblade.exec.common.constant.ModelConstant; +import com.alibaba.chaosblade.exec.common.util.BusinessParamUtil; +import com.alibaba.chaosblade.exec.plugin.http.HttpEnhancer; +import com.alibaba.chaosblade.exec.spi.BusinessDataGetter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -19,19 +24,72 @@ * @author shizhi.zhu@qunar.com */ @InternalPointCut(className = "com.ning.http.client.providers.netty.handler.HttpProtocol", methodName = "handle") -public class HttpProtocolEnhancer extends BeforeEnhancer { +public class HttpProtocolEnhancer extends HttpEnhancer { private static final Logger LOGGER = LoggerFactory.getLogger(HttpProtocolEnhancer.class); @Override public EnhancerModel doBeforeAdvice(ClassLoader classLoader, String className, Object object, Method method, - Object[] methodArguments) throws Exception { + Object[] methodArguments) throws Exception { + super.doBeforeAdvice(classLoader,className,object,method,methodArguments); if (!shouldAddCallPoint()) { return null; } + Object headers = getHttpHeader(className, object, method, methodArguments); + if (headers == null) { + return null; + } + List values = (List) ReflectUtil.invokeMethod(headers, "get", new String[]{HttpConstant.REQUEST_ID}); + if (values != null && !values.isEmpty()) { + String id = values.get(0); + StackTraceElement[] stackTrace = (StackTraceElement[]) GlobalContext.getDefaultInstance().remove(id); + ThreadLocalContext.Content content; + if (ThreadLocalContext.getInstance().get() == null) { + content = new ThreadLocalContext.Content(); + } else { + content = ThreadLocalContext.getInstance().get(); + } + content.setStackTraceElements(stackTrace); + ThreadLocalContext.getInstance().set(content); + } else { + LOGGER.warn("header not found, className:{}, methodName:{}", className, method.getName()); + } + return null; + } + + @Override + protected Map> getBusinessParams(String className, Object instance, Method method, Object[] methodArguments) throws Exception { + if (!shouldAddBusinessParam()) { + return null; + } + final Object headers = getHttpHeader(className, instance, method, methodArguments); + if (headers == null) { + return null; + } + ThreadLocalContext.Content content; + if (ThreadLocalContext.getInstance().get() == null) { + content = new ThreadLocalContext.Content(); + } else { + content = ThreadLocalContext.getInstance().get(); + } + content.settValue(BusinessParamUtil.getAndParse(HttpConstant.ASYNC_HTTP_TARGET_NAME, new BusinessDataGetter() { + @Override + public String get(String key) throws Exception { + List values = (List) ReflectUtil.invokeMethod(headers, "get", new Object[]{key}, false); + if (values != null && !values.isEmpty()) { + return values.get(0); + } + return null; + } + })); + ThreadLocalContext.getInstance().set(content); + return null; + } + private Object getHttpHeader(String className, Object object, Method method, + Object[] methodArguments) throws Exception { if (methodArguments.length < 2) { LOGGER.warn("argument's length less than 2, can't find NettyResponseFuture, className:{}, methodName:{}", - className, method.getName()); + className, method.getName()); return null; } Object future = methodArguments[1]; @@ -44,22 +102,31 @@ public EnhancerModel doBeforeAdvice(ClassLoader classLoader, String className, O LOGGER.warn("request not found, className:{}, methodName:{}", className, method.getName()); return null; } - Object headers = ReflectUtil.invokeMethod(request, "getHeaders"); - Object value = ReflectUtil.invokeMethod(headers, "get", new String[] {HttpConstant.REQUEST_ID}); - List values = (List)value; - if (values == null || values.isEmpty()) { - LOGGER.warn("header not found, className:{}, methodName:{}", className, method.getName()); - return null; - } - - String id = values.get(0); - StackTraceElement[] stackTrace = (StackTraceElement[])GlobalContext.getDefaultInstance().remove(id); - ThreadLocalContext.getInstance().set(stackTrace); - return null; + return headers; } + protected boolean shouldAddCallPoint() { return FlagUtil.hasFlag("http", HttpConstant.CALL_POINT_KEY); } + + @Override + protected int getTimeout(Object instance, Object[] methodArguments) { + return 0; + } + + @Override + protected void postDoBeforeAdvice(EnhancerModel enhancerModel) { + + } + + @Override + protected String getUrl(Object instance, Object[] object) throws Exception { + return null; + } + + protected boolean shouldAddBusinessParam() { + return FlagUtil.hasFlag("http", ModelConstant.BUSINESS_PARAMS); + } } diff --git a/chaosblade-exec-plugin/chaosblade-exec-plugin-http/src/main/java/com/alibaba/chaosblade/exec/plugin/http/httpclient3/HttpClient3Enhancer.java b/chaosblade-exec-plugin/chaosblade-exec-plugin-http/src/main/java/com/alibaba/chaosblade/exec/plugin/http/httpclient3/HttpClient3Enhancer.java index 9f6a730b..9184a01a 100644 --- a/chaosblade-exec-plugin/chaosblade-exec-plugin-http/src/main/java/com/alibaba/chaosblade/exec/plugin/http/httpclient3/HttpClient3Enhancer.java +++ b/chaosblade-exec-plugin/chaosblade-exec-plugin-http/src/main/java/com/alibaba/chaosblade/exec/plugin/http/httpclient3/HttpClient3Enhancer.java @@ -1,13 +1,17 @@ package com.alibaba.chaosblade.exec.plugin.http.httpclient3; import com.alibaba.chaosblade.exec.common.aop.EnhancerModel; +import com.alibaba.chaosblade.exec.common.util.BusinessParamUtil; import com.alibaba.chaosblade.exec.common.util.ReflectUtil; +import com.alibaba.chaosblade.exec.plugin.http.HttpConstant; import com.alibaba.chaosblade.exec.plugin.http.HttpEnhancer; import com.alibaba.chaosblade.exec.plugin.http.UrlUtils; +import com.alibaba.chaosblade.exec.spi.BusinessDataGetter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.lang.reflect.Method; +import java.util.Map; import static com.alibaba.chaosblade.exec.plugin.http.HttpConstant.*; @@ -22,12 +26,26 @@ public class HttpClient3Enhancer extends HttpEnhancer { private static final String GET_PARAMS = "getParams"; private static final String GET_SOCKET_TIMEOUT = "getSoTimeout"; private static final String GET_CONNECTION_TIMEOUT = "getConnectionTimeout"; + private static final String GET_REQUEST_HEADER = "getRequestHeader"; + private static final String GET_VALUE = "getValue"; @Override protected void postDoBeforeAdvice(EnhancerModel enhancerModel) { enhancerModel.addMatcher(HTTPCLIENT3, "true"); } + @Override + protected Map> getBusinessParams(String className, Object instance, Method method, final Object[] methodArguments) throws Exception { + return BusinessParamUtil.getAndParse(HTTPCLIENT3_TARGET_NAME, new BusinessDataGetter() { + @Override + public String get(String key) throws Exception { + Object httpMethod = methodArguments[1]; + Object header = ReflectUtil.invokeMethod(httpMethod, GET_REQUEST_HEADER, new Object[]{key}, false); + return (String) ReflectUtil.invokeMethod(header, GET_VALUE, new Object[0], false); + } + }); + } + @Override protected int getTimeout(Object instance, Object[] methodArguments) { try { diff --git a/chaosblade-exec-plugin/chaosblade-exec-plugin-http/src/main/java/com/alibaba/chaosblade/exec/plugin/http/httpclient3/HttpClient3Plugin.java b/chaosblade-exec-plugin/chaosblade-exec-plugin-http/src/main/java/com/alibaba/chaosblade/exec/plugin/http/httpclient3/HttpClient3Plugin.java index e6317c3e..5bc16232 100644 --- a/chaosblade-exec-plugin/chaosblade-exec-plugin-http/src/main/java/com/alibaba/chaosblade/exec/plugin/http/httpclient3/HttpClient3Plugin.java +++ b/chaosblade-exec-plugin/chaosblade-exec-plugin-http/src/main/java/com/alibaba/chaosblade/exec/plugin/http/httpclient3/HttpClient3Plugin.java @@ -2,6 +2,7 @@ import com.alibaba.chaosblade.exec.common.aop.Enhancer; import com.alibaba.chaosblade.exec.common.aop.PointCut; +import com.alibaba.chaosblade.exec.plugin.http.HttpConstant; import com.alibaba.chaosblade.exec.plugin.http.HttpPlugin; /** @@ -13,7 +14,7 @@ public class HttpClient3Plugin extends HttpPlugin { @Override public String getName() { - return "httpclient3"; + return HttpConstant.HTTPCLIENT3_TARGET_NAME; } @Override diff --git a/chaosblade-exec-plugin/chaosblade-exec-plugin-http/src/main/java/com/alibaba/chaosblade/exec/plugin/http/httpclient4/HttpClient4Enhancer.java b/chaosblade-exec-plugin/chaosblade-exec-plugin-http/src/main/java/com/alibaba/chaosblade/exec/plugin/http/httpclient4/HttpClient4Enhancer.java index 7af82a23..1d96e311 100644 --- a/chaosblade-exec-plugin/chaosblade-exec-plugin-http/src/main/java/com/alibaba/chaosblade/exec/plugin/http/httpclient4/HttpClient4Enhancer.java +++ b/chaosblade-exec-plugin/chaosblade-exec-plugin-http/src/main/java/com/alibaba/chaosblade/exec/plugin/http/httpclient4/HttpClient4Enhancer.java @@ -1,13 +1,17 @@ package com.alibaba.chaosblade.exec.plugin.http.httpclient4; import com.alibaba.chaosblade.exec.common.aop.EnhancerModel; +import com.alibaba.chaosblade.exec.common.util.BusinessParamUtil; import com.alibaba.chaosblade.exec.common.util.ReflectUtil; +import com.alibaba.chaosblade.exec.plugin.http.HttpConstant; import com.alibaba.chaosblade.exec.plugin.http.HttpEnhancer; import com.alibaba.chaosblade.exec.plugin.http.UrlUtils; +import com.alibaba.chaosblade.exec.spi.BusinessDataGetter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.lang.reflect.Method; +import java.util.Map; import static com.alibaba.chaosblade.exec.plugin.http.HttpConstant.*; @@ -25,9 +29,11 @@ public class HttpClient4Enhancer extends HttpEnhancer { private static final String REQUEST_GET_CONNECT_TIMEOUT = "getConnectTimeout"; private static final String REQUEST_GET_SOCKET_TIMEOUT = "getSocketTimeout"; private static final String GET_CONFIG = "getConfig"; + private static final String GET_FIRST_HEADER = "getFirstHeader"; private static final String CLIENT_GET_CONNECTION_TIMEOUT = "getConnectionTimeout"; private static final String CLIENT_GET_SOCKET_TIMEOUT = "getSoTimeout"; + private static final String HTTP_HEADER_GET_VALUE = "getValue"; private static final String HTTP_CONNECTION_PARAMS = "org.apache.http.params.HttpConnectionParams"; @@ -36,6 +42,18 @@ protected void postDoBeforeAdvice(EnhancerModel enhancerModel) { enhancerModel.addMatcher(HTTPCLIENT4, "true"); } + @Override + protected Map> getBusinessParams(String className, Object instance, Method method, final Object[] methodArguments) throws Exception { + return BusinessParamUtil.getAndParse(HTTPCLIENT4_TARGET_NAME, new BusinessDataGetter() { + @Override + public String get(String key) throws Exception { + Object request = methodArguments[1]; + Object header = ReflectUtil.invokeMethod(request, GET_FIRST_HEADER, new Object[]{key}, false); + return (String) ReflectUtil.invokeMethod(header, HTTP_HEADER_GET_VALUE, new Object[0], false); + } + }); + } + @Override protected int getTimeout(Object instance, Object[] methodArguments) { try { diff --git a/chaosblade-exec-plugin/chaosblade-exec-plugin-http/src/main/java/com/alibaba/chaosblade/exec/plugin/http/httpclient4/HttpClient4Plugin.java b/chaosblade-exec-plugin/chaosblade-exec-plugin-http/src/main/java/com/alibaba/chaosblade/exec/plugin/http/httpclient4/HttpClient4Plugin.java index aa441b06..3ec38597 100644 --- a/chaosblade-exec-plugin/chaosblade-exec-plugin-http/src/main/java/com/alibaba/chaosblade/exec/plugin/http/httpclient4/HttpClient4Plugin.java +++ b/chaosblade-exec-plugin/chaosblade-exec-plugin-http/src/main/java/com/alibaba/chaosblade/exec/plugin/http/httpclient4/HttpClient4Plugin.java @@ -2,6 +2,7 @@ import com.alibaba.chaosblade.exec.common.aop.Enhancer; import com.alibaba.chaosblade.exec.common.aop.PointCut; +import com.alibaba.chaosblade.exec.plugin.http.HttpConstant; import com.alibaba.chaosblade.exec.plugin.http.HttpPlugin; /** @@ -13,7 +14,7 @@ public class HttpClient4Plugin extends HttpPlugin { @Override public String getName() { - return "httpclient4"; + return HttpConstant.HTTPCLIENT4_TARGET_NAME; } @Override diff --git a/chaosblade-exec-plugin/chaosblade-exec-plugin-http/src/main/java/com/alibaba/chaosblade/exec/plugin/http/model/AsyncHttpClientMatcherSpec.java b/chaosblade-exec-plugin/chaosblade-exec-plugin-http/src/main/java/com/alibaba/chaosblade/exec/plugin/http/model/AsyncHttpClientMatcherSpec.java index c0aff450..523f4a7d 100644 --- a/chaosblade-exec-plugin/chaosblade-exec-plugin-http/src/main/java/com/alibaba/chaosblade/exec/plugin/http/model/AsyncHttpClientMatcherSpec.java +++ b/chaosblade-exec-plugin/chaosblade-exec-plugin-http/src/main/java/com/alibaba/chaosblade/exec/plugin/http/model/AsyncHttpClientMatcherSpec.java @@ -26,7 +26,7 @@ public class AsyncHttpClientMatcherSpec extends BasePredicateMatcherSpec { @Override public String getName() { - return HttpConstant.ASYNC_HTTP_CLIENT; + return HttpConstant.ASYNC_HTTP_TARGET_NAME; } @Override diff --git a/chaosblade-exec-plugin/chaosblade-exec-plugin-http/src/main/java/com/alibaba/chaosblade/exec/plugin/http/model/HttpModelSpec.java b/chaosblade-exec-plugin/chaosblade-exec-plugin-http/src/main/java/com/alibaba/chaosblade/exec/plugin/http/model/HttpModelSpec.java index ae17053f..dfe033f7 100644 --- a/chaosblade-exec-plugin/chaosblade-exec-plugin-http/src/main/java/com/alibaba/chaosblade/exec/plugin/http/model/HttpModelSpec.java +++ b/chaosblade-exec-plugin/chaosblade-exec-plugin-http/src/main/java/com/alibaba/chaosblade/exec/plugin/http/model/HttpModelSpec.java @@ -4,6 +4,7 @@ import com.alibaba.chaosblade.exec.common.model.action.ActionSpec; import com.alibaba.chaosblade.exec.common.model.action.delay.DelayActionSpec; import com.alibaba.chaosblade.exec.common.model.action.exception.ThrowCustomExceptionActionSpec; +import com.alibaba.chaosblade.exec.common.model.matcher.BusinessParamsMatcherSpec; import com.alibaba.chaosblade.exec.common.model.matcher.MatcherSpec; import java.util.ArrayList; @@ -65,6 +66,7 @@ protected List createNewMatcherSpecs() { matcherSpecs.add(new AsyncHttpClientMatcherSpec()); matcherSpecs.add(new UriMatcherDefSpec()); matcherSpecs.add(new CallPointMatcherSpec()); + matcherSpecs.add(new BusinessParamsMatcherSpec()); return matcherSpecs; } diff --git a/chaosblade-exec-plugin/chaosblade-exec-plugin-http/src/main/java/com/alibaba/chaosblade/exec/plugin/http/okhttp3/Okhttp3Enhancer.java b/chaosblade-exec-plugin/chaosblade-exec-plugin-http/src/main/java/com/alibaba/chaosblade/exec/plugin/http/okhttp3/Okhttp3Enhancer.java index 166c12aa..703e70fc 100644 --- a/chaosblade-exec-plugin/chaosblade-exec-plugin-http/src/main/java/com/alibaba/chaosblade/exec/plugin/http/okhttp3/Okhttp3Enhancer.java +++ b/chaosblade-exec-plugin/chaosblade-exec-plugin-http/src/main/java/com/alibaba/chaosblade/exec/plugin/http/okhttp3/Okhttp3Enhancer.java @@ -1,12 +1,18 @@ package com.alibaba.chaosblade.exec.plugin.http.okhttp3; import com.alibaba.chaosblade.exec.common.aop.EnhancerModel; +import com.alibaba.chaosblade.exec.common.util.BusinessParamUtil; import com.alibaba.chaosblade.exec.common.util.ReflectUtil; +import com.alibaba.chaosblade.exec.plugin.http.HttpConstant; import com.alibaba.chaosblade.exec.plugin.http.HttpEnhancer; import com.alibaba.chaosblade.exec.plugin.http.UrlUtils; +import com.alibaba.chaosblade.exec.spi.BusinessDataGetter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.lang.reflect.Method; +import java.util.Map; + import static com.alibaba.chaosblade.exec.plugin.http.HttpConstant.DEFAULT_TIMEOUT; import static com.alibaba.chaosblade.exec.plugin.http.HttpConstant.OKHTTP3; @@ -31,6 +37,18 @@ protected void postDoBeforeAdvice(EnhancerModel enhancerModel) { enhancerModel.addMatcher(OKHTTP3, "true"); } + @Override + protected Map> getBusinessParams(String className, final Object instance, Method method, final Object[] methodArguments) throws Exception { + return BusinessParamUtil.getAndParse(OKHTTP3, new BusinessDataGetter() { + @Override + public String get(String key) throws Exception { + Object request = ReflectUtil.invokeMethod(instance, "request", new Object[0], false); + return (String) ReflectUtil.invokeMethod(request, "header", new Object[]{key}, false); + } + }); + } + + @Override protected int getTimeout(Object instance, Object[] methodArguments) { try { Object client = ReflectUtil.getFieldValue(instance, "client", false); diff --git a/chaosblade-exec-plugin/chaosblade-exec-plugin-http/src/main/java/com/alibaba/chaosblade/exec/plugin/http/okhttp3/Okhttp3Plugin.java b/chaosblade-exec-plugin/chaosblade-exec-plugin-http/src/main/java/com/alibaba/chaosblade/exec/plugin/http/okhttp3/Okhttp3Plugin.java index 0478d61f..8c230036 100644 --- a/chaosblade-exec-plugin/chaosblade-exec-plugin-http/src/main/java/com/alibaba/chaosblade/exec/plugin/http/okhttp3/Okhttp3Plugin.java +++ b/chaosblade-exec-plugin/chaosblade-exec-plugin-http/src/main/java/com/alibaba/chaosblade/exec/plugin/http/okhttp3/Okhttp3Plugin.java @@ -2,6 +2,7 @@ import com.alibaba.chaosblade.exec.common.aop.Enhancer; import com.alibaba.chaosblade.exec.common.aop.PointCut; +import com.alibaba.chaosblade.exec.plugin.http.HttpConstant; import com.alibaba.chaosblade.exec.plugin.http.HttpPlugin; /** @@ -14,7 +15,7 @@ public class Okhttp3Plugin extends HttpPlugin { @Override public String getName() { - return "okhttp3"; + return HttpConstant.OKHTTP3_TARGET_NAME; } @Override diff --git a/chaosblade-exec-plugin/chaosblade-exec-plugin-http/src/main/java/com/alibaba/chaosblade/exec/plugin/http/resttemplate/RestTemplateEnhancer.java b/chaosblade-exec-plugin/chaosblade-exec-plugin-http/src/main/java/com/alibaba/chaosblade/exec/plugin/http/resttemplate/RestTemplateEnhancer.java index e9f10f80..59605680 100644 --- a/chaosblade-exec-plugin/chaosblade-exec-plugin-http/src/main/java/com/alibaba/chaosblade/exec/plugin/http/resttemplate/RestTemplateEnhancer.java +++ b/chaosblade-exec-plugin/chaosblade-exec-plugin-http/src/main/java/com/alibaba/chaosblade/exec/plugin/http/resttemplate/RestTemplateEnhancer.java @@ -6,10 +6,17 @@ import org.slf4j.LoggerFactory; import com.alibaba.chaosblade.exec.common.aop.EnhancerModel; +import com.alibaba.chaosblade.exec.common.util.BusinessParamUtil; import com.alibaba.chaosblade.exec.common.util.ReflectUtil; import com.alibaba.chaosblade.exec.plugin.http.HttpConstant; import com.alibaba.chaosblade.exec.plugin.http.HttpEnhancer; import com.alibaba.chaosblade.exec.plugin.http.UrlUtils; +import com.alibaba.chaosblade.exec.spi.BusinessDataGetter; + +import java.lang.reflect.Method; +import java.util.List; +import java.util.Map; + /** * @Author yuhan @@ -19,15 +26,32 @@ public class RestTemplateEnhancer extends HttpEnhancer { private static final Logger LOGGER = LoggerFactory.getLogger(RestTemplateEnhancer.class); public static final String COMPONENTS_CLIENT_HTTP_REQUEST_FACTORY = - "org.springframework.http.client.HttpComponentsClientHttpRequestFactory"; + "org.springframework.http.client.HttpComponentsClientHttpRequestFactory"; public static final String OK_HTTP_3_CLIENT_HTTP_REQUEST_FACTORY = - "org.springframework.http.client.OkHttp3ClientHttpRequestFactory"; + "org.springframework.http.client.OkHttp3ClientHttpRequestFactory"; @Override protected void postDoBeforeAdvice(EnhancerModel enhancerModel) { enhancerModel.addMatcher(HttpConstant.REST_KEY, "true"); } + @Override + protected Map> getBusinessParams(String className, Object instance, Method method, final Object[] methodArguments) throws Exception { + return BusinessParamUtil.getAndParse(HttpConstant.REST_TARGET_NAME, new BusinessDataGetter() { + @Override + public String get(String key) throws Exception { + Object requestCallback = methodArguments[2]; + Object requestEntity = ReflectUtil.getFieldValue(requestCallback, "requestEntity", false); + Object requestHeaders = ReflectUtil.invokeMethod(requestEntity, "getHeaders", new Object[0], false); + List header = (List) ReflectUtil.invokeMethod(requestHeaders, "get", new Object[]{key}, false); + if (header != null && !header.isEmpty()) { + return header.get(0); + } + return null; + } + }); + } + @Override protected int getTimeout(Object instance, Object[] methodArguments) { try { diff --git a/chaosblade-exec-plugin/chaosblade-exec-plugin-http/src/main/java/com/alibaba/chaosblade/exec/plugin/http/resttemplate/RestTemplatePlugin.java b/chaosblade-exec-plugin/chaosblade-exec-plugin-http/src/main/java/com/alibaba/chaosblade/exec/plugin/http/resttemplate/RestTemplatePlugin.java index 016aecba..2bba455d 100644 --- a/chaosblade-exec-plugin/chaosblade-exec-plugin-http/src/main/java/com/alibaba/chaosblade/exec/plugin/http/resttemplate/RestTemplatePlugin.java +++ b/chaosblade-exec-plugin/chaosblade-exec-plugin-http/src/main/java/com/alibaba/chaosblade/exec/plugin/http/resttemplate/RestTemplatePlugin.java @@ -2,6 +2,7 @@ import com.alibaba.chaosblade.exec.common.aop.Enhancer; import com.alibaba.chaosblade.exec.common.aop.PointCut; +import com.alibaba.chaosblade.exec.plugin.http.HttpConstant; import com.alibaba.chaosblade.exec.plugin.http.HttpPlugin; /** @@ -13,7 +14,7 @@ public class RestTemplatePlugin extends HttpPlugin { @Override public String getName() { - return "rest"; + return HttpConstant.REST_TARGET_NAME; } @Override diff --git a/chaosblade-exec-plugin/chaosblade-exec-plugin-mysql/src/main/java/com/alibaba/chaosblade/exec/plugin/mysql/MysqlConstant.java b/chaosblade-exec-plugin/chaosblade-exec-plugin-mysql/src/main/java/com/alibaba/chaosblade/exec/plugin/mysql/MysqlConstant.java index 0b8343ce..87e5b192 100644 --- a/chaosblade-exec-plugin/chaosblade-exec-plugin-mysql/src/main/java/com/alibaba/chaosblade/exec/plugin/mysql/MysqlConstant.java +++ b/chaosblade-exec-plugin/chaosblade-exec-plugin-mysql/src/main/java/com/alibaba/chaosblade/exec/plugin/mysql/MysqlConstant.java @@ -24,7 +24,7 @@ public interface MysqlConstant { String TARGET_NAME = "mysql"; String HOST_MATCHER_NAME = "host"; - String TABLE_MATCHER_NAME = "table"; + String TABLE_MATCHER_NAME = "select"; String DATABASE_MATCHER_NAME = "database"; String SQL_TYPE_MATCHER_NAME = "sqltype"; String PORT_MATCHER_NAME = "port"; diff --git a/chaosblade-exec-plugin/pom.xml b/chaosblade-exec-plugin/pom.xml index d716b36f..d634b5b5 100644 --- a/chaosblade-exec-plugin/pom.xml +++ b/chaosblade-exec-plugin/pom.xml @@ -55,6 +55,11 @@ chaosblade-exec-common ${project.version} + + com.alibaba.chaosblade + chaosblade-exec-spi + ${project.version} + diff --git a/chaosblade-exec-spi/pom.xml b/chaosblade-exec-spi/pom.xml new file mode 100644 index 00000000..dacbc9fe --- /dev/null +++ b/chaosblade-exec-spi/pom.xml @@ -0,0 +1,44 @@ + + + + + + chaosblade-exec-jvm + com.alibaba.chaosblade + 1.4.0 + + 4.0.0 + + chaosblade-exec-spi + + + + + org.apache.maven.plugins + maven-compiler-plugin + + 6 + 6 + + + + + + + diff --git a/chaosblade-exec-spi/src/main/java/com/alibaba/chaosblade/exec/spi/BusinessDataGetter.java b/chaosblade-exec-spi/src/main/java/com/alibaba/chaosblade/exec/spi/BusinessDataGetter.java new file mode 100644 index 00000000..9278cae6 --- /dev/null +++ b/chaosblade-exec-spi/src/main/java/com/alibaba/chaosblade/exec/spi/BusinessDataGetter.java @@ -0,0 +1,8 @@ +package com.alibaba.chaosblade.exec.spi; + +/** + * @author wufunc@gmail.com + */ +public interface BusinessDataGetter { + String get(String key) throws Exception; +} \ No newline at end of file diff --git a/doc/zh-cn/design.md b/doc/zh-cn/design.md index 1dae41b8..380e548f 100644 --- a/doc/zh-cn/design.md +++ b/doc/zh-cn/design.md @@ -132,7 +132,7 @@ public void beforeAdvice(String targetName, ./blade create servlet --requestpath=/topic delay --time=3000 ```` 该命令下发后,触发SandboxModule @Http("/create")注解标记的方法,将事件分发给com.alibaba.chaosblade.exec.service.handler.CreateHandler处理 -在判断必要的uid、target、action、model参数后调用handleInjection,handleInjection通过状态管理器注册本次实验,如果插件类型是PreCreateInjectionModelHandler的类型,将预处理一些东西。同是如果Action类型是DirectlyInjectionAction,那么将直接进行故障能力注入,如jvm oom等,如果不是那么将加载插件。 +在判断必要的uid、target、action、model参数后调用handleInjection,handleInjection通过状态管理器注册本次实验,如果插件类型是PreCreateInjectionModelHandler的类型,将预处理一些东西。同时如果Action类型是DirectlyInjectionAction,那么将直接进行故障能力注入,如jvm oom等,如果不是那么将加载插件。 #### ModelSpec - PreCreateInjectionModelHandler 预创建 @@ -188,7 +188,7 @@ public class ServletEnhancer extends BeforeEnhancer { @Override public EnhancerModel doBeforeAdvice(ClassLoader classLoader, String className, Object object, - Method method, Object[] methodArguments) + Method method, Object[] methodArguments,String targetName) throws Exception { // 获取原方法的一些参数 Object request = methodArguments[0]; @@ -323,7 +323,7 @@ public Response handle(Request request) { ````shell ./blade revoke 98e792c9a9a5dfea ```` -该命令下发后,触发SandboxModule unload()事件,同是插件卸载。 +该命令下发后,触发SandboxModule unload()事件,同时插件卸载。 ```java public void onUnload() throws Throwable { diff --git a/doc/zh-cn/plugin.md b/doc/zh-cn/plugin.md index 96380562..3c25d099 100644 --- a/doc/zh-cn/plugin.md +++ b/doc/zh-cn/plugin.md @@ -26,7 +26,7 @@ public class ServletEnhancer extends BeforeEnhancer { Object object, Method method, Object[] methodArguments - ) throws Exception { + ,String targetName) throws Exception { Object request = methodArguments[0]; // 执行被增强类的方法,获取一些需要的值 String queryString = ReflectUtil.invokeMethod(request, "getQueryString", new Object[] {}, false); diff --git a/pom.xml b/pom.xml index 4ee88541..a2c66a3c 100644 --- a/pom.xml +++ b/pom.xml @@ -25,6 +25,7 @@ pom 1.4.0 + chaosblade-exec-spi chaosblade-exec-bootstrap chaosblade-exec-common chaosblade-exec-plugin