提交 b820a396 编写于 作者: A ascrutae

support trace annotation

上级 998c04e0
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>apm-application-toolkit</artifactId>
<groupId>org.skywalking</groupId>
<version>3.2-2017</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>apm-toolkit-trace</artifactId>
<packaging>jar</packaging>
<url>http://maven.apache.org</url>
<build>
<plugins>
<plugin>
<!-- 源码插件 -->
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<!-- 发布时自动将源码同时发布的配置 -->
<executions>
<execution>
<id>attach-sources</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
<version>2.4</version>
</plugin>
</plugins>
</build>
<distributionManagement>
<repository>
<id>bintray-wu-sheng-sky-walking-repository</id>
<name>wu-sheng-sky-walking-repository</name>
<url>
https://api.bintray.com/maven/wu-sheng/skywalking/org.skywalking.apm-toolkit-trace/;publish=1
</url>
</repository>
</distributionManagement>
</project>
package org.skywalking.apm.toolkit.trace;
/**
* provide custom api that set tag for current active span.
*
* @author zhangxin
*/
public class ActiveSpan {
/**
* @param key tag key
* @param value tag value
*/
public static void tag(String key, String value) {
}
}
package org.skywalking.apm.toolkit.trace;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* The agent create local span if the method that annotation with {@link Trace}. The value of span operation name will
* fetch by {@link #operationName()}. if the value of {@link #operationName()} is blank string. the operation name will
* be set the class name + method name.
*
* @author zhangxin
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Trace {
/**
* @return operation name, the default value is blank string.
*/
String operationName() default "";
}
......@@ -19,5 +19,6 @@
<module>apm-toolkit-logback-1.x</module>
<module>apm-toolkit-trace-context</module>
<module>apm-toolkit-opentracing</module>
<module>apm-toolkit-trace</module>
</modules>
</project>
package org.skywalking.apm.agent.core.plugin.match;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import net.bytebuddy.description.annotation.AnnotationDescription;
......@@ -47,7 +48,7 @@ public class MethodAnnotationMatch implements IndirectMatch {
@Override
public boolean isMatch(TypeDescription typeDescription) {
for (MethodDescription.InDefinedShape methodDescription : typeDescription.getDeclaredMethods()) {
List<String> annotationList = Arrays.asList(annotations);
List<String> annotationList = new ArrayList<String>(Arrays.asList(annotations));
AnnotationList declaredAnnotations = methodDescription.getDeclaredAnnotations();
for (AnnotationDescription annotation : declaredAnnotations) {
......
......@@ -126,6 +126,12 @@
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.skywalking</groupId>
<artifactId>apm-toolkit-trace-activation</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
<build>
<finalName>skywalking-agent</finalName>
......
......@@ -24,10 +24,16 @@ public class SpanHelper {
public static List<LogDataEntity> getLogs(AbstractSpan tracingSpan) {
try {
return FieldGetter.get2LevelParentFieldValue(tracingSpan, "logs");
List<LogDataEntity> logs = FieldGetter.get2LevelParentFieldValue(tracingSpan, "logs");
if (logs != null) {
return logs;
}
} catch (Exception e) {
try {
return FieldGetter.getParentFieldValue(tracingSpan, "logs");
List<LogDataEntity> logs = FieldGetter.getParentFieldValue(tracingSpan, "logs");
if (logs != null) {
return logs;
}
} catch (Exception e1) {
}
......@@ -38,10 +44,16 @@ public class SpanHelper {
public static List<KeyValuePair> getTags(AbstractSpan tracingSpan) {
try {
return FieldGetter.get2LevelParentFieldValue(tracingSpan, "tags");
List<KeyValuePair> tags = FieldGetter.get2LevelParentFieldValue(tracingSpan, "tags");
if (tags != null) {
return tags;
}
} catch (Exception e) {
try {
return FieldGetter.getParentFieldValue(tracingSpan, "tags");
List<KeyValuePair> tags = FieldGetter.getParentFieldValue(tracingSpan, "tags");
if (tags != null) {
return tags;
}
} catch (Exception e1) {
}
......
......@@ -17,6 +17,10 @@ public class SpanAssert {
assertThat(SpanHelper.getLogs(span).size(), is(exceptedSize));
}
public static void assertTagSize(AbstractSpan span, int exceptedSize) {
assertThat(SpanHelper.getTags(span).size(), is(exceptedSize));
}
public static void assertException(LogDataEntity logDataEntity, Class<? extends Throwable> throwableClass,
String message) {
Assert.assertThat(logDataEntity.getLogs().size(), is(4));
......
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>apm-toolkit-activation</artifactId>
<groupId>org.skywalking</groupId>
<version>3.2-2017</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>apm-toolkit-trace-activation</artifactId>
<dependencies>
<dependency>
<groupId>org.skywalking</groupId>
<artifactId>apm-toolkit-trace</artifactId>
<version>${project.version}</version>
<scope>provided</scope>
</dependency>
</dependencies>
</project>
package org.skywalking.apm.toolkit.activation.trace;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.matcher.ElementMatcher;
import org.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
import org.skywalking.apm.agent.core.plugin.interceptor.StaticMethodsInterceptPoint;
import org.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassStaticMethodsEnhancePluginDefine;
import org.skywalking.apm.agent.core.plugin.match.ClassMatch;
import static net.bytebuddy.matcher.ElementMatchers.named;
import static org.skywalking.apm.agent.core.plugin.match.NameMatch.byName;
/**
* {@link TraceAnnotationActivation} enhance the <code>tag</code> method of <code>org.skywalking.apm.toolkit.trace.ActiveSpan</code>
* by <code>org.skywalking.apm.toolkit.activation.trace.ActiveSpanTagInterceptor</code>.
*
* @author zhangxin
*/
public class ActiveSpanTagActivation extends ClassStaticMethodsEnhancePluginDefine {
public static final String ENHANCE_CLASS = "org.skywalking.apm.toolkit.trace.ActiveSpan";
public static final String INTERCEPTOR_CLASS = "org.skywalking.apm.toolkit.activation.trace.ActiveSpanTagInterceptor";
public static final String INTERCEPTOR_METHOD_NAME = "tag";
@Override protected ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
return new ConstructorInterceptPoint[0];
}
@Override protected StaticMethodsInterceptPoint[] getStaticMethodsInterceptPoints() {
return new StaticMethodsInterceptPoint[] {
new StaticMethodsInterceptPoint() {
@Override public ElementMatcher<MethodDescription> getMethodsMatcher() {
return named(INTERCEPTOR_METHOD_NAME);
}
@Override public String getMethodsInterceptor() {
return INTERCEPTOR_CLASS;
}
@Override public boolean isOverrideArgs() {
return false;
}
}
};
}
@Override protected ClassMatch enhanceClass() {
return byName(ENHANCE_CLASS);
}
}
package org.skywalking.apm.toolkit.activation.trace;
import java.lang.reflect.Method;
import org.skywalking.apm.agent.core.context.ContextManager;
import org.skywalking.apm.agent.core.context.trace.AbstractSpan;
import org.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
import org.skywalking.apm.agent.core.plugin.interceptor.enhance.StaticMethodsAroundInterceptor;
public class ActiveSpanTagInterceptor implements StaticMethodsAroundInterceptor {
@Override public void beforeMethod(Class clazz, Method method, Object[] allArguments, Class<?>[] parameterTypes,
MethodInterceptResult result) {
AbstractSpan activeSpan = ContextManager.activeSpan();
activeSpan.tag(String.valueOf(allArguments[0]), String.valueOf(allArguments[1]));
}
@Override public Object afterMethod(Class clazz, Method method, Object[] allArguments, Class<?>[] parameterTypes,
Object ret) {
return ret;
}
@Override
public void handleMethodException(Class clazz, Method method, Object[] allArguments, Class<?>[] parameterTypes,
Throwable t) {
}
}
package org.skywalking.apm.toolkit.activation.trace;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.matcher.ElementMatcher;
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 static net.bytebuddy.matcher.ElementMatchers.isAnnotatedWith;
import static net.bytebuddy.matcher.ElementMatchers.named;
import static org.skywalking.apm.agent.core.plugin.match.MethodAnnotationMatch.byMethodAnnotationMatch;
/**
* {@link TraceAnnotationActivation} enhance all method that annotated with <code>org.skywalking.apm.toolkit.trace.annotation.Trace</code>
* by <code>org.skywalking.apm.toolkit.activation.trace.TraceAnnotationMethodInterceptor</code>.
*
* @author zhangxin
*/
public class TraceAnnotationActivation extends ClassInstanceMethodsEnhancePluginDefine {
public static final String TRACE_ANNOTATION_METHOD_INTERCEPTOR = "org.skywalking.apm.toolkit.activation.trace.TraceAnnotationMethodInterceptor";
public static final String TRACE_ANNOTATION = "org.skywalking.apm.toolkit.trace.annotation.Trace";
@Override protected ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
return new ConstructorInterceptPoint[0];
}
@Override protected InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
return new InstanceMethodsInterceptPoint[] {
new InstanceMethodsInterceptPoint() {
@Override public ElementMatcher<MethodDescription> getMethodsMatcher() {
return isAnnotatedWith(named(TRACE_ANNOTATION));
}
@Override public String getMethodsInterceptor() {
return TRACE_ANNOTATION_METHOD_INTERCEPTOR;
}
@Override public boolean isOverrideArgs() {
return false;
}
}
};
}
@Override protected ClassMatch enhanceClass() {
return byMethodAnnotationMatch(new String[] {TRACE_ANNOTATION});
}
}
package org.skywalking.apm.toolkit.activation.trace;
import java.lang.reflect.Method;
import org.skywalking.apm.agent.core.context.ContextManager;
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.toolkit.trace.Trace;
/**
* {@link TraceAnnotationMethodInterceptor} create a local span and set the operation name which fetch from
* <code>org.skywalking.apm.toolkit.trace.annotation.Trace.operationName</code>. if the fetch value is blank string, and
* the operation name will be the method name.
*
* @author zhangxin
*/
public class TraceAnnotationMethodInterceptor implements InstanceMethodsAroundInterceptor {
@Override
public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes,
MethodInterceptResult result) throws Throwable {
Trace trace = method.getAnnotation(Trace.class);
String operationName = trace.operationName();
if (operationName.length() == 0) {
operationName = generateOperationName(method);
}
ContextManager.createLocalSpan(operationName);
}
private String generateOperationName(Method method) {
StringBuilder operationName = new StringBuilder(method.getDeclaringClass().getName() + "." + method.getName() + "(");
Class<?>[] parameterTypes = method.getParameterTypes();
for (int i = 0; i < parameterTypes.length; i++) {
operationName.append(parameterTypes[i].getName());
if (i < (parameterTypes.length - 1)) {
operationName.append(",");
}
}
operationName.append(")");
return operationName.toString();
}
@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) {
ContextManager.activeSpan().errorOccurred().log(t);
}
}
trace-annotation=org.skywalking.apm.toolkit.activation.trace.ActiveSpanTagActivation
trace-annotation=org.skywalking.apm.toolkit.activation.trace.TraceAnnotationActivation
package org.skywalking.apm.toolkit.activation.trace;
import java.lang.reflect.Method;
import java.util.List;
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.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 org.skywalking.apm.toolkit.trace.Trace;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.skywalking.apm.agent.test.tools.SpanAssert.assertLogSize;
import static org.skywalking.apm.agent.test.tools.SpanAssert.assertTagSize;
@RunWith(PowerMockRunner.class)
@PowerMockRunnerDelegate(TracingSegmentRunner.class)
public class TraceAnnotationTest {
@SegmentStoragePoint
private SegmentStorage storage;
@Rule
public AgentServiceRule serviceRule = new AgentServiceRule();
@Mock
private EnhancedInstance enhancedInstance;
private TraceAnnotationMethodInterceptor methodInterceptor;
private ActiveSpanTagInterceptor tagInterceptor;
private Object[] tagParameters;
private Class[] tagParameterTypes;
@Before
public void setUp() throws Exception {
methodInterceptor = new TraceAnnotationMethodInterceptor();
tagInterceptor = new ActiveSpanTagInterceptor();
tagParameters = new Object[] {"testTagKey", "testTagValue"};
tagParameterTypes = new Class[] {String.class, String.class};
}
@Test
public void testTraceWithOperationName() throws Throwable {
Method withOperationNameMethod = TestAnnotationMethodClass.class.getDeclaredMethod("testMethodWithOperationName");
methodInterceptor.beforeMethod(enhancedInstance, withOperationNameMethod, null, null, null);
tagInterceptor.beforeMethod(TestAnnotationMethodClass.class, withOperationNameMethod, tagParameters, tagParameterTypes, null);
tagInterceptor.afterMethod(TestAnnotationMethodClass.class, withOperationNameMethod, tagParameters, tagParameterTypes, null);
methodInterceptor.afterMethod(enhancedInstance, withOperationNameMethod, null, null, null);
assertThat(storage.getTraceSegments().size(), is(1));
TraceSegment traceSegment = storage.getTraceSegments().get(0);
List<AbstractTracingSpan> spans = SegmentHelper.getSpans(traceSegment);
assertThat(spans.size(), is(1));
AbstractTracingSpan tracingSpan = spans.get(0);
assertThat(tracingSpan.getOperationName(), is("testMethod"));
assertLogSize(tracingSpan, 0);
assertTagSize(tracingSpan, 1);
List<KeyValuePair> tags = SpanHelper.getTags(tracingSpan);
assertThat(tags.get(0).getKey(), is("testTagKey"));
assertThat(tags.get(0).getValue(), is("testTagValue"));
}
@Test
public void testTrace() throws Throwable {
Method withOperationNameMethod = TestAnnotationMethodClass.class.getDeclaredMethod("testMethodWithDefaultValue");
methodInterceptor.beforeMethod(enhancedInstance, withOperationNameMethod, null, null, null);
methodInterceptor.afterMethod(enhancedInstance, withOperationNameMethod, null, null, null);
assertThat(storage.getTraceSegments().size(), is(1));
TraceSegment traceSegment = storage.getTraceSegments().get(0);
List<AbstractTracingSpan> spans = SegmentHelper.getSpans(traceSegment);
assertThat(spans.size(), is(1));
AbstractTracingSpan tracingSpan = spans.get(0);
assertThat(tracingSpan.getOperationName(), is(TestAnnotationMethodClass.class.getName() + "." + withOperationNameMethod.getName() + "()"));
assertLogSize(tracingSpan, 0);
assertTagSize(tracingSpan, 0);
}
private class TestAnnotationMethodClass {
@Trace(operationName = "testMethod")
public void testMethodWithOperationName() {
}
@Trace
public void testMethodWithDefaultValue() {
}
}
}
......@@ -15,6 +15,7 @@
<module>apm-toolkit-logback-1.x-activation</module>
<module>apm-toolkit-trace-context-activation</module>
<module>apm-toolkit-opentracing-activation</module>
<module>apm-toolkit-trace-activation</module>
</modules>
<artifactId>apm-toolkit-activation</artifactId>
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册