提交 a20d6ea2 编写于 作者: 彭勇升 Buddha 提交者: GitHub

Merge branch 'master' into feature/new-register-flow

......@@ -8,3 +8,4 @@ target/
.DS_Store
*~
packages/
**/dependency-reduced-pom.xml
......@@ -59,7 +59,7 @@ This project adheres to the Contributor Covenant [code of conduct](CODE_OF_CONDU
<img src="https://sky-walking.github.io/page-resources/3.2.1/instance_health.png"/>
- JVM Detail.
<img src="https://sky-walking.github.io/page-resources/3.2.1/instance_graph.png"/>
<img src="https://sky-walking.github.io/page-resources/3.2/instance_graph.png"/>
- Services Dependency Tree.
<img src="https://sky-walking.github.io/page-resources/3.2.1/service_dependency_tree.png"/>
......
......@@ -60,7 +60,7 @@ This project adheres to the Contributor Covenant [code of conduct](CODE_OF_CONDU
<img src="https://sky-walking.github.io/page-resources/3.2.1/instance_health.png"/>
- JVM明细信息
<img src="https://sky-walking.github.io/page-resources/3.2.1/instance_graph.png"/>
<img src="https://sky-walking.github.io/page-resources/3.2/instance_graph.png"/>
- 服务依赖树.
<img src="https://sky-walking.github.io/page-resources/3.2.1/service_dependency_tree.png"/>
......
......@@ -43,8 +43,10 @@ public class ComponentsDefine {
public static final OfficialComponent JETTY_CLIENT = new OfficialComponent(18, "JettyClient");
public static final OfficialComponent JETTY_SERVER = new OfficialComponent(19, "JettyServer");
public static final OfficialComponent JETTY_SERVER = new OfficialComponent(19, "JettyServer");
public static final OfficialComponent MEMCACHE = new OfficialComponent(20, "Memcache");
private static ComponentsDefine instance = new ComponentsDefine();
private String[] components;
......@@ -54,7 +56,7 @@ public class ComponentsDefine {
}
public ComponentsDefine() {
components = new String[20];
components = new String[21];
addComponent(TOMCAT);
addComponent(HTTPCLIENT);
addComponent(DUBBO);
......@@ -74,6 +76,7 @@ public class ComponentsDefine {
addComponent(NUTZ_HTTP);
addComponent(JETTY_CLIENT);
addComponent(JETTY_SERVER);
addComponent(MEMCACHE);
}
private void addComponent(OfficialComponent component) {
......@@ -87,4 +90,4 @@ public class ComponentsDefine {
return components[componentId];
}
}
}
}
\ No newline at end of file
......@@ -26,7 +26,7 @@ public abstract class AbstractClassEnhancePluginDefine {
* @throws PluginException, when set builder failure.
*/
public DynamicType.Builder<?> define(String transformClassName,
DynamicType.Builder<?> builder, ClassLoader classLoader) throws PluginException {
DynamicType.Builder<?> builder, ClassLoader classLoader, EnhanceContext context) throws PluginException {
String interceptorDefineClassName = this.getClass().getName();
if (StringUtil.isEmpty(transformClassName)) {
......@@ -53,15 +53,16 @@ public abstract class AbstractClassEnhancePluginDefine {
/**
* find origin class source code for interceptor
*/
DynamicType.Builder<?> newClassBuilder = this.enhance(transformClassName, builder, classLoader);
DynamicType.Builder<?> newClassBuilder = this.enhance(transformClassName, builder, classLoader, context);
context.initializationStageCompleted();
logger.debug("enhance class {} by {} completely.", transformClassName, interceptorDefineClassName);
return newClassBuilder;
}
protected abstract DynamicType.Builder<?> enhance(String enhanceOriginClassName,
DynamicType.Builder<?> newClassBuilder, ClassLoader classLoader) throws PluginException;
DynamicType.Builder<?> newClassBuilder, ClassLoader classLoader, EnhanceContext context) throws PluginException;
/**
* Define the {@link ClassMatch} for filtering class.
......
package org.skywalking.apm.agent.core.plugin;
/**
* The <code>EnhanceContext</code> represents the context or status for processing a class.
*
* Based on this context, the plugin core {@link org.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassEnhancePluginDefine}
* knows how to process the specific steps for every particular plugin.
*
* @author wusheng
*/
public class EnhanceContext {
private boolean isEnhanced = false;
/**
* The object has already been enhanced or extended.
* e.g. added the new field, or implemented the new interface
*/
private boolean objectExtended = false;
public boolean isEnhanced() {
return isEnhanced;
}
public void initializationStageCompleted() {
isEnhanced = true;
}
public boolean isObjectExtended() {
return objectExtended;
}
public void extendObjectCompleted() {
objectExtended = true;
}
}
......@@ -22,7 +22,7 @@ import static net.bytebuddy.matcher.ElementMatchers.not;
* @author wusheng
*/
public class PluginFinder {
private final Map<String, AbstractClassEnhancePluginDefine> nameMatchDefine = new HashMap<String, AbstractClassEnhancePluginDefine>();
private final Map<String, LinkedList<AbstractClassEnhancePluginDefine>> nameMatchDefine = new HashMap<String, LinkedList<AbstractClassEnhancePluginDefine>>();
private final List<AbstractClassEnhancePluginDefine> signatureMatchDefine = new LinkedList<AbstractClassEnhancePluginDefine>();
public PluginFinder(List<AbstractClassEnhancePluginDefine> plugins) {
......@@ -35,28 +35,34 @@ public class PluginFinder {
if (match instanceof NameMatch) {
NameMatch nameMatch = (NameMatch)match;
nameMatchDefine.put(nameMatch.getClassName(), plugin);
LinkedList<AbstractClassEnhancePluginDefine> pluginDefines = nameMatchDefine.get(nameMatch.getClassName());
if (pluginDefines == null) {
pluginDefines = new LinkedList<AbstractClassEnhancePluginDefine>();
nameMatchDefine.put(nameMatch.getClassName(), pluginDefines);
}
pluginDefines.add(plugin);
} else {
signatureMatchDefine.add(plugin);
}
}
}
public AbstractClassEnhancePluginDefine find(TypeDescription typeDescription,
public List<AbstractClassEnhancePluginDefine> find(TypeDescription typeDescription,
ClassLoader classLoader) {
List<AbstractClassEnhancePluginDefine> matchedPlugins = new LinkedList<AbstractClassEnhancePluginDefine>();
String typeName = typeDescription.getTypeName();
if (nameMatchDefine.containsKey(typeName)) {
return nameMatchDefine.get(typeName);
matchedPlugins.addAll(nameMatchDefine.get(typeName));
}
for (AbstractClassEnhancePluginDefine pluginDefine : signatureMatchDefine) {
IndirectMatch match = (IndirectMatch)pluginDefine.enhanceClass();
if (match.isMatch(typeDescription)) {
return pluginDefine;
matchedPlugins.add(pluginDefine);
}
}
return null;
return matchedPlugins;
}
public ElementMatcher<? super TypeDescription> buildMatch() {
......
......@@ -6,6 +6,7 @@ import net.bytebuddy.implementation.MethodDelegation;
import net.bytebuddy.implementation.SuperMethodCall;
import net.bytebuddy.implementation.bind.annotation.Morph;
import org.skywalking.apm.agent.core.plugin.AbstractClassEnhancePluginDefine;
import org.skywalking.apm.agent.core.plugin.EnhanceContext;
import org.skywalking.apm.agent.core.plugin.PluginException;
import org.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
import org.skywalking.apm.agent.core.plugin.interceptor.EnhanceException;
......@@ -46,10 +47,11 @@ public abstract class ClassEnhancePluginDefine extends AbstractClassEnhancePlugi
*/
@Override
protected DynamicType.Builder<?> enhance(String enhanceOriginClassName,
DynamicType.Builder<?> newClassBuilder, ClassLoader classLoader) throws PluginException {
DynamicType.Builder<?> newClassBuilder, ClassLoader classLoader,
EnhanceContext context) throws PluginException {
newClassBuilder = this.enhanceClass(enhanceOriginClassName, newClassBuilder, classLoader);
newClassBuilder = this.enhanceInstance(enhanceOriginClassName, newClassBuilder, classLoader);
newClassBuilder = this.enhanceInstance(enhanceOriginClassName, newClassBuilder, classLoader, context);
return newClassBuilder;
}
......@@ -62,7 +64,8 @@ public abstract class ClassEnhancePluginDefine extends AbstractClassEnhancePlugi
* @return new byte-buddy's builder for further manipulation.
*/
private DynamicType.Builder<?> enhanceInstance(String enhanceOriginClassName,
DynamicType.Builder<?> newClassBuilder, ClassLoader classLoader) throws PluginException {
DynamicType.Builder<?> newClassBuilder, ClassLoader classLoader,
EnhanceContext context) throws PluginException {
ConstructorInterceptPoint[] constructorInterceptPoints = getConstructorsInterceptPoints();
InstanceMethodsInterceptPoint[] instanceMethodsInterceptPoints = getInstanceMethodsInterceptPoints();
......@@ -83,16 +86,21 @@ public abstract class ClassEnhancePluginDefine extends AbstractClassEnhancePlugi
}
/**
* alter class source code.<br/>
* Manipulate class source code.<br/>
*
* new class need:<br/>
* 1.Add field, name {@link #CONTEXT_ATTR_NAME}.
* 2.Add a field accessor for this field.
*
* And make sure the source codes manipulation only occurs once.
*
*/
newClassBuilder = newClassBuilder.defineField(CONTEXT_ATTR_NAME, Object.class, ACC_PRIVATE)
.implement(EnhancedInstance.class)
.intercept(FieldAccessor.ofField(CONTEXT_ATTR_NAME));
if (!context.isObjectExtended()) {
newClassBuilder = newClassBuilder.defineField(CONTEXT_ATTR_NAME, Object.class, ACC_PRIVATE)
.implement(EnhancedInstance.class)
.intercept(FieldAccessor.ofField(CONTEXT_ATTR_NAME));
context.extendObjectCompleted();
}
/**
* 2. enhance constructors
......
......@@ -125,6 +125,11 @@
<artifactId>apm-jetty-server-9.x-plugin</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.skywalking</groupId>
<artifactId>apm-spymemcached-2.x-plugin</artifactId>
<version>${project.version}</version>
</dependency>
<!-- activation -->
<dependency>
......
package org.skywalking.apm.agent;
import java.lang.instrument.Instrumentation;
import java.util.List;
import net.bytebuddy.agent.builder.AgentBuilder;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.dynamic.DynamicType;
......@@ -9,6 +10,7 @@ import org.skywalking.apm.agent.core.boot.ServiceManager;
import org.skywalking.apm.agent.core.conf.SnifferConfigInitializer;
import org.skywalking.apm.agent.core.logging.EasyLogResolver;
import org.skywalking.apm.agent.core.plugin.AbstractClassEnhancePluginDefine;
import org.skywalking.apm.agent.core.plugin.EnhanceContext;
import org.skywalking.apm.agent.core.plugin.PluginBootstrap;
import org.skywalking.apm.agent.core.plugin.PluginException;
import org.skywalking.apm.agent.core.plugin.PluginFinder;
......@@ -54,13 +56,21 @@ public class SkyWalkingAgent {
@Override
public DynamicType.Builder<?> transform(DynamicType.Builder<?> builder, TypeDescription typeDescription,
ClassLoader classLoader, JavaModule module) {
AbstractClassEnhancePluginDefine pluginDefine = pluginFinder.find(typeDescription, classLoader);
if (pluginDefine != null) {
DynamicType.Builder<?> newBuilder = pluginDefine.define(typeDescription.getTypeName(), builder, classLoader);
if (newBuilder != null) {
List<AbstractClassEnhancePluginDefine> pluginDefines = pluginFinder.find(typeDescription, classLoader);
if (pluginDefines.size() > 0) {
DynamicType.Builder<?> newBuilder = builder;
EnhanceContext context = new EnhanceContext();
for (AbstractClassEnhancePluginDefine define : pluginDefines) {
DynamicType.Builder<?> possibleNewBuilder = define.define(typeDescription.getTypeName(), newBuilder, classLoader, context);
if (possibleNewBuilder != null) {
newBuilder = possibleNewBuilder;
}
}
if (context.isEnhanced()) {
logger.debug("Finish the prepare stage for {}.", typeDescription.getName());
return newBuilder;
}
return newBuilder;
}
logger.debug("Matched class {}, but ignore by finding mechanism.", typeDescription.getTypeName());
......
......@@ -26,6 +26,7 @@
<module>struts2-2.x-plugin</module>
<module>nutz-plugins</module>
<module>jetty-plugin</module>
<module>spymemcached-2.x-plugin</module>
</modules>
<packaging>pom</packaging>
......
package org.skywalking.apm.plugin.spring.mvc;
import java.lang.reflect.Method;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.skywalking.apm.agent.core.context.CarrierItem;
import org.skywalking.apm.agent.core.context.ContextCarrier;
import org.skywalking.apm.agent.core.context.ContextManager;
......@@ -13,33 +10,30 @@ import org.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance
import org.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
import org.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
import org.skywalking.apm.network.trace.component.ComponentsDefine;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;
/**
* The <code>ControllerServiceMethodInterceptor</code> only use the first mapping value.
* the abstract method inteceptor
*/
public class ControllerServiceMethodInterceptor implements InstanceMethodsAroundInterceptor {
public abstract class AbstractMethodInteceptor implements InstanceMethodsAroundInterceptor {
public abstract String getRequestURL(Method method);
@Override
public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes,
MethodInterceptResult result) throws Throwable {
MethodInterceptResult result) throws Throwable {
PathMappingCache pathMappingCache = (PathMappingCache)objInst.getSkyWalkingDynamicField();
String requestURL = pathMappingCache.findPathMapping(method);
if (requestURL == null) {
RequestMapping methodRequestMapping = method.getAnnotation(RequestMapping.class);
if (methodRequestMapping.value().length > 0) {
requestURL = methodRequestMapping.value()[0];
} else if (methodRequestMapping.path().length > 0) {
requestURL = methodRequestMapping.path()[0];
} else {
requestURL = "";
}
requestURL = getRequestURL(method);
pathMappingCache.addPathMapping(method, requestURL);
requestURL = pathMappingCache.findPathMapping(method);
}
HttpServletRequest request = ((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getRequest();
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
ContextCarrier contextCarrier = new ContextCarrier();
CarrierItem next = contextCarrier.items();
......@@ -57,7 +51,7 @@ public class ControllerServiceMethodInterceptor implements InstanceMethodsAround
@Override
public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes,
Object ret) throws Throwable {
Object ret) throws Throwable {
HttpServletResponse response = ((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getResponse();
AbstractSpan span = ContextManager.activeSpan();
......@@ -69,8 +63,9 @@ public class ControllerServiceMethodInterceptor implements InstanceMethodsAround
return ret;
}
@Override public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments,
Class<?>[] argumentsTypes, Throwable t) {
@Override
public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments,
Class<?>[] argumentsTypes, Throwable t) {
ContextManager.activeSpan().errorOccurred().log(t);
}
}
package org.skywalking.apm.plugin.spring.mvc;
import java.lang.reflect.Method;
import org.springframework.web.bind.annotation.RequestMapping;
/**
* The <code>RequestMappingMethodInterceptor</code> only use the first mapping value.
* it will inteceptor with <code>@RequestMapping</code>
* @author clevertension
*/
public class RequestMappingMethodInterceptor extends AbstractMethodInteceptor {
@Override
public String getRequestURL(Method method) {
String requestURL = "";
RequestMapping methodRequestMapping = method.getAnnotation(RequestMapping.class);
if (methodRequestMapping.value().length > 0) {
requestURL = methodRequestMapping.value()[0];
} else if (methodRequestMapping.path().length > 0) {
requestURL = methodRequestMapping.path()[0];
}
return requestURL;
}
}
package org.skywalking.apm.plugin.spring.mvc;
import java.lang.reflect.Method;
import org.springframework.web.bind.annotation.*;
/**
* The <code>RestMappingMethodInterceptor</code> only use the first mapping value.
* it will inteceptor with
* <code>@GetMapping</code>, <code>@PostMapping</code>, <code>@PutMapping</code>
* <code>@DeleteMapping</code>, <code>@PatchMapping</code>
* @author clevertension
*/
public class RestMappingMethodInterceptor extends AbstractMethodInteceptor {
@Override
public String getRequestURL(Method method) {
String requestURL = "";
GetMapping getMapping = method.getAnnotation(GetMapping.class);
PostMapping postMapping = method.getAnnotation(PostMapping.class);
PutMapping putMapping = method.getAnnotation(PutMapping.class);
DeleteMapping deleteMapping = method.getAnnotation(DeleteMapping.class);
PatchMapping patchMapping = method.getAnnotation(PatchMapping.class);
if (getMapping != null) {
if (getMapping.value().length > 0) {
requestURL = getMapping.value()[0];
} else if (getMapping.path().length > 0) {
requestURL = getMapping.path()[0];
}
} else if (postMapping != null) {
if (postMapping.value().length > 0) {
requestURL = postMapping.value()[0];
} else if (postMapping.path().length > 0) {
requestURL = postMapping.path()[0];
}
} else if (putMapping != null) {
if (putMapping.value().length > 0) {
requestURL = putMapping.value()[0];
} else if (putMapping.path().length > 0) {
requestURL = putMapping.path()[0];
}
} else if (deleteMapping != null) {
if (deleteMapping.value().length > 0) {
requestURL = deleteMapping.value()[0];
} else if (deleteMapping.path().length > 0) {
requestURL = deleteMapping.path()[0];
}
} else if (patchMapping != null) {
if (patchMapping.value().length > 0) {
requestURL = patchMapping.value()[0];
} else if (patchMapping.path().length > 0) {
requestURL = patchMapping.path()[0];
}
}
return requestURL;
}
}
......@@ -20,8 +20,8 @@ import static org.skywalking.apm.agent.core.plugin.match.ClassAnnotationMatch.by
* <code>org.skywalking.apm.plugin.spring.mvc.ControllerConstructorInterceptor</code> set the controller base path to
* dynamic field before execute constructor.
*
* <code>org.skywalking.apm.plugin.spring.mvc.ControllerServiceMethodInterceptor</code> get the request path from
* dynamic field first, if not found, <code>ControllerServiceMethodInterceptor</code> generate request path that
* <code>org.skywalking.apm.plugin.spring.mvc.RequestMappingMethodInterceptor</code> get the request path from
* dynamic field first, if not found, <code>RequestMappingMethodInterceptor</code> generate request path that
* combine the path value of current annotation on current method and the base path and set the new path to the dynamic
* filed
*
......@@ -56,7 +56,26 @@ public abstract class AbstractControllerInstrumentation extends ClassInstanceMet
@Override
public String getMethodsInterceptor() {
return "org.skywalking.apm.plugin.spring.mvc.ControllerServiceMethodInterceptor";
return "org.skywalking.apm.plugin.spring.mvc.RequestMappingMethodInterceptor";
}
@Override
public boolean isOverrideArgs() {
return false;
}
},
new InstanceMethodsInterceptPoint() {
@Override
public ElementMatcher<MethodDescription> getMethodsMatcher() {
return isAnnotatedWith(named("org.springframework.web.bind.annotation.GetMapping"))
.or(isAnnotatedWith(named("org.springframework.web.bind.annotation.PostMapping")))
.or(isAnnotatedWith(named("org.springframework.web.bind.annotation.PutMapping")))
.or(isAnnotatedWith(named("org.springframework.web.bind.annotation.DeleteMapping")))
.or(isAnnotatedWith(named("org.springframework.web.bind.annotation.PatchMapping")));
}
@Override
public String getMethodsInterceptor() {
return "org.skywalking.apm.plugin.spring.mvc.RestMappingMethodInterceptor";
}
@Override
......
package org.skywalking.apm.plugin.spring.mvc;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.modules.junit4.PowerMockRunner;
import org.powermock.modules.junit4.PowerMockRunnerDelegate;
import org.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
import org.skywalking.apm.agent.test.tools.TracingSegmentRunner;
import org.springframework.web.bind.annotation.RequestMapping;
import java.lang.reflect.Method;
@RunWith(PowerMockRunner.class)
@PowerMockRunnerDelegate(TracingSegmentRunner.class)
public class ControllerConstructorInterceptorTest {
private ControllerConstructorInterceptor controllerConstructorInterceptor;
private final MockEnhancedInstance1 inst1 = new MockEnhancedInstance1();
private final MockEnhancedInstance2 inst2 = new MockEnhancedInstance2();
private final MockEnhancedInstance3 inst3 = new MockEnhancedInstance3();
@Before
public void setUp() throws Exception {
controllerConstructorInterceptor = new ControllerConstructorInterceptor();
}
@Test
public void testOnConstruct_Accuracy1() throws Throwable {
controllerConstructorInterceptor.onConstruct(inst1, null);
PathMappingCache cache = (PathMappingCache)inst1.getSkyWalkingDynamicField();
Assert.assertNotNull(cache);
Object obj = new Object();
Method m = obj.getClass().getMethods()[0];
cache.addPathMapping(m, "#toString");
Assert.assertEquals("the two value should be equal", cache.findPathMapping(m), "/test1#toString");
}
@Test
public void testOnConstruct_Accuracy2() throws Throwable {
controllerConstructorInterceptor.onConstruct(inst2, null);
PathMappingCache cache = (PathMappingCache)inst2.getSkyWalkingDynamicField();
Assert.assertNotNull(cache);
Object obj = new Object();
Method m = obj.getClass().getMethods()[0];
cache.addPathMapping(m, "#toString");
Assert.assertEquals("the two value should be equal", cache.findPathMapping(m), "#toString");
}
@Test
public void testOnConstruct_Accuracy3() throws Throwable {
controllerConstructorInterceptor.onConstruct(inst3, null);
PathMappingCache cache = (PathMappingCache)inst3.getSkyWalkingDynamicField();
Assert.assertNotNull(cache);
Object obj = new Object();
Method m = obj.getClass().getMethods()[0];
cache.addPathMapping(m, "#toString");
Assert.assertEquals("the two value should be equal", cache.findPathMapping(m), "/test3#toString");
}
@RequestMapping(value="/test1")
private class MockEnhancedInstance1 implements EnhancedInstance {
private Object value;
@Override
public Object getSkyWalkingDynamicField() {
return value;
}
@Override
public void setSkyWalkingDynamicField(Object value) {
this.value = value;
}
}
private class MockEnhancedInstance2 implements EnhancedInstance {
private Object value;
@Override
public Object getSkyWalkingDynamicField() {
return value;
}
@Override
public void setSkyWalkingDynamicField(Object value) {
this.value = value;
}
}
@RequestMapping(path="/test3")
private class MockEnhancedInstance3 implements EnhancedInstance {
private Object value;
@Override
public Object getSkyWalkingDynamicField() {
return value;
}
@Override
public void setSkyWalkingDynamicField(Object value) {
this.value = value;
}
}
}
package org.skywalking.apm.plugin.spring.mvc;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.modules.junit4.PowerMockRunner;
import org.powermock.modules.junit4.PowerMockRunnerDelegate;
import org.skywalking.apm.agent.test.tools.TracingSegmentRunner;
import java.lang.reflect.Method;
import static org.powermock.api.mockito.PowerMockito.whenNew;
@RunWith(PowerMockRunner.class)
@PowerMockRunnerDelegate(TracingSegmentRunner.class)
public class PathMappingCacheTest {
private PathMappingCache pathMappingCache;
@Before
public void setUp() throws Exception {
pathMappingCache = new PathMappingCache("org.skywalking.apm.plugin.spring.mvc");
}
@Test
public void testAddPathMapping1() throws Throwable {
Object obj = new Object();
Method m = obj.getClass().getMethods()[0];
pathMappingCache.addPathMapping(m, "#toString");
Assert.assertEquals("the two value should be equal", pathMappingCache.findPathMapping(m), "org.skywalking.apm.plugin.spring.mvc#toString");
}
}
package org.skywalking.apm.plugin.spring.mvc;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.powermock.modules.junit4.PowerMockRunner;
import org.powermock.modules.junit4.PowerMockRunnerDelegate;
import org.skywalking.apm.agent.core.context.trace.*;
import org.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
import org.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
import org.skywalking.apm.agent.test.helper.SegmentHelper;
import org.skywalking.apm.agent.test.helper.SegmentRefHelper;
import org.skywalking.apm.agent.test.helper.SpanHelper;
import org.skywalking.apm.agent.test.tools.AgentServiceRule;
import org.skywalking.apm.agent.test.tools.SegmentStorage;
import org.skywalking.apm.agent.test.tools.SegmentStoragePoint;
import org.skywalking.apm.agent.test.tools.TracingSegmentRunner;
import org.skywalking.apm.network.trace.component.ComponentsDefine;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;
import java.util.List;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.mockito.Mockito.when;
import static org.skywalking.apm.agent.test.tools.SpanAssert.*;
@RunWith(PowerMockRunner.class)
@PowerMockRunnerDelegate(TracingSegmentRunner.class)
public class RequestMappingMethodInterceptorTest {
private RequestMappingMethodInterceptor interceptor;
@SegmentStoragePoint
private SegmentStorage segmentStorage;
@Rule
public AgentServiceRule serviceRule = new AgentServiceRule();
private ServletRequestAttributes servletRequestAttributes;
@Mock
private HttpServletRequest request;
@Mock
private HttpServletResponse response;
@Mock
private MethodInterceptResult methodInterceptResult;
private Object[] arguments;
private Class[] argumentType;
private EnhancedInstance enhancedInstance;
private ControllerConstructorInterceptor controllerConstructorInterceptor;
@Before
public void setUp() throws Exception {
interceptor = new RequestMappingMethodInterceptor();
enhancedInstance = new MockEnhancedInstance1();
controllerConstructorInterceptor = new ControllerConstructorInterceptor();
servletRequestAttributes = new ServletRequestAttributes(request, response);
when(request.getScheme()).thenReturn("http");
when(request.getServerName()).thenReturn("localhost");
when(request.getServerPort()).thenReturn(8080);
when(request.getRequestURI()).thenReturn("/test/testRequestURL");
when(request.getRequestURL()).thenReturn(new StringBuffer("http://localhost:8080/test/testRequestURL"));
when(response.getStatus()).thenReturn(200);
arguments = new Object[] {request, response};
argumentType = new Class[] {request.getClass(), response.getClass()};
}
@Test
public void testWithoutSerializedContextData() throws Throwable {
controllerConstructorInterceptor.onConstruct(enhancedInstance, null);
RequestMappingClass1 mappingClass1 = new RequestMappingClass1();
Method m = mappingClass1.getClass().getMethod("testRequestURL");
RequestContextHolder.setRequestAttributes(servletRequestAttributes);
interceptor.beforeMethod(enhancedInstance, m, arguments, argumentType, methodInterceptResult);
interceptor.afterMethod(enhancedInstance, m, arguments, argumentType, null);
assertThat(segmentStorage.getTraceSegments().size(), is(1));
TraceSegment traceSegment = segmentStorage.getTraceSegments().get(0);
List<AbstractTracingSpan> spans = SegmentHelper.getSpans(traceSegment);
assertHttpSpan(spans.get(0));
}
@Test
public void testWithOccurException() throws Throwable {
controllerConstructorInterceptor.onConstruct(enhancedInstance, null);
RequestMappingClass1 mappingClass1 = new RequestMappingClass1();
Method m = mappingClass1.getClass().getMethod("testRequestURL");
RequestContextHolder.setRequestAttributes(servletRequestAttributes);
interceptor.beforeMethod(enhancedInstance, m, arguments, argumentType, methodInterceptResult);
interceptor.handleMethodException(enhancedInstance, m, arguments, argumentType, new RuntimeException());
interceptor.afterMethod(enhancedInstance, m, arguments, argumentType, null);
assertThat(segmentStorage.getTraceSegments().size(), is(1));
TraceSegment traceSegment = segmentStorage.getTraceSegments().get(0);
List<AbstractTracingSpan> spans = SegmentHelper.getSpans(traceSegment);
assertHttpSpan(spans.get(0));
List<LogDataEntity> logDataEntities = SpanHelper.getLogs(spans.get(0));
assertThat(logDataEntities.size(), is(1));
assertException(logDataEntities.get(0), RuntimeException.class);
}
private void assertTraceSegmentRef(TraceSegmentRef ref) {
assertThat(SegmentRefHelper.getEntryApplicationInstanceId(ref), is(1));
assertThat(SegmentRefHelper.getSpanId(ref), is(3));
assertThat(SegmentRefHelper.getTraceSegmentId(ref).toString(), is("1.444.555"));
}
private void assertHttpSpan(AbstractTracingSpan span) {
assertThat(span.getOperationName(), is("/test/testRequestURL"));
assertComponent(span, ComponentsDefine.SPRING_MVC_ANNOTATION);
assertTag(span, 0, "http://localhost:8080/test/testRequestURL");
assertThat(span.isEntry(), is(true));
assertLayer(span, SpanLayer.HTTP);
}
@RequestMapping(value = "/test")
private class MockEnhancedInstance1 implements EnhancedInstance {
private Object value;
@Override
public Object getSkyWalkingDynamicField() {
return value;
}
@Override
public void setSkyWalkingDynamicField(Object value) {
this.value = value;
}
}
private class RequestMappingClass1 {
@RequestMapping("/testRequestURL")
public void testRequestURL() {
}
}
}
package org.skywalking.apm.plugin.spring.mvc;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.powermock.modules.junit4.PowerMockRunner;
import org.powermock.modules.junit4.PowerMockRunnerDelegate;
import org.skywalking.apm.agent.core.context.trace.*;
import org.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
import org.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
import org.skywalking.apm.agent.test.helper.SegmentHelper;
import org.skywalking.apm.agent.test.helper.SegmentRefHelper;
import org.skywalking.apm.agent.test.helper.SpanHelper;
import org.skywalking.apm.agent.test.tools.AgentServiceRule;
import org.skywalking.apm.agent.test.tools.SegmentStorage;
import org.skywalking.apm.agent.test.tools.SegmentStoragePoint;
import org.skywalking.apm.agent.test.tools.TracingSegmentRunner;
import org.skywalking.apm.network.trace.component.ComponentsDefine;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;
import java.util.List;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.mockito.Mockito.when;
import static org.skywalking.apm.agent.test.tools.SpanAssert.*;
@RunWith(PowerMockRunner.class)
@PowerMockRunnerDelegate(TracingSegmentRunner.class)
public class RestMappingMethodInterceptorTest {
private RestMappingMethodInterceptor interceptor;
@SegmentStoragePoint
private SegmentStorage segmentStorage;
@Rule
public AgentServiceRule serviceRule = new AgentServiceRule();
@Mock
private HttpServletRequest request;
@Mock
private HttpServletResponse response;
@Mock
private MethodInterceptResult methodInterceptResult;
private Object[] arguments;
private Class[] argumentType;
private EnhancedInstance enhancedInstance;
private ControllerConstructorInterceptor controllerConstructorInterceptor;
@Before
public void setUp() throws Exception {
interceptor = new RestMappingMethodInterceptor();
enhancedInstance = new RestMappingMethodInterceptorTest.MockEnhancedInstance1();
controllerConstructorInterceptor = new ControllerConstructorInterceptor();
when(request.getScheme()).thenReturn("http");
when(request.getServerName()).thenReturn("localhost");
when(request.getServerPort()).thenReturn(8080);
when(response.getStatus()).thenReturn(200);
arguments = new Object[] {request, response};
argumentType = new Class[] {request.getClass(), response.getClass()};
}
@Test
public void testGetMapping() throws Throwable {
controllerConstructorInterceptor.onConstruct(enhancedInstance, null);
RestMappingClass1 mappingClass1 = new RestMappingClass1();
Method m = mappingClass1.getClass().getMethod("getRequestURL");
when(request.getRequestURI()).thenReturn("/test/testRequestURL");
when(request.getRequestURL()).thenReturn(new StringBuffer("http://localhost:8080/test/getRequestURL"));
ServletRequestAttributes servletRequestAttributes = new ServletRequestAttributes(request, response);
RequestContextHolder.setRequestAttributes(servletRequestAttributes);
interceptor.beforeMethod(enhancedInstance, m, arguments, argumentType, methodInterceptResult);
interceptor.afterMethod(enhancedInstance, m, arguments, argumentType, null);
assertThat(segmentStorage.getTraceSegments().size(), is(1));
TraceSegment traceSegment = segmentStorage.getTraceSegments().get(0);
List<AbstractTracingSpan> spans = SegmentHelper.getSpans(traceSegment);
assertHttpSpan(spans.get(0), "/getRequestURL");
}
@Test
public void testPostMapping() throws Throwable {
controllerConstructorInterceptor.onConstruct(enhancedInstance, null);
RestMappingClass1 mappingClass1 = new RestMappingClass1();
Method m = mappingClass1.getClass().getMethod("postRequestURL");
when(request.getRequestURI()).thenReturn("/test/testRequestURL");
when(request.getRequestURL()).thenReturn(new StringBuffer("http://localhost:8080/test/postRequestURL"));
ServletRequestAttributes servletRequestAttributes = new ServletRequestAttributes(request, response);
RequestContextHolder.setRequestAttributes(servletRequestAttributes);
interceptor.beforeMethod(enhancedInstance, m, arguments, argumentType, methodInterceptResult);
interceptor.afterMethod(enhancedInstance, m, arguments, argumentType, null);
assertThat(segmentStorage.getTraceSegments().size(), is(1));
TraceSegment traceSegment = segmentStorage.getTraceSegments().get(0);
List<AbstractTracingSpan> spans = SegmentHelper.getSpans(traceSegment);
assertHttpSpan(spans.get(0), "/postRequestURL");
}
@Test
public void testPutMapping() throws Throwable {
controllerConstructorInterceptor.onConstruct(enhancedInstance, null);
RestMappingClass1 mappingClass1 = new RestMappingClass1();
Method m = mappingClass1.getClass().getMethod("putRequestURL");
when(request.getRequestURI()).thenReturn("/test/testRequestURL");
when(request.getRequestURL()).thenReturn(new StringBuffer("http://localhost:8080/test/putRequestURL"));
ServletRequestAttributes servletRequestAttributes = new ServletRequestAttributes(request, response);
RequestContextHolder.setRequestAttributes(servletRequestAttributes);
interceptor.beforeMethod(enhancedInstance, m, arguments, argumentType, methodInterceptResult);
interceptor.afterMethod(enhancedInstance, m, arguments, argumentType, null);
assertThat(segmentStorage.getTraceSegments().size(), is(1));
TraceSegment traceSegment = segmentStorage.getTraceSegments().get(0);
List<AbstractTracingSpan> spans = SegmentHelper.getSpans(traceSegment);
assertHttpSpan(spans.get(0), "/putRequestURL");
}
@Test
public void testDeleteMapping() throws Throwable {
controllerConstructorInterceptor.onConstruct(enhancedInstance, null);
RestMappingClass1 mappingClass1 = new RestMappingClass1();
Method m = mappingClass1.getClass().getMethod("deleteRequestURL");
when(request.getRequestURI()).thenReturn("/test/testRequestURL");
when(request.getRequestURL()).thenReturn(new StringBuffer("http://localhost:8080/test/deleteRequestURL"));
ServletRequestAttributes servletRequestAttributes = new ServletRequestAttributes(request, response);
RequestContextHolder.setRequestAttributes(servletRequestAttributes);
interceptor.beforeMethod(enhancedInstance, m, arguments, argumentType, methodInterceptResult);
interceptor.afterMethod(enhancedInstance, m, arguments, argumentType, null);
assertThat(segmentStorage.getTraceSegments().size(), is(1));
TraceSegment traceSegment = segmentStorage.getTraceSegments().get(0);
List<AbstractTracingSpan> spans = SegmentHelper.getSpans(traceSegment);
assertHttpSpan(spans.get(0), "/deleteRequestURL");
}
@Test
public void testPatchMapping() throws Throwable {
controllerConstructorInterceptor.onConstruct(enhancedInstance, null);
RestMappingClass1 mappingClass1 = new RestMappingClass1();
Method m = mappingClass1.getClass().getMethod("patchRequestURL");
when(request.getRequestURI()).thenReturn("/test/testRequestURL");
when(request.getRequestURL()).thenReturn(new StringBuffer("http://localhost:8080/test/patchRequestURL"));
ServletRequestAttributes servletRequestAttributes = new ServletRequestAttributes(request, response);
RequestContextHolder.setRequestAttributes(servletRequestAttributes);
interceptor.beforeMethod(enhancedInstance, m, arguments, argumentType, methodInterceptResult);
interceptor.afterMethod(enhancedInstance, m, arguments, argumentType, null);
assertThat(segmentStorage.getTraceSegments().size(), is(1));
TraceSegment traceSegment = segmentStorage.getTraceSegments().get(0);
List<AbstractTracingSpan> spans = SegmentHelper.getSpans(traceSegment);
assertHttpSpan(spans.get(0), "/patchRequestURL");
}
@Test
public void testDummy() throws Throwable {
controllerConstructorInterceptor.onConstruct(enhancedInstance, null);
RestMappingClass1 mappingClass1 = new RestMappingClass1();
Method m = mappingClass1.getClass().getMethod("dummy");
when(request.getRequestURI()).thenReturn("/test");
when(request.getRequestURL()).thenReturn(new StringBuffer("http://localhost:8080/test"));
ServletRequestAttributes servletRequestAttributes = new ServletRequestAttributes(request, response);
RequestContextHolder.setRequestAttributes(servletRequestAttributes);
interceptor.beforeMethod(enhancedInstance, m, arguments, argumentType, methodInterceptResult);
interceptor.afterMethod(enhancedInstance, m, arguments, argumentType, null);
assertThat(segmentStorage.getTraceSegments().size(), is(1));
TraceSegment traceSegment = segmentStorage.getTraceSegments().get(0);
List<AbstractTracingSpan> spans = SegmentHelper.getSpans(traceSegment);
assertHttpSpan(spans.get(0), "");
}
@Test
public void testWithOccurException() throws Throwable {
controllerConstructorInterceptor.onConstruct(enhancedInstance, null);
RestMappingClass1 mappingClass1 = new RestMappingClass1();
Method m = mappingClass1.getClass().getMethod("getRequestURL");
when(request.getRequestURI()).thenReturn("/test/testRequestURL");
when(request.getRequestURL()).thenReturn(new StringBuffer("http://localhost:8080/test/getRequestURL"));
ServletRequestAttributes servletRequestAttributes = new ServletRequestAttributes(request, response);
RequestContextHolder.setRequestAttributes(servletRequestAttributes);
interceptor.beforeMethod(enhancedInstance, m, arguments, argumentType, methodInterceptResult);
interceptor.handleMethodException(enhancedInstance, m, arguments, argumentType, new RuntimeException());
interceptor.afterMethod(enhancedInstance, m, arguments, argumentType, null);
assertThat(segmentStorage.getTraceSegments().size(), is(1));
TraceSegment traceSegment = segmentStorage.getTraceSegments().get(0);
List<AbstractTracingSpan> spans = SegmentHelper.getSpans(traceSegment);
assertHttpSpan(spans.get(0), "/getRequestURL");
List<LogDataEntity> logDataEntities = SpanHelper.getLogs(spans.get(0));
assertThat(logDataEntities.size(), is(1));
assertException(logDataEntities.get(0), RuntimeException.class);
}
private void assertTraceSegmentRef(TraceSegmentRef ref) {
assertThat(SegmentRefHelper.getEntryApplicationInstanceId(ref), is(1));
assertThat(SegmentRefHelper.getSpanId(ref), is(3));
assertThat(SegmentRefHelper.getTraceSegmentId(ref).toString(), is("1.444.555"));
}
private void assertHttpSpan(AbstractTracingSpan span, String suffix) {
assertThat(span.getOperationName(), is("/test" + suffix));
assertComponent(span, ComponentsDefine.SPRING_MVC_ANNOTATION);
assertTag(span, 0, "http://localhost:8080/test" + suffix);
assertThat(span.isEntry(), is(true));
assertLayer(span, SpanLayer.HTTP);
}
@RequestMapping(value = "/test")
private class MockEnhancedInstance1 implements EnhancedInstance {
private Object value;
@Override
public Object getSkyWalkingDynamicField() {
return value;
}
@Override
public void setSkyWalkingDynamicField(Object value) {
this.value = value;
}
}
private class RestMappingClass1 {
@GetMapping("/getRequestURL")
public void getRequestURL() {
}
@PostMapping("/postRequestURL")
public void postRequestURL() {
}
@PutMapping("/putRequestURL")
public void putRequestURL() {
}
@DeleteMapping("/deleteRequestURL")
public void deleteRequestURL() {
}
@PatchMapping("/patchRequestURL")
public void patchRequestURL() {
}
public void dummy() {
}
}
}
package org.skywalking.apm.plugin.spring.mvc.define;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.modules.junit4.PowerMockRunner;
import org.powermock.modules.junit4.PowerMockRunnerDelegate;
import org.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
import org.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
import org.skywalking.apm.agent.test.tools.TracingSegmentRunner;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.matcher.ElementMatchers;
import static net.bytebuddy.matcher.ElementMatchers.isAnnotatedWith;
import static net.bytebuddy.matcher.ElementMatchers.named;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
@RunWith(PowerMockRunner.class)
@PowerMockRunnerDelegate(TracingSegmentRunner.class)
public class ControllerInstrumentationTest {
private ControllerInstrumentation controllerInstrumentation;
@Before
public void setUp() throws Exception {
controllerInstrumentation = new ControllerInstrumentation();
}
@Test
public void testGetEnhanceAnnotations() throws Throwable {
Assert.assertArrayEquals(new String[] {ControllerInstrumentation.ENHANCE_ANNOTATION},
controllerInstrumentation.getEnhanceAnnotations());
}
@Test
public void testGetInstanceMethodsInterceptPoints() throws Throwable {
InstanceMethodsInterceptPoint[] methodPoints = controllerInstrumentation.getInstanceMethodsInterceptPoints();
assertThat(methodPoints.length, is(2));
assertThat(methodPoints[0].getMethodsInterceptor(), is("org.skywalking.apm.plugin.spring.mvc.RequestMappingMethodInterceptor"));
assertThat(methodPoints[1].getMethodsInterceptor(), is("org.skywalking.apm.plugin.spring.mvc.RestMappingMethodInterceptor"));
Assert.assertFalse(methodPoints[0].isOverrideArgs());
Assert.assertFalse(methodPoints[1].isOverrideArgs());
Assert.assertNotNull(methodPoints[0].getMethodsMatcher());
Assert.assertNotNull(methodPoints[1].getMethodsMatcher());
}
@Test
public void testGetConstructorsInterceptPoints() throws Throwable {
ConstructorInterceptPoint[] cips = controllerInstrumentation.getConstructorsInterceptPoints();
Assert.assertEquals(cips.length, 1);
ConstructorInterceptPoint cip = cips[0];
Assert.assertNotNull(cip);
Assert.assertEquals(cip.getConstructorInterceptor(), "org.skywalking.apm.plugin.spring.mvc.ControllerConstructorInterceptor");
Assert.assertTrue(cip.getConstructorMatcher().equals(ElementMatchers.any()));
}
}
package org.skywalking.apm.plugin.spring.mvc.define;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.modules.junit4.PowerMockRunner;
import org.powermock.modules.junit4.PowerMockRunnerDelegate;
import org.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
import org.skywalking.apm.agent.test.tools.TracingSegmentRunner;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
@RunWith(PowerMockRunner.class)
@PowerMockRunnerDelegate(TracingSegmentRunner.class)
public class RestControllerInstrumentationTest {
private RestControllerInstrumentation restControllerInstrumentation;
@Before
public void setUp() throws Exception {
restControllerInstrumentation = new RestControllerInstrumentation();
}
@Test
public void testGetEnhanceAnnotations() throws Throwable {
Assert.assertArrayEquals(new String[] {restControllerInstrumentation.ENHANCE_ANNOTATION},
restControllerInstrumentation.getEnhanceAnnotations());
}
@Test
public void testGetInstanceMethodsInterceptPoints() throws Throwable {
InstanceMethodsInterceptPoint[] methodPoints = restControllerInstrumentation.getInstanceMethodsInterceptPoints();
assertThat(methodPoints.length, is(2));
assertThat(methodPoints[0].getMethodsInterceptor(), is("org.skywalking.apm.plugin.spring.mvc.RequestMappingMethodInterceptor"));
assertThat(methodPoints[1].getMethodsInterceptor(), is("org.skywalking.apm.plugin.spring.mvc.RestMappingMethodInterceptor"));
Assert.assertFalse(methodPoints[0].isOverrideArgs());
Assert.assertFalse(methodPoints[1].isOverrideArgs());
Assert.assertNotNull(methodPoints[0].getMethodsMatcher());
Assert.assertNotNull(methodPoints[1].getMethodsMatcher());
}
}
<?xml version="1.0" encoding="UTF-8"?>
<project
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.skywalking</groupId>
<artifactId>apm-sdk-plugin</artifactId>
<version>3.2.3-2017</version>
</parent>
<artifactId>apm-spymemcached-2.x-plugin</artifactId>
<name>spymemcached-2.x-plugin</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<spymemcached.version>2.11.1</spymemcached.version>
</properties>
<dependencies>
<dependency>
<groupId>net.spy</groupId>
<artifactId>spymemcached</artifactId>
<version>${spymemcached.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.4.1</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
\ No newline at end of file
package org.skywalking.apm.plugin.spymemcached.v2;
import java.net.InetSocketAddress;
import java.util.List;
import org.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
import org.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceConstructorInterceptor;
public class MemcachedConstructorWithInetSocketAddressListArgInterceptor implements InstanceConstructorInterceptor {
@Override
public void onConstruct(EnhancedInstance objInst, Object[] allArguments) {
StringBuilder memcachConnInfo = new StringBuilder();
@SuppressWarnings("unchecked")
List<InetSocketAddress> inetSocketAddressList = (List<InetSocketAddress>)allArguments[1];
for (InetSocketAddress inetSocketAddress : inetSocketAddressList) {
String host = inetSocketAddress.getAddress().getHostAddress();
int port = inetSocketAddress.getPort();
memcachConnInfo.append(host).append(":").append(port).append(";");
}
if (memcachConnInfo.length() > 1) {
memcachConnInfo = new StringBuilder(memcachConnInfo.substring(0, memcachConnInfo.length() - 1));
}
objInst.setSkyWalkingDynamicField(memcachConnInfo.toString());
}
}
\ No newline at end of file
package org.skywalking.apm.plugin.spymemcached.v2;
import java.lang.reflect.Method;
import org.skywalking.apm.agent.core.context.ContextManager;
import org.skywalking.apm.agent.core.context.tag.Tags;
import org.skywalking.apm.agent.core.context.trace.AbstractSpan;
import org.skywalking.apm.agent.core.context.trace.SpanLayer;
import org.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
import org.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
import org.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
import org.skywalking.apm.network.trace.component.ComponentsDefine;
public class MemcachedMethodInterceptor implements InstanceMethodsAroundInterceptor {
private static final String SPY_MEMCACHE = "SpyMemcached/";
@Override
public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments,
Class<?>[] argumentsTypes, MethodInterceptResult result) throws Throwable {
String peer = String.valueOf(objInst.getSkyWalkingDynamicField());
AbstractSpan span = ContextManager.createExitSpan(SPY_MEMCACHE + method.getName(), peer);
span.setComponent(ComponentsDefine.MEMCACHE);
Tags.DB_TYPE.set(span, ComponentsDefine.MEMCACHE.getName());
SpanLayer.asDB(span);
Tags.DB_STATEMENT.set(span, method.getName() + " " + allArguments[0]);
}
@Override
public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments,
Class<?>[] argumentsTypes, Object ret) throws Throwable {
ContextManager.stopSpan();
return ret;
}
@Override public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments,
Class<?>[] argumentsTypes, Throwable t) {
AbstractSpan span = ContextManager.activeSpan();
span.errorOccurred();
span.log(t);
}
}
package org.skywalking.apm.plugin.spymemcached.v2.define;
import static org.skywalking.apm.agent.core.plugin.match.NameMatch.byName;
import java.util.List;
import org.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
import org.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
import org.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine;
import org.skywalking.apm.agent.core.plugin.match.ClassMatch;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.matcher.ElementMatcher;
import static net.bytebuddy.matcher.ElementMatchers.named;
import static net.bytebuddy.matcher.ElementMatchers.takesArgument;
/**
*
* {@link MemcachedInstrumentation} presents that skywalking intercept all constructors and methods of
* {@link net.spy.memcached.MemcachedClient}.
* {@link XMemcachedConstructorWithInetSocketAddressListArgInterceptor} intercepts the constructor with
* argument {@link java.net.InetSocketAddress}.
*
* @author IluckySi
*
*/
public class MemcachedInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
private static final String ENHANCE_CLASS = "net.spy.memcached.MemcachedClient";
private static final String CONSTRUCTOR_WITH_INETSOCKETADDRESS_LIST_ARG_INTERCEPT_CLASS = "org.skywalking.apm.plugin.spymemcached.v2.MemcachedConstructorWithInetSocketAddressListArgInterceptor";
private static final String METHOD_INTERCEPT_CLASS = "org.skywalking.apm.plugin.spymemcached.v2.MemcachedMethodInterceptor";
@Override
public ClassMatch enhanceClass() {
return byName(ENHANCE_CLASS);
}
@Override
protected ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
return new ConstructorInterceptPoint[] {
new ConstructorInterceptPoint() {
@Override
public ElementMatcher<MethodDescription> getConstructorMatcher() {
return takesArgument(1, List.class);
}
@Override
public String getConstructorInterceptor() {
return CONSTRUCTOR_WITH_INETSOCKETADDRESS_LIST_ARG_INTERCEPT_CLASS;
}
}
};
}
@Override
protected InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
return new InstanceMethodsInterceptPoint[] {
new InstanceMethodsInterceptPoint() {
@Override
public ElementMatcher<MethodDescription> getMethodsMatcher() {
return named("touch").or(named("append")) .or(named("prepend")).or(named("asyncCAS"))
.or(named("cas")) .or(named("add")).or(named("set")).or(named("replace"))
.or(named("asyncGet")).or(named("asyncGets")).or(named("gets")).or(named("getAndTouch"))
.or(named("get")).or(named("asyncGetBulk")) .or(named("asyncGetAndTouch"))
.or(named("getBulk")).or(named("getStats")) .or(named("incr"))
.or(named("decr")).or(named("asyncIncr")) .or(named("asyncDecr"))
.or(named("delete"));
}
@Override
public String getMethodsInterceptor() {
return METHOD_INTERCEPT_CLASS;
}
@Override public boolean isOverrideArgs() {
return false;
}
}
};
}
}
spymemcached-2.x=org.skywalking.apm.plugin.spymemcached.v2.define.MemcachedInstrumentation
\ No newline at end of file
package org.skywalking.apm.plugin.spymemcached.v2;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import java.net.InetSocketAddress;
import java.util.ArrayList;
import java.util.List;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import org.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
@RunWith(MockitoJUnitRunner.class)
public class MemcachedConstructorWithInetSocketAddressListArgInterceptorTest {
private MemcachedConstructorWithInetSocketAddressListArgInterceptor interceptor;
@Mock
private EnhancedInstance enhancedInstance;
@Before
public void setUp() throws Exception {
interceptor = new MemcachedConstructorWithInetSocketAddressListArgInterceptor();
}
@Test
public void onConstructWithInetSocketAddressList() {
List<InetSocketAddress> inetSocketAddressList = new ArrayList<InetSocketAddress>();
inetSocketAddressList.add(new InetSocketAddress("127.0.0.1", 11211));
inetSocketAddressList.add(new InetSocketAddress("127.0.0.2", 11211));
interceptor.onConstruct(enhancedInstance, new Object[]{null, inetSocketAddressList});
verify(enhancedInstance, times(1)).setSkyWalkingDynamicField("127.0.0.1:11211;127.0.0.2:11211");
}
}
package org.skywalking.apm.plugin.spymemcached.v2;
import static junit.framework.TestCase.assertNotNull;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.mockito.Mockito.when;
import java.lang.reflect.Method;
import java.util.List;
import org.hamcrest.CoreMatchers;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.powermock.modules.junit4.PowerMockRunner;
import org.powermock.modules.junit4.PowerMockRunnerDelegate;
import org.skywalking.apm.agent.core.context.trace.AbstractTracingSpan;
import org.skywalking.apm.agent.core.context.trace.LogDataEntity;
import org.skywalking.apm.agent.core.context.trace.SpanLayer;
import org.skywalking.apm.agent.core.context.trace.TraceSegment;
import org.skywalking.apm.agent.core.context.util.KeyValuePair;
import org.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
import org.skywalking.apm.agent.test.helper.SegmentHelper;
import org.skywalking.apm.agent.test.helper.SpanHelper;
import org.skywalking.apm.agent.test.tools.AgentServiceRule;
import org.skywalking.apm.agent.test.tools.SegmentStorage;
import org.skywalking.apm.agent.test.tools.SegmentStoragePoint;
import org.skywalking.apm.agent.test.tools.TracingSegmentRunner;
import net.spy.memcached.MemcachedClient;
@RunWith(PowerMockRunner.class)
@PowerMockRunnerDelegate(TracingSegmentRunner.class)
public class MemcachedMethodInterceptorTest {
@SegmentStoragePoint
private SegmentStorage segmentStorage;
@Rule
public AgentServiceRule serviceRule = new AgentServiceRule();
@Mock
private EnhancedInstance enhancedInstance;
private MemcachedMethodInterceptor interceptor;
private Object[] allArgument;
private Class[] argumentType;
@Before
public void setUp() throws Exception {
allArgument = new Object[] {"OperationKey", "OperationValue"};
argumentType = new Class[] {String.class, String.class};
interceptor = new MemcachedMethodInterceptor();
when(enhancedInstance.getSkyWalkingDynamicField()).thenReturn("127.0.0.1:11211");
}
@Test
public void testIntercept() throws Throwable {
interceptor.beforeMethod(enhancedInstance, getMockSetMethod(), allArgument, argumentType, null);
interceptor.afterMethod(enhancedInstance, getMockGetMethod(), allArgument, argumentType, null);
TraceSegment traceSegment = segmentStorage.getTraceSegments().get(0);
List<AbstractTracingSpan> spans = SegmentHelper.getSpans(traceSegment);
assertThat(spans.size(), is(1));
assertMemcacheSpan(spans.get(0));
}
@Test
public void testInterceptWithException() throws Throwable {
interceptor.beforeMethod(enhancedInstance, getMockSetMethod(), allArgument, argumentType, null);
interceptor.handleMethodException(enhancedInstance, getMockSetMethod(), allArgument, argumentType, new RuntimeException());
interceptor.afterMethod(enhancedInstance, getMockSetMethod(), allArgument, argumentType, null);
TraceSegment traceSegment = segmentStorage.getTraceSegments().get(0);
List<AbstractTracingSpan> spans = SegmentHelper.getSpans(traceSegment);
assertThat(spans.size(), is(1));
assertMemcacheSpan(spans.get(0));
assertLogData(SpanHelper.getLogs(spans.get(0)));
}
private void assertLogData(List<LogDataEntity> logDataEntities) {
assertThat(logDataEntities.size(), is(1));
LogDataEntity logData = logDataEntities.get(0);
Assert.assertThat(logData.getLogs().size(), is(4));
Assert.assertThat(logData.getLogs().get(0).getValue(), CoreMatchers.<Object>is("error"));
Assert.assertThat(logData.getLogs().get(1).getValue(), CoreMatchers.<Object>is(RuntimeException.class.getName()));
Assert.assertNull(logData.getLogs().get(2).getValue());
assertNotNull(logData.getLogs().get(3).getValue());
}
private void assertMemcacheSpan(AbstractTracingSpan span) {
assertThat(span.getOperationName(), is("SpyMemcached/set"));
assertThat(span.isExit(), is(true));
assertThat(SpanHelper.getComponentId(span), is(20));
List<KeyValuePair> tags = SpanHelper.getTags(span);
assertThat(tags.get(0).getValue(), is("Memcache"));
assertThat(tags.get(1).getValue(), is("set OperationKey"));
assertThat(SpanHelper.getLayer(span), is(SpanLayer.DB));
}
private Method getMockSetMethod() {
try {
return MemcachedClient.class.getMethod("set", String.class, int.class, Object.class);
} catch (NoSuchMethodException e) {
e.printStackTrace();
return null;
}
}
private Method getMockGetMethod() {
try {
return MemcachedClient.class.getMethod("get", String.class);
} catch (NoSuchMethodException e) {
e.printStackTrace();
return null;
}
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册