提交 e61cc136 编写于 作者: IluckySi's avatar IluckySi

Support SpyMemcached V2.x

上级 13920ea5
......@@ -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
......@@ -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>
......
......@@ -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>
......
<?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.
先完成此消息的编辑!
想要评论请 注册