Merge branch 'master' into feature/351
This commit is contained in:
commit
903a15a392
|
|
@ -31,6 +31,10 @@ public class ComponentsDefine {
|
|||
|
||||
public static final OfficialComponent OKHTTP = new OfficialComponent(12, "OKHttp");
|
||||
|
||||
public static final OfficialComponent SPRING_REST_TEMPLATE = new OfficialComponent(13, "SpringRestTemplate");
|
||||
|
||||
public static final OfficialComponent SPRING_MVC_ANNOTATION = new OfficialComponent(14, "SpringMVCAnnotation");
|
||||
|
||||
private static ComponentsDefine instance = new ComponentsDefine();
|
||||
|
||||
private String[] components;
|
||||
|
|
@ -40,7 +44,7 @@ public class ComponentsDefine {
|
|||
}
|
||||
|
||||
public ComponentsDefine() {
|
||||
components = new String[13];
|
||||
components = new String[15];
|
||||
addComponent(TOMCAT);
|
||||
addComponent(HTTPCLIENT);
|
||||
addComponent(DUBBO);
|
||||
|
|
@ -53,6 +57,8 @@ public class ComponentsDefine {
|
|||
addComponent(RESIN);
|
||||
addComponent(FEIGN);
|
||||
addComponent(OKHTTP);
|
||||
addComponent(SPRING_REST_TEMPLATE);
|
||||
addComponent(SPRING_MVC_ANNOTATION);
|
||||
}
|
||||
|
||||
private void addComponent(OfficialComponent component) {
|
||||
|
|
|
|||
|
|
@ -290,19 +290,19 @@ public class TracingContext implements AbstractTracerContext {
|
|||
.find(remotePeer).doInCondition(
|
||||
new PossibleFound.FoundAndObtain() {
|
||||
@Override
|
||||
public Object doProcess(final int applicationId) {
|
||||
public Object doProcess(final int peerId) {
|
||||
return DictionaryManager.findOperationNameCodeSection()
|
||||
.findOrPrepare4Register(applicationId, operationName)
|
||||
.findOnly(segment.getApplicationId(), operationName)
|
||||
.doInCondition(
|
||||
new PossibleFound.FoundAndObtain() {
|
||||
@Override
|
||||
public Object doProcess(int operationId) {
|
||||
return new ExitSpan(spanIdGenerator++, parentSpanId, operationId, applicationId);
|
||||
return new ExitSpan(spanIdGenerator++, parentSpanId, operationId, peerId);
|
||||
}
|
||||
}, new PossibleFound.NotFoundAndObtain() {
|
||||
@Override
|
||||
public Object doProcess() {
|
||||
return new ExitSpan(spanIdGenerator++, parentSpanId, operationName, remotePeer);
|
||||
return new ExitSpan(spanIdGenerator++, parentSpanId, operationName, peerId);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
@ -310,7 +310,20 @@ public class TracingContext implements AbstractTracerContext {
|
|||
new PossibleFound.NotFoundAndObtain() {
|
||||
@Override
|
||||
public Object doProcess() {
|
||||
return new ExitSpan(spanIdGenerator++, parentSpanId, operationName, remotePeer);
|
||||
return DictionaryManager.findOperationNameCodeSection()
|
||||
.findOnly(segment.getApplicationId(), operationName)
|
||||
.doInCondition(
|
||||
new PossibleFound.FoundAndObtain() {
|
||||
@Override
|
||||
public Object doProcess(int operationId) {
|
||||
return new ExitSpan(spanIdGenerator++, parentSpanId, operationId, remotePeer);
|
||||
}
|
||||
}, new PossibleFound.NotFoundAndObtain() {
|
||||
@Override
|
||||
public Object doProcess() {
|
||||
return new ExitSpan(spanIdGenerator++, parentSpanId, operationName, remotePeer);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
push(exitSpan);
|
||||
|
|
|
|||
|
|
@ -1,8 +1,6 @@
|
|||
package org.skywalking.apm.agent.core.context.trace;
|
||||
|
||||
import org.skywalking.apm.agent.core.dictionary.DictionaryManager;
|
||||
import org.skywalking.apm.agent.core.dictionary.DictionaryUtil;
|
||||
import org.skywalking.apm.agent.core.dictionary.PossibleFound;
|
||||
import org.skywalking.apm.network.trace.component.Component;
|
||||
|
||||
/**
|
||||
|
|
@ -18,19 +16,16 @@ import org.skywalking.apm.network.trace.component.Component;
|
|||
*
|
||||
* @author wusheng
|
||||
*/
|
||||
public class EntrySpan extends AbstractTracingSpan {
|
||||
private int stackDepth;
|
||||
public class EntrySpan extends StackBasedTracingSpan {
|
||||
private int currentMaxDepth;
|
||||
|
||||
public EntrySpan(int spanId, int parentSpanId, String operationName) {
|
||||
super(spanId, parentSpanId, operationName);
|
||||
this.stackDepth = 0;
|
||||
this.currentMaxDepth = 0;
|
||||
}
|
||||
|
||||
public EntrySpan(int spanId, int parentSpanId, int operationId) {
|
||||
super(spanId, parentSpanId, operationId);
|
||||
this.stackDepth = 0;
|
||||
this.currentMaxDepth = 0;
|
||||
}
|
||||
|
||||
|
|
@ -81,31 +76,6 @@ public class EntrySpan extends AbstractTracingSpan {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean finish(TraceSegment owner) {
|
||||
if (--stackDepth == 0) {
|
||||
if (this.operationId == DictionaryUtil.nullValue()) {
|
||||
this.operationId = (Integer)DictionaryManager.findOperationNameCodeSection()
|
||||
.findOrPrepare4Register(owner.getApplicationId(), operationName)
|
||||
.doInCondition(
|
||||
new PossibleFound.FoundAndObtain() {
|
||||
@Override public Object doProcess(int value) {
|
||||
return value;
|
||||
}
|
||||
},
|
||||
new PossibleFound.NotFoundAndObtain() {
|
||||
@Override public Object doProcess() {
|
||||
return DictionaryUtil.nullValue();
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
return super.finish(owner);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public AbstractTracingSpan setOperationName(String operationName) {
|
||||
if (stackDepth == currentMaxDepth) {
|
||||
|
|
|
|||
|
|
@ -17,32 +17,34 @@ import org.skywalking.apm.network.trace.component.Component;
|
|||
*
|
||||
* @author wusheng
|
||||
*/
|
||||
public class ExitSpan extends AbstractTracingSpan {
|
||||
private int stackDepth;
|
||||
public class ExitSpan extends StackBasedTracingSpan {
|
||||
private String peer;
|
||||
private int peerId;
|
||||
|
||||
public ExitSpan(int spanId, int parentSpanId, String operationName, String peer) {
|
||||
super(spanId, parentSpanId, operationName);
|
||||
this.stackDepth = 0;
|
||||
this.peer = peer;
|
||||
this.peerId = DictionaryUtil.nullValue();
|
||||
}
|
||||
|
||||
public ExitSpan(int spanId, int parentSpanId, int operationId, int peerId) {
|
||||
super(spanId, parentSpanId, operationId);
|
||||
this.stackDepth = 0;
|
||||
this.peer = null;
|
||||
this.peerId = peerId;
|
||||
}
|
||||
|
||||
public ExitSpan(int spanId, int parentSpanId, int operationId, String peer) {
|
||||
super(spanId, parentSpanId, operationId);
|
||||
this.stackDepth = 0;
|
||||
this.peer = peer;
|
||||
this.peerId = DictionaryUtil.nullValue();
|
||||
}
|
||||
|
||||
public ExitSpan(int spanId, int parentSpanId, String operationName, int peerId) {
|
||||
super(spanId, parentSpanId, operationName);
|
||||
this.peer = null;
|
||||
this.peerId = peerId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the {@link #startTime}, when the first start, which means the first service provided.
|
||||
*/
|
||||
|
|
@ -62,15 +64,6 @@ public class ExitSpan extends AbstractTracingSpan {
|
|||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean finish(TraceSegment owner) {
|
||||
if (--stackDepth == 0) {
|
||||
return super.finish(owner);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public AbstractTracingSpan setLayer(SpanLayer layer) {
|
||||
if (stackDepth == 1) {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,51 @@
|
|||
package org.skywalking.apm.agent.core.context.trace;
|
||||
|
||||
import org.skywalking.apm.agent.core.dictionary.DictionaryManager;
|
||||
import org.skywalking.apm.agent.core.dictionary.DictionaryUtil;
|
||||
import org.skywalking.apm.agent.core.dictionary.PossibleFound;
|
||||
|
||||
/**
|
||||
* The <code>StackBasedTracingSpan</code> represents a span with an inside stack construction.
|
||||
*
|
||||
* This kind of span can start and finish multi times in a stack-like invoke line.
|
||||
*
|
||||
* @author wusheng
|
||||
*/
|
||||
public abstract class StackBasedTracingSpan extends AbstractTracingSpan {
|
||||
protected int stackDepth;
|
||||
|
||||
protected StackBasedTracingSpan(int spanId, int parentSpanId, String operationName) {
|
||||
super(spanId, parentSpanId, operationName);
|
||||
this.stackDepth = 0;
|
||||
}
|
||||
|
||||
protected StackBasedTracingSpan(int spanId, int parentSpanId, int operationId) {
|
||||
super(spanId, parentSpanId, operationId);
|
||||
this.stackDepth = 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean finish(TraceSegment owner) {
|
||||
if (--stackDepth == 0) {
|
||||
if (this.operationId == DictionaryUtil.nullValue()) {
|
||||
this.operationId = (Integer)DictionaryManager.findOperationNameCodeSection()
|
||||
.findOrPrepare4Register(owner.getApplicationId(), operationName)
|
||||
.doInCondition(
|
||||
new PossibleFound.FoundAndObtain() {
|
||||
@Override public Object doProcess(int value) {
|
||||
return value;
|
||||
}
|
||||
},
|
||||
new PossibleFound.NotFoundAndObtain() {
|
||||
@Override public Object doProcess() {
|
||||
return DictionaryUtil.nullValue();
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
return super.finish(owner);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
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;
|
||||
|
|
@ -43,7 +44,7 @@ public class ClassAnnotationMatch implements IndirectMatch {
|
|||
|
||||
@Override
|
||||
public boolean isMatch(TypeDescription typeDescription) {
|
||||
List<String> annotationList = Arrays.asList(annotations);
|
||||
List<String> annotationList = new ArrayList<String>(Arrays.asList(annotations));
|
||||
AnnotationList declaredAnnotations = typeDescription.getDeclaredAnnotations();
|
||||
for (AnnotationDescription annotation : declaredAnnotations) {
|
||||
annotationList.remove(annotation.getAnnotationType().getActualName());
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import org.skywalking.apm.agent.core.context.trace.LogDataEntity;
|
|||
public class AbstractTracingSpanHelper {
|
||||
public static int getParentSpanId(AbstractTracingSpan tracingSpan) {
|
||||
try {
|
||||
return FieldGetter.getParentFieldValue(tracingSpan, "parentSpanId");
|
||||
return FieldGetter.get2LevelParentFieldValue(tracingSpan, "parentSpanId");
|
||||
} catch (Exception e) {
|
||||
}
|
||||
|
||||
|
|
@ -17,7 +17,7 @@ public class AbstractTracingSpanHelper {
|
|||
|
||||
public static List<LogDataEntity> getLogs(AbstractTracingSpan tracingSpan) {
|
||||
try {
|
||||
return FieldGetter.getParentFieldValue(tracingSpan, "logs");
|
||||
return FieldGetter.get2LevelParentFieldValue(tracingSpan, "logs");
|
||||
} catch (Exception e) {
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -10,9 +10,10 @@ public class FieldGetter {
|
|||
return (T)field.get(instance);
|
||||
}
|
||||
|
||||
public static <T> T getParentFieldValue(Object instance,
|
||||
|
||||
public static <T> T get2LevelParentFieldValue(Object instance,
|
||||
String fieldName) throws IllegalAccessException, NoSuchFieldException {
|
||||
Field field = instance.getClass().getSuperclass().getDeclaredField(fieldName);
|
||||
Field field = instance.getClass().getSuperclass().getSuperclass().getDeclaredField(fieldName);
|
||||
field.setAccessible(true);
|
||||
return (T)field.get(instance);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ public class SpanHelper {
|
|||
|
||||
public static SpanLayer getLayer(AbstractSpan tracingSpan) {
|
||||
try {
|
||||
return FieldGetter.getParentFieldValue(tracingSpan, "layer");
|
||||
return FieldGetter.get2LevelParentFieldValue(tracingSpan, "layer");
|
||||
} catch (Exception e) {
|
||||
}
|
||||
|
||||
|
|
@ -16,7 +16,7 @@ public class SpanHelper {
|
|||
|
||||
public static int getComponentId(AbstractSpan tracingSpan) {
|
||||
try {
|
||||
return FieldGetter.getParentFieldValue(tracingSpan, "componentId");
|
||||
return FieldGetter.get2LevelParentFieldValue(tracingSpan, "componentId");
|
||||
} catch (Exception e) {
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -80,6 +80,21 @@
|
|||
<artifactId>apm-feign-default-http-9.x-plugin</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.skywalking</groupId>
|
||||
<artifactId>apm-resttemplate-4.3.x-plugin</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.skywalking</groupId>
|
||||
<artifactId>apm-spring-concurrent-util-4.x-plugin</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.skywalking</groupId>
|
||||
<artifactId>apm-springmvc-annotation-4.x-plugin</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- activation -->
|
||||
<dependency>
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@
|
|||
<module>okhttp-3.x-plugin</module>
|
||||
<module>resin-3.x-plugin</module>
|
||||
<module>resin-4.x-plugin</module>
|
||||
<module>spring-plugins</module>
|
||||
</modules>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,24 @@
|
|||
<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>spring-plugins</artifactId>
|
||||
<groupId>org.skywalking</groupId>
|
||||
<version>3.2-2017</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>apm-spring-concurrent-util-4.x-plugin</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>concurrent-util-4.x-plugin</name>
|
||||
<url>http://maven.apache.org</url>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-core</artifactId>
|
||||
<version>4.3.10.RELEASE</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
package org.skywalking.apm.plugin.spring.concurrent;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.URI;
|
||||
import org.skywalking.apm.agent.core.context.ContextManager;
|
||||
import org.skywalking.apm.agent.core.context.ContextSnapshot;
|
||||
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 FailureCallbackInterceptor implements InstanceMethodsAroundInterceptor {
|
||||
|
||||
@Override
|
||||
public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes,
|
||||
MethodInterceptResult result) throws Throwable {
|
||||
Object[] cacheValues = (Object[])objInst.getSkyWalkingDynamicField();
|
||||
if (cacheValues == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
URI uri = (URI)cacheValues[0];
|
||||
AbstractSpan span = ContextManager.createLocalSpan("future/failureCallback:" + uri.getPath());
|
||||
span.errorOccurred().log((Throwable)allArguments[0]).setComponent(ComponentsDefine.SPRING_REST_TEMPLATE).setLayer(SpanLayer.HTTP);
|
||||
Tags.URL.set(span, uri.getPath());
|
||||
ContextManager.continued((ContextSnapshot)cacheValues[2]);
|
||||
}
|
||||
|
||||
@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);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
package org.skywalking.apm.plugin.spring.concurrent;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.URI;
|
||||
import org.skywalking.apm.agent.core.context.ContextManager;
|
||||
import org.skywalking.apm.agent.core.context.ContextSnapshot;
|
||||
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 SuccessCallbackInterceptor implements InstanceMethodsAroundInterceptor {
|
||||
|
||||
@Override
|
||||
public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes,
|
||||
MethodInterceptResult result) throws Throwable {
|
||||
Object[] cacheValues = (Object[])objInst.getSkyWalkingDynamicField();
|
||||
if (cacheValues == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
URI uri = (URI)cacheValues[0];
|
||||
AbstractSpan span = ContextManager.createLocalSpan("future/successCallback:" + uri.getPath());
|
||||
span.setComponent(ComponentsDefine.SPRING_REST_TEMPLATE).setLayer(SpanLayer.HTTP);
|
||||
Tags.URL.set(span, uri.getPath());
|
||||
ContextManager.continued((ContextSnapshot)cacheValues[2]);
|
||||
}
|
||||
|
||||
@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);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
package org.skywalking.apm.plugin.spring.concurrent.define;
|
||||
|
||||
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 org.skywalking.apm.plugin.spring.concurrent.FailureCallbackInterceptor;
|
||||
|
||||
import static net.bytebuddy.matcher.ElementMatchers.named;
|
||||
import static org.skywalking.apm.plugin.spring.concurrent.match.FailedCallbackMatch.failedCallbackMatch;
|
||||
|
||||
/**
|
||||
* {@link FailureCallbackInstrumentation} enhance the onFailure method that class inherited
|
||||
* <code>org.springframework.util.concurrent.FailureCallback</code> by {@link FailureCallbackInterceptor}.
|
||||
*
|
||||
* @author zhangxin
|
||||
*/
|
||||
public class FailureCallbackInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
|
||||
|
||||
public static final String FAILURE_CALLBACK_INTERCEPTOR = "org.skywalking.apm.plugin.spring.concurrent.FailureCallbackInterceptor";
|
||||
public static final String FAILURE_METHOD_NAME = "onFailure";
|
||||
|
||||
@Override
|
||||
protected ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
|
||||
return new ConstructorInterceptPoint[0];
|
||||
}
|
||||
|
||||
@Override
|
||||
protected InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
|
||||
return new InstanceMethodsInterceptPoint[] {
|
||||
new InstanceMethodsInterceptPoint() {
|
||||
@Override
|
||||
public ElementMatcher<MethodDescription> getMethodsMatcher() {
|
||||
return named(FAILURE_METHOD_NAME);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMethodsInterceptor() {
|
||||
return FAILURE_CALLBACK_INTERCEPTOR;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOverrideArgs() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ClassMatch enhanceClass() {
|
||||
return failedCallbackMatch();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
package org.skywalking.apm.plugin.spring.concurrent.define;
|
||||
|
||||
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.named;
|
||||
import static org.skywalking.apm.plugin.spring.concurrent.match.ListenableFutureCallbackMatch.listenableFutureCallbackMatch;
|
||||
|
||||
/**
|
||||
* {@link ListenableFutureCallbackInstrumentation} enhance <code>onSuccess</code> method and <code>oonFailure</code>
|
||||
* that class inherited <code>org.springframework.util.concurrent.ListenableFutureCallback</code> by
|
||||
* <code>org.skywalking.apm.plugin.spring.concurrent.SuccessCallbackInterceptor</code> and
|
||||
* <code>org.skywalking.apm.plugin.spring.concurrent.FailureCallbackInterceptor</code>.
|
||||
*
|
||||
* @author zhangxin
|
||||
*/
|
||||
public class ListenableFutureCallbackInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
|
||||
@Override
|
||||
protected ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
|
||||
return new ConstructorInterceptPoint[0];
|
||||
}
|
||||
|
||||
@Override
|
||||
protected InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
|
||||
return new InstanceMethodsInterceptPoint[] {
|
||||
new InstanceMethodsInterceptPoint() {
|
||||
@Override
|
||||
public ElementMatcher<MethodDescription> getMethodsMatcher() {
|
||||
return named(SuccessCallbackInstrumentation.SUCCESS_METHOD_NAME);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMethodsInterceptor() {
|
||||
return SuccessCallbackInstrumentation.SUCCESS_CALLBACK_INTERCEPTOR;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOverrideArgs() {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
new InstanceMethodsInterceptPoint() {
|
||||
@Override
|
||||
public ElementMatcher<MethodDescription> getMethodsMatcher() {
|
||||
return named(FailureCallbackInstrumentation.FAILURE_METHOD_NAME);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMethodsInterceptor() {
|
||||
return FailureCallbackInstrumentation.FAILURE_CALLBACK_INTERCEPTOR;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOverrideArgs() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ClassMatch enhanceClass() {
|
||||
return listenableFutureCallbackMatch();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
package org.skywalking.apm.plugin.spring.concurrent.define;
|
||||
|
||||
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.named;
|
||||
import static org.skywalking.apm.plugin.spring.concurrent.match.SuccessCallbackMatch.successCallbackMatch;
|
||||
|
||||
/**
|
||||
* {@link SuccessCallbackInstrumentation} enhance the <code>onSuccess</code> method that class inherited
|
||||
* <code>org.springframework.util.concurrent.SuccessCallback</code> by <code>org.skywalking.apm.plugin.spring.concurrent.SuccessCallbackInterceptor</code>.
|
||||
*
|
||||
* @author zhangxin
|
||||
*/
|
||||
public class SuccessCallbackInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
|
||||
|
||||
public static final String SUCCESS_CALLBACK_INTERCEPTOR =
|
||||
"org.skywalking.apm.plugin.spring.concurrent.SuccessCallbackInterceptor";
|
||||
public static final String SUCCESS_METHOD_NAME = "onSuccess";
|
||||
|
||||
@Override protected ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
|
||||
return new ConstructorInterceptPoint[0];
|
||||
}
|
||||
|
||||
@Override protected InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
|
||||
return new InstanceMethodsInterceptPoint[] {
|
||||
new InstanceMethodsInterceptPoint() {
|
||||
@Override public ElementMatcher<MethodDescription> getMethodsMatcher() {
|
||||
return named(SUCCESS_METHOD_NAME);
|
||||
}
|
||||
|
||||
@Override public String getMethodsInterceptor() {
|
||||
return SUCCESS_CALLBACK_INTERCEPTOR;
|
||||
}
|
||||
|
||||
@Override public boolean isOverrideArgs() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override protected ClassMatch enhanceClass() {
|
||||
return successCallbackMatch();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,77 @@
|
|||
package org.skywalking.apm.plugin.spring.concurrent.match;
|
||||
|
||||
import net.bytebuddy.description.type.TypeDescription;
|
||||
import net.bytebuddy.matcher.ElementMatcher;
|
||||
import org.skywalking.apm.agent.core.plugin.match.IndirectMatch;
|
||||
|
||||
import static net.bytebuddy.matcher.ElementMatchers.hasSuperType;
|
||||
import static net.bytebuddy.matcher.ElementMatchers.nameStartsWith;
|
||||
import static net.bytebuddy.matcher.ElementMatchers.named;
|
||||
import static net.bytebuddy.matcher.ElementMatchers.not;
|
||||
|
||||
/**
|
||||
* {@link EitherInterfaceMatch} match the class inherited {@link #getMatchInterface() } and not inherited {@link
|
||||
* #getMutexInterface()}
|
||||
*
|
||||
* @author zhangxin
|
||||
*/
|
||||
public abstract class EitherInterfaceMatch implements IndirectMatch {
|
||||
|
||||
private static final String SPRING_PACKAGE_PREFIX = "org.springframework";
|
||||
private static final String OBJECT_CLASS_NAME = "java.lang.Object";
|
||||
|
||||
protected EitherInterfaceMatch() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public ElementMatcher.Junction buildJunction() {
|
||||
return not(nameStartsWith(SPRING_PACKAGE_PREFIX)).
|
||||
and(hasSuperType(named(getMatchInterface())))
|
||||
.and(not(hasSuperType(named(getMutexInterface()))));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isMatch(TypeDescription typeDescription) {
|
||||
MatchResult matchResult = new MatchResult();
|
||||
for (TypeDescription.Generic generic : typeDescription.getInterfaces()) {
|
||||
matchHierarchyClazz(generic, matchResult);
|
||||
}
|
||||
|
||||
matchHierarchyClazz(typeDescription.getSuperClass(), matchResult);
|
||||
return matchResult.result();
|
||||
}
|
||||
|
||||
public abstract String getMatchInterface();
|
||||
|
||||
public abstract String getMutexInterface();
|
||||
|
||||
private void matchHierarchyClazz(TypeDescription.Generic clazz, MatchResult matchResult) {
|
||||
if (clazz.asRawType().getTypeName().equals(getMutexInterface())) {
|
||||
matchResult.findMutexInterface = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (clazz.asRawType().getTypeName().equals(getMatchInterface())) {
|
||||
matchResult.findMatchInterface = true;
|
||||
}
|
||||
|
||||
for (TypeDescription.Generic generic : clazz.getInterfaces()) {
|
||||
matchHierarchyClazz(generic, matchResult);
|
||||
}
|
||||
|
||||
TypeDescription.Generic superClazz = clazz.getSuperClass();
|
||||
if (superClazz != null && !clazz.getTypeName().equals(OBJECT_CLASS_NAME)) {
|
||||
matchHierarchyClazz(superClazz, matchResult);
|
||||
}
|
||||
}
|
||||
|
||||
private static class MatchResult {
|
||||
private boolean findMatchInterface = false;
|
||||
private boolean findMutexInterface = false;
|
||||
|
||||
public boolean result() {
|
||||
return findMatchInterface && !findMutexInterface;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
package org.skywalking.apm.plugin.spring.concurrent.match;
|
||||
|
||||
import org.skywalking.apm.agent.core.plugin.match.ClassMatch;
|
||||
|
||||
/**
|
||||
* {@link FailedCallbackMatch} match the class that inherited <code>org.springframework.util.concurrent.FailureCallback</code>
|
||||
* and not inherited <code>org.springframework.util.concurrent.SuccessCallback</code>
|
||||
*
|
||||
* @author zhangxin
|
||||
*/
|
||||
public class FailedCallbackMatch extends EitherInterfaceMatch {
|
||||
|
||||
private static final String MATCH_INTERFACE = "org.springframework.util.concurrent.FailureCallback";
|
||||
private static final String MUTEX_INTERFACE = "org.springframework.util.concurrent.SuccessCallback";
|
||||
|
||||
private FailedCallbackMatch() {
|
||||
|
||||
}
|
||||
|
||||
@Override public String getMatchInterface() {
|
||||
return MATCH_INTERFACE;
|
||||
}
|
||||
|
||||
@Override public String getMutexInterface() {
|
||||
return MUTEX_INTERFACE;
|
||||
}
|
||||
|
||||
public static ClassMatch failedCallbackMatch() {
|
||||
return new FailedCallbackMatch();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,65 @@
|
|||
package org.skywalking.apm.plugin.spring.concurrent.match;
|
||||
|
||||
import net.bytebuddy.description.type.TypeDescription;
|
||||
import net.bytebuddy.matcher.ElementMatcher;
|
||||
import org.skywalking.apm.agent.core.plugin.match.ClassMatch;
|
||||
import org.skywalking.apm.agent.core.plugin.match.IndirectMatch;
|
||||
|
||||
import static net.bytebuddy.matcher.ElementMatchers.hasSuperType;
|
||||
import static net.bytebuddy.matcher.ElementMatchers.nameStartsWith;
|
||||
import static net.bytebuddy.matcher.ElementMatchers.named;
|
||||
import static net.bytebuddy.matcher.ElementMatchers.not;
|
||||
|
||||
/**
|
||||
* {@link ListenableFutureCallbackMatch} match the class that inherited <code>org.springframework.util.concurrent.ListenableFutureCallback</code>.
|
||||
*
|
||||
* @author zhangxin
|
||||
*/
|
||||
public class ListenableFutureCallbackMatch implements IndirectMatch {
|
||||
|
||||
private static final String LISTENABLE_FUTURE_CALLBACK_CLASS_NAME = "org.springframework.util.concurrent.ListenableFutureCallback";
|
||||
|
||||
private ListenableFutureCallbackMatch() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public ElementMatcher.Junction buildJunction() {
|
||||
return not(nameStartsWith("org.springframework")).
|
||||
and(hasSuperType(named(LISTENABLE_FUTURE_CALLBACK_CLASS_NAME)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isMatch(TypeDescription typeDescription) {
|
||||
boolean isMatch = false;
|
||||
for (TypeDescription.Generic generic : typeDescription.getInterfaces()) {
|
||||
isMatch = isMatch || matchExactClass(generic);
|
||||
}
|
||||
|
||||
return isMatch || matchExactClass(typeDescription.getSuperClass());
|
||||
}
|
||||
|
||||
private boolean matchExactClass(TypeDescription.Generic clazz) {
|
||||
if (clazz.asRawType().getTypeName().equals(LISTENABLE_FUTURE_CALLBACK_CLASS_NAME)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
boolean isMatch = false;
|
||||
for (TypeDescription.Generic generic : clazz.getInterfaces()) {
|
||||
isMatch = isMatch || matchExactClass(generic);
|
||||
}
|
||||
|
||||
if (!isMatch) {
|
||||
TypeDescription.Generic superClazz = clazz.getSuperClass();
|
||||
if (superClazz != null && !clazz.getTypeName().equals("java.lang.Object")) {
|
||||
isMatch = isMatch || matchExactClass(superClazz);
|
||||
}
|
||||
}
|
||||
|
||||
return isMatch;
|
||||
}
|
||||
|
||||
public static ClassMatch listenableFutureCallbackMatch() {
|
||||
return new ListenableFutureCallbackMatch();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
package org.skywalking.apm.plugin.spring.concurrent.match;
|
||||
|
||||
import org.skywalking.apm.agent.core.plugin.match.ClassMatch;
|
||||
|
||||
/**
|
||||
* {@link SuccessCallbackMatch} match the class that inherited <code>org.springframework.util.concurrent.SuccessCallback</code>
|
||||
* and not inherited <code>org.springframework.util.concurrent.FailureCallback</code>
|
||||
*
|
||||
* @author zhangxin
|
||||
*/
|
||||
public class SuccessCallbackMatch extends EitherInterfaceMatch {
|
||||
|
||||
private static final String MATCH_INTERFACE = "org.springframework.util.concurrent.SuccessCallback";
|
||||
private static final String MUTEX_INTERFACE = "org.springframework.util.concurrent.FailureCallback";
|
||||
|
||||
private SuccessCallbackMatch() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMatchInterface() {
|
||||
return MATCH_INTERFACE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMutexInterface() {
|
||||
return MUTEX_INTERFACE;
|
||||
}
|
||||
|
||||
public static ClassMatch successCallbackMatch() {
|
||||
return new SuccessCallbackMatch();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
spring-concurrent-util-4.x=org.skywalking.apm.plugin.spring.concurrent.define.FailureCallbackInstrumentation
|
||||
spring-concurrent-util-4.x=org.skywalking.apm.plugin.spring.concurrent.define.SuccessCallbackInstrumentation
|
||||
spring-concurrent-util-4.x=org.skywalking.apm.plugin.spring.concurrent.define.ListenableFutureCallbackInstrumentation
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
<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>spring-plugins</artifactId>
|
||||
<groupId>org.skywalking</groupId>
|
||||
<version>3.2-2017</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>apm-springmvc-annotation-4.x-plugin</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>mvc-annotation-4.x-plugin</name>
|
||||
<url>http://maven.apache.org</url>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-core</artifactId>
|
||||
<version>4.3.10.RELEASE</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-webmvc</artifactId>
|
||||
<version>4.3.8.RELEASE</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.servlet</groupId>
|
||||
<artifactId>javax.servlet-api</artifactId>
|
||||
<version>4.0.0-b01</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
package org.skywalking.apm.plugin.spring.mvc;
|
||||
|
||||
import org.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
|
||||
import org.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceConstructorInterceptor;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
|
||||
/**
|
||||
* The <code>ControllerConstructorInterceptor</code> intercepts the Controller's constructor, in order to acquire the
|
||||
* mapping annotation, if exist.
|
||||
*
|
||||
* But, you can see we only use the first mapping value, <B>Why?</B>
|
||||
*
|
||||
* Right now, we intercept the controller by annotation as you known, so we CAN'T know which uri patten is actually
|
||||
* matched. Even we know, that costs a lot.
|
||||
*
|
||||
* If we want to resolve that, we must intercept the Spring MVC core codes, that is not a good choice for now.
|
||||
*
|
||||
* Comment by @wu-sheng
|
||||
*/
|
||||
public class ControllerConstructorInterceptor implements InstanceConstructorInterceptor {
|
||||
|
||||
@Override
|
||||
public void onConstruct(EnhancedInstance objInst, Object[] allArguments) {
|
||||
String basePath = "";
|
||||
RequestMapping basePathRequestMapping = objInst.getClass().getAnnotation(RequestMapping.class);
|
||||
if (basePathRequestMapping != null) {
|
||||
basePath = basePathRequestMapping.value()[0];
|
||||
}
|
||||
PathMappingCache pathMappingCache = new PathMappingCache(basePath);
|
||||
objInst.setSkyWalkingDynamicField(pathMappingCache);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
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.conf.Config;
|
||||
import org.skywalking.apm.agent.core.context.ContextCarrier;
|
||||
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;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.context.request.RequestContextHolder;
|
||||
import org.springframework.web.context.request.ServletRequestAttributes;
|
||||
|
||||
/**
|
||||
* The <code>ControllerServiceMethodInterceptor</code> only use the first mapping value.
|
||||
*
|
||||
* @See {@link ControllerConstructorInterceptor} to explain why we are doing this.
|
||||
*/
|
||||
public class ControllerServiceMethodInterceptor implements InstanceMethodsAroundInterceptor {
|
||||
@Override
|
||||
public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes,
|
||||
MethodInterceptResult result) throws Throwable {
|
||||
PathMappingCache pathMappingCache = (PathMappingCache)objInst.getSkyWalkingDynamicField();
|
||||
String requestURL = pathMappingCache.findPathMapping(method);
|
||||
if (requestURL == null) {
|
||||
requestURL = method.getAnnotation(RequestMapping.class).value()[0];
|
||||
pathMappingCache.addPathMapping(method, requestURL.toString());
|
||||
}
|
||||
|
||||
HttpServletRequest request = ((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getRequest();
|
||||
String tracingHeaderValue = request.getHeader(Config.Plugin.Propagation.HEADER_NAME);
|
||||
ContextCarrier contextCarrier = new ContextCarrier().deserialize(tracingHeaderValue);
|
||||
AbstractSpan span = ContextManager.createEntrySpan(requestURL, contextCarrier);
|
||||
Tags.URL.set(span, request.getRequestURL().toString());
|
||||
Tags.HTTP.METHOD.set(span, request.getMethod());
|
||||
span.setComponent(ComponentsDefine.SPRING_MVC_ANNOTATION);
|
||||
SpanLayer.asHttp(span);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes,
|
||||
Object ret) throws Throwable {
|
||||
HttpServletResponse response = ((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getResponse();
|
||||
|
||||
AbstractSpan span = ContextManager.activeSpan();
|
||||
if (response.getStatus() >= 400) {
|
||||
span.errorOccurred();
|
||||
Tags.STATUS_CODE.set(span, Integer.toString(response.getStatus()));
|
||||
}
|
||||
ContextManager.stopSpan();
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments,
|
||||
Class<?>[] argumentsTypes, Throwable t) {
|
||||
ContextManager.activeSpan().errorOccurred().log(t);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
package org.skywalking.apm.plugin.spring.mvc;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* The <code>PathMappingCache</code> represents a field
|
||||
*
|
||||
*
|
||||
* @author wusheng
|
||||
*/
|
||||
public class PathMappingCache {
|
||||
private String classPath = "";
|
||||
|
||||
private ConcurrentHashMap<Method, String> methodPathMapping = new ConcurrentHashMap<Method, String>();
|
||||
|
||||
public PathMappingCache(String classPath) {
|
||||
this.classPath = classPath;
|
||||
}
|
||||
|
||||
public String findPathMapping(Method method) {
|
||||
return methodPathMapping.get(method);
|
||||
}
|
||||
|
||||
public void addPathMapping(Method method, String methodPath) {
|
||||
methodPathMapping.put(method, classPath + methodPath);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,76 @@
|
|||
package org.skywalking.apm.plugin.spring.mvc.define;
|
||||
|
||||
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.any;
|
||||
import static net.bytebuddy.matcher.ElementMatchers.isAnnotatedWith;
|
||||
import static net.bytebuddy.matcher.ElementMatchers.named;
|
||||
import static org.skywalking.apm.agent.core.plugin.match.ClassAnnotationMatch.byClassAnnotationMatch;
|
||||
|
||||
/**
|
||||
* {@link ControllerInstrumentation} enhance all constructor and method annotated with
|
||||
* <code>org.springframework.web.bind.annotation.RequestMapping</code> that class has
|
||||
* <code>org.springframework.stereotype.Controller</code> annotation.
|
||||
*
|
||||
* <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
|
||||
* combine the path value of current annotation on current method and the base path and set the new path to the dynamic
|
||||
* filed
|
||||
*
|
||||
* @author zhangxin
|
||||
*/
|
||||
public abstract class AbstractControllerInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
|
||||
@Override
|
||||
protected ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
|
||||
return new ConstructorInterceptPoint[] {
|
||||
new ConstructorInterceptPoint() {
|
||||
@Override
|
||||
public ElementMatcher<MethodDescription> getConstructorMatcher() {
|
||||
return any();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getConstructorInterceptor() {
|
||||
return "org.skywalking.apm.plugin.spring.mvc.ControllerConstructorInterceptor";
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
protected InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
|
||||
return new InstanceMethodsInterceptPoint[] {
|
||||
new InstanceMethodsInterceptPoint() {
|
||||
@Override
|
||||
public ElementMatcher<MethodDescription> getMethodsMatcher() {
|
||||
return isAnnotatedWith(named("org.springframework.web.bind.annotation.RequestMapping"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMethodsInterceptor() {
|
||||
return "org.skywalking.apm.plugin.spring.mvc.ControllerServiceMethodInterceptor";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOverrideArgs() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ClassMatch enhanceClass() {
|
||||
return byClassAnnotationMatch(getEnhanceAnnotations());
|
||||
}
|
||||
|
||||
protected abstract String[] getEnhanceAnnotations();
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
package org.skywalking.apm.plugin.spring.mvc.define;
|
||||
|
||||
public class ControllerInstrumentation extends AbstractControllerInstrumentation {
|
||||
|
||||
public static final String ENHANCE_ANNOTATION = "org.springframework.stereotype.Controller";
|
||||
|
||||
@Override protected String[] getEnhanceAnnotations() {
|
||||
return new String[] {ENHANCE_ANNOTATION};
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
package org.skywalking.apm.plugin.spring.mvc.define;
|
||||
|
||||
public class RestControllerInstrumentation extends AbstractControllerInstrumentation {
|
||||
|
||||
public static final String ENHANCE_ANNOTATION = "org.springframework.web.bind.annotation.RestController";
|
||||
|
||||
@Override protected String[] getEnhanceAnnotations() {
|
||||
return new String[] {ENHANCE_ANNOTATION};
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
spring-mvc-annotation-4.x=org.skywalking.apm.plugin.spring.mvc.define.ControllerInstrumentation
|
||||
spring-mvc-annotation-4.x=org.skywalking.apm.plugin.spring.mvc.define.RestControllerInstrumentation
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
<?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">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>org.skywalking</groupId>
|
||||
<artifactId>apm-sdk-plugin</artifactId>
|
||||
<version>3.2-2017</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>spring-plugins</artifactId>
|
||||
<modules>
|
||||
<module>concurrent-util-4.x-plugin</module>
|
||||
<module>resttemplate-4.x-plugin</module>
|
||||
<module>mvc-annotation-4.x-plugin</module>
|
||||
</modules>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<name>apm-sdk-plugin</name>
|
||||
<url>http://maven.apache.org</url>
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
|
||||
</project>
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
<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>spring-plugins</artifactId>
|
||||
<groupId>org.skywalking</groupId>
|
||||
<version>3.2-2017</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>apm-resttemplate-4.3.x-plugin</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>resttemplate-4.3.x-plugin</name>
|
||||
<url>http://maven.apache.org</url>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-web</artifactId>
|
||||
<version>4.3.10.RELEASE</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
package org.skywalking.apm.plugin.spring.resttemplate.async;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.URI;
|
||||
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.EnhancedInstance;
|
||||
import org.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
|
||||
import org.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
|
||||
|
||||
public class FutureGetInterceptor implements InstanceMethodsAroundInterceptor {
|
||||
|
||||
@Override
|
||||
public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes,
|
||||
MethodInterceptResult result) throws Throwable {
|
||||
Object[] cacheValues = (Object[])objInst.getSkyWalkingDynamicField();
|
||||
ContextManager.createLocalSpan("future/get:" + ((URI)cacheValues[0]).getPath());
|
||||
}
|
||||
|
||||
@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 activeSpan = ContextManager.activeSpan();
|
||||
activeSpan.errorOccurred().log(t);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
package org.skywalking.apm.plugin.spring.resttemplate.async;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
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;
|
||||
|
||||
public class ResponseCallBackInterceptor implements InstanceMethodsAroundInterceptor {
|
||||
|
||||
@Override
|
||||
public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes,
|
||||
MethodInterceptResult result) throws Throwable {
|
||||
EnhancedInstance successCallBak = (EnhancedInstance)allArguments[0];
|
||||
successCallBak.setSkyWalkingDynamicField(objInst.getSkyWalkingDynamicField());
|
||||
|
||||
if (allArguments.length == 2) {
|
||||
EnhancedInstance failedCallBack = (EnhancedInstance)allArguments[1];
|
||||
failedCallBack.setSkyWalkingDynamicField(objInst.getSkyWalkingDynamicField());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes,
|
||||
Object ret) throws Throwable {
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments,
|
||||
Class<?>[] argumentsTypes, Throwable t) {
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
package org.skywalking.apm.plugin.spring.resttemplate.async;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.URI;
|
||||
import org.skywalking.apm.agent.core.context.ContextCarrier;
|
||||
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;
|
||||
import org.springframework.http.HttpMethod;
|
||||
|
||||
public class RestExecuteInterceptor implements InstanceMethodsAroundInterceptor {
|
||||
|
||||
@Override
|
||||
public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes,
|
||||
MethodInterceptResult result) throws Throwable {
|
||||
final URI requestURL = (URI)allArguments[0];
|
||||
final HttpMethod httpMethod = (HttpMethod)allArguments[1];
|
||||
final ContextCarrier contextCarrier = new ContextCarrier();
|
||||
String remotePeer = requestURL.getHost() + ":" + requestURL.getPort();
|
||||
AbstractSpan span = ContextManager.createExitSpan(requestURL.getPath(), contextCarrier, remotePeer);
|
||||
|
||||
span.setComponent(ComponentsDefine.SPRING_REST_TEMPLATE);
|
||||
Tags.URL.set(span, requestURL.getScheme() + "://" + requestURL.getHost() + ":" + requestURL.getPort() + requestURL.getPath());
|
||||
Tags.HTTP.METHOD.set(span, httpMethod.toString());
|
||||
SpanLayer.asHttp(span);
|
||||
Object[] cacheValues = new Object[3];
|
||||
cacheValues[0] = requestURL;
|
||||
cacheValues[1] = contextCarrier.serialize();
|
||||
objInst.setSkyWalkingDynamicField(cacheValues);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes,
|
||||
Object ret) throws Throwable {
|
||||
Object[] cacheValues = (Object[])objInst.getSkyWalkingDynamicField();
|
||||
cacheValues[2] = ContextManager.capture();
|
||||
if (ret != null) {
|
||||
((EnhancedInstance)ret).setSkyWalkingDynamicField(cacheValues);
|
||||
}
|
||||
ContextManager.stopSpan();
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments,
|
||||
Class<?>[] argumentsTypes, Throwable t) {
|
||||
ContextManager.activeSpan().errorOccurred().log(t);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,77 @@
|
|||
package org.skywalking.apm.plugin.spring.resttemplate.async.define;
|
||||
|
||||
import java.net.URI;
|
||||
import net.bytebuddy.description.method.MethodDescription;
|
||||
import net.bytebuddy.matcher.ElementMatcher;
|
||||
import org.skywalking.apm.agent.core.context.ContextSnapshot;
|
||||
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 org.skywalking.apm.plugin.spring.resttemplate.async.ResponseCallBackInterceptor;
|
||||
|
||||
import static net.bytebuddy.matcher.ElementMatchers.named;
|
||||
import static org.skywalking.apm.agent.core.plugin.match.NameMatch.byName;
|
||||
|
||||
/**
|
||||
* {@link ResponseExtractorFutureInstrumentation} enhance the <code>addCallback</code> method and <code>get</code> method of
|
||||
* <code>org.springframework.web.client.AsyncRestTemplate$ResponseExtractorFuture</code> by
|
||||
* <code>org.skywalking.apm.plugin.spring.resttemplate.async.ResponseCallBackInterceptor</code> and
|
||||
* <code>org.skywalking.apm.plugin.spring.resttemplate.async.FutureGetInterceptor</code>.
|
||||
*
|
||||
* {@link ResponseCallBackInterceptor} set the {@link URI} and {@link ContextSnapshot} to inherited
|
||||
* <code>org.springframework.util.concurrent.SuccessCallback</code> and <code>org.springframework.util.concurrent.FailureCallback</code>
|
||||
*
|
||||
* @author zhangxin
|
||||
*/
|
||||
public class ResponseExtractorFutureInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
|
||||
|
||||
private static final String ADD_CALLBACK_METHOD_NAME = "addCallback";
|
||||
private static final String ADD_CALLBACK_INTERCEPTOR = "org.skywalking.apm.plugin.spring.resttemplate.async.ResponseCallBackInterceptor";
|
||||
private static final String ENHANCE_CLASS = "org.springframework.web.client.AsyncRestTemplate$ResponseExtractorFuture";
|
||||
private static final String GET_METHOD_INTERCEPTOR = "org.skywalking.apm.plugin.spring.resttemplate.async.FutureGetInterceptor";
|
||||
private static final String GET_METHOD_NAME = "get";
|
||||
|
||||
@Override
|
||||
protected ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
|
||||
return new ConstructorInterceptPoint[0];
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
|
||||
return new InstanceMethodsInterceptPoint[] {
|
||||
new InstanceMethodsInterceptPoint() {
|
||||
@Override public ElementMatcher<MethodDescription> getMethodsMatcher() {
|
||||
return named(ADD_CALLBACK_METHOD_NAME);
|
||||
}
|
||||
|
||||
@Override public String getMethodsInterceptor() {
|
||||
return ADD_CALLBACK_INTERCEPTOR;
|
||||
}
|
||||
|
||||
@Override public boolean isOverrideArgs() {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
new InstanceMethodsInterceptPoint() {
|
||||
@Override public ElementMatcher<MethodDescription> getMethodsMatcher() {
|
||||
return named(GET_METHOD_NAME);
|
||||
}
|
||||
|
||||
@Override public String getMethodsInterceptor() {
|
||||
return GET_METHOD_INTERCEPTOR;
|
||||
}
|
||||
|
||||
@Override public boolean isOverrideArgs() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ClassMatch enhanceClass() {
|
||||
return byName(ENHANCE_CLASS);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,75 @@
|
|||
package org.skywalking.apm.plugin.spring.resttemplate.async.define;
|
||||
|
||||
import java.net.URI;
|
||||
import net.bytebuddy.description.method.MethodDescription;
|
||||
import net.bytebuddy.matcher.ElementMatcher;
|
||||
import org.skywalking.apm.agent.core.context.ContextSnapshot;
|
||||
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.named;
|
||||
import static org.skywalking.apm.agent.core.plugin.match.NameMatch.byName;
|
||||
|
||||
/**
|
||||
* {@link RestTemplateInstrumentation} enhance the <code>doExecute</code> method and <code>createAsyncRequest</code>
|
||||
* method of <code>org.springframework.web.client.AsyncRestTemplate</code> by <code>org.skywalking.apm.plugin.spring.resttemplate.async.RestExecuteInterceptor</code>
|
||||
* and <code>org.springframework.http.client.RestRequestInterceptor</code>.
|
||||
*
|
||||
* <code>org.springframework.http.client.RestRequestInterceptor</code> set {@link URI} and {@link ContextSnapshot} to
|
||||
* <code>org.springframework.web.client.AsyncRestTemplate$ResponseExtractorFuture</code> for propagate trace context
|
||||
* after execute <code>doExecute</code> .
|
||||
*
|
||||
* @author zhangxin
|
||||
*/
|
||||
public class RestTemplateInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
|
||||
|
||||
private static final String ENHANCE_CLASS = "org.springframework.web.client.AsyncRestTemplate";
|
||||
private static final String DO_EXECUTE_METHOD_NAME = "doExecute";
|
||||
private static final String DO_EXECUTE_INTERCEPTOR = "org.skywalking.apm.plugin.spring.resttemplate.async.RestExecuteInterceptor";
|
||||
private static final String CREATE_REQUEST_METHOD_NAME = "createAsyncRequest";
|
||||
private static final String CREATE_REQUEST_INTERCEPTOR = "org.springframework.http.client.RestRequestInterceptor";
|
||||
|
||||
@Override
|
||||
protected ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
|
||||
return new ConstructorInterceptPoint[0];
|
||||
}
|
||||
|
||||
@Override
|
||||
protected InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
|
||||
return new InstanceMethodsInterceptPoint[] {
|
||||
new InstanceMethodsInterceptPoint() {
|
||||
@Override public ElementMatcher<MethodDescription> getMethodsMatcher() {
|
||||
return named(DO_EXECUTE_METHOD_NAME);
|
||||
}
|
||||
|
||||
@Override public String getMethodsInterceptor() {
|
||||
return DO_EXECUTE_INTERCEPTOR;
|
||||
}
|
||||
|
||||
@Override public boolean isOverrideArgs() {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
new InstanceMethodsInterceptPoint() {
|
||||
@Override public ElementMatcher<MethodDescription> getMethodsMatcher() {
|
||||
return named(CREATE_REQUEST_METHOD_NAME);
|
||||
}
|
||||
|
||||
@Override public String getMethodsInterceptor() {
|
||||
return CREATE_REQUEST_INTERCEPTOR;
|
||||
}
|
||||
|
||||
@Override public boolean isOverrideArgs() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ClassMatch enhanceClass() {
|
||||
return byName(ENHANCE_CLASS);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
package org.skywalking.apm.plugin.spring.resttemplate.sync;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.URI;
|
||||
import org.skywalking.apm.agent.core.context.ContextCarrier;
|
||||
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;
|
||||
import org.springframework.http.HttpMethod;
|
||||
|
||||
public class RestExecuteInterceptor implements InstanceMethodsAroundInterceptor {
|
||||
|
||||
@Override
|
||||
public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes,
|
||||
MethodInterceptResult result) throws Throwable {
|
||||
final URI requestURL = (URI)allArguments[0];
|
||||
final HttpMethod httpMethod = (HttpMethod)allArguments[1];
|
||||
final ContextCarrier contextCarrier = new ContextCarrier();
|
||||
String remotePeer = requestURL.getHost() + ":" + requestURL.getPort();
|
||||
AbstractSpan span = ContextManager.createExitSpan(requestURL.getPath(), contextCarrier, remotePeer);
|
||||
|
||||
span.setComponent(ComponentsDefine.SPRING_REST_TEMPLATE);
|
||||
Tags.URL.set(span, requestURL.getScheme() + "://" + requestURL.getHost() + ":" + requestURL.getPort() + requestURL.getPath());
|
||||
Tags.HTTP.METHOD.set(span, httpMethod.toString());
|
||||
SpanLayer.asHttp(span);
|
||||
|
||||
objInst.setSkyWalkingDynamicField(contextCarrier.serialize());
|
||||
}
|
||||
|
||||
@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);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
package org.skywalking.apm.plugin.spring.resttemplate.sync;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import org.skywalking.apm.agent.core.conf.Config;
|
||||
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.springframework.http.client.AbstractClientHttpRequest;
|
||||
import org.springframework.http.client.ClientHttpRequest;
|
||||
|
||||
public class RestRequestInterceptor implements InstanceMethodsAroundInterceptor {
|
||||
|
||||
@Override
|
||||
public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes,
|
||||
MethodInterceptResult result) throws Throwable {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes,
|
||||
Object ret) throws Throwable {
|
||||
ClientHttpRequest clientHttpRequest = (ClientHttpRequest)ret;
|
||||
if (clientHttpRequest instanceof AbstractClientHttpRequest) {
|
||||
AbstractClientHttpRequest httpRequest = (AbstractClientHttpRequest)clientHttpRequest;
|
||||
httpRequest.getHeaders().set(Config.Plugin.Propagation.HEADER_NAME, String.valueOf(objInst.getSkyWalkingDynamicField()));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments,
|
||||
Class<?>[] argumentsTypes, Throwable t) {
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
package org.skywalking.apm.plugin.spring.resttemplate.sync;
|
||||
|
||||
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.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.springframework.http.client.ClientHttpResponse;
|
||||
|
||||
public class RestResponseInterceptor implements InstanceMethodsAroundInterceptor {
|
||||
|
||||
@Override
|
||||
public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes,
|
||||
MethodInterceptResult result) throws Throwable {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes,
|
||||
Object ret) throws Throwable {
|
||||
|
||||
ClientHttpResponse response = (ClientHttpResponse)allArguments[2];
|
||||
int statusCode = response.getStatusCode().value();
|
||||
AbstractSpan span = ContextManager.activeSpan();
|
||||
if (statusCode >= 400) {
|
||||
span.errorOccurred();
|
||||
Tags.STATUS_CODE.set(span, Integer.toString(statusCode));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments,
|
||||
Class<?>[] argumentsTypes, Throwable t) {
|
||||
ContextManager.activeSpan().errorOccurred().log(t);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,89 @@
|
|||
package org.skywalking.apm.plugin.spring.resttemplate.sync.define;
|
||||
|
||||
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.named;
|
||||
import static org.skywalking.apm.agent.core.plugin.match.NameMatch.byName;
|
||||
|
||||
/**
|
||||
* {@link RestTemplateInstrumentation} enhance the <code>doExecute</code> method,<code>handleResponse</code> method and
|
||||
* <code>handleResponse</code> method of <code>org.springframework.web.client.RestTemplate</code> by
|
||||
* <code>org.skywalking.apm.plugin.spring.resttemplate.sync.RestExecuteInterceptor</code>,
|
||||
* <code>org.skywalking.apm.plugin.spring.resttemplate.sync.RestResponseInterceptor</code> and
|
||||
* <code>org.skywalking.apm.plugin.spring.resttemplate.sync.RestRequestInterceptor</code>.
|
||||
*
|
||||
* <code>org.skywalking.apm.plugin.spring.resttemplate.sync.RestResponseInterceptor</code> set context to header for
|
||||
* propagate trace context after execute <code>createRequest</code>.
|
||||
*
|
||||
* @author zhangxin
|
||||
*/
|
||||
public class RestTemplateInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
|
||||
|
||||
private static final String ENHANCE_CLASS = "org.springframework.web.client.RestTemplate";
|
||||
private static final String DO_EXECUTE_METHOD_NAME = "doExecute";
|
||||
private static final String DO_EXECUTE_INTERCEPTOR = "org.skywalking.apm.plugin.spring.resttemplate.sync.RestExecuteInterceptor";
|
||||
private static final String HANDLE_REQUEST_METHOD_NAME = "handleResponse";
|
||||
private static final String HAND_REQUEST_INTERCEPTOR = "org.skywalking.apm.plugin.spring.resttemplate.sync.RestResponseInterceptor";
|
||||
private static final String CREATE_REQUEST_METHOD_NAME = "createRequest";
|
||||
private static final String CREATE_REQUEST_INTERCEPTOR = "org.skywalking.apm.plugin.spring.resttemplate.sync.RestRequestInterceptor";
|
||||
|
||||
@Override
|
||||
protected ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
|
||||
return new ConstructorInterceptPoint[0];
|
||||
}
|
||||
|
||||
@Override
|
||||
protected InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
|
||||
return new InstanceMethodsInterceptPoint[] {
|
||||
new InstanceMethodsInterceptPoint() {
|
||||
@Override public ElementMatcher<MethodDescription> getMethodsMatcher() {
|
||||
return named(DO_EXECUTE_METHOD_NAME);
|
||||
}
|
||||
|
||||
@Override public String getMethodsInterceptor() {
|
||||
return DO_EXECUTE_INTERCEPTOR;
|
||||
}
|
||||
|
||||
@Override public boolean isOverrideArgs() {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
new InstanceMethodsInterceptPoint() {
|
||||
@Override public ElementMatcher<MethodDescription> getMethodsMatcher() {
|
||||
return named(HANDLE_REQUEST_METHOD_NAME);
|
||||
}
|
||||
|
||||
@Override public String getMethodsInterceptor() {
|
||||
return HAND_REQUEST_INTERCEPTOR;
|
||||
}
|
||||
|
||||
@Override public boolean isOverrideArgs() {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
new InstanceMethodsInterceptPoint() {
|
||||
@Override public ElementMatcher<MethodDescription> getMethodsMatcher() {
|
||||
return named(CREATE_REQUEST_METHOD_NAME);
|
||||
}
|
||||
|
||||
@Override public String getMethodsInterceptor() {
|
||||
return CREATE_REQUEST_INTERCEPTOR;
|
||||
}
|
||||
|
||||
@Override public boolean isOverrideArgs() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ClassMatch enhanceClass() {
|
||||
return byName(ENHANCE_CLASS);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
package org.springframework.http.client;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import org.skywalking.apm.agent.core.conf.Config;
|
||||
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;
|
||||
|
||||
public class RestRequestInterceptor implements InstanceMethodsAroundInterceptor {
|
||||
|
||||
@Override
|
||||
public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes,
|
||||
MethodInterceptResult result) throws Throwable {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes,
|
||||
Object ret) throws Throwable {
|
||||
AbstractAsyncClientHttpRequest clientHttpRequest = (AbstractAsyncClientHttpRequest)ret;
|
||||
if (ret != null) {
|
||||
clientHttpRequest.getHeaders().set(Config.Plugin.Propagation.HEADER_NAME, String.valueOf(((Object[])objInst.getSkyWalkingDynamicField())[1]));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments,
|
||||
Class<?>[] argumentsTypes, Throwable t) {
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
spring-resttemplate-4.x=org.skywalking.apm.plugin.spring.resttemplate.async.define.RestTemplateInstrumentation
|
||||
spring-resttemplate-4.x=org.skywalking.apm.plugin.spring.resttemplate.async.define.ResponseExtractorFutureInstrumentation
|
||||
spring-resttemplate-4.x=org.skywalking.apm.plugin.spring.resttemplate.sync.define.RestTemplateInstrumentation
|
||||
|
|
@ -16,4 +16,12 @@ public class FieldGetter {
|
|||
field.setAccessible(true);
|
||||
return (T)field.get(instance);
|
||||
}
|
||||
|
||||
|
||||
public static <T> T get2LevelParentFieldValue(Object instance,
|
||||
String fieldName) throws IllegalAccessException, NoSuchFieldException {
|
||||
Field field = instance.getClass().getSuperclass().getSuperclass().getDeclaredField(fieldName);
|
||||
field.setAccessible(true);
|
||||
return (T)field.get(instance);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,8 +10,13 @@ import org.skywalking.apm.agent.core.context.util.KeyValuePair;
|
|||
public class SpanHelper {
|
||||
public static int getParentSpanId(AbstractSpan tracingSpan) {
|
||||
try {
|
||||
return FieldGetter.getParentFieldValue(tracingSpan, "parentSpanId");
|
||||
return FieldGetter.get2LevelParentFieldValue(tracingSpan, "parentSpanId");
|
||||
} catch (Exception e) {
|
||||
try {
|
||||
return FieldGetter.getParentFieldValue(tracingSpan, "parentSpanId");
|
||||
} catch (Exception e1) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return -9999;
|
||||
|
|
@ -19,8 +24,13 @@ public class SpanHelper {
|
|||
|
||||
public static List<LogDataEntity> getLogs(AbstractSpan tracingSpan) {
|
||||
try {
|
||||
return FieldGetter.getParentFieldValue(tracingSpan, "logs");
|
||||
return FieldGetter.get2LevelParentFieldValue(tracingSpan, "logs");
|
||||
} catch (Exception e) {
|
||||
try {
|
||||
return FieldGetter.getParentFieldValue(tracingSpan, "logs");
|
||||
} catch (Exception e1) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return Collections.emptyList();
|
||||
|
|
@ -28,8 +38,13 @@ public class SpanHelper {
|
|||
|
||||
public static List<KeyValuePair> getTags(AbstractSpan tracingSpan) {
|
||||
try {
|
||||
return FieldGetter.getParentFieldValue(tracingSpan, "tags");
|
||||
return FieldGetter.get2LevelParentFieldValue(tracingSpan, "tags");
|
||||
} catch (Exception e) {
|
||||
try {
|
||||
return FieldGetter.getParentFieldValue(tracingSpan, "tags");
|
||||
} catch (Exception e1) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return Collections.emptyList();
|
||||
|
|
@ -37,8 +52,13 @@ public class SpanHelper {
|
|||
|
||||
public static SpanLayer getLayer(AbstractSpan tracingSpan) {
|
||||
try {
|
||||
return FieldGetter.getParentFieldValue(tracingSpan, "layer");
|
||||
return FieldGetter.get2LevelParentFieldValue(tracingSpan, "layer");
|
||||
} catch (Exception e) {
|
||||
try {
|
||||
return FieldGetter.getParentFieldValue(tracingSpan, "layer");
|
||||
} catch (Exception e1) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
|
|
@ -46,8 +66,13 @@ public class SpanHelper {
|
|||
|
||||
public static String getComponentName(AbstractSpan tracingSpan) {
|
||||
try {
|
||||
return FieldGetter.getParentFieldValue(tracingSpan, "componentName");
|
||||
return FieldGetter.get2LevelParentFieldValue(tracingSpan, "componentName");
|
||||
} catch (Exception e) {
|
||||
try {
|
||||
return FieldGetter.getParentFieldValue(tracingSpan, "componentName");
|
||||
} catch (Exception e1) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
|
|
@ -55,8 +80,13 @@ public class SpanHelper {
|
|||
|
||||
public static int getComponentId(AbstractSpan tracingSpan) {
|
||||
try {
|
||||
return FieldGetter.getParentFieldValue(tracingSpan, "componentId");
|
||||
return FieldGetter.get2LevelParentFieldValue(tracingSpan, "componentId");
|
||||
} catch (Exception e) {
|
||||
try {
|
||||
return FieldGetter.getParentFieldValue(tracingSpan, "componentId");
|
||||
} catch (Exception e1) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
|
|
@ -64,8 +94,13 @@ public class SpanHelper {
|
|||
|
||||
public static boolean getErrorOccurred(AbstractSpan tracingSpan) {
|
||||
try {
|
||||
return FieldGetter.getParentFieldValue(tracingSpan, "errorOccurred");
|
||||
return FieldGetter.get2LevelParentFieldValue(tracingSpan, "errorOccurred");
|
||||
} catch (Exception e) {
|
||||
try {
|
||||
return FieldGetter.getParentFieldValue(tracingSpan, "errorOccurred");
|
||||
} catch (Exception e1) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
|
|
|
|||
Loading…
Reference in New Issue