Merge branch 'feature/collector' of https://github.com/wu-sheng/sky-walking into feature/collector
# Conflicts: # skywalking-collector/skywalking-collector-cluster/src/main/java/com/a/eye/skywalking/collector/actor/AbstractWorker.java
This commit is contained in:
commit
b6388251af
|
|
@ -43,8 +43,8 @@ public abstract class AbstractWorker<T> extends UntypedActor {
|
|||
}
|
||||
|
||||
public void tell(AbstractWorkerProvider targetWorkerProvider, WorkerSelector selector, T message) throws Throwable {
|
||||
List<WorkerRef> avaibleWorks = WorkersRefCenter.INSTANCE.availableWorks(targetWorkerProvider.roleName());
|
||||
selector.select(avaibleWorks, message).tell(message, getSelf());
|
||||
List<WorkerRef> availableWorks = WorkersRefCenter.INSTANCE.availableWorks(targetWorkerProvider.roleName());
|
||||
selector.select(availableWorks, message).tell(message, getSelf());
|
||||
}
|
||||
|
||||
void register(Member member) {
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@
|
|||
</goals>
|
||||
<configuration>
|
||||
<sources>
|
||||
<source>src/java/generated-source/protobuf/java</source>
|
||||
<source>${basedir}/target/generated-sources/protobuf/java</source>
|
||||
</sources>
|
||||
</configuration>
|
||||
</execution>
|
||||
|
|
@ -79,6 +79,8 @@
|
|||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
|
||||
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
|
|
|
|||
|
|
@ -48,22 +48,18 @@ public final class Tags {
|
|||
public static final class SPAN_LAYER {
|
||||
private static StringTag SPAN_LAYER_TAG = new StringTag("span.layer");
|
||||
|
||||
private static final String RDB_LAYER = "rdb";
|
||||
private static final String DB_LAYER = "db";
|
||||
private static final String RPC_FRAMEWORK_LAYER = "rpc";
|
||||
private static final String NOSQL_LAYER = "nosql";
|
||||
private static final String HTTP_LAYER = "http";
|
||||
|
||||
public static void asRDB(Span span) {
|
||||
SPAN_LAYER_TAG.set(span, RDB_LAYER);
|
||||
public static void asDB(Span span) {
|
||||
SPAN_LAYER_TAG.set(span, DB_LAYER);
|
||||
}
|
||||
|
||||
public static void asRPCFramework(Span span) {
|
||||
SPAN_LAYER_TAG.set(span, RPC_FRAMEWORK_LAYER);
|
||||
}
|
||||
|
||||
public static void asNoSQL(Span span) {
|
||||
SPAN_LAYER_TAG.set(span, NOSQL_LAYER);
|
||||
}
|
||||
|
||||
public static void asHttp(Span span) {
|
||||
SPAN_LAYER_TAG.set(span, HTTP_LAYER);
|
||||
|
|
@ -73,18 +69,14 @@ public final class Tags {
|
|||
return SPAN_LAYER_TAG.get(span);
|
||||
}
|
||||
|
||||
public static boolean isRDB(Span span) {
|
||||
return RDB_LAYER.equals(get(span));
|
||||
public static boolean isDB(Span span) {
|
||||
return DB_LAYER.equals(get(span));
|
||||
}
|
||||
|
||||
public static boolean isRPCFramework(Span span) {
|
||||
return RPC_FRAMEWORK_LAYER.equals(get(span));
|
||||
}
|
||||
|
||||
public static boolean isNoSQL(Span span) {
|
||||
return NOSQL_LAYER.equals(get(span));
|
||||
}
|
||||
|
||||
public static boolean isHttp(Span span) {
|
||||
return HTTP_LAYER.equals(get(span));
|
||||
}
|
||||
|
|
@ -107,9 +99,24 @@ public final class Tags {
|
|||
public static final StringTag PEER_HOST = new StringTag("peer.host");
|
||||
|
||||
/**
|
||||
* DB_URL records the url of the database access.
|
||||
* PEER_PORT records remote port of the peer
|
||||
*/
|
||||
public static final StringTag DB_URL = new StringTag("db.url");
|
||||
public static final IntTag PEER_PORT = new IntTag("peer.port");
|
||||
|
||||
/**
|
||||
* PEERS records multiple host address and port of remote
|
||||
*/
|
||||
public static final StringTag PEERS = new StringTag("peers");
|
||||
|
||||
/**
|
||||
* DB_TYPE records database type, such as sql, redis, cassandra and so on.
|
||||
*/
|
||||
public static final StringTag DB_TYPE = new StringTag("db.type");
|
||||
|
||||
/**
|
||||
* DB_INSTANCE records database instance name.
|
||||
*/
|
||||
public static final StringTag DB_INSTANCE = new StringTag("db.instance");
|
||||
|
||||
/**
|
||||
* DB_STATEMENT records the sql statement of the database access.
|
||||
|
|
|
|||
|
|
@ -45,11 +45,10 @@ public class SpanTestCase {
|
|||
Tags.ERROR.set(span1, true);
|
||||
Tags.STATUS_CODE.set(span1, 302);
|
||||
Tags.URL.set(span1, "http://127.0.0.1/serviceA");
|
||||
Tags.DB_URL.set(span1, "jdbc:127.0.0.1:user");
|
||||
Tags.DB_STATEMENT.set(span1, "select * from users");
|
||||
|
||||
Map<String, Object> tags = span1.getTags();
|
||||
Assert.assertEquals(8, tags.size());
|
||||
Assert.assertEquals(7, tags.size());
|
||||
Assert.assertTrue(Tags.SPAN_LAYER.isHttp(span1));
|
||||
Assert.assertEquals("127.0.0.1", Tags.PEER_HOST.get(span1));
|
||||
Assert.assertTrue(Tags.ERROR.get(span1));
|
||||
|
|
|
|||
|
|
@ -96,7 +96,7 @@ public class TraceSegmentTestCase {
|
|||
segment.archive(span1);
|
||||
|
||||
Span span2 = new Span(2, span1, "/db/sql");
|
||||
Tags.SPAN_LAYER.asNoSQL(span2);
|
||||
Tags.SPAN_LAYER.asDB(span2);
|
||||
span2.log(new NullPointerException());
|
||||
segment.archive(span2);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,15 +1,16 @@
|
|||
package com.a.eye.skywalking.agent;
|
||||
|
||||
import com.a.eye.skywalking.agent.junction.SkyWalkingEnhanceMatcher;
|
||||
import com.a.eye.skywalking.conf.Config;
|
||||
import com.a.eye.skywalking.api.conf.Config;
|
||||
import com.a.eye.skywalking.api.conf.SnifferConfigInitializer;
|
||||
import com.a.eye.skywalking.logging.EasyLogResolver;
|
||||
import com.a.eye.skywalking.api.logging.EasyLogResolver;
|
||||
import com.a.eye.skywalking.api.logging.api.ILog;
|
||||
import com.a.eye.skywalking.api.logging.api.LogManager;
|
||||
import com.a.eye.skywalking.api.plugin.AbstractClassEnhancePluginDefine;
|
||||
import com.a.eye.skywalking.api.plugin.PluginBootstrap;
|
||||
import com.a.eye.skywalking.api.plugin.PluginDefineCategory;
|
||||
import com.a.eye.skywalking.plugin.PluginException;
|
||||
import com.a.eye.skywalking.api.plugin.PluginException;
|
||||
|
||||
import net.bytebuddy.agent.builder.AgentBuilder;
|
||||
import net.bytebuddy.description.NamedElement;
|
||||
import net.bytebuddy.description.type.TypeDescription;
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@
|
|||
<dependency>
|
||||
<groupId>com.a.eye</groupId>
|
||||
<artifactId>skywalking-trace</artifactId>
|
||||
<version>3.0-2017</version>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.lmax</groupId>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package com.a.eye.skywalking.api.plugin.interceptor;
|
||||
|
||||
|
||||
import com.a.eye.skywalking.api.plugin.PluginException;
|
||||
|
||||
public class EnhanceException extends PluginException {
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import com.a.eye.skywalking.api.plugin.interceptor.EnhancedClassInstanceContext;
|
|||
import com.a.eye.skywalking.api.plugin.interceptor.InstanceMethodsInterceptPoint;
|
||||
import com.a.eye.skywalking.api.plugin.interceptor.StaticMethodsInterceptPoint;
|
||||
import com.a.eye.skywalking.api.util.StringUtil;
|
||||
|
||||
import net.bytebuddy.description.method.MethodDescription;
|
||||
import net.bytebuddy.dynamic.DynamicType;
|
||||
import net.bytebuddy.implementation.MethodDelegation;
|
||||
|
|
@ -25,7 +26,7 @@ import static net.bytebuddy.matcher.ElementMatchers.not;
|
|||
* This class controls all enhance operations, including enhance constructors, instance methods and static methods.
|
||||
* All the enhances base on three types interceptor point: {@link ConstructorInterceptPoint}, {@link InstanceMethodsInterceptPoint} and {@link StaticMethodsInterceptPoint}
|
||||
* If plugin is going to enhance constructors, instance methods, or both,
|
||||
* {@link ClassEnhancePluginDefine} will add a field of {@link EnhancedClassInstanceContext} type.
|
||||
* {@link ClassEnhancePluginDefine} will add a field of {@link com.a.eye.skywalking.api.plugin.interceptor.EnhancedClassInstanceContext} type.
|
||||
*
|
||||
* @author wusheng
|
||||
*/
|
||||
|
|
@ -44,7 +45,6 @@ public abstract class ClassEnhancePluginDefine extends AbstractClassEnhancePlugi
|
|||
* @param enhanceOriginClassName target class name
|
||||
* @param newClassBuilder byte-buddy's builder to manipulate class bytecode.
|
||||
* @return new byte-buddy's builder for further manipulation.
|
||||
* @throws PluginException
|
||||
*/
|
||||
@Override
|
||||
protected DynamicType.Builder<?> enhance(String enhanceOriginClassName, DynamicType.Builder<?> newClassBuilder) throws PluginException {
|
||||
|
|
@ -61,7 +61,6 @@ public abstract class ClassEnhancePluginDefine extends AbstractClassEnhancePlugi
|
|||
* @param enhanceOriginClassName target class name
|
||||
* @param newClassBuilder byte-buddy's builder to manipulate class bytecode.
|
||||
* @return new byte-buddy's builder for further manipulation.
|
||||
* @throws PluginException
|
||||
*/
|
||||
private DynamicType.Builder<?> enhanceInstance(String enhanceOriginClassName, DynamicType.Builder<?> newClassBuilder) throws PluginException {
|
||||
ConstructorInterceptPoint[] constructorInterceptPoints = getConstructorsInterceptPoints();
|
||||
|
|
@ -150,7 +149,6 @@ public abstract class ClassEnhancePluginDefine extends AbstractClassEnhancePlugi
|
|||
* @param enhanceOriginClassName target class name
|
||||
* @param newClassBuilder byte-buddy's builder to manipulate class bytecode.
|
||||
* @return new byte-buddy's builder for further manipulation.
|
||||
* @throws PluginException
|
||||
*/
|
||||
private DynamicType.Builder<?> enhanceClass(String enhanceOriginClassName, DynamicType.Builder<?> newClassBuilder) throws PluginException {
|
||||
StaticMethodsInterceptPoint[] staticMethodsInterceptPoints = getStaticMethodsInterceptPoints();
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package com.a.eye.skywalking.api.plugin.interceptor.enhance;
|
||||
|
||||
|
||||
import com.a.eye.skywalking.api.plugin.interceptor.StaticMethodsInterceptPoint;
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -1,18 +0,0 @@
|
|||
package com.a.eye.skywalking.api.plugin.dubbo;
|
||||
|
||||
import com.a.eye.skywalking.api.IBuriedPointType;
|
||||
|
||||
public enum DubboBuriedPointType implements IBuriedPointType {
|
||||
INSTANCE;
|
||||
|
||||
@Override
|
||||
public String getTypeName() {
|
||||
return "D";
|
||||
}
|
||||
|
||||
@Override
|
||||
public CallType getCallType() {
|
||||
return CallType.SYNC;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,36 +0,0 @@
|
|||
package com.a.eye.skywalking.api.plugin.dubbo;
|
||||
|
||||
import com.a.eye.skywalking.api.plugin.interceptor.InstanceMethodsInterceptPoint;
|
||||
import com.a.eye.skywalking.plugin.interceptor.ConstructorInterceptPoint;
|
||||
import com.a.eye.skywalking.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine;
|
||||
import net.bytebuddy.description.method.MethodDescription;
|
||||
import net.bytebuddy.matcher.ElementMatcher;
|
||||
|
||||
import static net.bytebuddy.matcher.ElementMatchers.named;
|
||||
|
||||
public class DubboPluginDefine extends ClassInstanceMethodsEnhancePluginDefine {
|
||||
@Override
|
||||
protected String enhanceClassName() {
|
||||
return "com.alibaba.dubbo.monitor.support.MonitorFilter";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
|
||||
return new InstanceMethodsInterceptPoint[]{new InstanceMethodsInterceptPoint() {
|
||||
@Override
|
||||
public ElementMatcher<MethodDescription> getMethodsMatcher() {
|
||||
return named("invoke");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMethodsInterceptor() {
|
||||
return "com.a.eye.skywalking.plugin.dubbo.MonitorFilterInterceptor";
|
||||
}
|
||||
}};
|
||||
}
|
||||
}
|
||||
|
|
@ -1,155 +0,0 @@
|
|||
package com.a.eye.skywalking.api.plugin.dubbo;
|
||||
|
||||
import com.a.eye.skywalking.api.plugin.dubbox.bugfix.below283.BugFixAcitve;
|
||||
import com.a.eye.skywalking.api.plugin.dubbox.bugfix.below283.SWBaseBean;
|
||||
import com.a.eye.skywalking.invoke.monitor.RPCClientInvokeMonitor;
|
||||
import com.a.eye.skywalking.invoke.monitor.RPCServerInvokeMonitor;
|
||||
import com.a.eye.skywalking.model.ContextData;
|
||||
import com.a.eye.skywalking.model.Identification;
|
||||
import com.a.eye.skywalking.api.plugin.interceptor.EnhancedClassInstanceContext;
|
||||
import com.a.eye.skywalking.plugin.interceptor.enhance.InstanceMethodInvokeContext;
|
||||
import com.a.eye.skywalking.api.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
|
||||
import com.a.eye.skywalking.api.plugin.interceptor.enhance.MethodInterceptResult;
|
||||
import com.alibaba.dubbo.rpc.Invocation;
|
||||
import com.alibaba.dubbo.rpc.Invoker;
|
||||
import com.alibaba.dubbo.rpc.Result;
|
||||
import com.alibaba.dubbo.rpc.RpcContext;
|
||||
|
||||
public class MonitorFilterInterceptor implements InstanceMethodsAroundInterceptor {
|
||||
@Override
|
||||
public void beforeMethod(EnhancedClassInstanceContext context, InstanceMethodInvokeContext interceptorContext,
|
||||
MethodInterceptResult result) {
|
||||
Object[] arguments = interceptorContext.allArguments();
|
||||
Invoker invoker = (Invoker) arguments[0];
|
||||
Invocation invocation = (Invocation) arguments[1];
|
||||
|
||||
RpcContext rpcContext = RpcContext.getContext();
|
||||
boolean isConsumer = rpcContext.isConsumerSide();
|
||||
context.set("isConsumer", isConsumer);
|
||||
if (isConsumer) {
|
||||
ContextData contextData =
|
||||
new RPCClientInvokeMonitor().beforeInvoke(createIdentification(invoker, invocation, true));
|
||||
String contextDataStr = contextData.toString();
|
||||
|
||||
//追加参数
|
||||
if (!BugFixAcitve.isActive) {
|
||||
// context.setAttachment("contextData", contextDataStr);
|
||||
// context的setAttachment方法在重试机制的时候并不会覆盖原有的Attachment
|
||||
// 参见Dubbo源代码:“com.alibaba.dubbo.rpc.RpcInvocation”
|
||||
// public void setAttachmentIfAbsent(String key, String value) {
|
||||
// if (attachments == null) {
|
||||
// attachments = new HashMap<String, String>();
|
||||
// }
|
||||
// if (! attachments.containsKey(key)) {
|
||||
// attachments.put(key, value);
|
||||
// }
|
||||
// }
|
||||
// 在Rest模式中attachment会被抹除,不会传入到服务端
|
||||
// Rest模式会将attachment存放到header里面,具体见com.alibaba.dubbo.rpc.protocol.rest.RpcContextFilter
|
||||
//invocation.getAttachments().put("contextData", contextDataStr);
|
||||
rpcContext.getAttachments().put("contextData", contextDataStr);
|
||||
} else {
|
||||
fix283SendNoAttachmentIssue(invocation, contextDataStr);
|
||||
}
|
||||
} else {
|
||||
// 读取参数
|
||||
String contextDataStr;
|
||||
|
||||
if (!BugFixAcitve.isActive) {
|
||||
contextDataStr = rpcContext.getAttachment("contextData");
|
||||
} else {
|
||||
contextDataStr = fix283RecvNoAttachmentIssue(invocation);
|
||||
}
|
||||
|
||||
ContextData contextData = null;
|
||||
if (contextDataStr != null && contextDataStr.length() > 0) {
|
||||
contextData = new ContextData(contextDataStr);
|
||||
}
|
||||
|
||||
new RPCServerInvokeMonitor().beforeInvoke(contextData, createIdentification(invoker, invocation, false));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object afterMethod(EnhancedClassInstanceContext context, InstanceMethodInvokeContext interceptorContext,
|
||||
Object ret) {
|
||||
Result result = (Result) ret;
|
||||
if (result != null && result.getException() != null) {
|
||||
dealException(result.getException(), context);
|
||||
}
|
||||
|
||||
if (isConsumer(context)) {
|
||||
new RPCClientInvokeMonitor().afterInvoke();
|
||||
} else {
|
||||
new RPCServerInvokeMonitor().afterInvoke();
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleMethodException(Throwable t, EnhancedClassInstanceContext context,
|
||||
InstanceMethodInvokeContext interceptorContext) {
|
||||
dealException(t, context);
|
||||
}
|
||||
|
||||
|
||||
private boolean isConsumer(EnhancedClassInstanceContext context) {
|
||||
return (Boolean) context.get("isConsumer");
|
||||
}
|
||||
|
||||
private void dealException(Throwable t, EnhancedClassInstanceContext context) {
|
||||
if (isConsumer(context)) {
|
||||
new RPCClientInvokeMonitor().occurException(t);
|
||||
} else {
|
||||
new RPCServerInvokeMonitor().occurException(t);
|
||||
}
|
||||
}
|
||||
|
||||
private static Identification createIdentification(Invoker<?> invoker, Invocation invocation, boolean isConsumer) {
|
||||
StringBuilder viewPoint = new StringBuilder();
|
||||
if (isConsumer) {
|
||||
viewPoint.append("comsumer:");
|
||||
} else {
|
||||
viewPoint.append("provider:");
|
||||
}
|
||||
viewPoint.append(invoker.getUrl().getProtocol() + "://");
|
||||
viewPoint.append(invoker.getUrl().getHost());
|
||||
viewPoint.append(":" + invoker.getUrl().getPort());
|
||||
viewPoint.append(invoker.getUrl().getAbsolutePath());
|
||||
viewPoint.append("." + invocation.getMethodName() + "(");
|
||||
for (Class<?> classes : invocation.getParameterTypes()) {
|
||||
viewPoint.append(classes.getSimpleName() + ",");
|
||||
}
|
||||
|
||||
if (invocation.getParameterTypes().length > 0) {
|
||||
viewPoint.delete(viewPoint.length() - 1, viewPoint.length());
|
||||
}
|
||||
|
||||
viewPoint.append(")");
|
||||
return Identification.newBuilder().viewPoint(viewPoint.toString()).spanType(DubboBuriedPointType.INSTANCE)
|
||||
.build();
|
||||
}
|
||||
|
||||
|
||||
private static void fix283SendNoAttachmentIssue(Invocation invocation, String contextDataStr) {
|
||||
|
||||
for (Object parameter : invocation.getArguments()) {
|
||||
if (parameter instanceof SWBaseBean) {
|
||||
((SWBaseBean) parameter).setContextData(contextDataStr);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static String fix283RecvNoAttachmentIssue(Invocation invocation) {
|
||||
for (Object parameter : invocation.getArguments()) {
|
||||
if (parameter instanceof SWBaseBean) {
|
||||
return ((SWBaseBean) parameter).getContextData();
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
package com.a.eye.skywalking.api.plugin.dubbox.bugfix.below283;
|
||||
|
||||
public final class BugFixAcitve {
|
||||
public static boolean isActive = false;
|
||||
|
||||
public BugFixAcitve(){
|
||||
isActive = true;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
package com.a.eye.skywalking.api.plugin.dubbox.bugfix.below283;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
public class SWBaseBean implements Serializable {
|
||||
private String contextData;
|
||||
|
||||
public String getContextData() {
|
||||
return contextData;
|
||||
}
|
||||
|
||||
public void setContextData(String contextData) {
|
||||
this.contextData = contextData;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
package com.a.eye.skywalking.plugin.dubbo;
|
||||
|
||||
import com.a.eye.skywalking.api.plugin.interceptor.ConstructorInterceptPoint;
|
||||
import com.a.eye.skywalking.api.plugin.interceptor.InstanceMethodsInterceptPoint;
|
||||
import com.a.eye.skywalking.api.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine;
|
||||
import com.alibaba.dubbo.rpc.Invocation;
|
||||
import com.alibaba.dubbo.rpc.Invoker;
|
||||
|
||||
import net.bytebuddy.description.method.MethodDescription;
|
||||
import net.bytebuddy.matcher.ElementMatcher;
|
||||
|
||||
import static net.bytebuddy.matcher.ElementMatchers.named;
|
||||
|
||||
/**
|
||||
* {@link DubboInstrumentation} presents that skywalking intercepts {@link com.alibaba.dubbo.monitor.support.MonitorFilter#invoke(Invoker, Invocation)}
|
||||
* by using {@link DubboInterceptor}.
|
||||
*
|
||||
* @author zhangxin
|
||||
*/
|
||||
public class DubboInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
|
||||
|
||||
private static final String ENHANCE_CLASS = "com.alibaba.dubbo.monitor.support.MonitorFilter";
|
||||
private static final String INTERCEPT_CLASS = "com.a.eye.skywalking.plugin.dubbo.DubboInterceptor";
|
||||
|
||||
@Override
|
||||
protected String enhanceClassName() {
|
||||
return ENHANCE_CLASS;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
|
||||
return new InstanceMethodsInterceptPoint[]{new InstanceMethodsInterceptPoint() {
|
||||
@Override
|
||||
public ElementMatcher<MethodDescription> getMethodsMatcher() {
|
||||
return named("invoke");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMethodsInterceptor() {
|
||||
return INTERCEPT_CLASS;
|
||||
}
|
||||
}};
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,185 @@
|
|||
package com.a.eye.skywalking.plugin.dubbo;
|
||||
|
||||
import com.a.eye.skywalking.api.context.ContextCarrier;
|
||||
import com.a.eye.skywalking.api.context.ContextManager;
|
||||
import com.a.eye.skywalking.api.plugin.interceptor.EnhancedClassInstanceContext;
|
||||
import com.a.eye.skywalking.api.plugin.interceptor.enhance.InstanceMethodInvokeContext;
|
||||
import com.a.eye.skywalking.api.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
|
||||
import com.a.eye.skywalking.api.plugin.interceptor.enhance.MethodInterceptResult;
|
||||
import com.a.eye.skywalking.plugin.dubbox.BugFixActive;
|
||||
import com.a.eye.skywalking.plugin.dubbox.SWBaseBean;
|
||||
import com.a.eye.skywalking.trace.Span;
|
||||
import com.a.eye.skywalking.trace.tag.Tags;
|
||||
import com.alibaba.dubbo.common.URL;
|
||||
import com.alibaba.dubbo.rpc.Invocation;
|
||||
import com.alibaba.dubbo.rpc.Invoker;
|
||||
import com.alibaba.dubbo.rpc.Result;
|
||||
import com.alibaba.dubbo.rpc.RpcContext;
|
||||
|
||||
/**
|
||||
* {@link DubboInterceptor} define how to enhance class {@link com.alibaba.dubbo.monitor.support.MonitorFilter#invoke(Invoker, Invocation)}.
|
||||
* the trace context transport to the provider side by {@link RpcContext#attachments}.but all the version of dubbo framework below 2.8.3
|
||||
* don't support {@link RpcContext#attachments}, we support another way to support it. it is that all request parameters of dubbo service
|
||||
* need to extend {@link SWBaseBean}, and {@link DubboInterceptor} will inject the trace context data to the {@link SWBaseBean} bean and
|
||||
* extract the trace context data from {@link SWBaseBean}, or the trace context data will not transport to the provider side.
|
||||
*
|
||||
* @author zhangxin
|
||||
*/
|
||||
public class DubboInterceptor implements InstanceMethodsAroundInterceptor {
|
||||
|
||||
public static final String ATTACHMENT_NAME_OF_CONTEXT_DATA = "contextData";
|
||||
public static final String DUBBO_COMPONENT = "Dubbo";
|
||||
|
||||
/**
|
||||
* <h2>Consumer:</h2>
|
||||
* The serialized trace context data will inject the first param that extend {@link SWBaseBean} of dubbo service
|
||||
* if the method {@link BugFixActive#active()} be called. or the serialized context data will inject to the
|
||||
* {@link RpcContext#attachments} for transport to provider side.
|
||||
*
|
||||
* <h2>Provider:</h2>
|
||||
* The serialized trace context data will extract from the first param that extend {@link SWBaseBean} of dubbo service
|
||||
* if the method {@link BugFixActive#active()} be called. or it will extract from {@link RpcContext#attachments}.
|
||||
* current trace segment will ref if the serialize context data is not null.
|
||||
*/
|
||||
@Override
|
||||
public void beforeMethod(EnhancedClassInstanceContext context, InstanceMethodInvokeContext interceptorContext,
|
||||
MethodInterceptResult result) {
|
||||
Object[] arguments = interceptorContext.allArguments();
|
||||
Invoker invoker = (Invoker) arguments[0];
|
||||
Invocation invocation = (Invocation) arguments[1];
|
||||
RpcContext rpcContext = RpcContext.getContext();
|
||||
boolean isConsumer = rpcContext.isConsumerSide();
|
||||
URL requestURL = invoker.getUrl();
|
||||
|
||||
Span span = ContextManager.INSTANCE.createSpan(generateOperationName(requestURL, invocation));
|
||||
Tags.URL.set(span, generateRequestURL(requestURL, invocation));
|
||||
Tags.COMPONENT.set(span, DUBBO_COMPONENT);
|
||||
Tags.PEER_HOST.set(span, requestURL.getHost());
|
||||
Tags.PEER_PORT.set(span, requestURL.getPort());
|
||||
Tags.SPAN_LAYER.asRPCFramework(span);
|
||||
|
||||
if (isConsumer) {
|
||||
Tags.SPAN_KIND.set(span, Tags.SPAN_KIND_CLIENT);
|
||||
ContextCarrier contextCarrier = new ContextCarrier();
|
||||
ContextManager.INSTANCE.inject(contextCarrier);
|
||||
if (!BugFixActive.isActive()) {
|
||||
//invocation.getAttachments().put("contextData", contextDataStr);
|
||||
//@see https://github.com/alibaba/dubbo/blob/dubbo-2.5.3/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/RpcInvocation.java#L154-L161
|
||||
rpcContext.getAttachments().put(ATTACHMENT_NAME_OF_CONTEXT_DATA, contextCarrier.serialize());
|
||||
} else {
|
||||
fix283SendNoAttachmentIssue(invocation, contextCarrier);
|
||||
}
|
||||
} else {
|
||||
Tags.SPAN_KIND.set(span, Tags.SPAN_KIND_SERVER);
|
||||
|
||||
ContextCarrier contextCarrier;
|
||||
if (!BugFixActive.isActive()) {
|
||||
contextCarrier = new ContextCarrier().deserialize(rpcContext.getAttachment(ATTACHMENT_NAME_OF_CONTEXT_DATA));
|
||||
} else {
|
||||
contextCarrier = fix283RecvNoAttachmentIssue(invocation);
|
||||
}
|
||||
|
||||
if (contextCarrier != null) {
|
||||
ContextManager.INSTANCE.extract(contextCarrier);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute after {@link com.alibaba.dubbo.monitor.support.MonitorFilter#invoke(Invoker, Invocation)},
|
||||
* when dubbo instrumentation is active。Check {@link Result#getException()} , if not NULL,
|
||||
* log the exception and set tag error=true.
|
||||
*/
|
||||
@Override
|
||||
public Object afterMethod(EnhancedClassInstanceContext context, InstanceMethodInvokeContext interceptorContext,
|
||||
Object ret) {
|
||||
Result result = (Result) ret;
|
||||
if (result != null && result.getException() != null) {
|
||||
dealException(result.getException());
|
||||
}
|
||||
|
||||
ContextManager.INSTANCE.stopSpan();
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleMethodException(Throwable t, EnhancedClassInstanceContext context,
|
||||
InstanceMethodInvokeContext interceptorContext) {
|
||||
dealException(t);
|
||||
}
|
||||
|
||||
/**
|
||||
* Log the throwable, which occurs in Dubbo RPC service.
|
||||
*/
|
||||
private void dealException(Throwable throwable) {
|
||||
Span span = ContextManager.INSTANCE.activeSpan();
|
||||
Tags.ERROR.set(span, true);
|
||||
span.log(throwable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Format operation name. e.g. com.a.eye.skywalking.plugin.test.Test.test(String)
|
||||
*
|
||||
* @return operation name.
|
||||
*/
|
||||
private String generateOperationName(URL requestURL, Invocation invocation) {
|
||||
StringBuilder operationName = new StringBuilder();
|
||||
operationName.append(requestURL.getPath());
|
||||
operationName.append("." + invocation.getMethodName() + "(");
|
||||
for (Class<?> classes : invocation.getParameterTypes()) {
|
||||
operationName.append(classes.getSimpleName() + ",");
|
||||
}
|
||||
|
||||
if (invocation.getParameterTypes().length > 0) {
|
||||
operationName.delete(operationName.length() - 1, operationName.length());
|
||||
}
|
||||
|
||||
operationName.append(")");
|
||||
|
||||
return operationName.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Format request url.
|
||||
* e.g. dubbo://127.0.0.1:20880/com.a.eye.skywalking.plugin.test.Test.test(String).
|
||||
*
|
||||
* @return request url.
|
||||
*/
|
||||
private String generateRequestURL(URL url, Invocation invocation) {
|
||||
StringBuilder requestURL = new StringBuilder();
|
||||
requestURL.append(url.getProtocol() + "://");
|
||||
requestURL.append(url.getHost());
|
||||
requestURL.append(":" + url.getPort() + "/");
|
||||
requestURL.append(generateOperationName(url, invocation));
|
||||
return requestURL.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the trace context.
|
||||
*
|
||||
* @param contextCarrier {@link ContextCarrier}.
|
||||
*/
|
||||
private void fix283SendNoAttachmentIssue(Invocation invocation, ContextCarrier contextCarrier) {
|
||||
for (Object parameter : invocation.getArguments()) {
|
||||
if (parameter instanceof SWBaseBean) {
|
||||
((SWBaseBean) parameter).setTraceContext(contextCarrier.serialize());
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch the trace context by using {@link Invocation#getArguments()}.
|
||||
*
|
||||
* @return trace context data.
|
||||
*/
|
||||
private ContextCarrier fix283RecvNoAttachmentIssue(Invocation invocation) {
|
||||
for (Object parameter : invocation.getArguments()) {
|
||||
if (parameter instanceof SWBaseBean) {
|
||||
return new ContextCarrier().deserialize(((SWBaseBean) parameter).getTraceContext());
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
package com.a.eye.skywalking.plugin.dubbox;
|
||||
|
||||
/**
|
||||
* {@link BugFixActive#active} is an flag that present the dubbox version is below 2.8.3,
|
||||
* The version 2.8.3 of dubbox don't support attachment. so skywalking provided another way
|
||||
* to support the function that transport the serialized context data. The way is that
|
||||
* all parameters of dubbo service need to extend {@link SWBaseBean}, {@link com.a.eye.skywalking.plugin.dubbo.DubboInterceptor}
|
||||
* fetch the serialized context data by using {@link SWBaseBean#getTraceContext()}.
|
||||
*
|
||||
* @author zhangxin
|
||||
*/
|
||||
public final class BugFixActive {
|
||||
|
||||
private static boolean active = false;
|
||||
|
||||
/**
|
||||
* Set active status, before startup dubbo services.
|
||||
*/
|
||||
public static void active() {
|
||||
BugFixActive.active = true;
|
||||
}
|
||||
|
||||
|
||||
public static boolean isActive() {
|
||||
return BugFixActive.active;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
package com.a.eye.skywalking.plugin.dubbox;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* All the request parameter of dubbox service need to extend {@link SWBaseBean} to transport
|
||||
* the serialized trace context to the provider side if the version of dubbox is below 2.8.3.
|
||||
*
|
||||
* @author zhangxin
|
||||
*/
|
||||
public class SWBaseBean implements Serializable {
|
||||
/**
|
||||
* Serialized trace context.
|
||||
*/
|
||||
private String traceContext;
|
||||
|
||||
public String getTraceContext() {
|
||||
return traceContext;
|
||||
}
|
||||
|
||||
public void setTraceContext(String traceContext) {
|
||||
this.traceContext = traceContext;
|
||||
}
|
||||
}
|
||||
|
|
@ -1 +1 @@
|
|||
com.a.eye.skywalking.plugin.dubbo.DubboPluginDefine
|
||||
com.a.eye.skywalking.plugin.dubbo.DubboInstrumentation
|
||||
|
|
|
|||
|
|
@ -0,0 +1,229 @@
|
|||
package com.a.eye.skywalking.plugin.dubbo;
|
||||
|
||||
import com.a.eye.skywalking.api.context.TracerContext;
|
||||
import com.a.eye.skywalking.api.plugin.interceptor.EnhancedClassInstanceContext;
|
||||
import com.a.eye.skywalking.api.plugin.interceptor.enhance.InstanceMethodInvokeContext;
|
||||
import com.a.eye.skywalking.api.plugin.interceptor.enhance.MethodInterceptResult;
|
||||
import com.a.eye.skywalking.plugin.dubbox.BugFixActive;
|
||||
import com.a.eye.skywalking.sniffer.mock.context.MockTracerContextListener;
|
||||
import com.a.eye.skywalking.sniffer.mock.context.SegmentAssert;
|
||||
import com.a.eye.skywalking.trace.LogData;
|
||||
import com.a.eye.skywalking.trace.Span;
|
||||
import com.a.eye.skywalking.trace.TraceSegment;
|
||||
import com.a.eye.skywalking.trace.TraceSegmentRef;
|
||||
import com.a.eye.skywalking.trace.tag.Tags;
|
||||
import com.alibaba.dubbo.common.URL;
|
||||
import com.alibaba.dubbo.rpc.Invocation;
|
||||
import com.alibaba.dubbo.rpc.Invoker;
|
||||
import com.alibaba.dubbo.rpc.Result;
|
||||
import com.alibaba.dubbo.rpc.RpcContext;
|
||||
|
||||
import org.hamcrest.CoreMatchers;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.Mockito;
|
||||
import org.powermock.core.classloader.annotations.PrepareForTest;
|
||||
import org.powermock.modules.junit4.PowerMockRunner;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.powermock.api.mockito.PowerMockito.mockStatic;
|
||||
import static org.powermock.api.mockito.PowerMockito.when;
|
||||
|
||||
|
||||
@RunWith(PowerMockRunner.class)
|
||||
@PrepareForTest({RpcContext.class, BugFixActive.class})
|
||||
public class DubboInterceptorTest {
|
||||
|
||||
private MockTracerContextListener mockTracerContextListener;
|
||||
private DubboInterceptor dubboInterceptor;
|
||||
private RequestParamForTestBelow283 testParam;
|
||||
@Mock
|
||||
private RpcContext rpcContext;
|
||||
@Mock
|
||||
private Invoker invoker;
|
||||
@Mock
|
||||
private Invocation invocation;
|
||||
@Mock
|
||||
private EnhancedClassInstanceContext classInstanceContext;
|
||||
@Mock
|
||||
private InstanceMethodInvokeContext methodInvokeContext;
|
||||
@Mock
|
||||
private MethodInterceptResult methodInterceptResult;
|
||||
@Mock
|
||||
private Result result;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
dubboInterceptor = new DubboInterceptor();
|
||||
testParam = new RequestParamForTestBelow283();
|
||||
mockTracerContextListener = new MockTracerContextListener();
|
||||
TracerContext.ListenerManager.add(mockTracerContextListener);
|
||||
|
||||
mockStatic(RpcContext.class);
|
||||
mockStatic(BugFixActive.class);
|
||||
when(invoker.getUrl()).thenReturn(URL.valueOf("dubbo://127.0.0.1:20880/com.a.eye.skywalking.test.TestDubboService"));
|
||||
when(invocation.getMethodName()).thenReturn("test");
|
||||
when(invocation.getParameterTypes()).thenReturn(new Class[]{String.class});
|
||||
when(invocation.getArguments()).thenReturn(new Object[]{testParam});
|
||||
Mockito.when(RpcContext.getContext()).thenReturn(rpcContext);
|
||||
when(rpcContext.isConsumerSide()).thenReturn(true);
|
||||
when(methodInvokeContext.allArguments()).thenReturn(new Object[]{invoker, invocation});
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testConsumerBelow283() {
|
||||
when(BugFixActive.isActive()).thenReturn(true);
|
||||
|
||||
dubboInterceptor.beforeMethod(classInstanceContext, methodInvokeContext, methodInterceptResult);
|
||||
dubboInterceptor.afterMethod(classInstanceContext, methodInvokeContext, result);
|
||||
|
||||
mockTracerContextListener.assertSize(1);
|
||||
mockTracerContextListener.assertTraceSegment(0, new SegmentAssert() {
|
||||
@Override
|
||||
public void call(TraceSegment traceSegment) {
|
||||
assertThat(traceSegment.getSpans().size(), is(1));
|
||||
assertConsumerSpan(traceSegment.getSpans().get(0));
|
||||
testParam.assertSelf("0", "127.0.0.1");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConsumerWithAttachment() {
|
||||
dubboInterceptor.beforeMethod(classInstanceContext, methodInvokeContext, methodInterceptResult);
|
||||
dubboInterceptor.afterMethod(classInstanceContext, methodInvokeContext, result);
|
||||
|
||||
mockTracerContextListener.assertSize(1);
|
||||
mockTracerContextListener.assertTraceSegment(0, new SegmentAssert() {
|
||||
@Override
|
||||
public void call(TraceSegment traceSegment) {
|
||||
assertThat(traceSegment.getSpans().size(), is(1));
|
||||
assertConsumerSpan(traceSegment.getSpans().get(0));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConsumerWithException() {
|
||||
dubboInterceptor.beforeMethod(classInstanceContext, methodInvokeContext, methodInterceptResult);
|
||||
dubboInterceptor.handleMethodException(new RuntimeException(), classInstanceContext, methodInvokeContext);
|
||||
dubboInterceptor.afterMethod(classInstanceContext, methodInvokeContext, result);
|
||||
|
||||
mockTracerContextListener.assertSize(1);
|
||||
mockTracerContextListener.assertTraceSegment(0, new SegmentAssert() {
|
||||
@Override
|
||||
public void call(TraceSegment traceSegment) {
|
||||
assertConsumerTraceSegmentInErrorCase(traceSegment);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConsumerWithResultHasException() {
|
||||
when(result.getException()).thenReturn(new RuntimeException());
|
||||
|
||||
dubboInterceptor.beforeMethod(classInstanceContext, methodInvokeContext, methodInterceptResult);
|
||||
dubboInterceptor.afterMethod(classInstanceContext, methodInvokeContext, result);
|
||||
|
||||
mockTracerContextListener.assertSize(1);
|
||||
mockTracerContextListener.assertTraceSegment(0, new SegmentAssert() {
|
||||
@Override
|
||||
public void call(TraceSegment traceSegment) {
|
||||
assertConsumerTraceSegmentInErrorCase(traceSegment);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testProviderWithAttachment() {
|
||||
when(rpcContext.isConsumerSide()).thenReturn(false);
|
||||
when(rpcContext.getAttachment(DubboInterceptor.ATTACHMENT_NAME_OF_CONTEXT_DATA)).thenReturn("302017.1487666919810.624424584.17332.1.1|1|REMOTE_APP|127.0.0.1");
|
||||
|
||||
dubboInterceptor.beforeMethod(classInstanceContext, methodInvokeContext, methodInterceptResult);
|
||||
dubboInterceptor.afterMethod(classInstanceContext, methodInvokeContext, result);
|
||||
assertProvider();
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testProviderBelow283() {
|
||||
when(rpcContext.isConsumerSide()).thenReturn(false);
|
||||
when(BugFixActive.isActive()).thenReturn(true);
|
||||
|
||||
testParam.setTraceContext("302017.1487666919810.624424584.17332.1.1|1|REMOTE_APP|127.0.0.1");
|
||||
|
||||
|
||||
dubboInterceptor.beforeMethod(classInstanceContext, methodInvokeContext, methodInterceptResult);
|
||||
dubboInterceptor.afterMethod(classInstanceContext, methodInvokeContext, result);
|
||||
|
||||
assertProvider();
|
||||
}
|
||||
|
||||
|
||||
private void assertConsumerTraceSegmentInErrorCase(TraceSegment traceSegment) {
|
||||
assertThat(traceSegment.getSpans().size(), is(1));
|
||||
assertConsumerSpan(traceSegment.getSpans().get(0));
|
||||
Span span = traceSegment.getSpans().get(0);
|
||||
assertThat(span.getLogs().size(), is(1));
|
||||
assertErrorLog(span.getLogs().get(0));
|
||||
}
|
||||
|
||||
private void assertErrorLog(LogData logData) {
|
||||
assertThat(logData.getFields().size(), is(4));
|
||||
assertThat(logData.getFields().get("event"), CoreMatchers.<Object>is("error"));
|
||||
assertThat(logData.getFields().get("error.kind"), CoreMatchers.<Object>is(RuntimeException.class.getName()));
|
||||
assertNull(logData.getFields().get("message"));
|
||||
}
|
||||
|
||||
|
||||
private void assertProvider() {
|
||||
final TraceSegmentRef expect = new TraceSegmentRef();
|
||||
expect.setSpanId(1);
|
||||
expect.setTraceSegmentId("302017.1487666919810.624424584.17332.1.1");
|
||||
|
||||
mockTracerContextListener.assertSize(1);
|
||||
mockTracerContextListener.assertTraceSegment(0, new SegmentAssert() {
|
||||
@Override
|
||||
public void call(TraceSegment traceSegment) {
|
||||
assertThat(traceSegment.getSpans().size(), is(1));
|
||||
assertProviderSpan(traceSegment.getSpans().get(0));
|
||||
assertTraceSegmentRef(traceSegment.getPrimaryRef(), expect);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void assertTraceSegmentRef(TraceSegmentRef actual, TraceSegmentRef expect) {
|
||||
assertThat(actual.getSpanId(), is(expect.getSpanId()));
|
||||
assertThat(actual.getTraceSegmentId(), is(expect.getTraceSegmentId()));
|
||||
}
|
||||
|
||||
|
||||
private void assertProviderSpan(Span span) {
|
||||
assertCommonsAttribute(span);
|
||||
assertThat(Tags.SPAN_KIND.get(span), is(Tags.SPAN_KIND_SERVER));
|
||||
}
|
||||
|
||||
private void assertConsumerSpan(Span span) {
|
||||
assertCommonsAttribute(span);
|
||||
assertThat(Tags.SPAN_KIND.get(span), is(Tags.SPAN_KIND_CLIENT));
|
||||
}
|
||||
|
||||
private void assertCommonsAttribute(Span span) {
|
||||
assertThat(Tags.SPAN_LAYER.isRPCFramework(span), is(true));
|
||||
assertThat(Tags.COMPONENT.get(span), is(DubboInterceptor.DUBBO_COMPONENT));
|
||||
assertThat(Tags.URL.get(span), is("dubbo://127.0.0.1:20880/com.a.eye.skywalking.test.TestDubboService.test(String)"));
|
||||
assertThat(span.getOperationName(), is("com.a.eye.skywalking.test.TestDubboService.test(String)"));
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
TracerContext.ListenerManager.remove(mockTracerContextListener);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
package com.a.eye.skywalking.plugin.dubbo;
|
||||
|
||||
import com.a.eye.skywalking.plugin.dubbox.SWBaseBean;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.endsWith;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
/**
|
||||
* {@link RequestParamForTestBelow283} store context data for test.
|
||||
*/
|
||||
public class RequestParamForTestBelow283 extends SWBaseBean {
|
||||
|
||||
/**
|
||||
* This method assert that {@link SWBaseBean#getTraceContext()} if it's not null and context data
|
||||
* will end with the expect span id.
|
||||
*
|
||||
* @param expectSpanId expect span id
|
||||
*/
|
||||
public void assertSelf(String expectSpanId, String expectHost) {
|
||||
assertNotNull(getTraceContext());
|
||||
assertThat(getTraceContext(), endsWith(expectSpanId + "|" + expectHost));
|
||||
}
|
||||
}
|
||||
|
|
@ -1,70 +0,0 @@
|
|||
package com.a.eye.skywalking.api.plugin.httpClient.v4;
|
||||
|
||||
import com.a.eye.skywalking.api.plugin.interceptor.EnhancedClassInstanceContext;
|
||||
import com.a.eye.skywalking.plugin.interceptor.enhance.ConstructorInvokeContext;
|
||||
import org.apache.http.HttpHost;
|
||||
import org.apache.http.HttpRequest;
|
||||
|
||||
import com.a.eye.skywalking.invoke.monitor.RPCClientInvokeMonitor;
|
||||
import com.a.eye.skywalking.model.Identification;
|
||||
import com.a.eye.skywalking.plugin.interceptor.enhance.InstanceMethodInvokeContext;
|
||||
import com.a.eye.skywalking.api.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
|
||||
import com.a.eye.skywalking.api.plugin.interceptor.enhance.MethodInterceptResult;
|
||||
|
||||
public class HttpClientExecuteInterceptor implements InstanceMethodsAroundInterceptor {
|
||||
/**
|
||||
* default headname of sky walking context<br/>
|
||||
*/
|
||||
public static String TRACE_HEAD_NAME = "SkyWalking-TRACING-NAME";
|
||||
|
||||
private static RPCClientInvokeMonitor rpcClientInvokeMonitor = new RPCClientInvokeMonitor();
|
||||
|
||||
@Override
|
||||
public void beforeMethod(EnhancedClassInstanceContext context,
|
||||
InstanceMethodInvokeContext interceptorContext, MethodInterceptResult result) {
|
||||
Object[] allArguments = interceptorContext.allArguments();
|
||||
if (allArguments[0] == null || allArguments[1] == null) {
|
||||
// illegal args, can't trace. ignore.
|
||||
return;
|
||||
}
|
||||
HttpHost httpHost = (HttpHost) allArguments[0];
|
||||
HttpRequest httpRequest = (HttpRequest) allArguments[1];
|
||||
httpRequest
|
||||
.setHeader(
|
||||
TRACE_HEAD_NAME,
|
||||
"ContextData="
|
||||
+ rpcClientInvokeMonitor.beforeInvoke(
|
||||
Identification
|
||||
.newBuilder()
|
||||
.viewPoint(
|
||||
httpHost.toURI()
|
||||
.toString())
|
||||
.spanType(
|
||||
WebBuriedPointType
|
||||
.INSTANCE)
|
||||
.build()).toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object afterMethod(EnhancedClassInstanceContext context,
|
||||
InstanceMethodInvokeContext interceptorContext, Object ret) {
|
||||
Object[] allArguments = interceptorContext.allArguments();
|
||||
if (allArguments[0] == null || allArguments[1] == null) {
|
||||
// illegal args, can't trace. ignore.
|
||||
return ret;
|
||||
}
|
||||
rpcClientInvokeMonitor.afterInvoke();
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleMethodException(Throwable t, EnhancedClassInstanceContext context, InstanceMethodInvokeContext interceptorContext) {
|
||||
Object[] allArguments = interceptorContext.allArguments();
|
||||
if (allArguments[0] == null || allArguments[1] == null) {
|
||||
// illegal args, can't trace. ignore.
|
||||
return;
|
||||
}
|
||||
rpcClientInvokeMonitor.occurException(t);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
package com.a.eye.skywalking.api.plugin.httpClient.v4;
|
||||
|
||||
import com.a.eye.skywalking.api.IBuriedPointType;
|
||||
|
||||
public enum WebBuriedPointType implements IBuriedPointType {
|
||||
INSTANCE;
|
||||
|
||||
@Override
|
||||
public String getTypeName() {
|
||||
return "W";
|
||||
}
|
||||
|
||||
@Override
|
||||
public CallType getCallType() {
|
||||
return CallType.SYNC;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,36 +0,0 @@
|
|||
package com.a.eye.skywalking.api.plugin.httpClient.v4.define;
|
||||
|
||||
import com.a.eye.skywalking.api.plugin.interceptor.InstanceMethodsInterceptPoint;
|
||||
import net.bytebuddy.description.method.MethodDescription;
|
||||
import net.bytebuddy.matcher.ElementMatcher;
|
||||
|
||||
import static net.bytebuddy.matcher.ElementMatchers.named;
|
||||
|
||||
public class AbstractHttpClientPluginDefine extends HttpClientPluginDefine {
|
||||
|
||||
@Override
|
||||
public String enhanceClassName() {
|
||||
return "org.apache.http.impl.client.AbstractHttpClient";
|
||||
}
|
||||
|
||||
/**
|
||||
* version 4.2, intercept method: execute, intercept<br/>
|
||||
* public final HttpResponse execute(HttpHost target, HttpRequest request,
|
||||
* HttpContext context)<br/>
|
||||
*
|
||||
*/
|
||||
@Override
|
||||
protected InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
|
||||
return new InstanceMethodsInterceptPoint[]{new InstanceMethodsInterceptPoint() {
|
||||
@Override
|
||||
public ElementMatcher<MethodDescription> getMethodsMatcher() {
|
||||
return named("doExecute");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMethodsInterceptor() {
|
||||
return getInstanceMethodsInterceptor();
|
||||
}
|
||||
}};
|
||||
}
|
||||
}
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
package com.a.eye.skywalking.api.plugin.httpClient.v4.define;
|
||||
|
||||
import com.a.eye.skywalking.plugin.interceptor.ConstructorInterceptPoint;
|
||||
import com.a.eye.skywalking.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine;
|
||||
|
||||
public abstract class HttpClientPluginDefine extends ClassInstanceMethodsEnhancePluginDefine {
|
||||
@Override
|
||||
protected ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
|
||||
return null;
|
||||
}
|
||||
|
||||
protected String getInstanceMethodsInterceptor() {
|
||||
return "com.a.eye.skywalking.plugin.httpClient.v4.HttpClientExecuteInterceptor";
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,85 @@
|
|||
package com.a.eye.skywalking.plugin.httpClient.v4;
|
||||
|
||||
|
||||
import com.a.eye.skywalking.api.context.ContextCarrier;
|
||||
import com.a.eye.skywalking.api.context.ContextManager;
|
||||
import com.a.eye.skywalking.api.plugin.interceptor.EnhancedClassInstanceContext;
|
||||
import com.a.eye.skywalking.api.plugin.interceptor.enhance.InstanceMethodInvokeContext;
|
||||
import com.a.eye.skywalking.api.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
|
||||
import com.a.eye.skywalking.api.plugin.interceptor.enhance.MethodInterceptResult;
|
||||
import com.a.eye.skywalking.trace.Span;
|
||||
import com.a.eye.skywalking.trace.tag.Tags;
|
||||
|
||||
import org.apache.http.Header;
|
||||
import org.apache.http.HttpHost;
|
||||
import org.apache.http.HttpRequest;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.StatusLine;
|
||||
|
||||
/**
|
||||
* {@link HttpClientExecuteInterceptor} transport the trace context by call {@link HttpRequest#setHeader(Header)},
|
||||
* The current span tag the {@link Tags#ERROR} if {@link StatusLine#getStatusCode()} is not equals 200.
|
||||
*
|
||||
* @author zhangxin
|
||||
*/
|
||||
public class HttpClientExecuteInterceptor implements InstanceMethodsAroundInterceptor {
|
||||
public static final String HEADER_NAME_OF_CONTEXT_DATA = "SKYWALKING_CONTEXT_DATA";
|
||||
|
||||
@Override
|
||||
public void beforeMethod(EnhancedClassInstanceContext context,
|
||||
InstanceMethodInvokeContext interceptorContext, MethodInterceptResult result) {
|
||||
Object[] allArguments = interceptorContext.allArguments();
|
||||
if (allArguments[0] == null || allArguments[1] == null) {
|
||||
// illegal args, can't trace. ignore.
|
||||
return;
|
||||
}
|
||||
HttpHost httpHost = (HttpHost) allArguments[0];
|
||||
HttpRequest httpRequest = (HttpRequest) allArguments[1];
|
||||
|
||||
Span span = ContextManager.INSTANCE.createSpan(httpRequest.getRequestLine().getUri());
|
||||
Tags.PEER_PORT.set(span, httpHost.getPort());
|
||||
Tags.PEER_HOST.set(span, httpHost.getHostName());
|
||||
Tags.SPAN_KIND.set(span, Tags.SPAN_KIND_CLIENT);
|
||||
Tags.URL.set(span, generateURL(httpHost, httpRequest));
|
||||
Tags.SPAN_LAYER.asHttp(span);
|
||||
|
||||
ContextCarrier contextCarrier = new ContextCarrier();
|
||||
ContextManager.INSTANCE.inject(contextCarrier);
|
||||
httpRequest.setHeader(HEADER_NAME_OF_CONTEXT_DATA, contextCarrier.serialize());
|
||||
}
|
||||
|
||||
/**
|
||||
* Format request URL.
|
||||
*
|
||||
* @return request URL
|
||||
*/
|
||||
private String generateURL(HttpHost httpHost, HttpRequest httpRequest) {
|
||||
return httpHost.getSchemeName() + "://" + httpHost.getHostName() + ":" + httpHost.getPort() + httpRequest.getRequestLine().getUri();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object afterMethod(EnhancedClassInstanceContext context,
|
||||
InstanceMethodInvokeContext interceptorContext, Object ret) {
|
||||
Object[] allArguments = interceptorContext.allArguments();
|
||||
if (allArguments[0] == null || allArguments[1] == null) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
HttpResponse response = (HttpResponse) ret;
|
||||
int statusCode = response.getStatusLine().getStatusCode();
|
||||
Span span = ContextManager.INSTANCE.activeSpan();
|
||||
if (statusCode != 200) {
|
||||
Tags.ERROR.set(span, true);
|
||||
}
|
||||
|
||||
Tags.STATUS_CODE.set(span, statusCode);
|
||||
ContextManager.INSTANCE.stopSpan();
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleMethodException(Throwable t, EnhancedClassInstanceContext context, InstanceMethodInvokeContext interceptorContext) {
|
||||
ContextManager.INSTANCE.activeSpan().log(t);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
package com.a.eye.skywalking.plugin.httpClient.v4.define;
|
||||
|
||||
|
||||
import com.a.eye.skywalking.api.plugin.interceptor.InstanceMethodsInterceptPoint;
|
||||
|
||||
import net.bytebuddy.description.method.MethodDescription;
|
||||
import net.bytebuddy.matcher.ElementMatcher;
|
||||
|
||||
import org.apache.http.HttpHost;
|
||||
import org.apache.http.HttpRequest;
|
||||
import org.apache.http.protocol.HttpContext;
|
||||
|
||||
import static net.bytebuddy.matcher.ElementMatchers.named;
|
||||
|
||||
/**
|
||||
* {@link AbstractHttpClientInstrumentation} presents that skywalking intercepts
|
||||
* {@link org.apache.http.impl.client.AbstractHttpClient#doExecute(HttpHost, HttpRequest, HttpContext)}
|
||||
* by using {@link HttpClientInstrumentation#INTERCEPT_CLASS}.
|
||||
*
|
||||
* @author zhangxin
|
||||
*/
|
||||
public class AbstractHttpClientInstrumentation extends HttpClientInstrumentation {
|
||||
|
||||
private static final String ENHANCE_CLASS = "org.apache.http.impl.client.AbstractHttpClient";
|
||||
|
||||
@Override
|
||||
public String enhanceClassName() {
|
||||
return ENHANCE_CLASS;
|
||||
}
|
||||
|
||||
/**
|
||||
* version 4.2, intercept method: execute, intercept<br/>
|
||||
* public final HttpResponse execute(HttpHost target, HttpRequest request,
|
||||
* HttpContext context)<br/>
|
||||
*/
|
||||
@Override
|
||||
protected InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
|
||||
return new InstanceMethodsInterceptPoint[]{new InstanceMethodsInterceptPoint() {
|
||||
@Override
|
||||
public ElementMatcher<MethodDescription> getMethodsMatcher() {
|
||||
return named("doExecute");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMethodsInterceptor() {
|
||||
return getInstanceMethodsInterceptor();
|
||||
}
|
||||
}};
|
||||
}
|
||||
}
|
||||
|
|
@ -1,12 +1,31 @@
|
|||
package com.a.eye.skywalking.api.plugin.httpClient.v4.define;
|
||||
package com.a.eye.skywalking.plugin.httpClient.v4.define;
|
||||
|
||||
|
||||
import com.a.eye.skywalking.api.plugin.interceptor.InstanceMethodsInterceptPoint;
|
||||
|
||||
import net.bytebuddy.description.method.MethodDescription;
|
||||
import net.bytebuddy.matcher.ElementMatcher;
|
||||
|
||||
import org.apache.http.HttpHost;
|
||||
import org.apache.http.HttpRequest;
|
||||
import org.apache.http.protocol.HttpContext;
|
||||
|
||||
import static net.bytebuddy.matcher.ElementMatchers.named;
|
||||
|
||||
public class DefaultRequestDirectorPluginDefine extends HttpClientPluginDefine {
|
||||
/**
|
||||
* {@link AbstractHttpClientInstrumentation} presents that skywalking intercepts
|
||||
* {@link org.apache.http.impl.client.DefaultRequestDirector#execute(HttpHost, HttpRequest, HttpContext)}
|
||||
* by using {@link HttpClientInstrumentation#INTERCEPT_CLASS}.
|
||||
*
|
||||
* @author zhangxin
|
||||
*/
|
||||
public class DefaultRequestDirectorInstrumentation extends HttpClientInstrumentation {
|
||||
|
||||
/**
|
||||
* Enhance class.
|
||||
*/
|
||||
private static final String enhanceClass = "org.apache.http.impl.client.DefaultRequestDirector";
|
||||
|
||||
/**
|
||||
* DefaultRequestDirector is default implement.<br/>
|
||||
* usually use in version 4.0-4.2<br/>
|
||||
|
|
@ -14,12 +33,12 @@ public class DefaultRequestDirectorPluginDefine extends HttpClientPluginDefine {
|
|||
*/
|
||||
@Override
|
||||
public String enhanceClassName() {
|
||||
return "org.apache.http.impl.client.DefaultRequestDirector";
|
||||
return enhanceClass;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
|
||||
return new InstanceMethodsInterceptPoint[] {new InstanceMethodsInterceptPoint() {
|
||||
return new InstanceMethodsInterceptPoint[]{new InstanceMethodsInterceptPoint() {
|
||||
@Override
|
||||
public ElementMatcher<MethodDescription> getMethodsMatcher() {
|
||||
return named("execute");
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
package com.a.eye.skywalking.plugin.httpClient.v4.define;
|
||||
|
||||
|
||||
import com.a.eye.skywalking.api.plugin.interceptor.ConstructorInterceptPoint;
|
||||
import com.a.eye.skywalking.api.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine;
|
||||
|
||||
/**
|
||||
* {@link HttpClientInstrumentation} present that skywalking intercepts {@link HttpClientInstrumentation#enhanceClassName()}
|
||||
* by using {@link com.a.eye.skywalking.plugin.httpClient.v4.HttpClientExecuteInterceptor}
|
||||
*
|
||||
* @author zhangxin
|
||||
*/
|
||||
public abstract class HttpClientInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
|
||||
|
||||
private static final String INTERCEPT_CLASS = "com.a.eye.skywalking.plugin.httpClient.v4.HttpClientExecuteInterceptor";
|
||||
|
||||
@Override
|
||||
protected ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
|
||||
return null;
|
||||
}
|
||||
|
||||
protected String getInstanceMethodsInterceptor() {
|
||||
return INTERCEPT_CLASS;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,15 +1,30 @@
|
|||
package com.a.eye.skywalking.api.plugin.httpClient.v4.define;
|
||||
package com.a.eye.skywalking.plugin.httpClient.v4.define;
|
||||
|
||||
|
||||
import com.a.eye.skywalking.api.plugin.interceptor.InstanceMethodsInterceptPoint;
|
||||
|
||||
import net.bytebuddy.description.method.MethodDescription;
|
||||
import net.bytebuddy.matcher.ElementMatcher;
|
||||
|
||||
import org.apache.http.HttpHost;
|
||||
import org.apache.http.HttpRequest;
|
||||
import org.apache.http.protocol.HttpContext;
|
||||
|
||||
import static net.bytebuddy.matcher.ElementMatchers.named;
|
||||
|
||||
public class InternalHttpClientPluginDefine extends HttpClientPluginDefine {
|
||||
/**
|
||||
* {@link AbstractHttpClientInstrumentation} presents that skywalking intercepts {@link org.apache.http.impl.client.InternalHttpClient#doExecute(HttpHost, HttpRequest, HttpContext)}
|
||||
* by using {@link HttpClientInstrumentation#INTERCEPT_CLASS}.
|
||||
*
|
||||
* @author zhangxin
|
||||
*/
|
||||
public class InternalHttpClientInstrumentation extends HttpClientInstrumentation {
|
||||
|
||||
private static final String ENHANCE_CLASS = "org.apache.http.impl.client.InternalHttpClient";
|
||||
|
||||
@Override
|
||||
public String enhanceClassName() {
|
||||
return "org.apache.http.impl.client.InternalHttpClient";
|
||||
return ENHANCE_CLASS;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -1,15 +1,31 @@
|
|||
package com.a.eye.skywalking.api.plugin.httpClient.v4.define;
|
||||
package com.a.eye.skywalking.plugin.httpClient.v4.define;
|
||||
|
||||
|
||||
import com.a.eye.skywalking.api.plugin.interceptor.InstanceMethodsInterceptPoint;
|
||||
|
||||
import net.bytebuddy.description.method.MethodDescription;
|
||||
import net.bytebuddy.matcher.ElementMatcher;
|
||||
|
||||
import org.apache.http.HttpHost;
|
||||
import org.apache.http.HttpRequest;
|
||||
import org.apache.http.protocol.HttpContext;
|
||||
|
||||
import static net.bytebuddy.matcher.ElementMatchers.named;
|
||||
|
||||
public class MinimalHttpClientPluginDefine extends HttpClientPluginDefine {
|
||||
/**
|
||||
* {@link AbstractHttpClientInstrumentation} presents that skywalking
|
||||
* intercepts {@link org.apache.http.impl.client.MinimalHttpClient#doExecute(HttpHost, HttpRequest, HttpContext)}
|
||||
* by using {@link HttpClientInstrumentation#INTERCEPT_CLASS}.
|
||||
*
|
||||
* @author zhangxin
|
||||
*/
|
||||
public class MinimalHttpClientInstrumentation extends HttpClientInstrumentation {
|
||||
|
||||
private static final String ENHANCE_CLASS = "org.apache.http.impl.client.MinimalHttpClient";
|
||||
|
||||
@Override
|
||||
public String enhanceClassName() {
|
||||
return "org.apache.http.impl.client.MinimalHttpClient";
|
||||
return ENHANCE_CLASS;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
com.a.eye.skywalking.plugin.httpClient.v4.define.AbstractHttpClientPluginDefine
|
||||
com.a.eye.skywalking.plugin.httpClient.v4.define.InternalHttpClientPluginDefine
|
||||
com.a.eye.skywalking.plugin.httpClient.v4.define.MinimalHttpClientPluginDefine
|
||||
com.a.eye.skywalking.plugin.httpClient.v4.define.DefaultRequestDirectorPluginDefine
|
||||
com.a.eye.skywalking.plugin.httpClient.v4.define.AbstractHttpClientInstrumentation
|
||||
com.a.eye.skywalking.plugin.httpClient.v4.define.InternalHttpClientInstrumentation
|
||||
com.a.eye.skywalking.plugin.httpClient.v4.define.MinimalHttpClientInstrumentation
|
||||
com.a.eye.skywalking.plugin.httpClient.v4.define.DefaultRequestDirectorInstrumentation
|
||||
|
|
|
|||
|
|
@ -1,68 +1,74 @@
|
|||
<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>skywalking-sdk-plugin</artifactId>
|
||||
<groupId>com.a.eye</groupId>
|
||||
<version>3.0-2017</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>skywalking-sdk-plugin</artifactId>
|
||||
<groupId>com.a.eye</groupId>
|
||||
<version>3.0-2017</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>skywalking-jdbc-plugin</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<artifactId>skywalking-jdbc-plugin</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>jdbc-plugin</name>
|
||||
<url>http://maven.apache.org</url>
|
||||
<name>jdbc-plugin</name>
|
||||
<url>http://maven.apache.org</url>
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.a.eye</groupId>
|
||||
<artifactId>skywalking-api</artifactId>
|
||||
<version>3.0-2017</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>mysql</groupId>
|
||||
<artifactId>mysql-connector-java</artifactId>
|
||||
<version>5.1.36</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.oracle</groupId>
|
||||
<artifactId>ojdbc14</artifactId>
|
||||
<version>10.2.0.4.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.h2database</groupId>
|
||||
<artifactId>h2</artifactId>
|
||||
<version>1.4.192</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.a.eye</groupId>
|
||||
<artifactId>skywalking-api</artifactId>
|
||||
<version>3.0-2017</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>mysql</groupId>
|
||||
<artifactId>mysql-connector-java</artifactId>
|
||||
<version>5.1.36</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.oracle</groupId>
|
||||
<artifactId>ojdbc14</artifactId>
|
||||
<version>10.2.0.4.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.h2database</groupId>
|
||||
<artifactId>h2</artifactId>
|
||||
<version>1.4.192</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>mysql</groupId>
|
||||
<artifactId>mysql-connector-java</artifactId>
|
||||
<version>[2.0.14,)</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-deploy-plugin</artifactId>
|
||||
</plugin>
|
||||
<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>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-deploy-plugin</artifactId>
|
||||
</plugin>
|
||||
<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>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
|
|
|
|||
|
|
@ -1,42 +0,0 @@
|
|||
package com.a.eye.skywalking.api.plugin.jdbc;
|
||||
|
||||
import com.a.eye.skywalking.api.plugin.jdbc.define.JDBCBuriedPointType;
|
||||
import com.a.eye.skywalking.invoke.monitor.RPCClientInvokeMonitor;
|
||||
import com.a.eye.skywalking.model.Identification;
|
||||
|
||||
import java.sql.SQLException;
|
||||
|
||||
/**
|
||||
* 连接级追踪,用于追踪用于Connection的操作追踪
|
||||
*
|
||||
* @author wusheng
|
||||
*/
|
||||
public class CallableStatementTracing {
|
||||
private static RPCClientInvokeMonitor rpcClientInvokeMonitor = new RPCClientInvokeMonitor();
|
||||
|
||||
public static <R> R execute(java.sql.CallableStatement realStatement,
|
||||
String connectInfo, String method, String sql, Executable<R> exec)
|
||||
throws SQLException {
|
||||
try {
|
||||
rpcClientInvokeMonitor.beforeInvoke(Identification
|
||||
.newBuilder()
|
||||
.viewPoint(connectInfo)
|
||||
.businessKey(
|
||||
"callableStatement."
|
||||
+ method
|
||||
+ (sql == null || sql.length() == 0 ? ""
|
||||
: ":" + sql)).spanType(JDBCBuriedPointType.INSTANCE).build());
|
||||
return exec.exe(realStatement, sql);
|
||||
} catch (SQLException e) {
|
||||
rpcClientInvokeMonitor.occurException(e);
|
||||
throw e;
|
||||
} finally {
|
||||
rpcClientInvokeMonitor.afterInvoke();
|
||||
}
|
||||
}
|
||||
|
||||
public interface Executable<R> {
|
||||
public R exe(java.sql.CallableStatement realConnection, String sql)
|
||||
throws SQLException;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,42 +0,0 @@
|
|||
package com.a.eye.skywalking.api.plugin.jdbc;
|
||||
|
||||
import com.a.eye.skywalking.api.plugin.jdbc.define.JDBCBuriedPointType;
|
||||
import com.a.eye.skywalking.model.Identification;
|
||||
import com.a.eye.skywalking.invoke.monitor.RPCClientInvokeMonitor;
|
||||
|
||||
import java.sql.SQLException;
|
||||
|
||||
/**
|
||||
* 连接级追踪,用于追踪用于Connection的操作追踪
|
||||
*
|
||||
* @author wusheng
|
||||
*/
|
||||
public class ConnectionTracing {
|
||||
private static RPCClientInvokeMonitor rpcClientInvokeMonitor = new RPCClientInvokeMonitor();
|
||||
|
||||
public static <R> R execute(java.sql.Connection realConnection,
|
||||
String connectInfo, String method, String sql, Executable<R> exec)
|
||||
throws SQLException {
|
||||
try {
|
||||
rpcClientInvokeMonitor.beforeInvoke(Identification
|
||||
.newBuilder()
|
||||
.viewPoint(connectInfo)
|
||||
.businessKey(
|
||||
"connection."
|
||||
+ method
|
||||
+ (sql == null || sql.length() == 0 ? ""
|
||||
: ":" + sql)).spanType(JDBCBuriedPointType.INSTANCE).build());
|
||||
return exec.exe(realConnection, sql);
|
||||
} catch (SQLException e) {
|
||||
rpcClientInvokeMonitor.occurException(e);
|
||||
throw e;
|
||||
} finally {
|
||||
rpcClientInvokeMonitor.afterInvoke();
|
||||
}
|
||||
}
|
||||
|
||||
public interface Executable<R> {
|
||||
public R exe(java.sql.Connection realConnection, String sql)
|
||||
throws SQLException;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,36 +0,0 @@
|
|||
package com.a.eye.skywalking.api.plugin.jdbc;
|
||||
|
||||
import com.a.eye.skywalking.api.context.ContextManager;
|
||||
import com.a.eye.skywalking.trace.Span;
|
||||
import com.a.eye.skywalking.trace.tag.Tags;
|
||||
import java.sql.SQLException;
|
||||
|
||||
/**
|
||||
* 连接级追踪,用于追踪用于Connection的操作追踪
|
||||
*
|
||||
* @author wusheng
|
||||
*/
|
||||
public class PreparedStatementTracing {
|
||||
|
||||
public static <R> R execute(java.sql.PreparedStatement realStatement,
|
||||
String connectInfo, String method, String sql, Executable<R> exec)
|
||||
throws SQLException {
|
||||
Span span = ContextManager.INSTANCE.createSpan("JDBC/PreparedStatement/" + method);
|
||||
try {
|
||||
Tags.SPAN_LAYER.asRDB(span);
|
||||
Tags.DB_URL.set(span, connectInfo);
|
||||
Tags.DB_STATEMENT.set(span, sql);
|
||||
return exec.exe(realStatement, sql);
|
||||
} catch (SQLException e) {
|
||||
span.log(e);
|
||||
throw e;
|
||||
} finally {
|
||||
ContextManager.INSTANCE.stopSpan(span);
|
||||
}
|
||||
}
|
||||
|
||||
public interface Executable<R> {
|
||||
R exe(java.sql.PreparedStatement realConnection, String sql)
|
||||
throws SQLException;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,42 +0,0 @@
|
|||
package com.a.eye.skywalking.api.plugin.jdbc;
|
||||
|
||||
import com.a.eye.skywalking.api.plugin.jdbc.define.JDBCBuriedPointType;
|
||||
import com.a.eye.skywalking.model.Identification;
|
||||
import com.a.eye.skywalking.invoke.monitor.RPCClientInvokeMonitor;
|
||||
|
||||
import java.sql.SQLException;
|
||||
|
||||
/**
|
||||
* 连接级追踪,用于追踪用于Statement的操作追踪
|
||||
*
|
||||
* @author wusheng
|
||||
*/
|
||||
public class StatementTracing {
|
||||
private static RPCClientInvokeMonitor rpcClientInvokeMonitor = new RPCClientInvokeMonitor();
|
||||
|
||||
public static <R> R execute(java.sql.Statement realStatement,
|
||||
String connectInfo, String method, String sql, Executable<R> exec)
|
||||
throws SQLException {
|
||||
try {
|
||||
rpcClientInvokeMonitor.beforeInvoke(Identification
|
||||
.newBuilder()
|
||||
.viewPoint(connectInfo)
|
||||
.businessKey(
|
||||
"statement."
|
||||
+ method
|
||||
+ (sql == null || sql.length() == 0 ? ""
|
||||
: ":" + sql)).spanType(JDBCBuriedPointType.INSTANCE).build());
|
||||
return exec.exe(realStatement, sql);
|
||||
} catch (SQLException e) {
|
||||
rpcClientInvokeMonitor.occurException(e);
|
||||
throw e;
|
||||
} finally {
|
||||
rpcClientInvokeMonitor.afterInvoke();
|
||||
}
|
||||
}
|
||||
|
||||
public interface Executable<R> {
|
||||
public R exe(java.sql.Statement realStatement, String sql)
|
||||
throws SQLException;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,32 +0,0 @@
|
|||
package com.a.eye.skywalking.api.plugin.jdbc.define;
|
||||
|
||||
import com.a.eye.skywalking.api.plugin.interceptor.ConstructorInterceptPoint;
|
||||
import com.a.eye.skywalking.api.plugin.interceptor.InstanceMethodsInterceptPoint;
|
||||
import com.a.eye.skywalking.plugin.interceptor.ConstructorInterceptPoint;
|
||||
import com.a.eye.skywalking.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine;
|
||||
import net.bytebuddy.description.method.MethodDescription;
|
||||
import net.bytebuddy.matcher.ElementMatcher;
|
||||
|
||||
import static net.bytebuddy.matcher.ElementMatchers.named;
|
||||
|
||||
public abstract class AbstractDatabasePluginDefine extends ClassInstanceMethodsEnhancePluginDefine {
|
||||
@Override
|
||||
protected ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
|
||||
return new InstanceMethodsInterceptPoint[]{new InstanceMethodsInterceptPoint() {
|
||||
@Override
|
||||
public ElementMatcher<MethodDescription> getMethodsMatcher() {
|
||||
return named("connect");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMethodsInterceptor() {
|
||||
return "com.a.eye.skywalking.plugin.jdbc.define.JDBCDriverInterceptor";
|
||||
}
|
||||
}};
|
||||
}
|
||||
}
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
package com.a.eye.skywalking.api.plugin.jdbc.define;
|
||||
|
||||
public class H2PluginDefine extends AbstractDatabasePluginDefine {
|
||||
@Override
|
||||
protected String enhanceClassName() {
|
||||
return "org.h2.Driver";
|
||||
}
|
||||
}
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
package com.a.eye.skywalking.api.plugin.jdbc.define;
|
||||
|
||||
import com.a.eye.skywalking.api.IBuriedPointType;
|
||||
|
||||
public enum JDBCBuriedPointType implements IBuriedPointType {
|
||||
|
||||
INSTANCE;
|
||||
|
||||
@Override
|
||||
public String getTypeName() {
|
||||
return "J";
|
||||
}
|
||||
|
||||
@Override
|
||||
public CallType getCallType() {
|
||||
return CallType.LOCAL;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
package com.a.eye.skywalking.api.plugin.jdbc.define;
|
||||
|
||||
/**
|
||||
* Created by xin on 16/8/4.
|
||||
*/
|
||||
public class MysqlPluginDefine extends AbstractDatabasePluginDefine {
|
||||
@Override
|
||||
protected String enhanceClassName() {
|
||||
return "com.mysql.jdbc.Driver";
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
package com.a.eye.skywalking.api.plugin.jdbc.define;
|
||||
|
||||
/**
|
||||
* Created by xin on 16/8/4.
|
||||
*/
|
||||
public class OraclePluginDefine extends AbstractDatabasePluginDefine {
|
||||
@Override
|
||||
protected String enhanceClassName() {
|
||||
return "oracle.jdbc.OracleDriver";
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
package com.a.eye.skywalking.plugin.jdbc;
|
||||
|
||||
|
||||
import com.a.eye.skywalking.api.context.ContextManager;
|
||||
import com.a.eye.skywalking.api.util.StringUtil;
|
||||
import com.a.eye.skywalking.trace.Span;
|
||||
import com.a.eye.skywalking.trace.tag.Tags;
|
||||
|
||||
import java.sql.SQLException;
|
||||
|
||||
/**
|
||||
* {@link CallableStatementTracing} create span with the {@link Span#operationName} start with
|
||||
* "JDBC/CallableStatement/"and set {@link ConnectionInfo#dbType} to the {@link Tags#COMPONENT}.
|
||||
*
|
||||
* Notice: {@link Tags#PEERS} may be is null if database connection url don't contain multiple hosts.
|
||||
*
|
||||
* @author zhangxin
|
||||
*/
|
||||
public class CallableStatementTracing {
|
||||
|
||||
public static <R> R execute(java.sql.CallableStatement realStatement,
|
||||
ConnectionInfo connectInfo, String method, String sql, Executable<R> exec)
|
||||
throws SQLException {
|
||||
try {
|
||||
Span span = ContextManager.INSTANCE.createSpan("JDBC/CallableStatement/" + method);
|
||||
Tags.DB_TYPE.set(span, "sql");
|
||||
Tags.DB_INSTANCE.set(span, connectInfo.getDatabaseName());
|
||||
Tags.DB_STATEMENT.set(span, sql);
|
||||
Tags.COMPONENT.set(span, connectInfo.getDBType());
|
||||
if (!StringUtil.isEmpty(connectInfo.getHosts())) {
|
||||
Tags.PEERS.set(span, connectInfo.getHosts());
|
||||
} else {
|
||||
Tags.PEER_PORT.set(span, connectInfo.getPort());
|
||||
Tags.PEER_HOST.set(span, connectInfo.getHost());
|
||||
}
|
||||
return exec.exe(realStatement, sql);
|
||||
} catch (SQLException e) {
|
||||
Span span = ContextManager.INSTANCE.activeSpan();
|
||||
Tags.ERROR.set(span, true);
|
||||
span.log(e);
|
||||
throw e;
|
||||
} finally {
|
||||
ContextManager.INSTANCE.stopSpan();
|
||||
}
|
||||
}
|
||||
|
||||
public interface Executable<R> {
|
||||
R exe(java.sql.CallableStatement realConnection, String sql)
|
||||
throws SQLException;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
package com.a.eye.skywalking.plugin.jdbc;
|
||||
|
||||
/**
|
||||
* {@link ConnectionInfo} stored the jdbc connection info, the connection info contains db type, host, port, database name.
|
||||
* The {@link #hosts} be null if {@link #host} is not null.
|
||||
*
|
||||
* @author zhangxin
|
||||
*/
|
||||
public class ConnectionInfo {
|
||||
/**
|
||||
* DB type, such as mysql, oracle, h2.
|
||||
*/
|
||||
private final String dbType;
|
||||
/**
|
||||
* Database host name.
|
||||
*/
|
||||
private String host;
|
||||
/**
|
||||
* Database port.
|
||||
*/
|
||||
private int port;
|
||||
/**
|
||||
* Operation database name.
|
||||
*/
|
||||
private final String databaseName;
|
||||
/**
|
||||
* Database hosts.
|
||||
*/
|
||||
private String hosts;
|
||||
|
||||
public ConnectionInfo(String dbType, String host, int port, String databaseName) {
|
||||
this.dbType = dbType;
|
||||
this.host = host;
|
||||
this.port = port;
|
||||
this.databaseName = databaseName;
|
||||
}
|
||||
|
||||
public ConnectionInfo(String dbType, String hosts, String databaseName) {
|
||||
this.dbType = dbType;
|
||||
this.hosts = hosts;
|
||||
this.databaseName = databaseName;
|
||||
}
|
||||
|
||||
public String getDBType() {
|
||||
return dbType;
|
||||
}
|
||||
|
||||
public String getHost() {
|
||||
return host;
|
||||
}
|
||||
|
||||
public int getPort() {
|
||||
return port;
|
||||
}
|
||||
|
||||
public String getDatabaseName() {
|
||||
return databaseName;
|
||||
}
|
||||
|
||||
public String getHosts() {
|
||||
return hosts;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
package com.a.eye.skywalking.plugin.jdbc;
|
||||
|
||||
|
||||
import com.a.eye.skywalking.api.context.ContextManager;
|
||||
import com.a.eye.skywalking.api.util.StringUtil;
|
||||
import com.a.eye.skywalking.trace.Span;
|
||||
import com.a.eye.skywalking.trace.tag.Tags;
|
||||
|
||||
import java.sql.SQLException;
|
||||
|
||||
/**
|
||||
* {@link ConnectionTracing} create span with the {@link Span#operationName} start with
|
||||
* "JDBC/Connection/"and set {@link ConnectionInfo#dbType} to the {@link Tags#COMPONENT}.
|
||||
*
|
||||
* Notice: {@link Tags#PEERS} may be is null if database connection url don't contain multiple hosts.
|
||||
*
|
||||
* @author zhangxin
|
||||
*/
|
||||
public class ConnectionTracing {
|
||||
|
||||
public static <R> R execute(java.sql.Connection realConnection,
|
||||
ConnectionInfo connectInfo, String method, String sql, Executable<R> exec)
|
||||
throws SQLException {
|
||||
try {
|
||||
Span span = ContextManager.INSTANCE.createSpan("JDBC/Connection/" + method);
|
||||
Tags.DB_TYPE.set(span, "sql");
|
||||
Tags.DB_INSTANCE.set(span, connectInfo.getDatabaseName());
|
||||
Tags.DB_STATEMENT.set(span, sql);
|
||||
Tags.COMPONENT.set(span, connectInfo.getDBType());
|
||||
if (!StringUtil.isEmpty(connectInfo.getHosts())) {
|
||||
Tags.PEERS.set(span, connectInfo.getHosts());
|
||||
} else {
|
||||
Tags.PEER_PORT.set(span, connectInfo.getPort());
|
||||
Tags.PEER_HOST.set(span, connectInfo.getHost());
|
||||
}
|
||||
return exec.exe(realConnection, sql);
|
||||
} catch (SQLException e) {
|
||||
Span span = ContextManager.INSTANCE.activeSpan();
|
||||
Tags.ERROR.set(span, true);
|
||||
span.log(e);
|
||||
throw e;
|
||||
} finally {
|
||||
ContextManager.INSTANCE.stopSpan();
|
||||
}
|
||||
}
|
||||
|
||||
public interface Executable<R> {
|
||||
R exe(java.sql.Connection realConnection, String sql)
|
||||
throws SQLException;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
package com.a.eye.skywalking.plugin.jdbc;
|
||||
|
||||
import com.a.eye.skywalking.api.context.ContextManager;
|
||||
import com.a.eye.skywalking.api.util.StringUtil;
|
||||
import com.a.eye.skywalking.trace.Span;
|
||||
import com.a.eye.skywalking.trace.tag.Tags;
|
||||
|
||||
import java.sql.SQLException;
|
||||
|
||||
/**
|
||||
* {@link PreparedStatementTracing} create span with the {@link Span#operationName} start with
|
||||
* "JDBC/PreparedStatement/"and set {@link ConnectionInfo#dbType} to the {@link Tags#COMPONENT}.
|
||||
*
|
||||
* Notice: {@link Tags#PEERS} may be is null if database connection url don't contain multiple hosts.
|
||||
*
|
||||
* @author zhangxin
|
||||
*/
|
||||
public class PreparedStatementTracing {
|
||||
|
||||
public static <R> R execute(java.sql.PreparedStatement realStatement,
|
||||
ConnectionInfo connectInfo, String method, String sql, Executable<R> exec)
|
||||
throws SQLException {
|
||||
try {
|
||||
Span span = ContextManager.INSTANCE.createSpan("JDBC/PreparedStatement/" + method);
|
||||
Tags.DB_TYPE.set(span, "sql");
|
||||
Tags.DB_INSTANCE.set(span, connectInfo.getDatabaseName());
|
||||
Tags.DB_STATEMENT.set(span, sql);
|
||||
Tags.COMPONENT.set(span, connectInfo.getDBType());
|
||||
if (!StringUtil.isEmpty(connectInfo.getHosts())) {
|
||||
Tags.PEERS.set(span, connectInfo.getHosts());
|
||||
} else {
|
||||
Tags.PEER_PORT.set(span, connectInfo.getPort());
|
||||
Tags.PEER_HOST.set(span, connectInfo.getHost());
|
||||
}
|
||||
return exec.exe(realStatement, sql);
|
||||
} catch (SQLException e) {
|
||||
Span span = ContextManager.INSTANCE.activeSpan();
|
||||
Tags.ERROR.set(span, true);
|
||||
span.log(e);
|
||||
throw e;
|
||||
} finally {
|
||||
ContextManager.INSTANCE.stopSpan();
|
||||
}
|
||||
}
|
||||
|
||||
public interface Executable<R> {
|
||||
R exe(java.sql.PreparedStatement realConnection, String sql)
|
||||
throws SQLException;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package com.a.eye.skywalking.api.plugin.jdbc;
|
||||
package com.a.eye.skywalking.plugin.jdbc;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.Reader;
|
||||
|
|
@ -11,11 +11,11 @@ import java.util.Map;
|
|||
public class SWCallableStatement implements CallableStatement {
|
||||
private Connection realConnection;
|
||||
private CallableStatement realStatement;
|
||||
private String connectInfo;
|
||||
private ConnectionInfo connectInfo;
|
||||
private String sql;
|
||||
|
||||
SWCallableStatement(Connection realConnection,
|
||||
CallableStatement realStatement, String connectInfo,
|
||||
CallableStatement realStatement, ConnectionInfo connectInfo,
|
||||
String sql) {
|
||||
this.realConnection = realConnection;
|
||||
this.realStatement = realStatement;
|
||||
|
|
@ -1,19 +1,33 @@
|
|||
package com.a.eye.skywalking.api.plugin.jdbc;
|
||||
package com.a.eye.skywalking.plugin.jdbc;
|
||||
|
||||
import java.sql.*;
|
||||
import com.a.eye.skywalking.plugin.jdbc.connectionurl.parser.URLParser;
|
||||
|
||||
import java.sql.Array;
|
||||
import java.sql.Blob;
|
||||
import java.sql.CallableStatement;
|
||||
import java.sql.Clob;
|
||||
import java.sql.Connection;
|
||||
import java.sql.DatabaseMetaData;
|
||||
import java.sql.NClob;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLClientInfoException;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.SQLWarning;
|
||||
import java.sql.SQLXML;
|
||||
import java.sql.Savepoint;
|
||||
import java.sql.Statement;
|
||||
import java.sql.Struct;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
public class SWConnection implements java.sql.Connection {
|
||||
private String connectInfo;
|
||||
public class SWConnection implements Connection {
|
||||
private ConnectionInfo connectInfo;
|
||||
private final Connection realConnection;
|
||||
|
||||
private final java.sql.Connection realConnection;
|
||||
|
||||
public SWConnection(String url, Properties info,
|
||||
java.sql.Connection realConnection) {
|
||||
public SWConnection(String url, Properties info, Connection realConnection) {
|
||||
super();
|
||||
this.connectInfo = url + "(" + info.getProperty("user") + ")";
|
||||
this.connectInfo = URLParser.parser(url);
|
||||
this.realConnection = realConnection;
|
||||
}
|
||||
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package com.a.eye.skywalking.api.plugin.jdbc;
|
||||
package com.a.eye.skywalking.plugin.jdbc;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.Reader;
|
||||
|
|
@ -10,11 +10,11 @@ import java.util.Calendar;
|
|||
public class SWPreparedStatement implements PreparedStatement {
|
||||
private Connection realConnection;
|
||||
private PreparedStatement realStatement;
|
||||
private String connectInfo;
|
||||
private ConnectionInfo connectInfo;
|
||||
private String sql;
|
||||
|
||||
SWPreparedStatement(Connection realConnection,
|
||||
PreparedStatement realStatement, String connectInfo,
|
||||
PreparedStatement realStatement, ConnectionInfo connectInfo,
|
||||
String sql) {
|
||||
this.realConnection = realConnection;
|
||||
this.realStatement = realStatement;
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package com.a.eye.skywalking.api.plugin.jdbc;
|
||||
package com.a.eye.skywalking.plugin.jdbc;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.ResultSet;
|
||||
|
|
@ -9,9 +9,9 @@ import java.sql.SQLWarning;
|
|||
public class SWStatement implements java.sql.Statement {
|
||||
private Connection realConnection;
|
||||
private java.sql.Statement realStatement;
|
||||
private String connectInfo;
|
||||
private ConnectionInfo connectInfo;
|
||||
|
||||
SWStatement(Connection realConnection, java.sql.Statement realStatement, String connectInfo) {
|
||||
SWStatement(Connection realConnection, java.sql.Statement realStatement, ConnectionInfo connectInfo) {
|
||||
this.realConnection = realConnection;
|
||||
this.realStatement = realStatement;
|
||||
this.connectInfo = connectInfo;
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
package com.a.eye.skywalking.plugin.jdbc;
|
||||
|
||||
|
||||
import com.a.eye.skywalking.api.context.ContextManager;
|
||||
import com.a.eye.skywalking.api.util.StringUtil;
|
||||
import com.a.eye.skywalking.trace.Span;
|
||||
import com.a.eye.skywalking.trace.tag.Tags;
|
||||
|
||||
import java.sql.SQLException;
|
||||
|
||||
/**
|
||||
* {@link StatementTracing} create span with the {@link Span#operationName} start with
|
||||
* "JDBC/Statement/"and set {@link ConnectionInfo#dbType} to the {@link Tags#COMPONENT}.
|
||||
*
|
||||
* Notice: {@link Tags#PEERS} may be is null if database connection url don't contain multiple hosts.
|
||||
*
|
||||
* @author zhangxin
|
||||
*/
|
||||
public class StatementTracing {
|
||||
public static <R> R execute(java.sql.Statement realStatement,
|
||||
ConnectionInfo connectInfo, String method, String sql, Executable<R> exec)
|
||||
throws SQLException {
|
||||
try {
|
||||
Span span = ContextManager.INSTANCE.createSpan("JDBC/Statement/" + method);
|
||||
Tags.DB_TYPE.set(span, "sql");
|
||||
Tags.DB_INSTANCE.set(span, connectInfo.getDatabaseName());
|
||||
Tags.DB_STATEMENT.set(span, sql);
|
||||
Tags.COMPONENT.set(span, connectInfo.getDBType());
|
||||
if (!StringUtil.isEmpty(connectInfo.getHosts())) {
|
||||
Tags.PEERS.set(span, connectInfo.getHosts());
|
||||
} else {
|
||||
Tags.PEER_PORT.set(span, connectInfo.getPort());
|
||||
Tags.PEER_HOST.set(span, connectInfo.getHost());
|
||||
}
|
||||
return exec.exe(realStatement, sql);
|
||||
} catch (SQLException e) {
|
||||
Span span = ContextManager.INSTANCE.activeSpan();
|
||||
Tags.ERROR.set(span, true);
|
||||
span.log(e);
|
||||
throw e;
|
||||
} finally {
|
||||
ContextManager.INSTANCE.stopSpan();
|
||||
}
|
||||
}
|
||||
|
||||
public interface Executable<R> {
|
||||
R exe(java.sql.Statement realStatement, String sql)
|
||||
throws SQLException;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
package com.a.eye.skywalking.plugin.jdbc.connectionurl.parser;
|
||||
|
||||
public abstract class AbstractURLParser implements ConnectionURLParser {
|
||||
|
||||
protected String url;
|
||||
|
||||
public AbstractURLParser(String url) {
|
||||
this.url = url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch the index range that database host and port from connection url.
|
||||
*
|
||||
* @return index range that database hosts.
|
||||
*/
|
||||
protected abstract int[] fetchDatabaseHostsIndexRange();
|
||||
|
||||
/**
|
||||
* Fetch the index range that database name from connection url.
|
||||
*
|
||||
* @return index range that database name.
|
||||
*/
|
||||
protected abstract int[] fetchDatabaseNameIndexRange();
|
||||
|
||||
/**
|
||||
* Fetch database host(s) from connection url.
|
||||
*
|
||||
* @return database host(s).
|
||||
*/
|
||||
protected String fetchDatabaseHostsFromURL() {
|
||||
int[] indexRange = fetchDatabaseHostsIndexRange();
|
||||
return url.substring(indexRange[0], indexRange[1]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch database name from connection url.
|
||||
*
|
||||
* @return database name.
|
||||
*/
|
||||
protected String fetchDatabaseNameFromURL() {
|
||||
int[] indexRange = fetchDatabaseNameIndexRange();
|
||||
return url.substring(indexRange[0], indexRange[1]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch database name from connection url.
|
||||
*
|
||||
* @return database name.
|
||||
*/
|
||||
protected String fetchDatabaseNameFromURL(int[] indexRange) {
|
||||
return url.substring(indexRange[0], indexRange[1]);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
package com.a.eye.skywalking.plugin.jdbc.connectionurl.parser;
|
||||
|
||||
import com.a.eye.skywalking.plugin.jdbc.ConnectionInfo;
|
||||
|
||||
|
||||
public interface ConnectionURLParser {
|
||||
/**
|
||||
* {@link ConnectionURLParser} parses database name and the database host(s) from connection url.
|
||||
*
|
||||
* @return connection info.
|
||||
*/
|
||||
ConnectionInfo parse();
|
||||
}
|
||||
|
|
@ -0,0 +1,112 @@
|
|||
package com.a.eye.skywalking.plugin.jdbc.connectionurl.parser;
|
||||
|
||||
import com.a.eye.skywalking.plugin.jdbc.ConnectionInfo;
|
||||
|
||||
/**
|
||||
* {@link H2URLParser} presents that skywalking how to parse the connection url of H2 database.
|
||||
* {@link ConnectionInfo#host} will return localhost and {@link ConnectionInfo#port} will return
|
||||
* -1 if H2 running with memory mode or file mode, or it will return the host and the port.
|
||||
*
|
||||
* {@link H2URLParser} check the connection url if contains "file" or "mem". if yes. the database
|
||||
* name substring the connection url from the index after "file" index or the "mem" index to the
|
||||
* index of first charset ";".
|
||||
*
|
||||
* The {@link ConnectionInfo#host} be set the string between charset "//" and the first charset "/" after
|
||||
* the charset "//", and {@link ConnectionInfo#databaseName} be set the string between the last index of "/" and
|
||||
* the first charset ";".
|
||||
*
|
||||
* @author zhangxin
|
||||
*/
|
||||
public class H2URLParser extends AbstractURLParser {
|
||||
|
||||
private static final String LOCALHOST = "localhost";
|
||||
private static final int DEFAULT_PORT = 8084;
|
||||
/**
|
||||
* Flag that H2 running with file mode.
|
||||
*/
|
||||
private static final String FILE_MODE_FLAG = "file";
|
||||
/**
|
||||
* Flag that H2 running with memory mode.
|
||||
*/
|
||||
private static final String MEMORY_MODE_FLAG = "mem";
|
||||
private static final String H2_DB_TYPE = "H2";
|
||||
|
||||
public H2URLParser(String url) {
|
||||
super(url);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int[] fetchDatabaseHostsIndexRange() {
|
||||
int hostLabelStartIndex = url.indexOf("//");
|
||||
int hostLabelEndIndex = url.indexOf("/", hostLabelStartIndex + 2);
|
||||
return new int[]{hostLabelStartIndex + 2, hostLabelEndIndex};
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int[] fetchDatabaseNameIndexRange() {
|
||||
int databaseStartTag = url.lastIndexOf("/");
|
||||
int databaseEndTag = url.indexOf(";");
|
||||
if (databaseEndTag == -1) {
|
||||
databaseEndTag = url.length();
|
||||
}
|
||||
return new int[]{databaseStartTag + 1, databaseEndTag};
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConnectionInfo parse() {
|
||||
int[] databaseNameRangeIndex = fetchDatabaseNameRangeIndexFromURLForH2FileMode();
|
||||
if (databaseNameRangeIndex != null) {
|
||||
return new ConnectionInfo(H2_DB_TYPE, LOCALHOST, -1, fetchDatabaseNameFromURL(databaseNameRangeIndex));
|
||||
}
|
||||
|
||||
databaseNameRangeIndex = fetchDatabaseNameRangeIndexFromURLForH2MemMode();
|
||||
if (databaseNameRangeIndex != null) {
|
||||
return new ConnectionInfo(H2_DB_TYPE, LOCALHOST, -1, fetchDatabaseNameFromURL(databaseNameRangeIndex));
|
||||
}
|
||||
|
||||
String[] hostAndPort = fetchDatabaseHostsFromURL().split(":");
|
||||
if (hostAndPort.length == 1) {
|
||||
return new ConnectionInfo(H2_DB_TYPE, hostAndPort[0], DEFAULT_PORT, fetchDatabaseNameFromURL());
|
||||
} else {
|
||||
return new ConnectionInfo(H2_DB_TYPE, hostAndPort[0], Integer.valueOf(hostAndPort[1]), fetchDatabaseNameFromURL());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch range index that the database name from connection url if H2 database running with file mode.
|
||||
*
|
||||
* @return range index that the database name.
|
||||
*/
|
||||
private int[] fetchDatabaseNameRangeIndexFromURLForH2FileMode() {
|
||||
int fileLabelIndex = url.indexOf(FILE_MODE_FLAG);
|
||||
int parameterLabelIndex = url.indexOf(";", fileLabelIndex);
|
||||
if (parameterLabelIndex == -1) {
|
||||
parameterLabelIndex = url.length();
|
||||
}
|
||||
|
||||
if (fileLabelIndex != -1) {
|
||||
return new int[]{fileLabelIndex + FILE_MODE_FLAG.length() + 1, parameterLabelIndex};
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch range index that the database name from connection url if H2 database running with memory mode.
|
||||
*
|
||||
* @return range index that the database name.
|
||||
*/
|
||||
private int[] fetchDatabaseNameRangeIndexFromURLForH2MemMode() {
|
||||
int fileLabelIndex = url.indexOf(MEMORY_MODE_FLAG);
|
||||
int parameterLabelIndex = url.indexOf(";", fileLabelIndex);
|
||||
if (parameterLabelIndex == -1) {
|
||||
parameterLabelIndex = url.length();
|
||||
}
|
||||
|
||||
if (fileLabelIndex != -1) {
|
||||
return new int[]{fileLabelIndex + MEMORY_MODE_FLAG.length() + 1, parameterLabelIndex};
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
package com.a.eye.skywalking.plugin.jdbc.connectionurl.parser;
|
||||
|
||||
import com.a.eye.skywalking.plugin.jdbc.ConnectionInfo;
|
||||
|
||||
/**
|
||||
* {@link MysqlURLParser} parse connection url of mysql.
|
||||
*
|
||||
* The {@link ConnectionInfo#host} be set the string between charset "//" and the first
|
||||
* charset "/" after the charset "//", and {@link ConnectionInfo#databaseName} be set the
|
||||
* string between the last index of "/" and the first charset "?". but one more thing, the
|
||||
* {@link ConnectionInfo#hosts} be set if the host container multiple host.
|
||||
*
|
||||
* @author zhangxin
|
||||
*/
|
||||
public class MysqlURLParser extends AbstractURLParser {
|
||||
|
||||
private static final int DEFAULT_PORT = 3306;
|
||||
private static final String DB_TYPE = "Mysql";
|
||||
|
||||
public MysqlURLParser(String url) {
|
||||
super(url);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int[] fetchDatabaseHostsIndexRange() {
|
||||
int hostLabelStartIndex = url.indexOf("//");
|
||||
int hostLabelEndIndex = url.indexOf("/", hostLabelStartIndex + 2);
|
||||
return new int[]{hostLabelStartIndex + 2, hostLabelEndIndex};
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int[] fetchDatabaseNameIndexRange() {
|
||||
int databaseStartTag = url.lastIndexOf("/");
|
||||
int databaseEndTag = url.indexOf("?", databaseStartTag);
|
||||
if (databaseEndTag == -1) {
|
||||
databaseEndTag = url.length();
|
||||
}
|
||||
return new int[]{databaseStartTag + 1, databaseEndTag};
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConnectionInfo parse() {
|
||||
int[] hostRangeIndex = fetchDatabaseHostsIndexRange();
|
||||
String hosts = url.substring(hostRangeIndex[0], hostRangeIndex[1]);
|
||||
String[] hostSegment = hosts.split(",");
|
||||
if (hostSegment.length > 1) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (String host : hostSegment) {
|
||||
if (host.split(":").length == 1) {
|
||||
sb.append(host + ":" + DEFAULT_PORT + ",");
|
||||
} else {
|
||||
sb.append(host + ",");
|
||||
}
|
||||
}
|
||||
return new ConnectionInfo(DB_TYPE, sb.toString(), fetchDatabaseNameFromURL());
|
||||
} else {
|
||||
String[] hostAndPort = hostSegment[0].split(":");
|
||||
if (hostAndPort.length != 1) {
|
||||
return new ConnectionInfo(DB_TYPE, hostAndPort[0], Integer.valueOf(hostAndPort[1]), fetchDatabaseNameFromURL());
|
||||
} else {
|
||||
return new ConnectionInfo(DB_TYPE, hostAndPort[0], DEFAULT_PORT, fetchDatabaseNameFromURL());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
package com.a.eye.skywalking.plugin.jdbc.connectionurl.parser;
|
||||
|
||||
import com.a.eye.skywalking.plugin.jdbc.ConnectionInfo;
|
||||
|
||||
/**
|
||||
* {@link OracleURLParser} presents that how to parse oracle connection url.
|
||||
*
|
||||
* The {@link ConnectionInfo#host} be set the string between charset "@" and the last
|
||||
* charset ":" after the charset "@", and {@link ConnectionInfo#databaseName} be set the
|
||||
* string that after the last index of ":".
|
||||
*
|
||||
* Note: {@link OracleURLParser} can parse the commons connection url. the commons
|
||||
* connection url is of the form: <code>jdbc:oracle:<drivertype>:@<database></code>,the other
|
||||
* the form of connection url cannot be parsed success.
|
||||
*
|
||||
* @author zhangxin
|
||||
*/
|
||||
public class OracleURLParser extends AbstractURLParser {
|
||||
|
||||
private static final String DB_TYPE = "Oracle";
|
||||
private static final int DEFAULT_PORT = 1521;
|
||||
|
||||
public OracleURLParser(String url) {
|
||||
super(url);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int[] fetchDatabaseHostsIndexRange() {
|
||||
int hostLabelStartIndex = url.indexOf("@");
|
||||
int hostLabelEndIndex = url.lastIndexOf(":");
|
||||
return new int[]{hostLabelStartIndex + 1, hostLabelEndIndex};
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int[] fetchDatabaseNameIndexRange() {
|
||||
return new int[0];
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConnectionInfo parse() {
|
||||
int[] hostRangeIndex = fetchDatabaseHostsIndexRange();
|
||||
String host = fetchDatabaseHostsFromURL();
|
||||
String[] hostSegment = splitDatabaseAddress(host);
|
||||
String databaseName = url.substring(hostRangeIndex[1] + 1);
|
||||
if (hostSegment.length == 1) {
|
||||
return new ConnectionInfo(DB_TYPE, host, DEFAULT_PORT, databaseName);
|
||||
} else {
|
||||
return new ConnectionInfo(DB_TYPE, hostSegment[0], Integer.valueOf(hostSegment[1]), databaseName);
|
||||
}
|
||||
}
|
||||
|
||||
private String[] splitDatabaseAddress(String address) {
|
||||
String[] hostSegment = address.split(":");
|
||||
return hostSegment;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
package com.a.eye.skywalking.plugin.jdbc.connectionurl.parser;
|
||||
|
||||
import com.a.eye.skywalking.plugin.jdbc.ConnectionInfo;
|
||||
|
||||
/**
|
||||
* {@link URLParser#parser(String)} support parse the connection url, such as Mysql, Oracle, H2 Database.
|
||||
* But there are some url cannot be parsed, such as Oracle connection url with multiple host.
|
||||
*
|
||||
* @author zhangxin
|
||||
*/
|
||||
public class URLParser {
|
||||
|
||||
private static final String MYSQL_JDBC_URL_PREFIX = "jdbc:mysql";
|
||||
private static final String ORACLE_JDBC_URL_PREFIX = "jdbc:oracle";
|
||||
private static final String H2_JDBC_URL_PREFIX = "jdbc:h2";
|
||||
|
||||
public static ConnectionInfo parser(String url) {
|
||||
ConnectionURLParser parser = null;
|
||||
if (url.startsWith(MYSQL_JDBC_URL_PREFIX)) {
|
||||
parser = new MysqlURLParser(url);
|
||||
} else if (url.startsWith(ORACLE_JDBC_URL_PREFIX)) {
|
||||
parser = new OracleURLParser(url);
|
||||
} else if (url.startsWith(H2_JDBC_URL_PREFIX)) {
|
||||
parser = new H2URLParser(url);
|
||||
}
|
||||
return parser.parse();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
package com.a.eye.skywalking.plugin.jdbc.define;
|
||||
|
||||
import com.a.eye.skywalking.api.plugin.interceptor.ConstructorInterceptPoint;
|
||||
import com.a.eye.skywalking.api.plugin.interceptor.InstanceMethodsInterceptPoint;
|
||||
import com.a.eye.skywalking.api.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine;
|
||||
import com.a.eye.skywalking.plugin.jdbc.SWConnection;
|
||||
|
||||
import net.bytebuddy.description.method.MethodDescription;
|
||||
import net.bytebuddy.matcher.ElementMatcher;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
import static net.bytebuddy.matcher.ElementMatchers.named;
|
||||
|
||||
/**
|
||||
* JDBC plugin using {@link JDBCDriverInterceptor} to intercept all the class that it has extend {@link java.sql.Driver#connect(String, Properties)},
|
||||
* and change the return object to {@link com.a.eye.skywalking.plugin.jdbc.SWConnection}, All the method of {@link com.a.eye.skywalking.plugin.jdbc.SWConnection}
|
||||
* is delegate to the real JDBC Driver Connection object.
|
||||
*
|
||||
* @author zhangxin
|
||||
*/
|
||||
public abstract class AbstractDatabaseInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
|
||||
|
||||
private static final String INTERCEPT_CLASS = "com.a.eye.skywalking.plugin.jdbc.define.JDBCDriverInterceptor";
|
||||
|
||||
@Override
|
||||
protected ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
|
||||
return new InstanceMethodsInterceptPoint[]{new InstanceMethodsInterceptPoint() {
|
||||
@Override
|
||||
public ElementMatcher<MethodDescription> getMethodsMatcher() {
|
||||
return named("connect");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMethodsInterceptor() {
|
||||
return INTERCEPT_CLASS;
|
||||
}
|
||||
}};
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
package com.a.eye.skywalking.plugin.jdbc.define;
|
||||
|
||||
/**
|
||||
* {@link H2Instrumentation} presents that skywalking intercepts {@link org.h2.Driver}.
|
||||
*
|
||||
* @author zhangxin
|
||||
*/
|
||||
public class H2Instrumentation extends AbstractDatabaseInstrumentation {
|
||||
|
||||
private static final String CLASS_OF_INTERCEPT_H2_DRIVER = "org.h2.Driver";
|
||||
|
||||
@Override
|
||||
protected String enhanceClassName() {
|
||||
return CLASS_OF_INTERCEPT_H2_DRIVER;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,32 +1,38 @@
|
|||
package com.a.eye.skywalking.api.plugin.jdbc.define;
|
||||
package com.a.eye.skywalking.plugin.jdbc.define;
|
||||
|
||||
import com.a.eye.skywalking.api.plugin.interceptor.EnhancedClassInstanceContext;
|
||||
import com.a.eye.skywalking.plugin.interceptor.enhance.ConstructorInvokeContext;
|
||||
import com.a.eye.skywalking.api.plugin.interceptor.enhance.MethodInterceptResult;
|
||||
import com.a.eye.skywalking.plugin.interceptor.enhance.InstanceMethodInvokeContext;
|
||||
import com.a.eye.skywalking.api.plugin.interceptor.enhance.InstanceMethodInvokeContext;
|
||||
import com.a.eye.skywalking.api.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
|
||||
import com.a.eye.skywalking.api.plugin.jdbc.SWConnection;
|
||||
import com.a.eye.skywalking.api.plugin.interceptor.enhance.MethodInterceptResult;
|
||||
import com.a.eye.skywalking.plugin.jdbc.SWConnection;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
* {@link JDBCDriverInterceptor} return {@link SWConnection} when {@link java.sql.Driver} to create connection,
|
||||
* instead of the {@link Connection} instance.
|
||||
*
|
||||
* @author zhangxin
|
||||
*/
|
||||
public class JDBCDriverInterceptor implements InstanceMethodsAroundInterceptor {
|
||||
@Override
|
||||
public void beforeMethod(EnhancedClassInstanceContext context, InstanceMethodInvokeContext interceptorContext,
|
||||
MethodInterceptResult result) {
|
||||
MethodInterceptResult result) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object afterMethod(EnhancedClassInstanceContext context, InstanceMethodInvokeContext interceptorContext,
|
||||
Object ret) {
|
||||
Object ret) {
|
||||
return new SWConnection((String) interceptorContext.allArguments()[0],
|
||||
(Properties) interceptorContext.allArguments()[1], (Connection) ret);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleMethodException(Throwable t, EnhancedClassInstanceContext context,
|
||||
InstanceMethodInvokeContext interceptorContext) {
|
||||
|
||||
InstanceMethodInvokeContext interceptorContext) {
|
||||
// do nothing.
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
package com.a.eye.skywalking.plugin.jdbc.define;
|
||||
|
||||
/**
|
||||
* {@link MysqlInstrumentation} presents that skywalking intercepts {@link com.mysql.jdbc.Driver}.
|
||||
*
|
||||
* @author zhangxin
|
||||
*/
|
||||
public class MysqlInstrumentation extends AbstractDatabaseInstrumentation {
|
||||
@Override
|
||||
protected String enhanceClassName() {
|
||||
return "com.mysql.jdbc.Driver";
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
package com.a.eye.skywalking.plugin.jdbc.define;
|
||||
|
||||
/**
|
||||
* {@link OracleInstrumentation} presents that skywalking intercepts the class <code>oracle.jdbc.OracleDriver
|
||||
* </code>.
|
||||
*
|
||||
* @author zhangxin
|
||||
*/
|
||||
public class OracleInstrumentation extends AbstractDatabaseInstrumentation {
|
||||
@Override
|
||||
protected String enhanceClassName() {
|
||||
return "oracle.jdbc.OracleDriver";
|
||||
}
|
||||
}
|
||||
|
|
@ -1,3 +1,3 @@
|
|||
com.a.eye.skywalking.plugin.jdbc.define.H2PluginDefine
|
||||
com.a.eye.skywalking.plugin.jdbc.define.MysqlPluginDefine
|
||||
com.a.eye.skywalking.plugin.jdbc.define.OraclePluginDefine
|
||||
com.a.eye.skywalking.plugin.jdbc.define.H2Instrumentation
|
||||
com.a.eye.skywalking.plugin.jdbc.define.MysqlInstrumentation
|
||||
com.a.eye.skywalking.plugin.jdbc.define.OracleInstrumentation
|
||||
|
|
|
|||
|
|
@ -0,0 +1,107 @@
|
|||
package com.a.eye.skywalking.plugin.jdbc.connectionurl.parser;
|
||||
|
||||
import com.a.eye.skywalking.plugin.jdbc.ConnectionInfo;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
|
||||
public class URLParserTest {
|
||||
@Test
|
||||
public void testParseMysqlJDBCURLWithHost() {
|
||||
ConnectionInfo connectionInfo = new URLParser().parser("jdbc:mysql//primaryhost/test");
|
||||
assertThat(connectionInfo.getDBType(), is("Mysql"));
|
||||
assertThat(connectionInfo.getDatabaseName(), is("test"));
|
||||
assertThat(connectionInfo.getHost(), is("primaryhost"));
|
||||
assertThat(connectionInfo.getPort(), is(3306));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseMysqlJDBCURLWithHostAndPort() {
|
||||
ConnectionInfo connectionInfo = new URLParser().parser("jdbc:mysql//primaryhost:3307/test?profileSQL=true");
|
||||
assertThat(connectionInfo.getDBType(), is("Mysql"));
|
||||
assertThat(connectionInfo.getDatabaseName(), is("test"));
|
||||
assertThat(connectionInfo.getHost(), is("primaryhost"));
|
||||
assertThat(connectionInfo.getPort(), is(3307));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseMysqlJDBCURLWithMultiHost() {
|
||||
ConnectionInfo connectionInfo = new URLParser().parser("jdbc:mysql//primaryhost:3307,secondaryhost1,secondaryhost2/test?profileSQL=true");
|
||||
assertThat(connectionInfo.getDBType(), is("Mysql"));
|
||||
assertThat(connectionInfo.getDatabaseName(), is("test"));
|
||||
assertThat(connectionInfo.getHosts(), is("primaryhost:3307,secondaryhost1:3306,secondaryhost2:3306,"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseMysqlJDBCURLWithConnectorJs() {
|
||||
ConnectionInfo connectionInfo = new URLParser().parser("jdbc:mysql:replication://master,slave1,slave2,slave3/test");
|
||||
assertThat(connectionInfo.getDBType(), is("Mysql"));
|
||||
assertThat(connectionInfo.getDatabaseName(), is("test"));
|
||||
assertThat(connectionInfo.getHosts(), is("master:3306,slave1:3306,slave2:3306,slave3:3306,"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseOracleJDBCURLWithHost() {
|
||||
ConnectionInfo connectionInfo = new URLParser().parser("jdbc:oracle:thin:@localhost:orcl");
|
||||
assertThat(connectionInfo.getDBType(), is("Oracle"));
|
||||
assertThat(connectionInfo.getDatabaseName(), is("orcl"));
|
||||
assertThat(connectionInfo.getHost(), is("localhost"));
|
||||
assertThat(connectionInfo.getPort(), is(1521));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseOracleJDBCURLWithHostAndPort() {
|
||||
ConnectionInfo connectionInfo = new URLParser().parser("jdbc:oracle:thin:@localhost:1522:orcl");
|
||||
assertThat(connectionInfo.getDBType(), is("Oracle"));
|
||||
assertThat(connectionInfo.getDatabaseName(), is("orcl"));
|
||||
assertThat(connectionInfo.getHost(), is("localhost"));
|
||||
assertThat(connectionInfo.getPort(), is(1522));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseOracleJDBCURLWithUserNameAndPassword() {
|
||||
ConnectionInfo connectionInfo = new URLParser().parser("jdbc:oracle:thin:scott/tiger@myhost:1521:orcl");
|
||||
assertThat(connectionInfo.getDBType(), is("Oracle"));
|
||||
assertThat(connectionInfo.getDatabaseName(), is("orcl"));
|
||||
assertThat(connectionInfo.getHost(), is("myhost"));
|
||||
assertThat(connectionInfo.getPort(), is(1521));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseH2JDBCURLWithEmbedded() {
|
||||
ConnectionInfo connectionInfo = new URLParser().parser("jdbc:h2:file:/data/sample");
|
||||
assertThat(connectionInfo.getDBType(), is("H2"));
|
||||
assertThat(connectionInfo.getDatabaseName(), is("/data/sample"));
|
||||
assertThat(connectionInfo.getHost(), is("localhost"));
|
||||
assertThat(connectionInfo.getPort(), is(-1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseH2JDBCURLWithEmbeddedRunningInWindows() {
|
||||
ConnectionInfo connectionInfo = new URLParser().parser("jdbc:h2:file:C:/data/sample");
|
||||
assertThat(connectionInfo.getDBType(), is("H2"));
|
||||
assertThat(connectionInfo.getDatabaseName(), is("C:/data/sample"));
|
||||
assertThat(connectionInfo.getHost(), is("localhost"));
|
||||
assertThat(connectionInfo.getPort(), is(-1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseH2JDBCURLWithMemoryMode() {
|
||||
ConnectionInfo connectionInfo = new URLParser().parser("jdbc:h2:mem:test_mem");
|
||||
assertThat(connectionInfo.getDBType(), is("H2"));
|
||||
assertThat(connectionInfo.getDatabaseName(), is("test_mem"));
|
||||
assertThat(connectionInfo.getHost(), is("localhost"));
|
||||
assertThat(connectionInfo.getPort(), is(-1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseH2JDBCURL() {
|
||||
ConnectionInfo connectionInfo = new URLParser().parser("jdbc:h2:tcp://localhost:8084/~/sample");
|
||||
assertThat(connectionInfo.getDBType(), is("H2"));
|
||||
assertThat(connectionInfo.getDatabaseName(), is("sample"));
|
||||
assertThat(connectionInfo.getHost(), is("localhost"));
|
||||
assertThat(connectionInfo.getPort(), is(8084));
|
||||
}
|
||||
}
|
||||
|
|
@ -1,21 +0,0 @@
|
|||
package com.a.eye.skywalking.api.plugin.jedis.v2;
|
||||
|
||||
import com.a.eye.skywalking.api.plugin.interceptor.EnhancedClassInstanceContext;
|
||||
import com.a.eye.skywalking.plugin.interceptor.enhance.ConstructorInvokeContext;
|
||||
import com.a.eye.skywalking.api.plugin.interceptor.enhance.InstanceConstructorInterceptor;
|
||||
import redis.clients.jedis.HostAndPort;
|
||||
|
||||
import static com.a.eye.skywalking.api.plugin.jedis.v2.JedisMethodInterceptor.REDIS_CONN_INFO_KEY;
|
||||
|
||||
/**
|
||||
* Created by xin on 16-6-12.
|
||||
*/
|
||||
public class JedisClusterConstructorInterceptor4HostAndPortArg implements InstanceConstructorInterceptor {
|
||||
@Override
|
||||
public void onConstruct(EnhancedClassInstanceContext context, ConstructorInvokeContext interceptorContext) {
|
||||
StringBuilder redisConnInfo = new StringBuilder();
|
||||
HostAndPort hostAndPort = (HostAndPort) interceptorContext.allArguments()[0];
|
||||
redisConnInfo.append(hostAndPort.toString()).append(";");
|
||||
context.set(REDIS_CONN_INFO_KEY, redisConnInfo.toString());
|
||||
}
|
||||
}
|
||||
|
|
@ -1,22 +0,0 @@
|
|||
package com.a.eye.skywalking.api.plugin.jedis.v2;
|
||||
|
||||
import com.a.eye.skywalking.api.plugin.interceptor.EnhancedClassInstanceContext;
|
||||
import com.a.eye.skywalking.plugin.interceptor.enhance.ConstructorInvokeContext;
|
||||
import com.a.eye.skywalking.api.plugin.interceptor.enhance.InstanceConstructorInterceptor;
|
||||
import redis.clients.jedis.JedisShardInfo;
|
||||
|
||||
import static com.a.eye.skywalking.api.plugin.jedis.v2.JedisMethodInterceptor.REDIS_CONN_INFO_KEY;
|
||||
|
||||
/**
|
||||
* Created by wusheng on 2016/12/1.
|
||||
*/
|
||||
public class JedisConstructorInterceptor4ShardInfoArg implements InstanceConstructorInterceptor {
|
||||
|
||||
@Override
|
||||
public void onConstruct(EnhancedClassInstanceContext context, ConstructorInvokeContext interceptorContext) {
|
||||
String redisConnInfo;
|
||||
JedisShardInfo shardInfo = (JedisShardInfo) interceptorContext.allArguments()[0];
|
||||
redisConnInfo = shardInfo.getHost() + ":" + shardInfo.getPort();
|
||||
context.set(REDIS_CONN_INFO_KEY, redisConnInfo);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,21 +0,0 @@
|
|||
package com.a.eye.skywalking.api.plugin.jedis.v2;
|
||||
|
||||
import com.a.eye.skywalking.api.plugin.interceptor.EnhancedClassInstanceContext;
|
||||
import com.a.eye.skywalking.plugin.interceptor.enhance.ConstructorInvokeContext;
|
||||
import com.a.eye.skywalking.api.plugin.interceptor.enhance.InstanceConstructorInterceptor;
|
||||
|
||||
import static com.a.eye.skywalking.api.plugin.jedis.v2.JedisMethodInterceptor.REDIS_CONN_INFO_KEY;
|
||||
|
||||
public class JedisConstructorInterceptor4StringArg implements InstanceConstructorInterceptor {
|
||||
|
||||
@Override
|
||||
public void onConstruct(EnhancedClassInstanceContext context, ConstructorInvokeContext interceptorContext) {
|
||||
String redisConnInfo;
|
||||
redisConnInfo = (String) interceptorContext.allArguments()[0];
|
||||
if (interceptorContext.allArguments().length > 1) {
|
||||
redisConnInfo += ":" + interceptorContext.allArguments()[1];
|
||||
}
|
||||
context.set(REDIS_CONN_INFO_KEY, redisConnInfo);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,23 +0,0 @@
|
|||
package com.a.eye.skywalking.api.plugin.jedis.v2;
|
||||
|
||||
import com.a.eye.skywalking.api.plugin.interceptor.EnhancedClassInstanceContext;
|
||||
import com.a.eye.skywalking.plugin.interceptor.enhance.ConstructorInvokeContext;
|
||||
import com.a.eye.skywalking.api.plugin.interceptor.enhance.InstanceConstructorInterceptor;
|
||||
|
||||
import java.net.URI;
|
||||
|
||||
import static com.a.eye.skywalking.api.plugin.jedis.v2.JedisMethodInterceptor.REDIS_CONN_INFO_KEY;
|
||||
|
||||
/**
|
||||
* Created by wusheng on 2016/12/1.
|
||||
*/
|
||||
public class JedisConstructorInterceptor4UriArg implements InstanceConstructorInterceptor {
|
||||
|
||||
@Override
|
||||
public void onConstruct(EnhancedClassInstanceContext context, ConstructorInvokeContext interceptorContext) {
|
||||
String redisConnInfo;
|
||||
URI uri = (URI) interceptorContext.allArguments()[0];
|
||||
redisConnInfo = uri.getHost() + ":" + uri.getPort();
|
||||
context.set(REDIS_CONN_INFO_KEY, redisConnInfo);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,52 +0,0 @@
|
|||
package com.a.eye.skywalking.api.plugin.jedis.v2;
|
||||
|
||||
import com.a.eye.skywalking.model.Identification;
|
||||
import com.a.eye.skywalking.api.plugin.interceptor.EnhancedClassInstanceContext;
|
||||
import com.a.eye.skywalking.plugin.interceptor.assist.NoCocurrencyAceessObject;
|
||||
import com.a.eye.skywalking.plugin.interceptor.enhance.InstanceMethodInvokeContext;
|
||||
import com.a.eye.skywalking.api.plugin.interceptor.enhance.MethodInterceptResult;
|
||||
|
||||
public class JedisMethodInterceptor extends NoCocurrencyAceessObject {
|
||||
protected static final String REDIS_CONN_INFO_KEY = "redisClusterConnInfo";
|
||||
|
||||
|
||||
@Override
|
||||
public void beforeMethod(EnhancedClassInstanceContext context, InstanceMethodInvokeContext interceptorContext, MethodInterceptResult result) {
|
||||
this.whenEnter(context, new Runnable() {
|
||||
@Override public void run() {
|
||||
/**
|
||||
* redis server wouldn't process rpc context. ignore the
|
||||
* return(ContextData) of sender's beforeSend
|
||||
*/
|
||||
Identification.IdentificationBuilder builder = Identification
|
||||
.newBuilder()
|
||||
.viewPoint(
|
||||
context.get(REDIS_CONN_INFO_KEY, String.class)
|
||||
+ " " + interceptorContext.methodName())
|
||||
.spanType(RedisBuriedPointType.INSTANCE);
|
||||
if (interceptorContext.allArguments().length > 0
|
||||
&& interceptorContext.allArguments()[0] instanceof String) {
|
||||
builder.businessKey("key="
|
||||
+ interceptorContext.allArguments()[0]);
|
||||
}
|
||||
rpcClientInvokeMonitor.beforeInvoke(builder.build());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object afterMethod(EnhancedClassInstanceContext context, InstanceMethodInvokeContext interceptorContext, Object ret) {
|
||||
this.whenExist(context, new Runnable(){
|
||||
@Override public void run() {
|
||||
rpcClientInvokeMonitor.afterInvoke();
|
||||
}
|
||||
});
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleMethodException(Throwable t, EnhancedClassInstanceContext context, InstanceMethodInvokeContext interceptorContext) {
|
||||
rpcClientInvokeMonitor.occurException(t);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
package com.a.eye.skywalking.api.plugin.jedis.v2;
|
||||
|
||||
import com.a.eye.skywalking.api.IBuriedPointType;
|
||||
|
||||
public enum RedisBuriedPointType implements IBuriedPointType {
|
||||
INSTANCE;
|
||||
|
||||
@Override
|
||||
public String getTypeName() {
|
||||
return "Redis";
|
||||
}
|
||||
|
||||
@Override
|
||||
public CallType getCallType() {
|
||||
return CallType.SYNC;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,62 +0,0 @@
|
|||
package com.a.eye.skywalking.api.plugin.jedis.v2.define;
|
||||
|
||||
import com.a.eye.skywalking.api.plugin.interceptor.InstanceMethodsInterceptPoint;
|
||||
import com.a.eye.skywalking.plugin.bytebuddy.AllObjectDefaultMethodsMatch;
|
||||
import com.a.eye.skywalking.plugin.bytebuddy.ArgumentTypeNameMatch;
|
||||
import com.a.eye.skywalking.plugin.interceptor.ConstructorInterceptPoint;
|
||||
import com.a.eye.skywalking.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine;
|
||||
import net.bytebuddy.description.method.MethodDescription;
|
||||
import net.bytebuddy.matcher.ElementMatcher;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import static com.a.eye.skywalking.plugin.bytebuddy.ArgumentTypeNameMatch.takesArgumentWithType;
|
||||
import static net.bytebuddy.matcher.ElementMatchers.*;
|
||||
|
||||
public class JedisClusterPluginDefine extends ClassInstanceMethodsEnhancePluginDefine {
|
||||
|
||||
@Override
|
||||
public String enhanceClassName() {
|
||||
return "redis.clients.jedis.JedisCluster";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
|
||||
return new ConstructorInterceptPoint[] {new ConstructorInterceptPoint() {
|
||||
@Override
|
||||
public ElementMatcher<MethodDescription> getConstructorMatcher() {
|
||||
return takesArgument(0, Set.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getConstructorInterceptor() {
|
||||
return "com.a.eye.skywalking.plugin.jedis.v2.JedisClusterConstructorInterceptor4SetArg";
|
||||
}
|
||||
}, new ConstructorInterceptPoint() {
|
||||
@Override
|
||||
public ElementMatcher<MethodDescription> getConstructorMatcher() {
|
||||
return takesArgumentWithType(0, "redis.clients.jedis.HostAndPort");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getConstructorInterceptor() {
|
||||
return "com.a.eye.skywalking.plugin.jedis.v2.JedisClusterConstructorInterceptor4HostAndPortArg";
|
||||
}
|
||||
}};
|
||||
}
|
||||
|
||||
@Override
|
||||
protected InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
|
||||
return new InstanceMethodsInterceptPoint[] {new InstanceMethodsInterceptPoint() {
|
||||
@Override
|
||||
public ElementMatcher<MethodDescription> getMethodsMatcher() {
|
||||
return any().and(not(AllObjectDefaultMethodsMatch.INSTANCE));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMethodsInterceptor() {
|
||||
return "com.a.eye.skywalking.plugin.jedis.v2.JedisMethodInterceptor";
|
||||
}
|
||||
}};
|
||||
}
|
||||
}
|
||||
|
|
@ -1,81 +0,0 @@
|
|||
package com.a.eye.skywalking.api.plugin.jedis.v2.define;
|
||||
|
||||
import com.a.eye.skywalking.api.plugin.interceptor.ConstructorInterceptPoint;
|
||||
import com.a.eye.skywalking.api.plugin.interceptor.InstanceMethodsInterceptPoint;
|
||||
import com.a.eye.skywalking.plugin.bytebuddy.AllObjectDefaultMethodsMatch;
|
||||
import com.a.eye.skywalking.plugin.interceptor.ConstructorInterceptPoint;
|
||||
import com.a.eye.skywalking.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine;
|
||||
import net.bytebuddy.description.method.MethodDescription;
|
||||
import net.bytebuddy.matcher.ElementMatcher;
|
||||
import net.bytebuddy.matcher.ElementMatchers;
|
||||
|
||||
import java.net.URI;
|
||||
|
||||
import static com.a.eye.skywalking.plugin.bytebuddy.ArgumentTypeNameMatch.takesArgumentWithType;
|
||||
import static net.bytebuddy.matcher.ElementMatchers.*;
|
||||
|
||||
public class JedisPluginDefine extends ClassInstanceMethodsEnhancePluginDefine {
|
||||
|
||||
@Override
|
||||
public String enhanceClassName() {
|
||||
return "redis.clients.jedis.Jedis";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
|
||||
return new ConstructorInterceptPoint[] {new ConstructorInterceptPoint() {
|
||||
@Override
|
||||
public ElementMatcher<MethodDescription> getConstructorMatcher() {
|
||||
return takesArgument(0, String.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getConstructorInterceptor() {
|
||||
return "com.a.eye.skywalking.plugin.jedis.v2.JedisConstructorInterceptor4StringArg";
|
||||
}
|
||||
}, new ConstructorInterceptPoint() {
|
||||
@Override
|
||||
public ElementMatcher<MethodDescription> getConstructorMatcher() {
|
||||
return takesArgumentWithType(0, "redis.clients.jedis.HostAndPort");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getConstructorInterceptor() {
|
||||
return "com.a.eye.skywalking.plugin.jedis.v2.JedisConstructorInterceptor4ShardInfoArgg";
|
||||
}
|
||||
}, new ConstructorInterceptPoint() {
|
||||
@Override
|
||||
public ElementMatcher<MethodDescription> getConstructorMatcher() {
|
||||
return takesArgument(0, URI.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getConstructorInterceptor() {
|
||||
return "com.a.eye.skywalking.plugin.jedis.v2.JedisConstructorInterceptor4UriArg";
|
||||
}
|
||||
}};
|
||||
}
|
||||
|
||||
@Override
|
||||
protected InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
|
||||
return new InstanceMethodsInterceptPoint[] {new InstanceMethodsInterceptPoint() {
|
||||
@Override
|
||||
public ElementMatcher<MethodDescription> getMethodsMatcher() {
|
||||
return not(ElementMatchers.<MethodDescription>isPrivate()
|
||||
.or(AllObjectDefaultMethodsMatch.INSTANCE)
|
||||
.or(named("close"))
|
||||
.or(named("getDB"))
|
||||
.or(named("connect"))
|
||||
.or(named("setDataSource"))
|
||||
.or(named("resetState"))
|
||||
.or(named("clusterSlots"))
|
||||
.or(named("checkIsInMultiOrPipeline")));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMethodsInterceptor() {
|
||||
return "com.a.eye.skywalking.plugin.jedis.v2.JedisMethodInterceptor";
|
||||
}
|
||||
}};
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
package com.a.eye.skywalking.plugin.jedis.v2;
|
||||
|
||||
import com.a.eye.skywalking.api.plugin.interceptor.EnhancedClassInstanceContext;
|
||||
import com.a.eye.skywalking.api.plugin.interceptor.enhance.ConstructorInvokeContext;
|
||||
import com.a.eye.skywalking.api.plugin.interceptor.enhance.InstanceConstructorInterceptor;
|
||||
|
||||
import redis.clients.jedis.HostAndPort;
|
||||
|
||||
import static com.a.eye.skywalking.plugin.jedis.v2.JedisMethodInterceptor.KEY_OF_REDIS_CONN_INFO;
|
||||
import static com.a.eye.skywalking.plugin.jedis.v2.JedisMethodInterceptor.KEY_OF_REDIS_HOST;
|
||||
import static com.a.eye.skywalking.plugin.jedis.v2.JedisMethodInterceptor.KEY_OF_REDIS_PORT;
|
||||
|
||||
/**
|
||||
* {@link JedisClusterConstructorWithHostAndPortArgInterceptor} record the host and port information from {@link EnhancedClassInstanceContext#context},
|
||||
* and each host and port will spilt ;.
|
||||
*
|
||||
* @author zhangxin
|
||||
*/
|
||||
public class JedisClusterConstructorWithHostAndPortArgInterceptor implements InstanceConstructorInterceptor {
|
||||
|
||||
@Override
|
||||
public void onConstruct(EnhancedClassInstanceContext context, ConstructorInvokeContext interceptorContext) {
|
||||
StringBuilder redisConnInfo = new StringBuilder();
|
||||
HostAndPort hostAndPort = (HostAndPort) interceptorContext.allArguments()[0];
|
||||
redisConnInfo.append(hostAndPort.toString()).append(";");
|
||||
context.set(KEY_OF_REDIS_CONN_INFO, redisConnInfo.toString());
|
||||
context.set(KEY_OF_REDIS_HOST, hostAndPort.getHost());
|
||||
context.set(KEY_OF_REDIS_PORT, hostAndPort.getPort());
|
||||
}
|
||||
}
|
||||
|
|
@ -1,19 +1,20 @@
|
|||
package com.a.eye.skywalking.api.plugin.jedis.v2;
|
||||
package com.a.eye.skywalking.plugin.jedis.v2;
|
||||
|
||||
import com.a.eye.skywalking.api.plugin.interceptor.EnhancedClassInstanceContext;
|
||||
import com.a.eye.skywalking.plugin.interceptor.enhance.ConstructorInvokeContext;
|
||||
|
||||
import com.a.eye.skywalking.api.plugin.interceptor.enhance.ConstructorInvokeContext;
|
||||
import com.a.eye.skywalking.api.plugin.interceptor.enhance.InstanceConstructorInterceptor;
|
||||
import redis.clients.jedis.HostAndPort;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import static com.a.eye.skywalking.api.plugin.jedis.v2.JedisMethodInterceptor.REDIS_CONN_INFO_KEY;
|
||||
import redis.clients.jedis.HostAndPort;
|
||||
|
||||
/**
|
||||
* Created by xin on 16-6-12.
|
||||
* {@link JedisClusterConstructorWithHostAndPortArgInterceptor} record the host and port information that fetch
|
||||
* from {@link EnhancedClassInstanceContext#context}, and each host and port will spilt ;.
|
||||
*
|
||||
* @author zhangxin
|
||||
*/
|
||||
public class JedisClusterConstructorInterceptor4SetArg implements InstanceConstructorInterceptor {
|
||||
public class JedisClusterConstructorWithListHostAndPortArgInterceptor implements InstanceConstructorInterceptor {
|
||||
@Override
|
||||
public void onConstruct(EnhancedClassInstanceContext context, ConstructorInvokeContext interceptorContext) {
|
||||
StringBuilder redisConnInfo = new StringBuilder();
|
||||
|
|
@ -21,6 +22,7 @@ public class JedisClusterConstructorInterceptor4SetArg implements InstanceConstr
|
|||
for (HostAndPort hostAndPort : hostAndPorts) {
|
||||
redisConnInfo.append(hostAndPort.toString()).append(";");
|
||||
}
|
||||
context.set(REDIS_CONN_INFO_KEY, redisConnInfo.toString());
|
||||
context.set(JedisMethodInterceptor.KEY_OF_REDIS_CONN_INFO, redisConnInfo.toString());
|
||||
context.set(JedisMethodInterceptor.KEY_OF_REDIS_HOSTS, redisConnInfo);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
package com.a.eye.skywalking.plugin.jedis.v2;
|
||||
|
||||
import com.a.eye.skywalking.api.plugin.interceptor.EnhancedClassInstanceContext;
|
||||
import com.a.eye.skywalking.api.plugin.interceptor.enhance.ConstructorInvokeContext;
|
||||
import com.a.eye.skywalking.api.plugin.interceptor.enhance.InstanceConstructorInterceptor;
|
||||
|
||||
import redis.clients.jedis.JedisShardInfo;
|
||||
|
||||
/**
|
||||
* {@link JedisClusterConstructorWithHostAndPortArgInterceptor} will record the host
|
||||
* and port information from {@link EnhancedClassInstanceContext#context}.
|
||||
*
|
||||
* @author zhangxin
|
||||
*/
|
||||
public class JedisConstructorWithShardInfoArgInterceptor implements InstanceConstructorInterceptor {
|
||||
|
||||
@Override
|
||||
public void onConstruct(EnhancedClassInstanceContext context, ConstructorInvokeContext interceptorContext) {
|
||||
String redisConnInfo;
|
||||
JedisShardInfo shardInfo = (JedisShardInfo) interceptorContext.allArguments()[0];
|
||||
redisConnInfo = shardInfo.getHost() + ":" + shardInfo.getPort();
|
||||
context.set(JedisMethodInterceptor.KEY_OF_REDIS_CONN_INFO, redisConnInfo);
|
||||
context.set(JedisMethodInterceptor.KEY_OF_REDIS_HOST, shardInfo.getHost());
|
||||
context.set(JedisMethodInterceptor.KEY_OF_REDIS_PORT, shardInfo.getPort());
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
package com.a.eye.skywalking.plugin.jedis.v2;
|
||||
|
||||
import com.a.eye.skywalking.api.plugin.interceptor.EnhancedClassInstanceContext;
|
||||
import com.a.eye.skywalking.api.plugin.interceptor.enhance.ConstructorInvokeContext;
|
||||
import com.a.eye.skywalking.api.plugin.interceptor.enhance.InstanceConstructorInterceptor;
|
||||
|
||||
/**
|
||||
* {@link JedisClusterConstructorWithHostAndPortArgInterceptor} record the host
|
||||
* and port information from {@link EnhancedClassInstanceContext#context}.
|
||||
*
|
||||
* @author zhangxin
|
||||
*/
|
||||
public class JedisConstructorWithStringArgInterceptor implements InstanceConstructorInterceptor {
|
||||
|
||||
@Override
|
||||
public void onConstruct(EnhancedClassInstanceContext context, ConstructorInvokeContext interceptorContext) {
|
||||
String host = (String) interceptorContext.allArguments()[0];
|
||||
int port = 6379;
|
||||
if (interceptorContext.allArguments().length > 1) {
|
||||
port = (Integer) interceptorContext.allArguments()[1];
|
||||
}
|
||||
context.set(JedisMethodInterceptor.KEY_OF_REDIS_CONN_INFO, host + ":" + port);
|
||||
context.set(JedisMethodInterceptor.KEY_OF_REDIS_HOST, host);
|
||||
context.set(JedisMethodInterceptor.KEY_OF_REDIS_PORT, port);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
package com.a.eye.skywalking.plugin.jedis.v2;
|
||||
|
||||
import com.a.eye.skywalking.api.plugin.interceptor.EnhancedClassInstanceContext;
|
||||
import com.a.eye.skywalking.api.plugin.interceptor.enhance.ConstructorInvokeContext;
|
||||
import com.a.eye.skywalking.api.plugin.interceptor.enhance.InstanceConstructorInterceptor;
|
||||
|
||||
import java.net.URI;
|
||||
|
||||
/**
|
||||
* {@link JedisClusterConstructorWithHostAndPortArgInterceptor} record the host and port information that fetch
|
||||
* from {@link EnhancedClassInstanceContext#context}.
|
||||
*
|
||||
* @author zhangxin
|
||||
*/
|
||||
public class JedisConstructorWithUriArgInterceptor implements InstanceConstructorInterceptor {
|
||||
|
||||
@Override
|
||||
public void onConstruct(EnhancedClassInstanceContext context, ConstructorInvokeContext interceptorContext) {
|
||||
String redisConnInfo;
|
||||
URI uri = (URI) interceptorContext.allArguments()[0];
|
||||
redisConnInfo = uri.getHost() + ":" + uri.getPort();
|
||||
context.set(JedisMethodInterceptor.KEY_OF_REDIS_CONN_INFO, redisConnInfo);
|
||||
context.set(JedisMethodInterceptor.KEY_OF_REDIS_HOST, uri.getHost());
|
||||
context.set(JedisMethodInterceptor.KEY_OF_REDIS_PORT, uri.getPort());
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,91 @@
|
|||
package com.a.eye.skywalking.plugin.jedis.v2;
|
||||
|
||||
import com.a.eye.skywalking.api.context.ContextManager;
|
||||
import com.a.eye.skywalking.api.plugin.interceptor.EnhancedClassInstanceContext;
|
||||
import com.a.eye.skywalking.api.plugin.interceptor.assist.NoCocurrencyAceessObject;
|
||||
import com.a.eye.skywalking.api.plugin.interceptor.enhance.InstanceMethodInvokeContext;
|
||||
import com.a.eye.skywalking.api.plugin.interceptor.enhance.MethodInterceptResult;
|
||||
import com.a.eye.skywalking.api.util.StringUtil;
|
||||
import com.a.eye.skywalking.trace.Span;
|
||||
import com.a.eye.skywalking.trace.tag.Tags;
|
||||
|
||||
/**
|
||||
* {@link JedisMethodInterceptor} intercept all method of {@link redis.clients.jedis.Jedis}
|
||||
* or {@link redis.clients.jedis.JedisCluster}. {@link JedisMethodInterceptor} record
|
||||
* the redis host, operation name and the key of the operation.
|
||||
*
|
||||
* @author zhangxin
|
||||
*/
|
||||
public class JedisMethodInterceptor extends NoCocurrencyAceessObject {
|
||||
/**
|
||||
* The key name that redis connection information in {@link EnhancedClassInstanceContext#context}.
|
||||
*/
|
||||
protected static final String KEY_OF_REDIS_CONN_INFO = "REDIS_CONNECTION_INFO";
|
||||
/**
|
||||
* The key name that multiple redis hosts in {@link EnhancedClassInstanceContext#context}.
|
||||
*/
|
||||
protected static final String KEY_OF_REDIS_HOSTS = "KEY_OF_REDIS_HOSTS";
|
||||
/**
|
||||
* The key name that redis host in {@link EnhancedClassInstanceContext#context}.
|
||||
* it will be null if the value that fetch from {@link EnhancedClassInstanceContext#context}
|
||||
* by using {@link #KEY_OF_REDIS_HOSTS} is not null.
|
||||
*/
|
||||
protected static final String KEY_OF_REDIS_HOST = "KEY_OF_REDIS_HOST";
|
||||
/**
|
||||
* The key name that redis port in {@link EnhancedClassInstanceContext#context}.
|
||||
* It can not be null if the value that fetch from {@link EnhancedClassInstanceContext#context} by
|
||||
* using {@link #KEY_OF_REDIS_HOST} is not null.
|
||||
*/
|
||||
protected static final String KEY_OF_REDIS_PORT = "KEY_OF_REDIS_PORT";
|
||||
|
||||
private static final String REDIS_COMPONENT = "Redis";
|
||||
|
||||
|
||||
@Override
|
||||
public void beforeMethod(final EnhancedClassInstanceContext context, final InstanceMethodInvokeContext interceptorContext, MethodInterceptResult result) {
|
||||
this.whenEnter(context, new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Span span = ContextManager.INSTANCE.createSpan(context.get(KEY_OF_REDIS_CONN_INFO, String.class) + " " + interceptorContext.methodName());
|
||||
Tags.COMPONENT.set(span, REDIS_COMPONENT);
|
||||
Tags.DB_TYPE.set(span, REDIS_COMPONENT);
|
||||
tagPeer(span, context);
|
||||
Tags.SPAN_LAYER.asDB(span);
|
||||
|
||||
if (interceptorContext.allArguments().length > 0
|
||||
&& interceptorContext.allArguments()[0] instanceof String) {
|
||||
Tags.DB_STATEMENT.set(span, interceptorContext.methodName() + " " + interceptorContext.allArguments()[0]);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* set peer host information for the current active span.
|
||||
*/
|
||||
private void tagPeer(Span span, EnhancedClassInstanceContext context) {
|
||||
String redisHosts = (String) context.get(KEY_OF_REDIS_HOSTS);
|
||||
if (!StringUtil.isEmpty(redisHosts)) {
|
||||
Tags.PEERS.set(span, (String) context.get(KEY_OF_REDIS_HOSTS));
|
||||
} else {
|
||||
Tags.PEER_HOST.set(span, (String) context.get(KEY_OF_REDIS_HOST));
|
||||
Tags.PEER_PORT.set(span, (Integer) context.get(KEY_OF_REDIS_PORT));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object afterMethod(EnhancedClassInstanceContext context, InstanceMethodInvokeContext interceptorContext, Object ret) {
|
||||
this.whenExist(context, new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
ContextManager.INSTANCE.stopSpan();
|
||||
}
|
||||
});
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleMethodException(Throwable t, EnhancedClassInstanceContext context, InstanceMethodInvokeContext interceptorContext) {
|
||||
ContextManager.INSTANCE.activeSpan().log(t);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,81 @@
|
|||
package com.a.eye.skywalking.plugin.jedis.v2.define;
|
||||
|
||||
import com.a.eye.skywalking.api.plugin.bytebuddy.AllObjectDefaultMethodsMatch;
|
||||
import com.a.eye.skywalking.api.plugin.interceptor.ConstructorInterceptPoint;
|
||||
import com.a.eye.skywalking.api.plugin.interceptor.InstanceMethodsInterceptPoint;
|
||||
import com.a.eye.skywalking.api.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine;
|
||||
import com.a.eye.skywalking.plugin.jedis.v2.JedisClusterConstructorWithListHostAndPortArgInterceptor;
|
||||
import com.a.eye.skywalking.plugin.jedis.v2.JedisMethodInterceptor;
|
||||
|
||||
import net.bytebuddy.description.method.MethodDescription;
|
||||
import net.bytebuddy.matcher.ElementMatcher;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import static com.a.eye.skywalking.api.plugin.bytebuddy.ArgumentTypeNameMatch.takesArgumentWithType;
|
||||
import static net.bytebuddy.matcher.ElementMatchers.any;
|
||||
import static net.bytebuddy.matcher.ElementMatchers.not;
|
||||
import static net.bytebuddy.matcher.ElementMatchers.takesArgument;
|
||||
|
||||
/**
|
||||
* {@link JedisClusterInstrumentation} presents that skywalking intercepts all constructors and methods of {@link redis.clients.jedis.JedisCluster}.
|
||||
* {@link com.a.eye.skywalking.plugin.jedis.v2.JedisClusterConstructorWithHostAndPortArgInterceptor} intercepts all constructor with argument {@link redis.clients.jedis.HostAndPort}
|
||||
* and the other constructor intercept by class {@link JedisClusterConstructorWithListHostAndPortArgInterceptor}.
|
||||
* {@link JedisMethodInterceptor} intercept all methods of {@link redis.clients.jedis.JedisCluster}
|
||||
*
|
||||
* @author zhangxin
|
||||
*/
|
||||
public class JedisClusterInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
|
||||
|
||||
private static final String ARGUMENT_TYPE_NAME = "redis.clients.jedis.HostAndPort";
|
||||
private static final String ENHANCE_CLASS = "redis.clients.jedis.JedisCluster";
|
||||
private static final String CONSTRUCTOR_WITH_LIST_HOSTANDPORT_ARG_INTERCEPT_CLASS = "com.a.eye.skywalking.plugin.jedis.v2.JedisClusterConstructorWithListHostAndPortArgInterceptor";
|
||||
private static final String METHOD_INTERCEPT_CLASS = "com.a.eye.skywalking.plugin.jedis.v2.JedisMethodInterceptor";
|
||||
private static final String CONSTRUCTOR_WITH_HOSTANDPORT_ARG_INTERCEPT_CLASS = "com.a.eye.skywalking.plugin.jedis.v2.JedisClusterConstructorWithHostAndPortArgInterceptor";
|
||||
|
||||
|
||||
@Override
|
||||
public String enhanceClassName() {
|
||||
return ENHANCE_CLASS;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
|
||||
return new ConstructorInterceptPoint[]{new ConstructorInterceptPoint() {
|
||||
@Override
|
||||
public ElementMatcher<MethodDescription> getConstructorMatcher() {
|
||||
return takesArgument(0, Set.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getConstructorInterceptor() {
|
||||
return CONSTRUCTOR_WITH_LIST_HOSTANDPORT_ARG_INTERCEPT_CLASS;
|
||||
}
|
||||
}, new ConstructorInterceptPoint() {
|
||||
@Override
|
||||
public ElementMatcher<MethodDescription> getConstructorMatcher() {
|
||||
return takesArgumentWithType(0, ARGUMENT_TYPE_NAME);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getConstructorInterceptor() {
|
||||
return CONSTRUCTOR_WITH_HOSTANDPORT_ARG_INTERCEPT_CLASS;
|
||||
}
|
||||
}};
|
||||
}
|
||||
|
||||
@Override
|
||||
protected InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
|
||||
return new InstanceMethodsInterceptPoint[]{new InstanceMethodsInterceptPoint() {
|
||||
@Override
|
||||
public ElementMatcher<MethodDescription> getMethodsMatcher() {
|
||||
return any().and(not(AllObjectDefaultMethodsMatch.INSTANCE));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMethodsInterceptor() {
|
||||
return METHOD_INTERCEPT_CLASS;
|
||||
}
|
||||
}};
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,102 @@
|
|||
package com.a.eye.skywalking.plugin.jedis.v2.define;
|
||||
|
||||
import com.a.eye.skywalking.api.plugin.bytebuddy.AllObjectDefaultMethodsMatch;
|
||||
import com.a.eye.skywalking.api.plugin.interceptor.ConstructorInterceptPoint;
|
||||
import com.a.eye.skywalking.api.plugin.interceptor.InstanceMethodsInterceptPoint;
|
||||
import com.a.eye.skywalking.api.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine;
|
||||
import com.a.eye.skywalking.plugin.jedis.v2.JedisConstructorWithShardInfoArgInterceptor;
|
||||
import com.a.eye.skywalking.plugin.jedis.v2.JedisConstructorWithUriArgInterceptor;
|
||||
import com.a.eye.skywalking.plugin.jedis.v2.JedisMethodInterceptor;
|
||||
|
||||
import net.bytebuddy.description.method.MethodDescription;
|
||||
import net.bytebuddy.matcher.ElementMatcher;
|
||||
import net.bytebuddy.matcher.ElementMatchers;
|
||||
|
||||
import java.net.URI;
|
||||
|
||||
import static com.a.eye.skywalking.api.plugin.bytebuddy.ArgumentTypeNameMatch.takesArgumentWithType;
|
||||
import static net.bytebuddy.matcher.ElementMatchers.named;
|
||||
import static net.bytebuddy.matcher.ElementMatchers.not;
|
||||
import static net.bytebuddy.matcher.ElementMatchers.takesArgument;
|
||||
|
||||
/**
|
||||
* {@link JedisInstrumentation} presents that skywalking intercept all constructors and methods of {@link redis.clients.jedis.Jedis}.
|
||||
* {@link JedisConstructorWithShardInfoArgInterceptor} intercepts all constructor with argument {@link redis.clients.jedis.HostAndPort}
|
||||
* ,{@link JedisConstructorWithUriArgInterceptor} intercepts the constructors with uri argument and
|
||||
* the other constructor intercept by class {@link JedisConstructorWithShardInfoArgInterceptor}.
|
||||
* {@link JedisMethodInterceptor} intercept all methods of {@link redis.clients.jedis.Jedis}.
|
||||
*
|
||||
* @author zhangxin
|
||||
*/
|
||||
public class JedisInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
|
||||
|
||||
private static final String HOST_AND_PROT_ARG_TYPE_NAME = "redis.clients.jedis.HostAndPort";
|
||||
private static final String ENHANCE_CLASS = "redis.clients.jedis.Jedis";
|
||||
private static final String CONSTRUCTOR_WITH_STRING_ARG_INTERCEPT_CLASS = "com.a.eye.skywalking.plugin.jedis.v2.JedisConstructorWithStringArgInterceptor";
|
||||
private static final String CONSTRUCTOR_WITH_SHARD_INFO_ARG_INTERCEPT_CLASS = "com.a.eye.skywalking.plugin.jedis.v2.JedisConstructorWithShardInfoArgInterceptor";
|
||||
private static final String CONSTRUCTOR_WITH_URI_ARG_INTERCEPT_CLASS = "com.a.eye.skywalking.plugin.jedis.v2.JedisConstructorWithUriArgInterceptor";
|
||||
private static final String JEDIS_METHOD_INTERCET_CLASS = "com.a.eye.skywalking.plugin.jedis.v2.JedisMethodInterceptor";
|
||||
|
||||
@Override
|
||||
public String enhanceClassName() {
|
||||
return ENHANCE_CLASS;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
|
||||
return new ConstructorInterceptPoint[]{new ConstructorInterceptPoint() {
|
||||
@Override
|
||||
public ElementMatcher<MethodDescription> getConstructorMatcher() {
|
||||
return takesArgument(0, String.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getConstructorInterceptor() {
|
||||
return CONSTRUCTOR_WITH_STRING_ARG_INTERCEPT_CLASS;
|
||||
}
|
||||
}, new ConstructorInterceptPoint() {
|
||||
@Override
|
||||
public ElementMatcher<MethodDescription> getConstructorMatcher() {
|
||||
return takesArgumentWithType(0, HOST_AND_PROT_ARG_TYPE_NAME);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getConstructorInterceptor() {
|
||||
return CONSTRUCTOR_WITH_SHARD_INFO_ARG_INTERCEPT_CLASS;
|
||||
}
|
||||
}, new ConstructorInterceptPoint() {
|
||||
@Override
|
||||
public ElementMatcher<MethodDescription> getConstructorMatcher() {
|
||||
return takesArgument(0, URI.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getConstructorInterceptor() {
|
||||
return CONSTRUCTOR_WITH_URI_ARG_INTERCEPT_CLASS;
|
||||
}
|
||||
}};
|
||||
}
|
||||
|
||||
@Override
|
||||
protected InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
|
||||
return new InstanceMethodsInterceptPoint[]{new InstanceMethodsInterceptPoint() {
|
||||
@Override
|
||||
public ElementMatcher<MethodDescription> getMethodsMatcher() {
|
||||
return not(ElementMatchers.<MethodDescription>isPrivate()
|
||||
.or(AllObjectDefaultMethodsMatch.INSTANCE)
|
||||
.or(named("close"))
|
||||
.or(named("getDB"))
|
||||
.or(named("connect"))
|
||||
.or(named("setDataSource"))
|
||||
.or(named("resetState"))
|
||||
.or(named("clusterSlots"))
|
||||
.or(named("checkIsInMultiOrPipeline")));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMethodsInterceptor() {
|
||||
return JEDIS_METHOD_INTERCET_CLASS;
|
||||
}
|
||||
}};
|
||||
}
|
||||
}
|
||||
|
|
@ -1,2 +1,2 @@
|
|||
com.a.eye.skywalking.plugin.jedis.v2.define.JedisPluginDefine
|
||||
com.a.eye.skywalking.plugin.jedis.v2.define.JedisClusterPluginDefine
|
||||
com.a.eye.skywalking.plugin.jedis.v2.define.JedisClusterInstrumentation
|
||||
com.a.eye.skywalking.plugin.jedis.v2.define.JedisInstrumentation
|
||||
|
|
|
|||
|
|
@ -1,19 +0,0 @@
|
|||
package com.a.eye.skywalking.api.plugin.motan;
|
||||
|
||||
import com.a.eye.skywalking.api.IBuriedPointType;
|
||||
|
||||
public enum MotanBuriedPointType implements IBuriedPointType {
|
||||
|
||||
INSTANCE;
|
||||
|
||||
@Override
|
||||
public String getTypeName() {
|
||||
return "MO";
|
||||
}
|
||||
|
||||
@Override
|
||||
public CallType getCallType() {
|
||||
return CallType.SYNC;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,60 +0,0 @@
|
|||
package com.a.eye.skywalking.api.plugin.motan;
|
||||
|
||||
import com.a.eye.skywalking.invoke.monitor.RPCClientInvokeMonitor;
|
||||
import com.a.eye.skywalking.model.ContextData;
|
||||
import com.a.eye.skywalking.model.Identification;
|
||||
import com.a.eye.skywalking.api.plugin.interceptor.EnhancedClassInstanceContext;
|
||||
import com.a.eye.skywalking.plugin.interceptor.enhance.ConstructorInvokeContext;
|
||||
import com.a.eye.skywalking.plugin.interceptor.enhance.InstanceMethodInvokeContext;
|
||||
import com.a.eye.skywalking.api.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
|
||||
import com.a.eye.skywalking.api.plugin.interceptor.enhance.MethodInterceptResult;
|
||||
import com.weibo.api.motan.rpc.Request;
|
||||
import com.weibo.api.motan.rpc.URL;
|
||||
|
||||
/**
|
||||
* Motan client interceptor
|
||||
*/
|
||||
public class MotanClientCallInterceptor implements InstanceMethodsAroundInterceptor{
|
||||
|
||||
private static final String REQUEST_URL = "REQUEST_URL";
|
||||
|
||||
@Override
|
||||
public void beforeMethod(EnhancedClassInstanceContext context, InstanceMethodInvokeContext interceptorContext,
|
||||
MethodInterceptResult result) {
|
||||
URL url = (URL) context.get(REQUEST_URL);
|
||||
Request request = (Request) interceptorContext.allArguments()[0];
|
||||
if (url != null) {
|
||||
ContextData contextData = new RPCClientInvokeMonitor()
|
||||
.beforeInvoke(generateIdentify(request, url));
|
||||
String contextDataStr = contextData.toString();
|
||||
request.setAttachment("contextData", contextDataStr);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object afterMethod(EnhancedClassInstanceContext context, InstanceMethodInvokeContext interceptorContext,
|
||||
Object ret) {
|
||||
new RPCClientInvokeMonitor().afterInvoke();
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleMethodException(Throwable t, EnhancedClassInstanceContext context,
|
||||
InstanceMethodInvokeContext interceptorContext) {
|
||||
new RPCClientInvokeMonitor().occurException(t);
|
||||
}
|
||||
|
||||
|
||||
private static String generateViewPoint(URL serviceURI, Request request) {
|
||||
StringBuilder viewPoint = new StringBuilder(serviceURI.getUri());
|
||||
viewPoint.append("." + request.getMethodName());
|
||||
viewPoint.append("(" + request.getParamtersDesc() + ")?group=" + serviceURI.getGroup());
|
||||
return viewPoint.toString();
|
||||
}
|
||||
|
||||
|
||||
public static Identification generateIdentify(Request request, URL serviceURI) {
|
||||
return Identification.newBuilder().viewPoint(generateViewPoint(serviceURI, request))
|
||||
.spanType(MotanBuriedPointType.INSTANCE).build();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,29 +0,0 @@
|
|||
package com.a.eye.skywalking.api.plugin.motan;
|
||||
|
||||
import com.a.eye.skywalking.api.plugin.interceptor.EnhancedClassInstanceContext;
|
||||
import com.a.eye.skywalking.plugin.interceptor.enhance.InstanceMethodInvokeContext;
|
||||
import com.a.eye.skywalking.api.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
|
||||
import com.a.eye.skywalking.api.plugin.interceptor.enhance.MethodInterceptResult;
|
||||
|
||||
/**
|
||||
* Created by xin on 2017/1/23.
|
||||
*/
|
||||
public class MotanClientFetchCallURLInterceptor implements InstanceMethodsAroundInterceptor {
|
||||
|
||||
private static final String REQUEST_URL = "REQUEST_URL";
|
||||
|
||||
@Override
|
||||
public void beforeMethod(EnhancedClassInstanceContext context, InstanceMethodInvokeContext interceptorContext, MethodInterceptResult result) {
|
||||
context.set(REQUEST_URL, interceptorContext.allArguments()[0]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object afterMethod(EnhancedClassInstanceContext context, InstanceMethodInvokeContext interceptorContext, Object ret) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleMethodException(Throwable t, EnhancedClassInstanceContext context, InstanceMethodInvokeContext interceptorContext) {
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -1,57 +0,0 @@
|
|||
package com.a.eye.skywalking.api.plugin.motan;
|
||||
|
||||
import com.a.eye.skywalking.invoke.monitor.RPCServerInvokeMonitor;
|
||||
import com.a.eye.skywalking.model.ContextData;
|
||||
import com.a.eye.skywalking.model.Identification;
|
||||
import com.a.eye.skywalking.api.plugin.interceptor.EnhancedClassInstanceContext;
|
||||
import com.a.eye.skywalking.plugin.interceptor.enhance.ConstructorInvokeContext;
|
||||
import com.a.eye.skywalking.api.plugin.interceptor.enhance.InstanceConstructorInterceptor;
|
||||
import com.a.eye.skywalking.plugin.interceptor.enhance.InstanceMethodInvokeContext;
|
||||
import com.a.eye.skywalking.api.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
|
||||
import com.a.eye.skywalking.api.plugin.interceptor.enhance.MethodInterceptResult;
|
||||
import com.weibo.api.motan.rpc.Request;
|
||||
import com.weibo.api.motan.rpc.URL;
|
||||
|
||||
public class MotanServerInterceptor implements InstanceConstructorInterceptor, InstanceMethodsAroundInterceptor {
|
||||
@Override
|
||||
public void onConstruct(EnhancedClassInstanceContext context, ConstructorInvokeContext interceptorContext) {
|
||||
context.set("serviceURI", interceptorContext.allArguments()[0]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beforeMethod(EnhancedClassInstanceContext context, InstanceMethodInvokeContext interceptorContext,
|
||||
MethodInterceptResult result) {
|
||||
com.weibo.api.motan.rpc.Request request = (com.weibo.api.motan.rpc.Request) interceptorContext.allArguments()[0];
|
||||
if (request != null) {
|
||||
new RPCServerInvokeMonitor().beforeInvoke(new ContextData(request.getAttachments().get("contextData")),
|
||||
generateIdentify(request, (com.weibo.api.motan.rpc.URL) context.get("serviceURI")));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object afterMethod(EnhancedClassInstanceContext context, InstanceMethodInvokeContext interceptorContext,
|
||||
Object ret) {
|
||||
new RPCServerInvokeMonitor().afterInvoke();
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleMethodException(Throwable t, EnhancedClassInstanceContext context,
|
||||
InstanceMethodInvokeContext interceptorContext) {
|
||||
new RPCServerInvokeMonitor().occurException(t);
|
||||
}
|
||||
|
||||
|
||||
private static String generateViewPoint(URL serviceURI, Request request) {
|
||||
StringBuilder viewPoint = new StringBuilder(serviceURI.getUri());
|
||||
viewPoint.append("." + request.getMethodName());
|
||||
viewPoint.append("(" + request.getParamtersDesc() + ")?group=" + serviceURI.getGroup());
|
||||
return viewPoint.toString();
|
||||
}
|
||||
|
||||
|
||||
public static Identification generateIdentify(Request request, URL serviceURI) {
|
||||
return Identification.newBuilder().viewPoint(generateViewPoint(serviceURI, request))
|
||||
.spanType(MotanBuriedPointType.INSTANCE).build();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,47 +0,0 @@
|
|||
package com.a.eye.skywalking.api.plugin.motan.define;
|
||||
|
||||
import com.a.eye.skywalking.api.plugin.interceptor.InstanceMethodsInterceptPoint;
|
||||
import com.a.eye.skywalking.plugin.interceptor.ConstructorInterceptPoint;
|
||||
import com.a.eye.skywalking.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine;
|
||||
|
||||
import net.bytebuddy.description.method.MethodDescription;
|
||||
import net.bytebuddy.matcher.ElementMatcher;
|
||||
|
||||
import static net.bytebuddy.matcher.ElementMatchers.named;
|
||||
|
||||
public class MotanClientDefine extends ClassInstanceMethodsEnhancePluginDefine {
|
||||
@Override
|
||||
protected String enhanceClassName() {
|
||||
return "com.weibo.api.motan.cluster.support.ClusterSpi";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
|
||||
return new ConstructorInterceptPoint[0];
|
||||
}
|
||||
|
||||
@Override
|
||||
protected InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
|
||||
return new InstanceMethodsInterceptPoint[]{new InstanceMethodsInterceptPoint() {
|
||||
@Override
|
||||
public ElementMatcher<MethodDescription> getMethodsMatcher() {
|
||||
return named("setUrl");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMethodsInterceptor() {
|
||||
return "com.a.eye.skywalking.plugin.motan.MotanClientFetchCallURLInterceptor";
|
||||
}
|
||||
}, new InstanceMethodsInterceptPoint() {
|
||||
@Override
|
||||
public ElementMatcher<MethodDescription> getMethodsMatcher() {
|
||||
return named("call");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMethodsInterceptor() {
|
||||
return "com.a.eye.skywalking.plugin.motan.MotanClientCallInterceptor";
|
||||
}
|
||||
}};
|
||||
}
|
||||
}
|
||||
|
|
@ -1,49 +0,0 @@
|
|||
package com.a.eye.skywalking.api.plugin.motan.define;
|
||||
|
||||
import com.a.eye.skywalking.api.plugin.interceptor.ConstructorInterceptPoint;
|
||||
import com.a.eye.skywalking.api.plugin.interceptor.InstanceMethodsInterceptPoint;
|
||||
import com.a.eye.skywalking.plugin.interceptor.ConstructorInterceptPoint;
|
||||
import com.a.eye.skywalking.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine;
|
||||
import net.bytebuddy.description.method.MethodDescription;
|
||||
import net.bytebuddy.matcher.ElementMatcher;
|
||||
|
||||
import static net.bytebuddy.matcher.ElementMatchers.any;
|
||||
import static net.bytebuddy.matcher.ElementMatchers.named;
|
||||
|
||||
public class MotanServerDefine extends ClassInstanceMethodsEnhancePluginDefine {
|
||||
|
||||
@Override
|
||||
protected String enhanceClassName() {
|
||||
return "com.weibo.api.motan.rpc.AbstractProvider";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
|
||||
return new ConstructorInterceptPoint[] {new ConstructorInterceptPoint() {
|
||||
@Override
|
||||
public ElementMatcher<MethodDescription> getConstructorMatcher() {
|
||||
return any();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getConstructorInterceptor() {
|
||||
return "com.a.eye.skywalking.plugin.motan.MotanServerInterceptor";
|
||||
}
|
||||
}};
|
||||
}
|
||||
|
||||
@Override
|
||||
protected InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
|
||||
return new InstanceMethodsInterceptPoint[] {new InstanceMethodsInterceptPoint() {
|
||||
@Override
|
||||
public ElementMatcher<MethodDescription> getMethodsMatcher() {
|
||||
return named("call");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMethodsInterceptor() {
|
||||
return "com.a.eye.skywalking.plugin.motan.MotanServerInterceptor";
|
||||
}
|
||||
}};
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
package com.a.eye.skywalking.plugin.motan;
|
||||
|
||||
import com.a.eye.skywalking.api.plugin.interceptor.EnhancedClassInstanceContext;
|
||||
import com.a.eye.skywalking.api.plugin.interceptor.enhance.InstanceMethodInvokeContext;
|
||||
import com.a.eye.skywalking.api.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
|
||||
import com.a.eye.skywalking.api.plugin.interceptor.enhance.MethodInterceptResult;
|
||||
|
||||
/**
|
||||
* {@link MotanConsumerFetchRequestURLInterceptor} record {@link com.weibo.api.motan.rpc.URL} to {@link EnhancedClassInstanceContext#context}
|
||||
* for the operation name that create span need.
|
||||
*
|
||||
* @author zhangxin
|
||||
*/
|
||||
public class MotanConsumerFetchRequestURLInterceptor implements InstanceMethodsAroundInterceptor {
|
||||
|
||||
private static final String CONTEXT_NAME_OF_REQUEST_URL = "REQUEST_URL";
|
||||
|
||||
/**
|
||||
* Fetch the request url from the first param of all constructor, and put request
|
||||
* url into {@link EnhancedClassInstanceContext#context}.
|
||||
*
|
||||
* @param context instance context, a class instance only has one {@link EnhancedClassInstanceContext} instance.
|
||||
* @param interceptorContext method context, includes class name, method name, etc.
|
||||
* @param result change this result, if you want to truncate the method.
|
||||
*/
|
||||
@Override
|
||||
public void beforeMethod(EnhancedClassInstanceContext context, InstanceMethodInvokeContext interceptorContext, MethodInterceptResult result) {
|
||||
context.set(CONTEXT_NAME_OF_REQUEST_URL, interceptorContext.allArguments()[0]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object afterMethod(EnhancedClassInstanceContext context, InstanceMethodInvokeContext interceptorContext, Object ret) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleMethodException(Throwable t, EnhancedClassInstanceContext context, InstanceMethodInvokeContext interceptorContext) {
|
||||
// do nothing
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,92 @@
|
|||
package com.a.eye.skywalking.plugin.motan;
|
||||
|
||||
import com.a.eye.skywalking.api.context.ContextCarrier;
|
||||
import com.a.eye.skywalking.api.context.ContextManager;
|
||||
import com.a.eye.skywalking.api.plugin.interceptor.EnhancedClassInstanceContext;
|
||||
import com.a.eye.skywalking.api.plugin.interceptor.enhance.InstanceMethodInvokeContext;
|
||||
import com.a.eye.skywalking.api.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
|
||||
import com.a.eye.skywalking.api.plugin.interceptor.enhance.MethodInterceptResult;
|
||||
import com.a.eye.skywalking.trace.Span;
|
||||
import com.a.eye.skywalking.trace.tag.Tags;
|
||||
import com.weibo.api.motan.rpc.Request;
|
||||
import com.weibo.api.motan.rpc.Response;
|
||||
import com.weibo.api.motan.rpc.URL;
|
||||
|
||||
/**
|
||||
* {@link MotanConsumerInvokeInterceptor} create span by fetch request url from
|
||||
* {@link EnhancedClassInstanceContext#context} and transport serialized context
|
||||
* data to provider side through {@link Request#setAttachment(String, String)}.
|
||||
*
|
||||
* @author zhangxin
|
||||
*/
|
||||
public class MotanConsumerInvokeInterceptor implements InstanceMethodsAroundInterceptor {
|
||||
|
||||
/**
|
||||
* Context name of request url in {@link EnhancedClassInstanceContext#context}.
|
||||
*/
|
||||
private static final String CONTEXT_NAME_OF_REQUEST_URL = "REQUEST_URL";
|
||||
|
||||
/**
|
||||
* Attachment key of the serialized context data.
|
||||
*/
|
||||
private static final String ATTACHMENT_KEY_OF_CONTEXT_DATA = "contextData";
|
||||
|
||||
/**
|
||||
* Motan component
|
||||
*/
|
||||
private static final String MOTAN_COMPONENT = "Motan";
|
||||
|
||||
@Override
|
||||
public void beforeMethod(EnhancedClassInstanceContext context, InstanceMethodInvokeContext interceptorContext,
|
||||
MethodInterceptResult result) {
|
||||
URL url = (URL) context.get(CONTEXT_NAME_OF_REQUEST_URL);
|
||||
|
||||
if (url != null) {
|
||||
Request request = (Request) interceptorContext.allArguments()[0];
|
||||
|
||||
Span span = ContextManager.INSTANCE.createSpan(generateOperationName(url, request));
|
||||
Tags.PEER_HOST.set(span, url.getHost());
|
||||
Tags.PEER_PORT.set(span, url.getPort());
|
||||
Tags.COMPONENT.set(span, MOTAN_COMPONENT);
|
||||
Tags.URL.set(span, url.getIdentity());
|
||||
Tags.SPAN_KIND.set(span, Tags.SPAN_KIND_CLIENT);
|
||||
Tags.SPAN_LAYER.asRPCFramework(span);
|
||||
|
||||
ContextCarrier contextCarrier = new ContextCarrier();
|
||||
ContextManager.INSTANCE.inject(contextCarrier);
|
||||
request.setAttachment(ATTACHMENT_KEY_OF_CONTEXT_DATA, contextCarrier.serialize());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object afterMethod(EnhancedClassInstanceContext context, InstanceMethodInvokeContext interceptorContext,
|
||||
Object ret) {
|
||||
Response response = (Response) ret;
|
||||
if (response != null && response.getException() != null) {
|
||||
Span span = ContextManager.INSTANCE.activeSpan();
|
||||
span.log(response.getException());
|
||||
Tags.ERROR.set(span, true);
|
||||
}
|
||||
|
||||
ContextManager.INSTANCE.stopSpan();
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleMethodException(Throwable t, EnhancedClassInstanceContext context,
|
||||
InstanceMethodInvokeContext interceptorContext) {
|
||||
ContextManager.INSTANCE.activeSpan().log(t);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Generate operation name.
|
||||
*
|
||||
* @return operation name.
|
||||
*/
|
||||
private static String generateOperationName(URL serviceURI, Request request) {
|
||||
return new StringBuilder(serviceURI.getPath()).append(".").append(request.getMethodName()).append("(")
|
||||
.append(request.getParamtersDesc()).append(")").toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,92 @@
|
|||
package com.a.eye.skywalking.plugin.motan;
|
||||
|
||||
import com.a.eye.skywalking.api.context.ContextCarrier;
|
||||
import com.a.eye.skywalking.api.context.ContextManager;
|
||||
import com.a.eye.skywalking.api.plugin.interceptor.EnhancedClassInstanceContext;
|
||||
import com.a.eye.skywalking.api.plugin.interceptor.enhance.ConstructorInvokeContext;
|
||||
import com.a.eye.skywalking.api.plugin.interceptor.enhance.InstanceConstructorInterceptor;
|
||||
import com.a.eye.skywalking.api.plugin.interceptor.enhance.InstanceMethodInvokeContext;
|
||||
import com.a.eye.skywalking.api.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
|
||||
import com.a.eye.skywalking.api.plugin.interceptor.enhance.MethodInterceptResult;
|
||||
import com.a.eye.skywalking.trace.Span;
|
||||
import com.a.eye.skywalking.trace.tag.Tags;
|
||||
import com.weibo.api.motan.rpc.Request;
|
||||
import com.weibo.api.motan.rpc.Response;
|
||||
import com.weibo.api.motan.rpc.URL;
|
||||
|
||||
/**
|
||||
* Current trace segment will ref the trace segment from previous level if the serialized context data that fetch
|
||||
* from {@link Request#getAttachments()} is not null.
|
||||
*
|
||||
* {@link MotanProviderInterceptor} intercept all constructor of {@link com.weibo.api.motan.rpc.AbstractProvider} for record
|
||||
* the request url from consumer side.
|
||||
*
|
||||
* @author zhangxin
|
||||
*/
|
||||
public class MotanProviderInterceptor implements InstanceConstructorInterceptor, InstanceMethodsAroundInterceptor {
|
||||
|
||||
/**
|
||||
* The
|
||||
*/
|
||||
private static final String KEY_NAME_OF_REQUEST_URL = "REQUEST_URL";
|
||||
|
||||
/**
|
||||
* The {@link Request#getAttachments()} key. It maps to the serialized {@link ContextCarrier}.
|
||||
*/
|
||||
private static final String ATTACHMENT_KEY_OF_CONTEXT_DATA = "contextData";
|
||||
/**
|
||||
* Motan component
|
||||
*/
|
||||
private static final String MOTAN_COMPONENT = "Motan";
|
||||
|
||||
@Override
|
||||
public void onConstruct(EnhancedClassInstanceContext context, ConstructorInvokeContext interceptorContext) {
|
||||
context.set(KEY_NAME_OF_REQUEST_URL, interceptorContext.allArguments()[0]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beforeMethod(EnhancedClassInstanceContext context, InstanceMethodInvokeContext interceptorContext,
|
||||
MethodInterceptResult result) {
|
||||
URL url = (URL) context.get(KEY_NAME_OF_REQUEST_URL);
|
||||
if (url != null) {
|
||||
com.weibo.api.motan.rpc.Request request = (com.weibo.api.motan.rpc.Request) interceptorContext.allArguments()[0];
|
||||
Span span = ContextManager.INSTANCE.createSpan(generateViewPoint(url, request));
|
||||
Tags.COMPONENT.set(span, MOTAN_COMPONENT);
|
||||
Tags.URL.set(span, url.getIdentity());
|
||||
Tags.PEER_PORT.set(span, url.getPort());
|
||||
Tags.PEER_HOST.set(span, url.getHost());
|
||||
Tags.SPAN_KIND.set(span, Tags.SPAN_KIND_SERVER);
|
||||
Tags.SPAN_LAYER.asRPCFramework(span);
|
||||
|
||||
String serializedContextData = request.getAttachments().get(ATTACHMENT_KEY_OF_CONTEXT_DATA);
|
||||
ContextManager.INSTANCE.extract(new ContextCarrier().deserialize(serializedContextData));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object afterMethod(EnhancedClassInstanceContext context, InstanceMethodInvokeContext interceptorContext,
|
||||
Object ret) {
|
||||
Response response = (Response) ret;
|
||||
if (response != null && response.getException() != null) {
|
||||
Span span = ContextManager.INSTANCE.activeSpan();
|
||||
Tags.ERROR.set(span, true);
|
||||
span.log(response.getException());
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleMethodException(Throwable t, EnhancedClassInstanceContext context,
|
||||
InstanceMethodInvokeContext interceptorContext) {
|
||||
ContextManager.INSTANCE.activeSpan().log(t);
|
||||
}
|
||||
|
||||
|
||||
private static String generateViewPoint(URL serviceURI, Request request) {
|
||||
StringBuilder viewPoint = new StringBuilder(serviceURI.getUri());
|
||||
viewPoint.append("." + request.getMethodName());
|
||||
viewPoint.append("(" + request.getParamtersDesc() + ")");
|
||||
return viewPoint.toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
package com.a.eye.skywalking.plugin.motan.define;
|
||||
|
||||
import com.a.eye.skywalking.api.plugin.interceptor.ConstructorInterceptPoint;
|
||||
import com.a.eye.skywalking.api.plugin.interceptor.InstanceMethodsInterceptPoint;
|
||||
import com.a.eye.skywalking.api.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine;
|
||||
import com.a.eye.skywalking.plugin.motan.MotanConsumerFetchRequestURLInterceptor;
|
||||
import com.a.eye.skywalking.plugin.motan.MotanConsumerInvokeInterceptor;
|
||||
import com.weibo.api.motan.rpc.Request;
|
||||
import com.weibo.api.motan.rpc.URL;
|
||||
|
||||
import net.bytebuddy.description.method.MethodDescription;
|
||||
import net.bytebuddy.matcher.ElementMatcher;
|
||||
|
||||
import static net.bytebuddy.matcher.ElementMatchers.named;
|
||||
|
||||
/**
|
||||
* {@link MotanConsumerInstrumentation} presents that skywalking intercept
|
||||
* {@link com.weibo.api.motan.cluster.support.ClusterSpi#call(Request)} by using {@link MotanConsumerInvokeInterceptor} and
|
||||
* intercept {@link com.weibo.api.motan.cluster.support.ClusterSpi#setUrl(URL)} by using
|
||||
* {@link MotanConsumerFetchRequestURLInterceptor} to intercept{@link MotanConsumerFetchRequestURLInterceptor}.
|
||||
*
|
||||
* @author zhangxin
|
||||
*/
|
||||
public class MotanConsumerInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
|
||||
|
||||
private static final String ENHANCE_CLASS = "com.weibo.api.motan.cluster.support.ClusterSpi";
|
||||
|
||||
private static final String FETCH_REQUEST_URL_INTERCEPT_CLASS = "com.a.eye.skywalking.plugin.motan.MotanConsumerFetchRequestURLInterceptor";
|
||||
|
||||
private static final String INVOKE_INTERCEPT_CLASS = "com.a.eye.skywalking.plugin.motan.MotanConsumerInvokeInterceptor";
|
||||
|
||||
@Override
|
||||
protected String enhanceClassName() {
|
||||
return ENHANCE_CLASS;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
|
||||
return new ConstructorInterceptPoint[0];
|
||||
}
|
||||
|
||||
@Override
|
||||
protected InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
|
||||
return new InstanceMethodsInterceptPoint[]{new InstanceMethodsInterceptPoint() {
|
||||
@Override
|
||||
public ElementMatcher<MethodDescription> getMethodsMatcher() {
|
||||
return named("setUrl");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMethodsInterceptor() {
|
||||
return FETCH_REQUEST_URL_INTERCEPT_CLASS;
|
||||
}
|
||||
}, new InstanceMethodsInterceptPoint() {
|
||||
@Override
|
||||
public ElementMatcher<MethodDescription> getMethodsMatcher() {
|
||||
return named("call");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMethodsInterceptor() {
|
||||
return INVOKE_INTERCEPT_CLASS;
|
||||
}
|
||||
}};
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,72 @@
|
|||
package com.a.eye.skywalking.plugin.motan.define;
|
||||
|
||||
import com.a.eye.skywalking.api.plugin.interceptor.ConstructorInterceptPoint;
|
||||
import com.a.eye.skywalking.api.plugin.interceptor.InstanceMethodsInterceptPoint;
|
||||
import com.a.eye.skywalking.api.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine;
|
||||
import com.a.eye.skywalking.plugin.motan.MotanProviderInterceptor;
|
||||
import com.weibo.api.motan.rpc.Request;
|
||||
|
||||
import net.bytebuddy.description.method.MethodDescription;
|
||||
import net.bytebuddy.matcher.ElementMatcher;
|
||||
|
||||
import static net.bytebuddy.matcher.ElementMatchers.any;
|
||||
import static net.bytebuddy.matcher.ElementMatchers.named;
|
||||
|
||||
/**
|
||||
* {@link MotanProviderInstrumentation} presents that skywalking will use
|
||||
* {@link MotanProviderInterceptor} to intercept
|
||||
* all constructor of {@link com.weibo.api.motan.rpc.AbstractProvider} and
|
||||
* {@link com.weibo.api.motan.rpc.AbstractProvider#call(Request)}.
|
||||
*
|
||||
* @author zhangxin
|
||||
*/
|
||||
public class MotanProviderInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
|
||||
|
||||
/**
|
||||
* Enhance class.
|
||||
*/
|
||||
private static final String ENHANCE_CLASS = "com.weibo.api.motan.rpc.AbstractProvider";
|
||||
/**
|
||||
* Class that intercept all constructor of ${@link com.weibo.api.motan.rpc.AbstractProvider}.
|
||||
*/
|
||||
private static final String CONSTRUCTOR_INTERCEPT_CLASS = "com.a.eye.skywalking.plugin.motan.MotanProviderInterceptor";
|
||||
/**
|
||||
* Class that intercept {@link com.weibo.api.motan.rpc.AbstractProvider#call(Request)}.
|
||||
*/
|
||||
private static final String PROVIDER_INVOKE_INTERCEPT_CLASS = "com.a.eye.skywalking.plugin.motan.MotanProviderInterceptor";
|
||||
|
||||
@Override
|
||||
protected String enhanceClassName() {
|
||||
return ENHANCE_CLASS;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
|
||||
return new ConstructorInterceptPoint[]{new ConstructorInterceptPoint() {
|
||||
@Override
|
||||
public ElementMatcher<MethodDescription> getConstructorMatcher() {
|
||||
return any();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getConstructorInterceptor() {
|
||||
return CONSTRUCTOR_INTERCEPT_CLASS;
|
||||
}
|
||||
}};
|
||||
}
|
||||
|
||||
@Override
|
||||
protected InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
|
||||
return new InstanceMethodsInterceptPoint[]{new InstanceMethodsInterceptPoint() {
|
||||
@Override
|
||||
public ElementMatcher<MethodDescription> getMethodsMatcher() {
|
||||
return named("call");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMethodsInterceptor() {
|
||||
return PROVIDER_INVOKE_INTERCEPT_CLASS;
|
||||
}
|
||||
}};
|
||||
}
|
||||
}
|
||||
|
|
@ -1,2 +1,2 @@
|
|||
com.a.eye.skywalking.plugin.motan.define.MotanClientDefine
|
||||
com.a.eye.skywalking.plugin.motan.define.MotanServerDefine
|
||||
com.a.eye.skywalking.plugin.motan.define.MotanConsumerInstrumentation
|
||||
com.a.eye.skywalking.plugin.motan.define.MotanProviderInstrumentation
|
||||
|
|
|
|||
|
|
@ -31,7 +31,13 @@
|
|||
<dependency>
|
||||
<groupId>com.a.eye</groupId>
|
||||
<artifactId>skywalking-api</artifactId>
|
||||
<version>3.0-2017</version>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.a.eye</groupId>
|
||||
<artifactId>skywalking-sniffer-mock</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,70 +0,0 @@
|
|||
package com.a.eye.skywalking.api.plugin.tomcat78x;
|
||||
|
||||
import com.a.eye.skywalking.api.Tracing;
|
||||
import com.a.eye.skywalking.invoke.monitor.RPCServerInvokeMonitor;
|
||||
import com.a.eye.skywalking.model.ContextData;
|
||||
import com.a.eye.skywalking.model.Identification;
|
||||
import com.a.eye.skywalking.api.plugin.interceptor.EnhancedClassInstanceContext;
|
||||
import com.a.eye.skywalking.plugin.interceptor.enhance.ConstructorInvokeContext;
|
||||
import com.a.eye.skywalking.plugin.interceptor.enhance.InstanceMethodInvokeContext;
|
||||
import com.a.eye.skywalking.api.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
|
||||
import com.a.eye.skywalking.api.plugin.interceptor.enhance.MethodInterceptResult;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
public class TomcatPluginInterceptor implements InstanceMethodsAroundInterceptor {
|
||||
private final String secondKey = "ContextData";
|
||||
private String tracingName = DEFAULT_TRACE_NAME;
|
||||
private static final String DEFAULT_TRACE_NAME = "SkyWalking-TRACING-NAME";
|
||||
private static final String TRACE_ID_HEADER_NAME = "SW-TraceId";
|
||||
|
||||
@Override
|
||||
public void beforeMethod(EnhancedClassInstanceContext context, InstanceMethodInvokeContext interceptorContext, MethodInterceptResult result) {
|
||||
Object[] args = interceptorContext.allArguments();
|
||||
HttpServletRequest requests = (HttpServletRequest) args[0];
|
||||
String tracingHeaderValue = requests.getHeader(tracingName);
|
||||
ContextData contextData = null;
|
||||
if (tracingHeaderValue != null) {
|
||||
String contextDataStr = null;
|
||||
int index = tracingHeaderValue.indexOf("=");
|
||||
if (index > 0) {
|
||||
String key = tracingHeaderValue.substring(0, index);
|
||||
if (secondKey.equals(key)) {
|
||||
contextDataStr = tracingHeaderValue.substring(index + 1);
|
||||
}
|
||||
}
|
||||
|
||||
if (contextDataStr != null && contextDataStr.length() > 0) {
|
||||
contextData = new ContextData(contextDataStr);
|
||||
}
|
||||
}
|
||||
RPCServerInvokeMonitor rpcServerInvokeMonitor = new RPCServerInvokeMonitor();
|
||||
rpcServerInvokeMonitor.beforeInvoke(contextData, generateIdentification(requests));
|
||||
}
|
||||
|
||||
|
||||
private Identification generateIdentification(HttpServletRequest request) {
|
||||
return Identification.newBuilder()
|
||||
.viewPoint(request.getRequestURL().toString())
|
||||
.spanType(WebBuriedPointType.INSTANCE)
|
||||
.build();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Object afterMethod(EnhancedClassInstanceContext context, InstanceMethodInvokeContext interceptorContext, Object ret) {
|
||||
Object[] args = interceptorContext.allArguments();
|
||||
HttpServletResponse httpServletResponse = (HttpServletResponse) args[1];
|
||||
httpServletResponse.addHeader(TRACE_ID_HEADER_NAME, Tracing.getTraceId());
|
||||
new RPCServerInvokeMonitor().afterInvoke();
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleMethodException(Throwable t, EnhancedClassInstanceContext context,
|
||||
InstanceMethodInvokeContext interceptorContext) {
|
||||
new RPCServerInvokeMonitor().occurException(t);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
package com.a.eye.skywalking.api.plugin.tomcat78x;
|
||||
|
||||
import com.a.eye.skywalking.api.IBuriedPointType;
|
||||
|
||||
public enum WebBuriedPointType implements IBuriedPointType {
|
||||
INSTANCE;
|
||||
|
||||
@Override
|
||||
public String getTypeName() {
|
||||
return "W";
|
||||
}
|
||||
|
||||
@Override
|
||||
public CallType getCallType() {
|
||||
return CallType.SYNC;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,36 +0,0 @@
|
|||
package com.a.eye.skywalking.api.plugin.tomcat78x.define;
|
||||
|
||||
import com.a.eye.skywalking.plugin.interceptor.ConstructorInterceptPoint;
|
||||
import com.a.eye.skywalking.api.plugin.interceptor.InstanceMethodsInterceptPoint;
|
||||
import com.a.eye.skywalking.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine;
|
||||
import net.bytebuddy.description.method.MethodDescription;
|
||||
import net.bytebuddy.matcher.ElementMatcher;
|
||||
|
||||
import static net.bytebuddy.matcher.ElementMatchers.named;
|
||||
|
||||
public class TomcatPluginDefine extends ClassInstanceMethodsEnhancePluginDefine {
|
||||
@Override
|
||||
protected String enhanceClassName() {
|
||||
return "org.apache.catalina.core.StandardEngineValve";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
|
||||
return new InstanceMethodsInterceptPoint[]{new InstanceMethodsInterceptPoint() {
|
||||
@Override
|
||||
public ElementMatcher<MethodDescription> getMethodsMatcher() {
|
||||
return named("invoke");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMethodsInterceptor() {
|
||||
return "com.a.eye.skywalking.plugin.tomcat78x.TomcatPluginInterceptor";
|
||||
}
|
||||
}};
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,79 @@
|
|||
package com.a.eye.skywalking.plugin.tomcat78x;
|
||||
|
||||
import com.a.eye.skywalking.api.context.ContextCarrier;
|
||||
import com.a.eye.skywalking.api.context.ContextManager;
|
||||
import com.a.eye.skywalking.api.plugin.interceptor.EnhancedClassInstanceContext;
|
||||
import com.a.eye.skywalking.api.plugin.interceptor.enhance.InstanceMethodInvokeContext;
|
||||
import com.a.eye.skywalking.api.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
|
||||
import com.a.eye.skywalking.api.plugin.interceptor.enhance.MethodInterceptResult;
|
||||
import com.a.eye.skywalking.api.util.StringUtil;
|
||||
import com.a.eye.skywalking.trace.Span;
|
||||
import com.a.eye.skywalking.trace.tag.Tags;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
/**
|
||||
* {@link TomcatInterceptor} fetch the serialized context data by using {@link HttpServletRequest#getHeader(String)}.
|
||||
* The {@link com.a.eye.skywalking.trace.TraceSegment#primaryRef} of current trace segment will reference to the trace segment id
|
||||
* of the previous level if the serialized context is not null.
|
||||
*/
|
||||
public class TomcatInterceptor implements InstanceMethodsAroundInterceptor {
|
||||
/**
|
||||
* Header name that the serialized context data stored in {@link HttpServletRequest#getHeader(String)}.
|
||||
*/
|
||||
public static final String HEADER_NAME_OF_CONTEXT_DATA = "SKYWALKING_CONTEXT_DATA";
|
||||
/**
|
||||
* Tomcat component.
|
||||
*/
|
||||
public static final String TOMCAT_COMPONENT = "Tomcat";
|
||||
|
||||
/**
|
||||
* The {@link com.a.eye.skywalking.trace.TraceSegment#primaryRef} of current trace segment will reference to the trace segment id
|
||||
* of the previous level if the serialized context is not null.
|
||||
*
|
||||
* @param context instance context, a class instance only has one {@link EnhancedClassInstanceContext} instance.
|
||||
* @param interceptorContext method context, includes class name, method name, etc.
|
||||
* @param result change this result, if you want to truncate the method.
|
||||
*/
|
||||
@Override
|
||||
public void beforeMethod(EnhancedClassInstanceContext context, InstanceMethodInvokeContext interceptorContext, MethodInterceptResult result) {
|
||||
Object[] args = interceptorContext.allArguments();
|
||||
HttpServletRequest request = (HttpServletRequest) args[0];
|
||||
|
||||
Span span = ContextManager.INSTANCE.createSpan(request.getRequestURI());
|
||||
Tags.COMPONENT.set(span, TOMCAT_COMPONENT);
|
||||
Tags.SPAN_KIND.set(span, Tags.SPAN_KIND_SERVER);
|
||||
Tags.URL.set(span, request.getRequestURL().toString());
|
||||
Tags.SPAN_LAYER.asHttp(span);
|
||||
|
||||
String tracingHeaderValue = request.getHeader(HEADER_NAME_OF_CONTEXT_DATA);
|
||||
if (!StringUtil.isEmpty(tracingHeaderValue)) {
|
||||
ContextManager.INSTANCE.extract(new ContextCarrier().deserialize(tracingHeaderValue));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object afterMethod(EnhancedClassInstanceContext context, InstanceMethodInvokeContext interceptorContext, Object ret) {
|
||||
HttpServletResponse response = (HttpServletResponse) interceptorContext.allArguments()[1];
|
||||
|
||||
Span span = ContextManager.INSTANCE.activeSpan();
|
||||
Tags.STATUS_CODE.set(span, response.getStatus());
|
||||
|
||||
if (response.getStatus() != 200) {
|
||||
Tags.ERROR.set(span, true);
|
||||
}
|
||||
|
||||
ContextManager.INSTANCE.stopSpan();
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleMethodException(Throwable t, EnhancedClassInstanceContext context,
|
||||
InstanceMethodInvokeContext interceptorContext) {
|
||||
Span span = ContextManager.INSTANCE.activeSpan();
|
||||
span.log(t);
|
||||
Tags.ERROR.set(span, true);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
package com.a.eye.skywalking.plugin.tomcat78x.define;
|
||||
|
||||
import com.a.eye.skywalking.api.plugin.interceptor.ConstructorInterceptPoint;
|
||||
import com.a.eye.skywalking.api.plugin.interceptor.InstanceMethodsInterceptPoint;
|
||||
import com.a.eye.skywalking.api.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine;
|
||||
import com.a.eye.skywalking.plugin.tomcat78x.TomcatInterceptor;
|
||||
|
||||
import net.bytebuddy.description.method.MethodDescription;
|
||||
import net.bytebuddy.matcher.ElementMatcher;
|
||||
|
||||
import org.apache.catalina.connector.Request;
|
||||
import org.apache.catalina.connector.Response;
|
||||
|
||||
import static net.bytebuddy.matcher.ElementMatchers.named;
|
||||
|
||||
/**
|
||||
* {@link TomcatInstrumentation} presents that skywalking using class {@link TomcatInterceptor} to
|
||||
* intercept {@link org.apache.catalina.core.StandardEngineValve#invoke(Request, Response)}.
|
||||
*
|
||||
* @author zhangxin
|
||||
*/
|
||||
public class TomcatInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
|
||||
|
||||
/**
|
||||
* Enhance class.
|
||||
*/
|
||||
private static final String ENHANCE_CLASS = "org.apache.catalina.core.StandardEngineValve";
|
||||
|
||||
/**
|
||||
* Intercept class.
|
||||
*/
|
||||
private static final String INTERCEPT_CLASS = "com.a.eye.skywalking.plugin.tomcat78x.TomcatInterceptor";
|
||||
|
||||
@Override
|
||||
protected String enhanceClassName() {
|
||||
return ENHANCE_CLASS;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
|
||||
return new InstanceMethodsInterceptPoint[]{new InstanceMethodsInterceptPoint() {
|
||||
@Override
|
||||
public ElementMatcher<MethodDescription> getMethodsMatcher() {
|
||||
return named("invoke");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMethodsInterceptor() {
|
||||
return INTERCEPT_CLASS;
|
||||
}
|
||||
}};
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue