support new api for each plugin
This commit is contained in:
parent
1f3f25d691
commit
7ccaa419e1
|
|
@ -9,4 +9,22 @@ public class ComponentsDefine {
|
|||
public static final OfficialComponent HTTPCLIENT = new OfficialComponent(2, "HttpClient");
|
||||
|
||||
public static final OfficialComponent DUBBO = new OfficialComponent(3, "Dubbo");
|
||||
|
||||
public static final OfficialComponent H2 = new OfficialComponent(4, "H2");
|
||||
|
||||
public static final OfficialComponent MYSQL = new OfficialComponent(5, "Mysql");
|
||||
|
||||
public static final OfficialComponent ORACLE = new OfficialComponent(6, "ORACLE");
|
||||
|
||||
public static final OfficialComponent REDIS = new OfficialComponent(7, "Redis");
|
||||
|
||||
public static final OfficialComponent MOTAN = new OfficialComponent(8, "Motan");
|
||||
|
||||
public static final OfficialComponent MONGODB = new OfficialComponent(9, "MongoDB");
|
||||
|
||||
public static final OfficialComponent RESIN = new OfficialComponent(10, "Resin");
|
||||
|
||||
public static final OfficialComponent FEIGN = new OfficialComponent(11, "Feign");
|
||||
|
||||
public static final OfficialComponent OKHTTP = new OfficialComponent(12, "OKHttp");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,9 @@ import io.grpc.internal.DnsNameResolverProvider;
|
|||
import io.grpc.netty.NettyChannelBuilder;
|
||||
import io.grpc.stub.StreamObserver;
|
||||
import org.junit.Assert;
|
||||
import org.skywalking.apm.network.collecor.proto.Downstream;
|
||||
import org.skywalking.apm.network.proto.Downstream;
|
||||
import org.skywalking.apm.network.proto.TraceSegmentServiceGrpc;
|
||||
import org.skywalking.apm.network.proto.UpstreamSegment;
|
||||
|
||||
/**
|
||||
* @author wusheng
|
||||
|
|
|
|||
|
|
@ -155,7 +155,7 @@ public abstract class AbstractTracingSpan implements AbstractSpan {
|
|||
return this;
|
||||
}
|
||||
|
||||
public SpanObject.Builder transform(){
|
||||
public SpanObject.Builder transform() {
|
||||
SpanObject.Builder spanBuilder = SpanObject.newBuilder();
|
||||
|
||||
spanBuilder.setSpanId(this.spanId);
|
||||
|
|
|
|||
|
|
@ -1,9 +1,6 @@
|
|||
package org.skywalking.apm.agent.core.context.trace;
|
||||
|
||||
import org.skywalking.apm.agent.core.context.util.KeyValuePair;
|
||||
import org.skywalking.apm.agent.core.dictionary.DictionaryUtil;
|
||||
import org.skywalking.apm.network.proto.SpanObject;
|
||||
import org.skywalking.apm.network.proto.SpanType;
|
||||
import org.skywalking.apm.network.trace.component.Component;
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ public class LocalSpan extends AbstractTracingSpan {
|
|||
return this;
|
||||
}
|
||||
|
||||
@Override public SpanObject transform() {
|
||||
@Override public SpanObject.Builder transform() {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ package org.skywalking.apm.agent.core.context.trace;
|
|||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import org.skywalking.apm.agent.core.context.util.KeyValuePair;
|
||||
import org.skywalking.apm.network.proto.KeyWithStringValue;
|
||||
import org.skywalking.apm.network.proto.LogMessage;
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -13,7 +13,6 @@ import org.skywalking.apm.agent.core.dictionary.PossibleFound;
|
|||
import org.skywalking.apm.logging.ILog;
|
||||
import org.skywalking.apm.logging.LogManager;
|
||||
import org.skywalking.apm.network.proto.TraceSegmentObject;
|
||||
import org.skywalking.apm.network.proto.TraceSegmentReference;
|
||||
import org.skywalking.apm.network.proto.UpstreamSegment;
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -1,11 +1,8 @@
|
|||
package org.skywalking.apm.agent.core.context.trace;
|
||||
|
||||
import java.util.List;
|
||||
import org.skywalking.apm.agent.core.context.ContextCarrier;
|
||||
import org.skywalking.apm.agent.core.context.ids.DistributedTraceId;
|
||||
import org.skywalking.apm.agent.core.dictionary.DictionaryUtil;
|
||||
import org.skywalking.apm.network.proto.TraceSegmentReference;
|
||||
import org.skywalking.apm.network.proto.UpstreamSegment;
|
||||
|
||||
/**
|
||||
* {@link TraceSegmentRef} is like a pointer, which ref to another {@link TraceSegment},
|
||||
|
|
|
|||
|
|
@ -1,12 +1,10 @@
|
|||
package org.skywalking.apm.agent.core.plugin.interceptor.enhance;
|
||||
|
||||
import net.bytebuddy.description.method.MethodDescription;
|
||||
import net.bytebuddy.dynamic.DynamicType;
|
||||
import net.bytebuddy.implementation.FieldAccessor;
|
||||
import net.bytebuddy.implementation.MethodDelegation;
|
||||
import net.bytebuddy.implementation.SuperMethodCall;
|
||||
import net.bytebuddy.implementation.bind.annotation.Morph;
|
||||
import net.bytebuddy.matcher.ElementMatchers;
|
||||
import org.skywalking.apm.agent.core.plugin.AbstractClassEnhancePluginDefine;
|
||||
import org.skywalking.apm.agent.core.plugin.PluginException;
|
||||
import org.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
|
||||
|
|
@ -101,7 +99,7 @@ public abstract class ClassEnhancePluginDefine extends AbstractClassEnhancePlugi
|
|||
*/
|
||||
if (existedConstructorInterceptPoint) {
|
||||
for (ConstructorInterceptPoint constructorInterceptPoint : constructorInterceptPoints) {
|
||||
newClassBuilder = newClassBuilder.constructor(ElementMatchers.<MethodDescription>any()).intercept(SuperMethodCall.INSTANCE
|
||||
newClassBuilder = newClassBuilder.constructor(constructorInterceptPoint.getConstructorMatcher()).intercept(SuperMethodCall.INSTANCE
|
||||
.andThen(MethodDelegation.withDefaultConfiguration()
|
||||
.to(new ConstructorInter(constructorInterceptPoint.getConstructorInterceptor(), classLoader))
|
||||
)
|
||||
|
|
|
|||
|
|
@ -11,5 +11,5 @@ public interface InstanceConstructorInterceptor {
|
|||
/**
|
||||
* Called before the origin constructor invocation.
|
||||
*/
|
||||
void onConstruct(Object objInst, Object[] allArguments);
|
||||
void onConstruct(EnhancedInstance objInst, Object[] allArguments);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
package org.skywalking.apm.agent.core.remote;
|
||||
|
||||
import org.skywalking.apm.agent.core.boot.BootService;
|
||||
import org.skywalking.apm.agent.core.remote.DiscoveryRestServiceClient;
|
||||
|
||||
/**
|
||||
* The <code>CollectorDiscoveryService</code> is responsible for start {@link DiscoveryRestServiceClient}.
|
||||
|
|
|
|||
|
|
@ -16,8 +16,11 @@ import org.skywalking.apm.agent.core.context.ContextCarrier;
|
|||
import org.skywalking.apm.agent.core.context.ContextManager;
|
||||
import org.skywalking.apm.agent.core.context.tag.Tags;
|
||||
import org.skywalking.apm.agent.core.context.trace.AbstractSpan;
|
||||
import org.skywalking.apm.agent.core.context.trace.SpanLayer;
|
||||
import org.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
|
||||
import org.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
|
||||
import org.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
|
||||
import org.skywalking.apm.network.trace.component.ComponentsDefine;
|
||||
|
||||
/**
|
||||
* {@link DefaultHttpClientInterceptor} intercept the default implementation of http calls by the Feign.
|
||||
|
|
@ -29,32 +32,25 @@ public class DefaultHttpClientInterceptor implements InstanceMethodsAroundInterc
|
|||
private static final String COMPONENT_NAME = "FeignDefaultHttp";
|
||||
|
||||
/**
|
||||
* Get the {@link feign.Request} from {@link EnhancedClassInstanceContext}, then create {@link Span} and set host,
|
||||
* Get the {@link feign.Request} from {@link EnhancedInstance}, then create {@link AbstractSpan} and set host,
|
||||
* port, kind, component, url from {@link feign.Request}.
|
||||
* Through the reflection of the way, set the http header of context data into {@link feign.Request#headers}.
|
||||
*
|
||||
* @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.
|
||||
* @throws Throwable
|
||||
*/
|
||||
@Override
|
||||
public void beforeMethod(EnhancedClassInstanceContext context, InstanceMethodInvokeContext interceptorContext,
|
||||
MethodInterceptResult result) throws Throwable {
|
||||
Request request = (Request)interceptorContext.allArguments()[0];
|
||||
@Override public void beforeMethod(EnhancedInstance objInst, String methodName, Object[] allArguments,
|
||||
Class<?>[] argumentsTypes, MethodInterceptResult result) throws Throwable {
|
||||
Request request = (Request)allArguments[0];
|
||||
|
||||
URL url = new URL(request.url());
|
||||
AbstractSpan span = ContextManager.createSpan(request.url());
|
||||
span.setPeerHost(url.getHost());
|
||||
span.setPort(url.getPort());
|
||||
Tags.SPAN_KIND.set(span, Tags.SPAN_KIND_CLIENT);
|
||||
Tags.COMPONENT.set(span, COMPONENT_NAME);
|
||||
ContextCarrier contextCarrier = new ContextCarrier();
|
||||
String remotePeer = url.getHost() + ":" + url.getPort();
|
||||
AbstractSpan span = ContextManager.createExitSpan(request.url(), contextCarrier, remotePeer);
|
||||
span.setComponent(ComponentsDefine.FEIGN);
|
||||
Tags.HTTP.METHOD.set(span, request.method());
|
||||
Tags.URL.set(span, url.getPath());
|
||||
Tags.SPAN_LAYER.asHttp(span);
|
||||
|
||||
ContextCarrier contextCarrier = new ContextCarrier();
|
||||
ContextManager.inject(contextCarrier);
|
||||
SpanLayer.asHttp(span);
|
||||
|
||||
List<String> contextCollection = new ArrayList<String>();
|
||||
contextCollection.add(contextCarrier.serialize());
|
||||
|
|
@ -75,34 +71,32 @@ public class DefaultHttpClientInterceptor implements InstanceMethodsAroundInterc
|
|||
/**
|
||||
* Get the status code from {@link Response}, when status code greater than 400, it means there was some errors in
|
||||
* the server.
|
||||
* Finish the {@link Span}.
|
||||
* Finish the {@link AbstractSpan}.
|
||||
*
|
||||
* @param context instance context, a class instance only has one {@link EnhancedClassInstanceContext} instance.
|
||||
* @param interceptorContext method context, includes class name, method name, etc.
|
||||
* @param ret the method's original return value.
|
||||
* @return
|
||||
* @throws Throwable
|
||||
*/
|
||||
@Override
|
||||
public Object afterMethod(EnhancedClassInstanceContext context, InstanceMethodInvokeContext interceptorContext,
|
||||
Object ret) throws Throwable {
|
||||
@Override public Object afterMethod(EnhancedInstance objInst, String methodName, Object[] allArguments,
|
||||
Class<?>[] argumentsTypes, Object ret) throws Throwable {
|
||||
Response response = (Response)ret;
|
||||
int statusCode = response.status();
|
||||
|
||||
AbstractSpan span = ContextManager.activeSpan();
|
||||
if (statusCode >= 400) {
|
||||
Tags.ERROR.set(span, true);
|
||||
span.errorOccurred();
|
||||
Tags.STATUS_CODE.set(span, statusCode + "");
|
||||
}
|
||||
|
||||
Tags.STATUS_CODE.set(span, statusCode);
|
||||
ContextManager.stopSpan();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override public void handleMethodException(Throwable t, EnhancedClassInstanceContext context,
|
||||
InstanceMethodInvokeContext interceptorContext) {
|
||||
Tags.ERROR.set(ContextManager.activeSpan(), true);
|
||||
ContextManager.activeSpan().log(t);
|
||||
@Override public void handleMethodException(EnhancedInstance objInst, String methodName, Object[] allArguments,
|
||||
Class<?>[] argumentsTypes, Throwable t) {
|
||||
AbstractSpan activeSpan = ContextManager.activeSpan();
|
||||
activeSpan.log(t);
|
||||
activeSpan.errorOccurred();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -47,6 +47,10 @@ public class DefaultHttpClientInstrumentation extends ClassInstanceMethodsEnhanc
|
|||
@Override public String getMethodsInterceptor() {
|
||||
return INTERCEPT_CLASS;
|
||||
}
|
||||
|
||||
@Override public boolean isOverrideArgs() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,11 +2,9 @@ package org.skywalking.apm.plugin.httpClient.v4;
|
|||
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
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;
|
||||
import org.skywalking.apm.agent.core.conf.Config;
|
||||
import org.skywalking.apm.agent.core.context.ContextCarrier;
|
||||
import org.skywalking.apm.agent.core.context.ContextManager;
|
||||
|
|
@ -18,12 +16,6 @@ import org.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsA
|
|||
import org.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
|
||||
import org.skywalking.apm.network.trace.component.ComponentsDefine;
|
||||
|
||||
/**
|
||||
* {@link HttpClientExecuteInterceptor} transport the trace context by call {@link HttpRequest#setHeader(Header)},
|
||||
* The {@link Tags#STATUS_CODE} will be set if {@link StatusLine#getStatusCode()} is not equals 200.
|
||||
*
|
||||
* @author zhangxin
|
||||
*/
|
||||
public class HttpClientExecuteInterceptor implements InstanceMethodsAroundInterceptor {
|
||||
|
||||
@Override public void beforeMethod(EnhancedInstance objInst, String methodName, Object[] allArguments,
|
||||
|
|
@ -60,9 +52,9 @@ public class HttpClientExecuteInterceptor implements InstanceMethodsAroundInterc
|
|||
HttpResponse response = (HttpResponse)ret;
|
||||
int statusCode = response.getStatusLine().getStatusCode();
|
||||
AbstractSpan span = ContextManager.activeSpan();
|
||||
if (statusCode != 200) {
|
||||
if (statusCode >= 400) {
|
||||
span.errorOccurred();
|
||||
Tags.STATUS_CODE.set(span, statusCode + "");
|
||||
Tags.STATUS_CODE.set(span, Integer.toString(statusCode));
|
||||
}
|
||||
|
||||
ContextManager.stopSpan();
|
||||
|
|
|
|||
|
|
@ -1,42 +1,35 @@
|
|||
package org.skywalking.apm.plugin.jdbc;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import org.skywalking.apm.agent.core.context.ContextCarrier;
|
||||
import org.skywalking.apm.agent.core.context.ContextManager;
|
||||
import org.skywalking.apm.agent.core.context.tag.Tags;
|
||||
import org.skywalking.apm.agent.core.context.trace.AbstractSpan;
|
||||
import org.skywalking.apm.agent.core.context.trace.SpanLayer;
|
||||
import org.skywalking.apm.util.StringUtil;
|
||||
|
||||
/**
|
||||
* {@link CallableStatementTracing} create span with the {@link Span#operationName} start with
|
||||
* "JDBC/CallableStatement/"and set {@link ConnectionInfo#dbType} to the {@link Tags#COMPONENT}.
|
||||
* <p>
|
||||
* Notice: {@link Span#peerHost} 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)
|
||||
ConnectionInfo connectInfo, String method, String sql, Executable<R> exec)
|
||||
throws SQLException {
|
||||
try {
|
||||
AbstractSpan span = ContextManager.createSpan(connectInfo.getDBType() + "/JDBI/CallableStatement/" + method);
|
||||
String remotePeer;
|
||||
if (!StringUtil.isEmpty(connectInfo.getHosts())) {
|
||||
remotePeer = connectInfo.getHosts();
|
||||
} else {
|
||||
remotePeer = connectInfo.getHost() + ":" + connectInfo.getPort();
|
||||
}
|
||||
AbstractSpan span = ContextManager.createExitSpan(connectInfo.getDBType() + "/JDBI/CallableStatement/" + method, new ContextCarrier(), remotePeer);
|
||||
Tags.DB_TYPE.set(span, "sql");
|
||||
Tags.SPAN_KIND.set(span, Tags.SPAN_KIND_CLIENT);
|
||||
SpanLayer.asDB(span);
|
||||
Tags.DB_INSTANCE.set(span, connectInfo.getDatabaseName());
|
||||
Tags.DB_STATEMENT.set(span, sql);
|
||||
Tags.SPAN_LAYER.asDB(span);
|
||||
Tags.COMPONENT.set(span, connectInfo.getDBType());
|
||||
if (!StringUtil.isEmpty(connectInfo.getHosts())) {
|
||||
span.setPeers(connectInfo.getHosts());
|
||||
} else {
|
||||
span.setPeerHost(connectInfo.getHost());
|
||||
span.setPort(connectInfo.getPort());
|
||||
}
|
||||
span.setComponent(connectInfo.getComponent());
|
||||
return exec.exe(realStatement, sql);
|
||||
} catch (SQLException e) {
|
||||
AbstractSpan span = ContextManager.activeSpan();
|
||||
Tags.ERROR.set(span, true);
|
||||
span.errorOccurred();
|
||||
span.log(e);
|
||||
throw e;
|
||||
} finally {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
package org.skywalking.apm.plugin.jdbc;
|
||||
|
||||
import org.skywalking.apm.network.trace.component.OfficialComponent;
|
||||
|
||||
/**
|
||||
* {@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.
|
||||
|
|
@ -28,17 +30,24 @@ public class ConnectionInfo {
|
|||
*/
|
||||
private String hosts;
|
||||
|
||||
public ConnectionInfo(String dbType, String host, int port, String databaseName) {
|
||||
/**
|
||||
* Component
|
||||
*/
|
||||
private final OfficialComponent component;
|
||||
|
||||
public ConnectionInfo(OfficialComponent component, String dbType, String host, int port, String databaseName) {
|
||||
this.dbType = dbType;
|
||||
this.host = host;
|
||||
this.port = port;
|
||||
this.databaseName = databaseName;
|
||||
this.component = component;
|
||||
}
|
||||
|
||||
public ConnectionInfo(String dbType, String hosts, String databaseName) {
|
||||
public ConnectionInfo(OfficialComponent component, String dbType, String hosts, String databaseName) {
|
||||
this.dbType = dbType;
|
||||
this.hosts = hosts;
|
||||
this.databaseName = databaseName;
|
||||
this.component = component;
|
||||
}
|
||||
|
||||
public String getDBType() {
|
||||
|
|
@ -60,4 +69,9 @@ public class ConnectionInfo {
|
|||
public String getHosts() {
|
||||
return hosts;
|
||||
}
|
||||
|
||||
public OfficialComponent getComponent() {
|
||||
return component;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,43 +1,35 @@
|
|||
package org.skywalking.apm.plugin.jdbc;
|
||||
|
||||
import org.skywalking.apm.agent.core.context.ContextManager;
|
||||
import org.skywalking.apm.agent.core.context.trace.AbstractSpan;
|
||||
import org.skywalking.apm.util.StringUtil;
|
||||
import org.skywalking.apm.agent.core.context.tag.Tags;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import org.skywalking.apm.agent.core.context.ContextCarrier;
|
||||
import org.skywalking.apm.agent.core.context.ContextManager;
|
||||
import org.skywalking.apm.agent.core.context.tag.Tags;
|
||||
import org.skywalking.apm.agent.core.context.trace.AbstractSpan;
|
||||
import org.skywalking.apm.agent.core.context.trace.SpanLayer;
|
||||
import org.skywalking.apm.util.StringUtil;
|
||||
|
||||
/**
|
||||
* {@link ConnectionTracing} create span with the {@link Span#operationName} start with
|
||||
* "JDBC/Connection/"and set {@link ConnectionInfo#dbType} to the {@link Tags#COMPONENT}.
|
||||
* <p>
|
||||
* Notice: {@link Span#peerHost} 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)
|
||||
ConnectionInfo connectInfo, String method, String sql, Executable<R> exec)
|
||||
throws SQLException {
|
||||
try {
|
||||
AbstractSpan span = ContextManager.createSpan(connectInfo.getDBType() + "/JDBI/Connection/" + method);
|
||||
String remotePeer;
|
||||
if (!StringUtil.isEmpty(connectInfo.getHosts())) {
|
||||
remotePeer = connectInfo.getHosts();
|
||||
} else {
|
||||
remotePeer = connectInfo.getHost() + ":" + connectInfo.getPort();
|
||||
}
|
||||
AbstractSpan span = ContextManager.createExitSpan(connectInfo.getDBType() + "/JDBI/Connection/" + method, new ContextCarrier(), remotePeer);
|
||||
Tags.DB_TYPE.set(span, "sql");
|
||||
Tags.SPAN_KIND.set(span, Tags.SPAN_KIND_CLIENT);
|
||||
Tags.DB_INSTANCE.set(span, connectInfo.getDatabaseName());
|
||||
Tags.DB_STATEMENT.set(span, sql);
|
||||
Tags.COMPONENT.set(span, connectInfo.getDBType());
|
||||
Tags.SPAN_LAYER.asDB(span);
|
||||
if (!StringUtil.isEmpty(connectInfo.getHosts())) {
|
||||
span.setPeers(connectInfo.getHosts());
|
||||
} else {
|
||||
span.setPeerHost(connectInfo.getHost());
|
||||
span.setPort(connectInfo.getPort());
|
||||
}
|
||||
span.setComponent(connectInfo.getComponent());
|
||||
SpanLayer.asDB(span);
|
||||
return exec.exe(realConnection, sql);
|
||||
} catch (SQLException e) {
|
||||
AbstractSpan span = ContextManager.activeSpan();
|
||||
Tags.ERROR.set(span, true);
|
||||
span.errorOccurred();
|
||||
span.log(e);
|
||||
throw e;
|
||||
} finally {
|
||||
|
|
|
|||
|
|
@ -1,42 +1,37 @@
|
|||
package org.skywalking.apm.plugin.jdbc;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import org.skywalking.apm.agent.core.context.ContextCarrier;
|
||||
import org.skywalking.apm.agent.core.context.ContextManager;
|
||||
import org.skywalking.apm.agent.core.context.tag.Tags;
|
||||
import org.skywalking.apm.agent.core.context.trace.AbstractSpan;
|
||||
import org.skywalking.apm.agent.core.context.trace.SpanLayer;
|
||||
import org.skywalking.apm.util.StringUtil;
|
||||
|
||||
/**
|
||||
* {@link PreparedStatementTracing} create span with the {@link Span#operationName} start with
|
||||
* "JDBC/PreparedStatement/"and set {@link ConnectionInfo#dbType} to the {@link Tags#COMPONENT}.
|
||||
* <p>
|
||||
* Notice: {@link Span#peerHost} 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)
|
||||
ConnectionInfo connectInfo, String method, String sql, Executable<R> exec)
|
||||
throws SQLException {
|
||||
try {
|
||||
AbstractSpan span = ContextManager.createSpan(connectInfo.getDBType() + "/JDBI/PreparedStatement/" + method);
|
||||
String remotePeer;
|
||||
if (!StringUtil.isEmpty(connectInfo.getHosts())) {
|
||||
remotePeer = connectInfo.getHosts();
|
||||
} else {
|
||||
remotePeer = connectInfo.getHost() + ":" + connectInfo.getPort();
|
||||
}
|
||||
|
||||
AbstractSpan span = ContextManager.createExitSpan(connectInfo.getDBType() + "/JDBI/PreparedStatement/" + method, new ContextCarrier(), remotePeer);
|
||||
Tags.DB_TYPE.set(span, "sql");
|
||||
Tags.SPAN_KIND.set(span, Tags.SPAN_KIND_CLIENT);
|
||||
Tags.DB_INSTANCE.set(span, connectInfo.getDatabaseName());
|
||||
Tags.DB_STATEMENT.set(span, sql);
|
||||
Tags.COMPONENT.set(span, connectInfo.getDBType());
|
||||
if (!StringUtil.isEmpty(connectInfo.getHosts())) {
|
||||
span.setPeers(connectInfo.getHosts());
|
||||
} else {
|
||||
span.setPeerHost(connectInfo.getHost());
|
||||
span.setPort(connectInfo.getPort());
|
||||
}
|
||||
Tags.SPAN_LAYER.asDB(span);
|
||||
span.setComponent(connectInfo.getComponent());
|
||||
|
||||
SpanLayer.asDB(span);
|
||||
return exec.exe(realStatement, sql);
|
||||
} catch (SQLException e) {
|
||||
AbstractSpan span = ContextManager.activeSpan();
|
||||
Tags.ERROR.set(span, true);
|
||||
span.errorOccurred();
|
||||
span.log(e);
|
||||
throw e;
|
||||
} finally {
|
||||
|
|
|
|||
|
|
@ -1,41 +1,35 @@
|
|||
package org.skywalking.apm.plugin.jdbc;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import org.skywalking.apm.agent.core.context.ContextCarrier;
|
||||
import org.skywalking.apm.agent.core.context.ContextManager;
|
||||
import org.skywalking.apm.agent.core.context.tag.Tags;
|
||||
import org.skywalking.apm.agent.core.context.trace.AbstractSpan;
|
||||
import org.skywalking.apm.agent.core.context.trace.SpanLayer;
|
||||
import org.skywalking.apm.util.StringUtil;
|
||||
|
||||
/**
|
||||
* {@link StatementTracing} create span with the {@link Span#operationName} start with
|
||||
* "JDBC/Statement/"and set {@link ConnectionInfo#dbType} to the {@link Tags#COMPONENT}.
|
||||
* <p>
|
||||
* Notice: {@link Span#peerHost} 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)
|
||||
ConnectionInfo connectInfo, String method, String sql, Executable<R> exec)
|
||||
throws SQLException {
|
||||
try {
|
||||
AbstractSpan span = ContextManager.createSpan(connectInfo.getDBType() + "/JDBI/Statement/" + method);
|
||||
String remotePeer;
|
||||
if (!StringUtil.isEmpty(connectInfo.getHosts())) {
|
||||
remotePeer = connectInfo.getHosts();
|
||||
} else {
|
||||
remotePeer = connectInfo.getHost() + ":" + connectInfo.getPort();
|
||||
}
|
||||
|
||||
AbstractSpan span = ContextManager.createExitSpan(connectInfo.getDBType() + "/JDBI/Statement/" + method, new ContextCarrier(), remotePeer);
|
||||
Tags.DB_TYPE.set(span, "sql");
|
||||
Tags.SPAN_KIND.set(span, Tags.SPAN_KIND_CLIENT);
|
||||
Tags.DB_INSTANCE.set(span, connectInfo.getDatabaseName());
|
||||
Tags.DB_STATEMENT.set(span, sql);
|
||||
Tags.COMPONENT.set(span, connectInfo.getDBType());
|
||||
Tags.SPAN_LAYER.asDB(span);
|
||||
if (!StringUtil.isEmpty(connectInfo.getHosts())) {
|
||||
span.setPeers(connectInfo.getHosts());
|
||||
} else {
|
||||
span.setPeerHost(connectInfo.getHost());
|
||||
span.setPort(connectInfo.getPort());
|
||||
}
|
||||
span.setComponent(connectInfo.getDBType());
|
||||
SpanLayer.asDB(span);
|
||||
return exec.exe(realStatement, sql);
|
||||
} catch (SQLException e) {
|
||||
AbstractSpan span = ContextManager.activeSpan();
|
||||
Tags.ERROR.set(span, true);
|
||||
span.errorOccurred();
|
||||
span.log(e);
|
||||
throw e;
|
||||
} finally {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package org.skywalking.apm.plugin.jdbc.connectionurl.parser;
|
||||
|
||||
import org.skywalking.apm.network.trace.component.ComponentsDefine;
|
||||
import org.skywalking.apm.plugin.jdbc.ConnectionInfo;
|
||||
|
||||
/**
|
||||
|
|
@ -56,19 +57,19 @@ public class H2URLParser extends AbstractURLParser {
|
|||
public ConnectionInfo parse() {
|
||||
int[] databaseNameRangeIndex = fetchDatabaseNameRangeIndexFromURLForH2FileMode();
|
||||
if (databaseNameRangeIndex != null) {
|
||||
return new ConnectionInfo(H2_DB_TYPE, LOCALHOST, -1, fetchDatabaseNameFromURL(databaseNameRangeIndex));
|
||||
return new ConnectionInfo(ComponentsDefine.H2, H2_DB_TYPE, LOCALHOST, -1, fetchDatabaseNameFromURL(databaseNameRangeIndex));
|
||||
}
|
||||
|
||||
databaseNameRangeIndex = fetchDatabaseNameRangeIndexFromURLForH2MemMode();
|
||||
if (databaseNameRangeIndex != null) {
|
||||
return new ConnectionInfo(H2_DB_TYPE, LOCALHOST, -1, fetchDatabaseNameFromURL(databaseNameRangeIndex));
|
||||
return new ConnectionInfo(ComponentsDefine.H2, 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());
|
||||
return new ConnectionInfo(ComponentsDefine.H2, H2_DB_TYPE, hostAndPort[0], DEFAULT_PORT, fetchDatabaseNameFromURL());
|
||||
} else {
|
||||
return new ConnectionInfo(H2_DB_TYPE, hostAndPort[0], Integer.valueOf(hostAndPort[1]), fetchDatabaseNameFromURL());
|
||||
return new ConnectionInfo(ComponentsDefine.H2, H2_DB_TYPE, hostAndPort[0], Integer.valueOf(hostAndPort[1]), fetchDatabaseNameFromURL());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package org.skywalking.apm.plugin.jdbc.connectionurl.parser;
|
||||
|
||||
import org.skywalking.apm.network.trace.component.ComponentsDefine;
|
||||
import org.skywalking.apm.plugin.jdbc.ConnectionInfo;
|
||||
|
||||
/**
|
||||
|
|
@ -52,13 +53,13 @@ public class MysqlURLParser extends AbstractURLParser {
|
|||
sb.append(host + ",");
|
||||
}
|
||||
}
|
||||
return new ConnectionInfo(DB_TYPE, sb.toString(), fetchDatabaseNameFromURL());
|
||||
return new ConnectionInfo(ComponentsDefine.MYSQL, 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());
|
||||
return new ConnectionInfo(ComponentsDefine.MYSQL, DB_TYPE, hostAndPort[0], Integer.valueOf(hostAndPort[1]), fetchDatabaseNameFromURL());
|
||||
} else {
|
||||
return new ConnectionInfo(DB_TYPE, hostAndPort[0], DEFAULT_PORT, fetchDatabaseNameFromURL());
|
||||
return new ConnectionInfo(ComponentsDefine.MYSQL, DB_TYPE, hostAndPort[0], DEFAULT_PORT, fetchDatabaseNameFromURL());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package org.skywalking.apm.plugin.jdbc.connectionurl.parser;
|
||||
|
||||
import org.skywalking.apm.network.trace.component.ComponentsDefine;
|
||||
import org.skywalking.apm.plugin.jdbc.ConnectionInfo;
|
||||
|
||||
/**
|
||||
|
|
@ -43,9 +44,9 @@ public class OracleURLParser extends AbstractURLParser {
|
|||
String[] hostSegment = splitDatabaseAddress(host);
|
||||
String databaseName = url.substring(hostRangeIndex[1] + 1);
|
||||
if (hostSegment.length == 1) {
|
||||
return new ConnectionInfo(DB_TYPE, host, DEFAULT_PORT, databaseName);
|
||||
return new ConnectionInfo(ComponentsDefine.ORACLE, DB_TYPE, host, DEFAULT_PORT, databaseName);
|
||||
} else {
|
||||
return new ConnectionInfo(DB_TYPE, hostSegment[0], Integer.valueOf(hostSegment[1]), databaseName);
|
||||
return new ConnectionInfo(ComponentsDefine.ORACLE, DB_TYPE, hostSegment[0], Integer.valueOf(hostSegment[1]), databaseName);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -39,6 +39,10 @@ public abstract class AbstractDatabaseInstrumentation extends ClassInstanceMetho
|
|||
public String getMethodsInterceptor() {
|
||||
return INTERCEPT_CLASS;
|
||||
}
|
||||
|
||||
@Override public boolean isOverrideArgs() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
package org.skywalking.apm.plugin.jdbc.define;
|
||||
|
||||
import org.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
|
||||
import org.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
|
||||
import org.skywalking.apm.plugin.jdbc.SWConnection;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.util.Properties;
|
||||
import org.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
|
||||
import org.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
|
||||
import org.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
|
||||
import org.skywalking.apm.plugin.jdbc.SWConnection;
|
||||
|
||||
/**
|
||||
* {@link JDBCDriverInterceptor} return {@link SWConnection} when {@link java.sql.Driver} to create connection,
|
||||
|
|
@ -14,23 +14,20 @@ import java.util.Properties;
|
|||
* @author zhangxin
|
||||
*/
|
||||
public class JDBCDriverInterceptor implements InstanceMethodsAroundInterceptor {
|
||||
@Override
|
||||
public void beforeMethod(EnhancedClassInstanceContext context, InstanceMethodInvokeContext interceptorContext,
|
||||
MethodInterceptResult result) {
|
||||
// do nothing
|
||||
|
||||
@Override public void beforeMethod(EnhancedInstance objInst, String methodName, Object[] allArguments,
|
||||
Class<?>[] argumentsTypes, MethodInterceptResult result) throws Throwable {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object afterMethod(EnhancedClassInstanceContext context, InstanceMethodInvokeContext interceptorContext,
|
||||
Object ret) {
|
||||
return new SWConnection((String) interceptorContext.allArguments()[0],
|
||||
(Properties) interceptorContext.allArguments()[1], (Connection) ret);
|
||||
@Override public Object afterMethod(EnhancedInstance objInst, String methodName, Object[] allArguments,
|
||||
Class<?>[] argumentsTypes, Object ret) throws Throwable {
|
||||
return new SWConnection((String)allArguments[0],
|
||||
(Properties)allArguments[1], (Connection)ret);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleMethodException(Throwable t, EnhancedClassInstanceContext context,
|
||||
InstanceMethodInvokeContext interceptorContext) {
|
||||
// do nothing.
|
||||
}
|
||||
@Override public void handleMethodException(EnhancedInstance objInst, String methodName, Object[] allArguments,
|
||||
Class<?>[] argumentsTypes, Throwable t) {
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,25 +1,14 @@
|
|||
package org.skywalking.apm.plugin.jedis.v2;
|
||||
|
||||
import org.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
|
||||
import org.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceConstructorInterceptor;
|
||||
import redis.clients.jedis.HostAndPort;
|
||||
|
||||
import static org.skywalking.apm.plugin.jedis.v2.JedisMethodInterceptor.*;
|
||||
|
||||
/**
|
||||
* {@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());
|
||||
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());
|
||||
public void onConstruct(EnhancedInstance objInst, Object[] allArguments) {
|
||||
HostAndPort hostAndPort = (HostAndPort)allArguments[0];
|
||||
objInst.setSkyWalkingDynamicField(hostAndPort.getHost() + ":" + hostAndPort.getPort());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,25 +1,20 @@
|
|||
package org.skywalking.apm.plugin.jedis.v2;
|
||||
|
||||
import java.util.Set;
|
||||
import org.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
|
||||
import org.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceConstructorInterceptor;
|
||||
import redis.clients.jedis.HostAndPort;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* {@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 JedisClusterConstructorWithListHostAndPortArgInterceptor implements InstanceConstructorInterceptor {
|
||||
|
||||
@Override
|
||||
public void onConstruct(EnhancedClassInstanceContext context, ConstructorInvokeContext interceptorContext) {
|
||||
public void onConstruct(EnhancedInstance objInst, Object[] allArguments) {
|
||||
StringBuilder redisConnInfo = new StringBuilder();
|
||||
Set<HostAndPort> hostAndPorts = (Set<HostAndPort>) interceptorContext.allArguments()[0];
|
||||
Set<HostAndPort> hostAndPorts = (Set<HostAndPort>)allArguments[0];
|
||||
for (HostAndPort hostAndPort : hostAndPorts) {
|
||||
redisConnInfo.append(hostAndPort.toString()).append(";");
|
||||
}
|
||||
context.set(JedisMethodInterceptor.KEY_OF_REDIS_CONN_INFO, redisConnInfo.toString());
|
||||
context.set(JedisMethodInterceptor.KEY_OF_REDIS_HOSTS, redisConnInfo.toString());
|
||||
|
||||
objInst.setSkyWalkingDynamicField(redisConnInfo.toString());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,23 +1,16 @@
|
|||
package org.skywalking.apm.plugin.jedis.v2;
|
||||
|
||||
import org.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
|
||||
import org.skywalking.apm.agent.core.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) {
|
||||
public void onConstruct(EnhancedInstance objInst, Object[] allArguments) {
|
||||
String redisConnInfo;
|
||||
JedisShardInfo shardInfo = (JedisShardInfo) interceptorContext.allArguments()[0];
|
||||
JedisShardInfo shardInfo = (JedisShardInfo)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());
|
||||
objInst.setSkyWalkingDynamicField(redisConnInfo);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,25 +1,18 @@
|
|||
package org.skywalking.apm.plugin.jedis.v2;
|
||||
|
||||
import org.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
|
||||
import org.skywalking.apm.agent.core.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];
|
||||
public void onConstruct(EnhancedInstance objInst, Object[] allArguments) {
|
||||
String host = (String)allArguments[0];
|
||||
String port = "6379";
|
||||
if (allArguments.length > 1) {
|
||||
port = String.valueOf(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);
|
||||
}
|
||||
|
||||
objInst.setSkyWalkingDynamicField(host + ":" + port);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,24 +1,14 @@
|
|||
package org.skywalking.apm.plugin.jedis.v2;
|
||||
|
||||
import java.net.URI;
|
||||
import org.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
|
||||
import org.skywalking.apm.agent.core.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());
|
||||
public void onConstruct(EnhancedInstance objInst, Object[] allArguments) {
|
||||
URI uri = (URI)allArguments[0];
|
||||
objInst.setSkyWalkingDynamicField(uri.getHost() + ":" + uri.getPort());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,106 +1,40 @@
|
|||
package org.skywalking.apm.plugin.jedis.v2;
|
||||
|
||||
import org.skywalking.apm.agent.core.context.ContextCarrier;
|
||||
import org.skywalking.apm.agent.core.context.ContextManager;
|
||||
import org.skywalking.apm.agent.core.context.tag.Tags;
|
||||
import org.skywalking.apm.agent.core.context.trace.AbstractSpan;
|
||||
import org.skywalking.apm.agent.core.plugin.interceptor.assist.NoConcurrencyAccessObject;
|
||||
import org.skywalking.apm.agent.core.context.trace.SpanLayer;
|
||||
import org.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
|
||||
import org.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
|
||||
import org.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
|
||||
import org.skywalking.apm.util.StringUtil;
|
||||
import org.skywalking.apm.network.trace.component.ComponentsDefine;
|
||||
|
||||
/**
|
||||
* {@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 NoConcurrencyAccessObject implements InstanceMethodsAroundInterceptor {
|
||||
/**
|
||||
* 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";
|
||||
public class JedisMethodInterceptor implements InstanceMethodsAroundInterceptor {
|
||||
|
||||
private static final String REDIS_COMPONENT = "Redis";
|
||||
@Override public void beforeMethod(EnhancedInstance objInst, String methodName, Object[] allArguments,
|
||||
Class<?>[] argumentsTypes, MethodInterceptResult result) throws Throwable {
|
||||
String peer = String.valueOf(objInst.getSkyWalkingDynamicField());
|
||||
AbstractSpan span = ContextManager.createExitSpan("Jedis/" + methodName, new ContextCarrier(), peer);
|
||||
span.setComponent(ComponentsDefine.REDIS);
|
||||
Tags.DB_TYPE.set(span, "Redis");
|
||||
SpanLayer.asDB(span);
|
||||
|
||||
@Override
|
||||
public void beforeMethod(final EnhancedClassInstanceContext context,
|
||||
final InstanceMethodInvokeContext interceptorContext, MethodInterceptResult result) {
|
||||
this.whenEnter(context, interceptorContext);
|
||||
}
|
||||
|
||||
/**
|
||||
* set peer host information for the current active span.
|
||||
*/
|
||||
private void tagPeer(AbstractSpan span, EnhancedClassInstanceContext context) {
|
||||
String redisHosts = (String)context.get(KEY_OF_REDIS_HOSTS);
|
||||
if (!StringUtil.isEmpty(redisHosts)) {
|
||||
span.setPeers((String)context.get(KEY_OF_REDIS_HOST));
|
||||
} else {
|
||||
span.setPeerHost((String)context.get(KEY_OF_REDIS_HOST));
|
||||
Integer port = (Integer)context.get(KEY_OF_REDIS_PORT);
|
||||
if (port != null) {
|
||||
span.setPort(port);
|
||||
}
|
||||
if (allArguments.length > 0 && allArguments[0] instanceof String) {
|
||||
Tags.DB_STATEMENT.set(span, methodName + " " + allArguments[0]);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object afterMethod(EnhancedClassInstanceContext context, InstanceMethodInvokeContext interceptorContext,
|
||||
Object ret) {
|
||||
this.whenExist(context);
|
||||
@Override public Object afterMethod(EnhancedInstance objInst, String methodName, Object[] allArguments,
|
||||
Class<?>[] argumentsTypes, Object ret) throws Throwable {
|
||||
ContextManager.stopSpan();
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleMethodException(Throwable t, EnhancedClassInstanceContext context,
|
||||
InstanceMethodInvokeContext interceptorContext) {
|
||||
ContextManager.activeSpan().log(t);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void enter(EnhancedClassInstanceContext context, InstanceMethodInvokeContext interceptorContext) {
|
||||
AbstractSpan span = ContextManager.createSpan("Jedis/" + interceptorContext.methodName());
|
||||
Tags.COMPONENT.set(span, REDIS_COMPONENT);
|
||||
Tags.DB_TYPE.set(span, REDIS_COMPONENT);
|
||||
Tags.SPAN_KIND.set(span, Tags.SPAN_KIND_CLIENT);
|
||||
tagPeer(span, context);
|
||||
Tags.SPAN_LAYER.asDB(span);
|
||||
String host = (String)context.get(KEY_OF_REDIS_HOST);
|
||||
if (StringUtil.isEmpty(host)) {
|
||||
span.setPeers((String)context.get(KEY_OF_REDIS_HOSTS));
|
||||
} else {
|
||||
span.setPeerHost(host);
|
||||
Integer port = (Integer)context.get(KEY_OF_REDIS_PORT);
|
||||
if (port != null) {
|
||||
span.setPort(port);
|
||||
}
|
||||
}
|
||||
|
||||
if (interceptorContext.allArguments().length > 0
|
||||
&& interceptorContext.allArguments()[0] instanceof String) {
|
||||
Tags.DB_STATEMENT.set(span, interceptorContext.methodName() + " " + interceptorContext.allArguments()[0]);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void exit() {
|
||||
ContextManager.stopSpan();
|
||||
@Override public void handleMethodException(EnhancedInstance objInst, String methodName, Object[] allArguments,
|
||||
Class<?>[] argumentsTypes, Throwable t) {
|
||||
AbstractSpan span = ContextManager.activeSpan();
|
||||
span.errorOccurred();
|
||||
span.log(t);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,69 @@
|
|||
package org.skywalking.apm.plugin.jedis.v2;
|
||||
|
||||
import net.bytebuddy.description.method.MethodDescription;
|
||||
import net.bytebuddy.matcher.ElementMatcher;
|
||||
|
||||
import static net.bytebuddy.matcher.ElementMatchers.named;
|
||||
|
||||
public enum RedisMethodMatch {
|
||||
INSTANCE;
|
||||
|
||||
private ElementMatcher.Junction<MethodDescription> getIntersectionalMethodMacher() {
|
||||
return named("zcount").or(named("sunionstore")).or(named("zunionstore"))
|
||||
.or(named("del")).or(named("zinterstore")).or(named("echo"))
|
||||
.or(named("hscan")).or(named("psubscribe")).or(named("type"))
|
||||
.or(named("sinterstore")).or(named("setex")).or(named("zlexcount"))
|
||||
.or(named("brpoplpush")).or(named("bitcount")).or(named("llen"))
|
||||
.or(named("zscan")).or(named("lpushx")).or(named("bitpos"))
|
||||
.or(named("setnx")).or(named("hvals")).or(named("evalsha"))
|
||||
.or(named("substr")).or(named("geodist")).or(named("zrangeByLex"))
|
||||
.or(named("geoadd")).or(named("expire")).or(named("bitop"))
|
||||
.or(named("zrangeByScore")).or(named("smove")).or(named("lset"))
|
||||
.or(named("decrBy")).or(named("pttl")).or(named("scan"))
|
||||
.or(named("zrank")).or(named("blpop")).or(named("rpoplpush"))
|
||||
.or(named("zremrangeByLex")).or(named("get")).or(named("lpop"))
|
||||
.or(named("persist")).or(named("scriptExists")).or(named("georadius"))
|
||||
.or(named("set")).or(named("srandmember")).or(named("incr")).or(named("setbit"))
|
||||
.or(named("hexists")).or(named("expireAt")).or(named("pexpire")).or(named("zcard"))
|
||||
.or(named("bitfield")).or(named("zrevrangeByLex")).or(named("sinter")).or(named("srem"))
|
||||
.or(named("getrange")).or(named("rename")).or(named("zrevrank")).or(named("exists"))
|
||||
.or(named("setrange")).or(named("zremrangeByRank")).or(named("sadd")).or(named("sdiff"))
|
||||
.or(named("zrevrange")).or(named("getbit")).or(named("scard")).or(named("sdiffstore"))
|
||||
.or(named("zrevrangeByScore")).or(named("zincrby")).or(named("rpushx")).or(named("psetex"))
|
||||
.or(named("zrevrangeWithScores")).or(named("strlen")).or(named("hdel")).or(named("zremrangeByScore"))
|
||||
.or(named("geohash")).or(named("brpop")).or(named("lrem")).or(named("hlen")).or(named("decr"))
|
||||
.or(named("scriptLoad")).or(named("lpush")).or(named("lindex")).or(named("zrange")).or(named("incrBy"))
|
||||
.or(named("getSet")).or(named("ltrim")).or(named("incrByFloat")).or(named("rpop")).or(named("sort"))
|
||||
.or(named("zrevrangeByScoreWithScores")).or(named("pfadd")).or(named("eval")).or(named("linsert"))
|
||||
.or(named("pfcount")).or(named("hkeys")).or(named("hsetnx")).or(named("hincrBy")).or(named("hgetAll"))
|
||||
.or(named("hset")).or(named("spop")).or(named("zrangeWithScores")).or(named("hincrByFloat"))
|
||||
.or(named("hmset")).or(named("renamenx")).or(named("zrem")).or(named("msetnx")).or(named("hmget"))
|
||||
.or(named("sunion")).or(named("hget")).or(named("zadd")).or(named("move")).or(named("subscribe"))
|
||||
.or(named("geopos")).or(named("mset")).or(named("zrangeByScoreWithScores")).or(named("zscore"))
|
||||
.or(named("pexpireAt")).or(named("georadiusByMember")).or(named("ttl")).or(named("lrange"))
|
||||
.or(named("smembers")).or(named("pfmerge")).or(named("rpush")).or(named("publish"))
|
||||
.or(named("mget")).or(named("sscan")).or(named("append")).or(named("sismember"));
|
||||
}
|
||||
|
||||
public ElementMatcher<MethodDescription> getJedisMethodMatcher() {
|
||||
return getIntersectionalMethodMacher().or(named("sentinelMasters")).or(named("clusterReplicate")).or(named("readonly"))
|
||||
.or(named("randomKey")).or(named("clusterInfo")).or(named("pubsubNumSub"))
|
||||
.or(named("sentinelSlaves")).or(named("clusterSetSlotImporting")).or(named("clusterSlaves"))
|
||||
.or(named("clusterFailover")).or(named("clusterSetSlotMigrating")).or(named("watch"))
|
||||
.or(named("clientKill")).or(named("clusterKeySlot")).or(named("clusterCountKeysInSlot"))
|
||||
.or(named("sentinelGetMasterAddrByName")).or(named("objectRefcount")).or(named("clusterMeet"))
|
||||
.or(named("sentinelSet")).or(named("clusterSetSlotNode")).or(named("clusterAddSlots"))
|
||||
.or(named("pubsubNumPat")).or(named("slowlogGet")).or(named("sentinelReset")).or(named("clusterNodes"))
|
||||
.or(named("sentinelMonitor")).or(named("configGet")).or(named("objectIdletime"))
|
||||
.or(named("pubsubChannels")).or(named("getParams")).or(named("sentinelRemove"))
|
||||
.or(named("migrate")).or(named("clusterForget")).or(named("asking")).or(named("keys"))
|
||||
.or(named("clientSetname")).or(named("clusterSaveConfig")).or(named("configSet"))
|
||||
.or(named("dump")).or(named("clusterFlushSlots")).or(named("clusterGetKeysInSlot"))
|
||||
.or(named("clusterReset")).or(named("restore")).or(named("clusterDelSlots"))
|
||||
.or(named("sentinelFailover")).or(named("clusterSetSlotStable")).or(named("objectEncoding"));
|
||||
}
|
||||
|
||||
public ElementMatcher<MethodDescription> getJedisClusterMethodMatcher() {
|
||||
return getIntersectionalMethodMacher();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,18 +1,17 @@
|
|||
package org.skywalking.apm.plugin.jedis.v2.define;
|
||||
|
||||
import java.util.Set;
|
||||
import net.bytebuddy.description.method.MethodDescription;
|
||||
import net.bytebuddy.matcher.ElementMatcher;
|
||||
import org.skywalking.apm.agent.core.plugin.bytebuddy.AllObjectDefaultMethodsMatch;
|
||||
import org.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
|
||||
import org.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
|
||||
import org.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine;
|
||||
import org.skywalking.apm.plugin.jedis.v2.JedisClusterConstructorWithHostAndPortArgInterceptor;
|
||||
import org.skywalking.apm.plugin.jedis.v2.JedisClusterConstructorWithListHostAndPortArgInterceptor;
|
||||
import org.skywalking.apm.plugin.jedis.v2.JedisMethodInterceptor;
|
||||
import org.skywalking.apm.plugin.jedis.v2.RedisMethodMatch;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import static net.bytebuddy.matcher.ElementMatchers.*;
|
||||
import static net.bytebuddy.matcher.ElementMatchers.takesArgument;
|
||||
import static org.skywalking.apm.agent.core.plugin.bytebuddy.ArgumentTypeNameMatch.takesArgumentWithType;
|
||||
|
||||
/**
|
||||
|
|
@ -71,13 +70,17 @@ public class JedisClusterInstrumentation extends ClassInstanceMethodsEnhancePlug
|
|||
new InstanceMethodsInterceptPoint() {
|
||||
@Override
|
||||
public ElementMatcher<MethodDescription> getMethodsMatcher() {
|
||||
return any().and(not(AllObjectDefaultMethodsMatch.INSTANCE));
|
||||
return RedisMethodMatch.INSTANCE.getJedisClusterMethodMatcher();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMethodsInterceptor() {
|
||||
return METHOD_INTERCEPT_CLASS;
|
||||
}
|
||||
|
||||
@Override public boolean isOverrideArgs() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,19 +1,17 @@
|
|||
package org.skywalking.apm.plugin.jedis.v2.define;
|
||||
|
||||
import java.net.URI;
|
||||
import net.bytebuddy.description.method.MethodDescription;
|
||||
import net.bytebuddy.matcher.ElementMatcher;
|
||||
import net.bytebuddy.matcher.ElementMatchers;
|
||||
import org.skywalking.apm.agent.core.plugin.bytebuddy.AllObjectDefaultMethodsMatch;
|
||||
import org.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
|
||||
import org.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
|
||||
import org.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine;
|
||||
import org.skywalking.apm.plugin.jedis.v2.JedisConstructorWithShardInfoArgInterceptor;
|
||||
import org.skywalking.apm.plugin.jedis.v2.JedisConstructorWithUriArgInterceptor;
|
||||
import org.skywalking.apm.plugin.jedis.v2.JedisMethodInterceptor;
|
||||
import org.skywalking.apm.plugin.jedis.v2.RedisMethodMatch;
|
||||
|
||||
import java.net.URI;
|
||||
|
||||
import static net.bytebuddy.matcher.ElementMatchers.*;
|
||||
import static net.bytebuddy.matcher.ElementMatchers.takesArgument;
|
||||
import static org.skywalking.apm.agent.core.plugin.bytebuddy.ArgumentTypeNameMatch.takesArgumentWithType;
|
||||
|
||||
/**
|
||||
|
|
@ -85,21 +83,17 @@ public class JedisInstrumentation extends ClassInstanceMethodsEnhancePluginDefin
|
|||
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")));
|
||||
return RedisMethodMatch.INSTANCE.getJedisMethodMatcher();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMethodsInterceptor() {
|
||||
return JEDIS_METHOD_INTERCET_CLASS;
|
||||
}
|
||||
|
||||
@Override public boolean isOverrideArgs() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,13 @@
|
|||
package org.skywalking.apm.plugin.mongodb.v3;
|
||||
|
||||
import com.mongodb.ReadPreference;
|
||||
import com.mongodb.ServerAddress;
|
||||
import com.mongodb.bulk.DeleteRequest;
|
||||
import com.mongodb.bulk.InsertRequest;
|
||||
import com.mongodb.bulk.UpdateRequest;
|
||||
import com.mongodb.bulk.WriteRequest;
|
||||
import com.mongodb.connection.Cluster;
|
||||
import com.mongodb.connection.ServerDescription;
|
||||
import com.mongodb.operation.CountOperation;
|
||||
import com.mongodb.operation.CreateCollectionOperation;
|
||||
import com.mongodb.operation.CreateIndexesOperation;
|
||||
|
|
@ -27,11 +30,16 @@ import com.mongodb.operation.WriteOperation;
|
|||
import java.util.List;
|
||||
import org.bson.BsonDocument;
|
||||
import org.skywalking.apm.agent.core.conf.Config;
|
||||
import org.skywalking.apm.agent.core.context.ContextCarrier;
|
||||
import org.skywalking.apm.agent.core.context.ContextManager;
|
||||
import org.skywalking.apm.agent.core.context.tag.Tags;
|
||||
import org.skywalking.apm.agent.core.context.trace.AbstractSpan;
|
||||
import org.skywalking.apm.agent.core.context.trace.SpanLayer;
|
||||
import org.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
|
||||
import org.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceConstructorInterceptor;
|
||||
import org.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
|
||||
import org.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
|
||||
import org.skywalking.apm.network.trace.component.ComponentsDefine;
|
||||
|
||||
/**
|
||||
* {@link MongoDBMethodInterceptor} intercept method of {@link com.mongodb.Mongo#execute(ReadOperation, ReadPreference)}
|
||||
|
|
@ -40,16 +48,10 @@ import org.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptR
|
|||
*
|
||||
* @author baiyang
|
||||
*/
|
||||
public class MongoDBMethodInterceptor implements InstanceMethodsAroundInterceptor {
|
||||
public class MongoDBMethodInterceptor implements InstanceMethodsAroundInterceptor, InstanceConstructorInterceptor {
|
||||
|
||||
/**
|
||||
* The key name that MongoDB host in {@link EnhancedClassInstanceContext#context}.
|
||||
*/
|
||||
static final String MONGODB_HOST = "MONGODB_HOST";
|
||||
|
||||
/**
|
||||
* The key name that MongoDB port in {@link EnhancedClassInstanceContext#context}.
|
||||
*/
|
||||
static final String MONGODB_PORT = "MONGODB_PORT";
|
||||
|
||||
private static final String MONGODB_COMPONENT = "MongoDB";
|
||||
|
|
@ -60,40 +62,6 @@ public class MongoDBMethodInterceptor implements InstanceMethodsAroundIntercepto
|
|||
|
||||
private static final String EMPTY = "";
|
||||
|
||||
@Override
|
||||
public void beforeMethod(final EnhancedClassInstanceContext context,
|
||||
final InstanceMethodInvokeContext interceptorContext, final MethodInterceptResult result) {
|
||||
Object[] arguments = interceptorContext.allArguments();
|
||||
|
||||
String methodName = arguments[0].getClass().getSimpleName();
|
||||
AbstractSpan span = ContextManager.createSpan(METHOD + methodName);
|
||||
Tags.COMPONENT.set(span, MONGODB_COMPONENT);
|
||||
Tags.DB_TYPE.set(span, MONGODB_COMPONENT);
|
||||
Tags.SPAN_KIND.set(span, Tags.SPAN_KIND_CLIENT);
|
||||
Tags.SPAN_LAYER.asDB(span);
|
||||
|
||||
if (Config.Plugin.MongoDB.TRACE_PARAM) {
|
||||
Tags.DB_STATEMENT.set(span, methodName + " " + this.getTraceParam(arguments[0]));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object afterMethod(EnhancedClassInstanceContext context, InstanceMethodInvokeContext interceptorContext,
|
||||
Object ret) {
|
||||
AbstractSpan span = ContextManager.activeSpan();
|
||||
span.setPeerHost((String)context.get(MONGODB_HOST));
|
||||
span.setPort((Integer)context.get(MONGODB_PORT));
|
||||
ContextManager.stopSpan();
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleMethodException(Throwable t, EnhancedClassInstanceContext context,
|
||||
InstanceMethodInvokeContext interceptorContext) {
|
||||
ContextManager.activeSpan().log(t);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert ReadOperation interface or WriteOperation interface to the implementation class. Get the method name and
|
||||
* filter info.
|
||||
|
|
@ -101,55 +69,55 @@ public class MongoDBMethodInterceptor implements InstanceMethodsAroundIntercepto
|
|||
@SuppressWarnings("rawtypes")
|
||||
private String getTraceParam(Object obj) {
|
||||
if (obj instanceof CountOperation) {
|
||||
BsonDocument filter = ((CountOperation) obj).getFilter();
|
||||
BsonDocument filter = ((CountOperation)obj).getFilter();
|
||||
return limitFilter(filter.toString());
|
||||
} else if (obj instanceof DistinctOperation) {
|
||||
BsonDocument filter = ((DistinctOperation) obj).getFilter();
|
||||
BsonDocument filter = ((DistinctOperation)obj).getFilter();
|
||||
return limitFilter(filter.toString());
|
||||
} else if (obj instanceof FindOperation) {
|
||||
BsonDocument filter = ((FindOperation) obj).getFilter();
|
||||
BsonDocument filter = ((FindOperation)obj).getFilter();
|
||||
return limitFilter(filter.toString());
|
||||
} else if (obj instanceof GroupOperation) {
|
||||
BsonDocument filter = ((GroupOperation) obj).getFilter();
|
||||
BsonDocument filter = ((GroupOperation)obj).getFilter();
|
||||
return limitFilter(filter.toString());
|
||||
} else if (obj instanceof ListCollectionsOperation) {
|
||||
BsonDocument filter = ((ListCollectionsOperation) obj).getFilter();
|
||||
BsonDocument filter = ((ListCollectionsOperation)obj).getFilter();
|
||||
return limitFilter(filter.toString());
|
||||
} else if (obj instanceof MapReduceWithInlineResultsOperation) {
|
||||
BsonDocument filter = ((ListCollectionsOperation) obj).getFilter();
|
||||
BsonDocument filter = ((ListCollectionsOperation)obj).getFilter();
|
||||
return limitFilter(filter.toString());
|
||||
} else if (obj instanceof DeleteOperation) {
|
||||
List<DeleteRequest> writeRequestList = ((DeleteOperation) obj).getDeleteRequests();
|
||||
List<DeleteRequest> writeRequestList = ((DeleteOperation)obj).getDeleteRequests();
|
||||
return getFilter(writeRequestList);
|
||||
} else if (obj instanceof InsertOperation) {
|
||||
List<InsertRequest> writeRequestList = ((InsertOperation) obj).getInsertRequests();
|
||||
List<InsertRequest> writeRequestList = ((InsertOperation)obj).getInsertRequests();
|
||||
return getFilter(writeRequestList);
|
||||
} else if (obj instanceof UpdateOperation) {
|
||||
List<UpdateRequest> writeRequestList = ((UpdateOperation) obj).getUpdateRequests();
|
||||
List<UpdateRequest> writeRequestList = ((UpdateOperation)obj).getUpdateRequests();
|
||||
return getFilter(writeRequestList);
|
||||
} else if (obj instanceof CreateCollectionOperation) {
|
||||
String filter = ((CreateCollectionOperation) obj).getCollectionName();
|
||||
String filter = ((CreateCollectionOperation)obj).getCollectionName();
|
||||
return limitFilter(filter);
|
||||
} else if (obj instanceof CreateIndexesOperation) {
|
||||
List<String> filter = ((CreateIndexesOperation) obj).getIndexNames();
|
||||
List<String> filter = ((CreateIndexesOperation)obj).getIndexNames();
|
||||
return limitFilter(filter.toString());
|
||||
} else if (obj instanceof CreateViewOperation) {
|
||||
String filter = ((CreateViewOperation) obj).getViewName();
|
||||
String filter = ((CreateViewOperation)obj).getViewName();
|
||||
return limitFilter(filter);
|
||||
} else if (obj instanceof FindAndDeleteOperation) {
|
||||
BsonDocument filter = ((FindAndDeleteOperation) obj).getFilter();
|
||||
BsonDocument filter = ((FindAndDeleteOperation)obj).getFilter();
|
||||
return limitFilter(filter.toString());
|
||||
} else if (obj instanceof FindAndReplaceOperation) {
|
||||
BsonDocument filter = ((FindAndReplaceOperation) obj).getFilter();
|
||||
BsonDocument filter = ((FindAndReplaceOperation)obj).getFilter();
|
||||
return limitFilter(filter.toString());
|
||||
} else if (obj instanceof FindAndUpdateOperation) {
|
||||
BsonDocument filter = ((FindAndUpdateOperation) obj).getFilter();
|
||||
BsonDocument filter = ((FindAndUpdateOperation)obj).getFilter();
|
||||
return limitFilter(filter.toString());
|
||||
} else if (obj instanceof MapReduceToCollectionOperation) {
|
||||
BsonDocument filter = ((MapReduceToCollectionOperation) obj).getFilter();
|
||||
BsonDocument filter = ((MapReduceToCollectionOperation)obj).getFilter();
|
||||
return limitFilter(filter.toString());
|
||||
} else if (obj instanceof MixedBulkWriteOperation) {
|
||||
List<? extends WriteRequest> writeRequestList = ((MixedBulkWriteOperation) obj).getWriteRequests();
|
||||
List<? extends WriteRequest> writeRequestList = ((MixedBulkWriteOperation)obj).getWriteRequests();
|
||||
return getFilter(writeRequestList);
|
||||
} else {
|
||||
return EMPTY;
|
||||
|
|
@ -160,11 +128,11 @@ public class MongoDBMethodInterceptor implements InstanceMethodsAroundIntercepto
|
|||
StringBuilder params = new StringBuilder();
|
||||
for (WriteRequest request : writeRequestList) {
|
||||
if (request instanceof InsertRequest) {
|
||||
params.append(((InsertRequest) request).getDocument().toString()).append(",");
|
||||
params.append(((InsertRequest)request).getDocument().toString()).append(",");
|
||||
} else if (request instanceof DeleteRequest) {
|
||||
params.append(((DeleteRequest) request).getFilter()).append(",");
|
||||
params.append(((DeleteRequest)request).getFilter()).append(",");
|
||||
} else if (request instanceof UpdateRequest) {
|
||||
params.append(((UpdateRequest) request).getFilter()).append(",");
|
||||
params.append(((UpdateRequest)request).getFilter()).append(",");
|
||||
}
|
||||
if (params.length() > FILTER_LENGTH_LIMIT) {
|
||||
params.append("...");
|
||||
|
|
@ -183,4 +151,45 @@ public class MongoDBMethodInterceptor implements InstanceMethodsAroundIntercepto
|
|||
}
|
||||
}
|
||||
|
||||
@Override public void beforeMethod(EnhancedInstance objInst, String methodName, Object[] allArguments,
|
||||
Class<?>[] argumentsTypes, MethodInterceptResult result) throws Throwable {
|
||||
Object[] arguments = allArguments;
|
||||
|
||||
String executeMethod = arguments[0].getClass().getSimpleName();
|
||||
String remotePeer = (String)objInst.getSkyWalkingDynamicField();
|
||||
AbstractSpan span = ContextManager.createExitSpan(METHOD + methodName, new ContextCarrier(), remotePeer);
|
||||
span.setComponent(ComponentsDefine.MONGODB);
|
||||
Tags.DB_TYPE.set(span, MONGODB_COMPONENT);
|
||||
SpanLayer.asDB(span);
|
||||
|
||||
if (Config.Plugin.MongoDB.TRACE_PARAM) {
|
||||
Tags.DB_STATEMENT.set(span, executeMethod + " " + this.getTraceParam(arguments[0]));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override public Object afterMethod(EnhancedInstance objInst, String methodName, Object[] allArguments,
|
||||
Class<?>[] argumentsTypes, Object ret) throws Throwable {
|
||||
ContextManager.stopSpan();
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override public void handleMethodException(EnhancedInstance objInst, String methodName, Object[] allArguments,
|
||||
Class<?>[] argumentsTypes, Throwable t) {
|
||||
AbstractSpan activeSpan = ContextManager.activeSpan();
|
||||
activeSpan.errorOccurred();
|
||||
activeSpan.log(t);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConstruct(EnhancedInstance objInst, Object[] allArguments) {
|
||||
Cluster cluster = (Cluster)allArguments[0];
|
||||
StringBuilder peers = new StringBuilder();
|
||||
for (ServerDescription description : cluster.getDescription().getServerDescriptions()) {
|
||||
ServerAddress address = description.getAddress();
|
||||
peers.append(address.getHost() + ":" + address.getPort() + ";");
|
||||
}
|
||||
|
||||
objInst.setSkyWalkingDynamicField(peers.subSequence(0, peers.length() - 1).toString());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,47 +0,0 @@
|
|||
package org.skywalking.apm.plugin.mongodb.v3;
|
||||
|
||||
import com.mongodb.ReadPreference;
|
||||
import com.mongodb.ServerAddress;
|
||||
import com.mongodb.binding.ReadBinding;
|
||||
import org.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
|
||||
import org.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
|
||||
|
||||
/**
|
||||
* {@link MongoDBReadBindingInterceptor} record the host and port information
|
||||
* from {@link EnhancedClassInstanceContext#context},
|
||||
*
|
||||
* @author baiyang
|
||||
*/
|
||||
public class MongoDBReadBindingInterceptor implements
|
||||
InstanceMethodsAroundInterceptor {
|
||||
|
||||
@Override
|
||||
public void beforeMethod(EnhancedClassInstanceContext context,
|
||||
InstanceMethodInvokeContext interceptorContext,
|
||||
MethodInterceptResult result) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute after {@link com.mongodb.Mongo#getReadBinding(ReadPreference)},
|
||||
* record the host and port information
|
||||
*/
|
||||
@Override
|
||||
public Object afterMethod(EnhancedClassInstanceContext context,
|
||||
InstanceMethodInvokeContext interceptorContext, Object ret) {
|
||||
ReadBinding readBinding = (ReadBinding) ret;
|
||||
ServerAddress serverAddress = readBinding.getReadConnectionSource()
|
||||
.getServerDescription().getAddress();
|
||||
String host = serverAddress.getHost();
|
||||
Integer port = serverAddress.getPort();
|
||||
context.set(MongoDBMethodInterceptor.MONGODB_HOST, host);
|
||||
context.set(MongoDBMethodInterceptor.MONGODB_PORT, port);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleMethodException(Throwable t,
|
||||
EnhancedClassInstanceContext context,
|
||||
InstanceMethodInvokeContext interceptorContext) {
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,42 +0,0 @@
|
|||
package org.skywalking.apm.plugin.mongodb.v3;
|
||||
|
||||
import com.mongodb.ServerAddress;
|
||||
import com.mongodb.binding.WriteBinding;
|
||||
import org.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
|
||||
import org.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
|
||||
|
||||
/**
|
||||
* {@link MongoDBWriteBindingInterceptor} record the host and port information from {@link
|
||||
* EnhancedClassInstanceContext#context}
|
||||
*
|
||||
* @author baiyang
|
||||
*/
|
||||
public class MongoDBWriteBindingInterceptor implements InstanceMethodsAroundInterceptor {
|
||||
|
||||
@Override
|
||||
public void beforeMethod(EnhancedClassInstanceContext context, InstanceMethodInvokeContext interceptorContext,
|
||||
MethodInterceptResult result) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute after {@link com.mongodb.Mongo#getWriteBinding()},
|
||||
* record the host and port information
|
||||
*/
|
||||
@Override
|
||||
public Object afterMethod(EnhancedClassInstanceContext context, InstanceMethodInvokeContext interceptorContext,
|
||||
Object ret) {
|
||||
WriteBinding writeBinding = (WriteBinding) ret;
|
||||
ServerAddress serverAddress = writeBinding.getWriteConnectionSource().getServerDescription().getAddress();
|
||||
String host = serverAddress.getHost();
|
||||
Integer port = serverAddress.getPort();
|
||||
context.set(MongoDBMethodInterceptor.MONGODB_HOST, host);
|
||||
context.set(MongoDBMethodInterceptor.MONGODB_PORT, port);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleMethodException(Throwable t, EnhancedClassInstanceContext context,
|
||||
InstanceMethodInvokeContext interceptorContext) {
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,33 +1,36 @@
|
|||
package org.skywalking.apm.plugin.mongodb.v3.define;
|
||||
|
||||
import com.mongodb.connection.Cluster;
|
||||
import net.bytebuddy.description.method.MethodDescription;
|
||||
import net.bytebuddy.matcher.ElementMatcher;
|
||||
import org.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
|
||||
import org.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
|
||||
import org.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine;
|
||||
import org.skywalking.apm.plugin.mongodb.v3.MongoDBMethodInterceptor;
|
||||
|
||||
import static net.bytebuddy.matcher.ElementMatchers.named;
|
||||
import static net.bytebuddy.matcher.ElementMatchers.takesArgument;
|
||||
|
||||
/**
|
||||
* {@link MongoDBInstrumentation} presents that skywalking intercepts {@link com.mongodb.Mongo#execute(com.mongodb.operation.ReadOperation,
|
||||
* com.mongodb.ReadPreference)},{@link com.mongodb.Mongo#execute(com.mongodb.operation.WriteOperation)} by using {@link MongoDBMethodInterceptor}.
|
||||
*
|
||||
* @author baiyang
|
||||
*/
|
||||
public class MongoDBInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
|
||||
|
||||
private static final String ENHANCE_CLASS = "com.mongodb.Mongo";
|
||||
|
||||
private static final String MONGDB_READ_BINDING_CLASS = "org.skywalking.apm.plugin.mongodb.v3.MongoDBReadBindingInterceptor";
|
||||
|
||||
private static final String MONGDB_WRITE_BINDING_CLASS = "org.skywalking.apm.plugin.mongodb.v3.MongoDBWriteBindingInterceptor";
|
||||
|
||||
private static final String MONGDB_METHOD_INTERCET_CLASS = "org.skywalking.apm.plugin.mongodb.v3.MongoDBMethodInterceptor";
|
||||
|
||||
@Override
|
||||
protected ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
|
||||
return null;
|
||||
return new ConstructorInterceptPoint[] {
|
||||
new ConstructorInterceptPoint() {
|
||||
@Override
|
||||
public ElementMatcher<MethodDescription> getConstructorMatcher() {
|
||||
return takesArgument(1, Cluster.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getConstructorInterceptor() {
|
||||
return MONGDB_METHOD_INTERCET_CLASS;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -43,28 +46,13 @@ public class MongoDBInstrumentation extends ClassInstanceMethodsEnhancePluginDef
|
|||
public String getMethodsInterceptor() {
|
||||
return MONGDB_METHOD_INTERCET_CLASS;
|
||||
}
|
||||
}, new InstanceMethodsInterceptPoint() {
|
||||
@Override
|
||||
public ElementMatcher<MethodDescription> getMethodsMatcher() {
|
||||
return named("getReadBinding");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMethodsInterceptor() {
|
||||
return MONGDB_READ_BINDING_CLASS;
|
||||
public boolean isOverrideArgs() {
|
||||
return false;
|
||||
}
|
||||
}, new InstanceMethodsInterceptPoint() {
|
||||
@Override
|
||||
public ElementMatcher<MethodDescription> getMethodsMatcher() {
|
||||
return named("getWriteBinding");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMethodsInterceptor() {
|
||||
return MONGDB_WRITE_BINDING_CLASS;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -8,71 +8,60 @@ import org.skywalking.apm.agent.core.context.ContextCarrier;
|
|||
import org.skywalking.apm.agent.core.context.ContextManager;
|
||||
import org.skywalking.apm.agent.core.context.tag.Tags;
|
||||
import org.skywalking.apm.agent.core.context.trace.AbstractSpan;
|
||||
import org.skywalking.apm.agent.core.context.trace.SpanLayer;
|
||||
import org.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
|
||||
import org.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceConstructorInterceptor;
|
||||
import org.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
|
||||
import org.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
|
||||
import org.skywalking.apm.network.trace.component.ComponentsDefine;
|
||||
|
||||
/**
|
||||
* {@link MotanProviderInterceptor} create span by fetch request url from
|
||||
* {@link EnhancedClassInstanceContext#context} and transport serialized context
|
||||
* {@link EnhancedInstance#getSkyWalkingDynamicField()} and transport serialized context
|
||||
* data to provider side through {@link Request#setAttachment(String, String)}.
|
||||
*
|
||||
* @author zhangxin
|
||||
*/
|
||||
public class MotanConsumerInterceptor implements InstanceConstructorInterceptor, InstanceMethodsAroundInterceptor {
|
||||
|
||||
/**
|
||||
* The
|
||||
*/
|
||||
private static final String KEY_NAME_OF_REQUEST_URL = "REQUEST_URL";
|
||||
|
||||
/**
|
||||
* 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()[1]);
|
||||
public void onConstruct(EnhancedInstance objInst, Object[] allArguments) {
|
||||
objInst.setSkyWalkingDynamicField(allArguments[1]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beforeMethod(EnhancedClassInstanceContext context, InstanceMethodInvokeContext interceptorContext,
|
||||
MethodInterceptResult result) {
|
||||
URL url = (URL) context.get(KEY_NAME_OF_REQUEST_URL);
|
||||
Request request = (Request) interceptorContext.allArguments()[0];
|
||||
if (url != null) {
|
||||
AbstractSpan span = ContextManager.createSpan(generateOperationName(url, request));
|
||||
span.setPeerHost(url.getHost());
|
||||
span.setPort(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);
|
||||
public void beforeMethod(EnhancedInstance objInst, String methodName, Object[] allArguments,
|
||||
Class<?>[] argumentsTypes, MethodInterceptResult result) throws Throwable {
|
||||
|
||||
URL url = (URL)objInst.getSkyWalkingDynamicField();
|
||||
Request request = (Request)allArguments[0];
|
||||
if (url != null) {
|
||||
ContextCarrier contextCarrier = new ContextCarrier();
|
||||
ContextManager.inject(contextCarrier);
|
||||
String remotePeer = url.getHost() + " :" + url.getPort();
|
||||
AbstractSpan span = ContextManager.createExitSpan(generateOperationName(url, request), contextCarrier, remotePeer);
|
||||
span.setComponent(ComponentsDefine.MOTAN);
|
||||
Tags.URL.set(span, url.getIdentity());
|
||||
SpanLayer.asRPCFramework(span);
|
||||
request.setAttachment(Config.Plugin.Propagation.HEADER_NAME, contextCarrier.serialize());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object afterMethod(EnhancedClassInstanceContext context, InstanceMethodInvokeContext interceptorContext,
|
||||
Object ret) {
|
||||
Response response = (Response) ret;
|
||||
@Override public Object afterMethod(EnhancedInstance objInst, String methodName, Object[] allArguments,
|
||||
Class<?>[] argumentsTypes, Object ret) throws Throwable {
|
||||
Response response = (Response)ret;
|
||||
if (response != null && response.getException() != null) {
|
||||
AbstractSpan span = ContextManager.activeSpan();
|
||||
Tags.ERROR.set(span, true);
|
||||
span.errorOccurred();
|
||||
span.log(response.getException());
|
||||
}
|
||||
ContextManager.stopSpan();
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleMethodException(Throwable t, EnhancedClassInstanceContext context,
|
||||
InstanceMethodInvokeContext interceptorContext) {
|
||||
ContextManager.activeSpan().log(t);
|
||||
@Override public void handleMethodException(EnhancedInstance objInst, String methodName, Object[] allArguments,
|
||||
Class<?>[] argumentsTypes, Throwable t) {
|
||||
AbstractSpan span = ContextManager.activeSpan();
|
||||
span.errorOccurred();
|
||||
span.log(t);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -84,5 +73,4 @@ public class MotanConsumerInterceptor implements InstanceConstructorInterceptor,
|
|||
return new StringBuilder(serviceURI.getPath()).append(".").append(request.getMethodName()).append("(")
|
||||
.append(request.getParamtersDesc()).append(")").toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,11 +5,12 @@ import com.weibo.api.motan.rpc.Response;
|
|||
import org.skywalking.apm.agent.core.conf.Config;
|
||||
import org.skywalking.apm.agent.core.context.ContextCarrier;
|
||||
import org.skywalking.apm.agent.core.context.ContextManager;
|
||||
import org.skywalking.apm.agent.core.context.tag.Tags;
|
||||
import org.skywalking.apm.agent.core.context.trace.AbstractSpan;
|
||||
import org.skywalking.apm.agent.core.context.trace.SpanLayer;
|
||||
import org.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
|
||||
import org.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
|
||||
import org.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
|
||||
import org.skywalking.apm.util.StringUtil;
|
||||
import org.skywalking.apm.network.trace.component.ComponentsDefine;
|
||||
|
||||
/**
|
||||
* Current trace segment will ref the trace segment if the serialized trace context that fetch from {@link
|
||||
|
|
@ -21,44 +22,35 @@ import org.skywalking.apm.util.StringUtil;
|
|||
* @author zhangxin
|
||||
*/
|
||||
public class MotanProviderInterceptor implements InstanceMethodsAroundInterceptor {
|
||||
/**
|
||||
* Motan component
|
||||
*/
|
||||
private static final String MOTAN_COMPONENT = "Motan";
|
||||
|
||||
@Override
|
||||
public void beforeMethod(EnhancedClassInstanceContext context, InstanceMethodInvokeContext interceptorContext,
|
||||
MethodInterceptResult result) {
|
||||
Request request = (Request) interceptorContext.allArguments()[0];
|
||||
AbstractSpan span = ContextManager.createSpan(generateViewPoint(request));
|
||||
Tags.COMPONENT.set(span, MOTAN_COMPONENT);
|
||||
Tags.SPAN_KIND.set(span, Tags.SPAN_KIND_SERVER);
|
||||
Tags.SPAN_LAYER.asRPCFramework(span);
|
||||
|
||||
@Override public void beforeMethod(EnhancedInstance objInst, String methodName, Object[] allArguments,
|
||||
Class<?>[] argumentsTypes, MethodInterceptResult result) throws Throwable {
|
||||
Request request = (Request)allArguments[0];
|
||||
String serializedContextData = request.getAttachments().get(Config.Plugin.Propagation.HEADER_NAME);
|
||||
if (!StringUtil.isEmpty(serializedContextData)) {
|
||||
ContextManager.extract(new ContextCarrier().deserialize(serializedContextData));
|
||||
}
|
||||
ContextCarrier contextCarrier = new ContextCarrier().deserialize(serializedContextData);
|
||||
AbstractSpan span = ContextManager.createEntrySpan(generateViewPoint(request), contextCarrier);
|
||||
SpanLayer.asRPCFramework(span);
|
||||
span.setComponent(ComponentsDefine.MOTAN);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object afterMethod(EnhancedClassInstanceContext context, InstanceMethodInvokeContext interceptorContext,
|
||||
Object ret) {
|
||||
Response response = (Response) ret;
|
||||
@Override public Object afterMethod(EnhancedInstance objInst, String methodName, Object[] allArguments,
|
||||
Class<?>[] argumentsTypes, Object ret) throws Throwable {
|
||||
Response response = (Response)ret;
|
||||
if (response != null && response.getException() != null) {
|
||||
AbstractSpan span = ContextManager.activeSpan();
|
||||
span.log(response.getException());
|
||||
Tags.ERROR.set(span, true);
|
||||
span.errorOccurred();
|
||||
}
|
||||
|
||||
ContextManager.stopSpan();
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleMethodException(Throwable t, EnhancedClassInstanceContext context,
|
||||
InstanceMethodInvokeContext interceptorContext) {
|
||||
ContextManager.activeSpan().log(t);
|
||||
@Override public void handleMethodException(EnhancedInstance objInst, String methodName, Object[] allArguments,
|
||||
Class<?>[] argumentsTypes, Throwable t) {
|
||||
AbstractSpan activeSpan = ContextManager.activeSpan();
|
||||
activeSpan.errorOccurred();
|
||||
activeSpan.log(t);
|
||||
}
|
||||
|
||||
private static String generateViewPoint(Request request) {
|
||||
|
|
|
|||
|
|
@ -44,6 +44,10 @@ public class MotanConsumerInstrumentation extends ClassInstanceMethodsEnhancePlu
|
|||
public String getMethodsInterceptor() {
|
||||
return INVOKE_INTERCEPT_CLASS;
|
||||
}
|
||||
|
||||
@Override public boolean isOverrideArgs() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -69,6 +69,10 @@ public class MotanProviderInstrumentation extends ClassInstanceMethodsEnhancePlu
|
|||
public String getMethodsInterceptor() {
|
||||
return PROVIDER_INVOKE_INTERCEPT_CLASS;
|
||||
}
|
||||
|
||||
@Override public boolean isOverrideArgs() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package org.skywalking.apm.plugin.okhttp.v3;
|
|||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Modifier;
|
||||
import okhttp3.Headers;
|
||||
import okhttp3.HttpUrl;
|
||||
import okhttp3.OkHttpClient;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.Response;
|
||||
|
|
@ -11,9 +12,12 @@ import org.skywalking.apm.agent.core.context.ContextCarrier;
|
|||
import org.skywalking.apm.agent.core.context.ContextManager;
|
||||
import org.skywalking.apm.agent.core.context.tag.Tags;
|
||||
import org.skywalking.apm.agent.core.context.trace.AbstractSpan;
|
||||
import org.skywalking.apm.agent.core.context.trace.SpanLayer;
|
||||
import org.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
|
||||
import org.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceConstructorInterceptor;
|
||||
import org.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
|
||||
import org.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
|
||||
import org.skywalking.apm.network.trace.component.ComponentsDefine;
|
||||
|
||||
/**
|
||||
* {@link RealCallInterceptor} intercept the synchronous http calls by the discovery of okhttp.
|
||||
|
|
@ -22,49 +26,37 @@ import org.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptR
|
|||
*/
|
||||
public class RealCallInterceptor implements InstanceMethodsAroundInterceptor, InstanceConstructorInterceptor {
|
||||
|
||||
private static final String COMPONENT_NAME = "OKHttp";
|
||||
|
||||
private static final String REQUEST_CONTEXT_KEY = "SWRequestContextKey";
|
||||
|
||||
/**
|
||||
* Intercept the {@link okhttp3.RealCall#RealCall(OkHttpClient, Request, boolean)}, then put the second argument of
|
||||
* {@link okhttp3.Request} into {@link EnhancedClassInstanceContext} with the key of {@link
|
||||
* RealCallInterceptor#REQUEST_CONTEXT_KEY}.
|
||||
* {@link okhttp3.Request} into {@link EnhancedInstance}.
|
||||
*
|
||||
* @param context a new added instance field
|
||||
* @param interceptorContext constructor invocation context.
|
||||
* @param objInst a new added instance field
|
||||
* @param allArguments constructor invocation context.
|
||||
*/
|
||||
@Override
|
||||
public void onConstruct(EnhancedClassInstanceContext context, ConstructorInvokeContext interceptorContext) {
|
||||
context.set(REQUEST_CONTEXT_KEY, interceptorContext.allArguments()[1]);
|
||||
public void onConstruct(EnhancedInstance objInst, Object[] allArguments) {
|
||||
objInst.setSkyWalkingDynamicField(allArguments[1]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the {@link okhttp3.Request} from {@link EnhancedClassInstanceContext}, then create {@link Span} and set host,
|
||||
* Get the {@link okhttp3.Request} from {@link EnhancedInstance}, then create {@link AbstractSpan} and set host,
|
||||
* port, kind, component, url from {@link okhttp3.Request}.
|
||||
* Through the reflection of the way, set the http header of context data into {@link okhttp3.Request#headers}.
|
||||
*
|
||||
* @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.
|
||||
* @throws Throwable
|
||||
*/
|
||||
@Override
|
||||
public void beforeMethod(EnhancedClassInstanceContext context, InstanceMethodInvokeContext interceptorContext,
|
||||
MethodInterceptResult result) throws Throwable {
|
||||
Request request = (Request)context.get(REQUEST_CONTEXT_KEY);
|
||||
|
||||
AbstractSpan span = ContextManager.createSpan(request.url().uri().toString());
|
||||
span.setPeerHost(request.url().host());
|
||||
span.setPort(request.url().port());
|
||||
Tags.SPAN_KIND.set(span, Tags.SPAN_KIND_CLIENT);
|
||||
Tags.COMPONENT.set(span, COMPONENT_NAME);
|
||||
Tags.HTTP.METHOD.set(span, request.method());
|
||||
Tags.URL.set(span, request.url().url().getPath());
|
||||
Tags.SPAN_LAYER.asHttp(span);
|
||||
@Override public void beforeMethod(EnhancedInstance objInst, String methodName, Object[] allArguments,
|
||||
Class<?>[] argumentsTypes, MethodInterceptResult result) throws Throwable {
|
||||
Request request = (Request)objInst.getSkyWalkingDynamicField();
|
||||
|
||||
ContextCarrier contextCarrier = new ContextCarrier();
|
||||
ContextManager.inject(contextCarrier);
|
||||
HttpUrl requestUrl = request.url();
|
||||
AbstractSpan span = ContextManager.createExitSpan(requestUrl.uri().toString(), contextCarrier, requestUrl.host() + ":" + requestUrl.port());
|
||||
span.setComponent(ComponentsDefine.OKHTTP);
|
||||
Tags.HTTP.METHOD.set(span, request.method());
|
||||
Tags.URL.set(span, requestUrl.url().getPath());
|
||||
SpanLayer.asHttp(span);
|
||||
|
||||
Field headersField = Request.class.getDeclaredField("headers");
|
||||
Field modifiersField = Field.class.getDeclaredField("modifiers");
|
||||
|
|
@ -79,34 +71,31 @@ public class RealCallInterceptor implements InstanceMethodsAroundInterceptor, In
|
|||
/**
|
||||
* Get the status code from {@link Response}, when status code greater than 400, it means there was some errors in
|
||||
* the server.
|
||||
* Finish the {@link Span}.
|
||||
* Finish the {@link AbstractSpan}.
|
||||
*
|
||||
* @param context instance context, a class instance only has one {@link EnhancedClassInstanceContext} instance.
|
||||
* @param interceptorContext method context, includes class name, method name, etc.
|
||||
* @param ret the method's original return value.
|
||||
* @return
|
||||
* @throws Throwable
|
||||
*/
|
||||
@Override
|
||||
public Object afterMethod(EnhancedClassInstanceContext context, InstanceMethodInvokeContext interceptorContext,
|
||||
Object ret) throws Throwable {
|
||||
public Object afterMethod(EnhancedInstance objInst, String methodName, Object[] allArguments,
|
||||
Class<?>[] argumentsTypes, Object ret) throws Throwable {
|
||||
Response response = (Response)ret;
|
||||
int statusCode = response.code();
|
||||
|
||||
AbstractSpan span = ContextManager.activeSpan();
|
||||
if (statusCode >= 400) {
|
||||
Tags.ERROR.set(span, true);
|
||||
span.errorOccurred();
|
||||
Tags.STATUS_CODE.set(span, Integer.toString(statusCode));
|
||||
}
|
||||
|
||||
Tags.STATUS_CODE.set(span, statusCode);
|
||||
ContextManager.stopSpan();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override public void handleMethodException(Throwable t, EnhancedClassInstanceContext context,
|
||||
InstanceMethodInvokeContext interceptorContext) {
|
||||
Tags.ERROR.set(ContextManager.activeSpan(), true);
|
||||
ContextManager.activeSpan().log(t);
|
||||
@Override public void handleMethodException(EnhancedInstance objInst, String methodName, Object[] allArguments,
|
||||
Class<?>[] argumentsTypes, Throwable t) {
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -58,6 +58,10 @@ public class RealCallInstrumentation extends ClassInstanceMethodsEnhancePluginDe
|
|||
@Override public String getMethodsInterceptor() {
|
||||
return INTERCEPT_CLASS;
|
||||
}
|
||||
|
||||
@Override public boolean isOverrideArgs() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,9 +7,11 @@ import org.skywalking.apm.agent.core.context.ContextCarrier;
|
|||
import org.skywalking.apm.agent.core.context.ContextManager;
|
||||
import org.skywalking.apm.agent.core.context.tag.Tags;
|
||||
import org.skywalking.apm.agent.core.context.trace.AbstractSpan;
|
||||
import org.skywalking.apm.agent.core.context.trace.SpanLayer;
|
||||
import org.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
|
||||
import org.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
|
||||
import org.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
|
||||
import org.skywalking.apm.util.StringUtil;
|
||||
import org.skywalking.apm.network.trace.component.ComponentsDefine;
|
||||
|
||||
/**
|
||||
* {@link ResinV3Interceptor} intercept method of{@link com.caucho.server.dispatch.ServletInvocation#service(javax.servlet.ServletRequest,
|
||||
|
|
@ -18,28 +20,37 @@ import org.skywalking.apm.util.StringUtil;
|
|||
* @author baiyang
|
||||
*/
|
||||
public class ResinV3Interceptor implements InstanceMethodsAroundInterceptor {
|
||||
/**
|
||||
* Resin component.
|
||||
*/
|
||||
public static final String RESIN_COMPONENT = "Resin";
|
||||
|
||||
@Override public void beforeMethod(EnhancedInstance objInst, String methodName, Object[] allArguments,
|
||||
Class<?>[] argumentsTypes, MethodInterceptResult result) throws Throwable {
|
||||
CauchoRequest request = (CauchoRequest)allArguments[0];
|
||||
String tracingHeaderValue = request.getHeader(Config.Plugin.Propagation.HEADER_NAME);
|
||||
ContextCarrier contextCarrier = new ContextCarrier().deserialize(tracingHeaderValue);
|
||||
AbstractSpan span = ContextManager.createEntrySpan(request.getPageURI(), contextCarrier);
|
||||
span.setComponent(ComponentsDefine.RESIN);
|
||||
Tags.URL.set(span, appendRequestURL(request));
|
||||
SpanLayer.asHttp(span);
|
||||
}
|
||||
|
||||
@Override public Object afterMethod(EnhancedInstance objInst, String methodName, Object[] allArguments,
|
||||
Class<?>[] argumentsTypes, Object ret) throws Throwable {
|
||||
HttpResponse response = (HttpResponse)allArguments[1];
|
||||
AbstractSpan span = ContextManager.activeSpan();
|
||||
|
||||
if (response.getStatusCode() >= 400) {
|
||||
Tags.STATUS_CODE.set(span, Integer.toString(response.getStatusCode()));
|
||||
span.errorOccurred();
|
||||
}
|
||||
ContextManager.stopSpan();
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beforeMethod(EnhancedClassInstanceContext context, InstanceMethodInvokeContext interceptorContext,
|
||||
MethodInterceptResult result) {
|
||||
Object[] args = interceptorContext.allArguments();
|
||||
CauchoRequest request = (CauchoRequest)args[0];
|
||||
AbstractSpan span = ContextManager.createSpan(request.getPageURI());
|
||||
Tags.COMPONENT.set(span, RESIN_COMPONENT);
|
||||
span.setPeerHost(request.getServerName());
|
||||
span.setPort(request.getServerPort());
|
||||
Tags.SPAN_KIND.set(span, Tags.SPAN_KIND_SERVER);
|
||||
Tags.URL.set(span, appendRequestURL(request));
|
||||
Tags.SPAN_LAYER.asHttp(span);
|
||||
|
||||
String tracingHeaderValue = request.getHeader(Config.Plugin.Propagation.HEADER_NAME);
|
||||
if (!StringUtil.isEmpty(tracingHeaderValue)) {
|
||||
ContextManager.extract(new ContextCarrier().deserialize(tracingHeaderValue));
|
||||
}
|
||||
public void handleMethodException(EnhancedInstance objInst, String methodName, Object[] allArguments,
|
||||
Class<?>[] argumentsTypes, Throwable t) {
|
||||
AbstractSpan activeSpan = ContextManager.activeSpan();
|
||||
activeSpan.log(t);
|
||||
activeSpan.errorOccurred();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -58,26 +69,4 @@ public class ResinV3Interceptor implements InstanceMethodsAroundInterceptor {
|
|||
sb.append(request.getPageURI());
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object afterMethod(EnhancedClassInstanceContext context, InstanceMethodInvokeContext interceptorContext,
|
||||
Object ret) {
|
||||
HttpResponse response = (HttpResponse)interceptorContext.allArguments()[1];
|
||||
AbstractSpan span = ContextManager.activeSpan();
|
||||
Tags.STATUS_CODE.set(span, response.getStatusCode());
|
||||
|
||||
if (response.getStatusCode() != 200) {
|
||||
Tags.ERROR.set(span, true);
|
||||
}
|
||||
ContextManager.stopSpan();
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleMethodException(Throwable t, EnhancedClassInstanceContext context,
|
||||
InstanceMethodInvokeContext interceptorContext) {
|
||||
AbstractSpan span = ContextManager.activeSpan();
|
||||
span.log(t);
|
||||
Tags.ERROR.set(span, true);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,6 +39,11 @@ public class ResinV3Instrumentation extends ClassInstanceMethodsEnhancePluginDef
|
|||
public String getMethodsInterceptor() {
|
||||
return METHOD_INTERCET_CLASS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOverrideArgs() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,36 +7,48 @@ import org.skywalking.apm.agent.core.context.ContextCarrier;
|
|||
import org.skywalking.apm.agent.core.context.ContextManager;
|
||||
import org.skywalking.apm.agent.core.context.tag.Tags;
|
||||
import org.skywalking.apm.agent.core.context.trace.AbstractSpan;
|
||||
import org.skywalking.apm.agent.core.context.trace.SpanLayer;
|
||||
import org.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
|
||||
import org.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
|
||||
import org.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
|
||||
import org.skywalking.apm.util.StringUtil;
|
||||
import org.skywalking.apm.network.trace.component.ComponentsDefine;
|
||||
|
||||
/**
|
||||
* Created by Baiyang on 2017/5/2.
|
||||
*/
|
||||
public class ResinV4Interceptor implements InstanceMethodsAroundInterceptor {
|
||||
/**
|
||||
* Resin component.
|
||||
*/
|
||||
public static final String RESIN_COMPONENT = "Resin";
|
||||
@Override
|
||||
public void beforeMethod(EnhancedInstance objInst, String methodName, Object[] allArguments,
|
||||
Class<?>[] argumentsTypes, MethodInterceptResult result) throws Throwable {
|
||||
CauchoRequest request = (CauchoRequest)allArguments[0];
|
||||
String tracingHeaderValue = request.getHeader(Config.Plugin.Propagation.HEADER_NAME);
|
||||
ContextCarrier contextCarrier = new ContextCarrier().deserialize(tracingHeaderValue);
|
||||
AbstractSpan span = ContextManager.createEntrySpan(request.getPageURI(), contextCarrier);
|
||||
span.setComponent(ComponentsDefine.RESIN);
|
||||
Tags.URL.set(span, appendRequestURL(request));
|
||||
SpanLayer.asHttp(span);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beforeMethod(EnhancedClassInstanceContext context, InstanceMethodInvokeContext interceptorContext,
|
||||
MethodInterceptResult result) {
|
||||
Object[] args = interceptorContext.allArguments();
|
||||
CauchoRequest request = (CauchoRequest)args[0];
|
||||
AbstractSpan span = ContextManager.createSpan(request.getPageURI());
|
||||
Tags.COMPONENT.set(span, RESIN_COMPONENT);
|
||||
span.setPeerHost(request.getServerName());
|
||||
span.setPort(request.getServerPort());
|
||||
Tags.SPAN_KIND.set(span, Tags.SPAN_KIND_SERVER);
|
||||
Tags.URL.set(span, appendRequestURL(request));
|
||||
Tags.SPAN_LAYER.asHttp(span);
|
||||
public Object afterMethod(EnhancedInstance objInst, String methodName, Object[] allArguments,
|
||||
Class<?>[] argumentsTypes, Object ret) throws Throwable {
|
||||
HttpServletResponse response = (HttpServletResponse)allArguments[1];
|
||||
AbstractSpan span = ContextManager.activeSpan();
|
||||
|
||||
String tracingHeaderValue = request.getHeader(Config.Plugin.Propagation.HEADER_NAME);
|
||||
if (!StringUtil.isEmpty(tracingHeaderValue)) {
|
||||
ContextManager.extract(new ContextCarrier().deserialize(tracingHeaderValue));
|
||||
if (response.getStatus() >= 400) {
|
||||
Tags.STATUS_CODE.set(span, Integer.toString(response.getStatus()));
|
||||
span.errorOccurred();
|
||||
}
|
||||
ContextManager.stopSpan();
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override public void handleMethodException(EnhancedInstance objInst, String methodName, Object[] allArguments,
|
||||
Class<?>[] argumentsTypes, Throwable t) {
|
||||
AbstractSpan activeSpan = ContextManager.activeSpan();
|
||||
activeSpan.log(t);
|
||||
activeSpan.errorOccurred();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -55,26 +67,4 @@ public class ResinV4Interceptor implements InstanceMethodsAroundInterceptor {
|
|||
sb.append(request.getPageURI());
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object afterMethod(EnhancedClassInstanceContext context, InstanceMethodInvokeContext interceptorContext,
|
||||
Object ret) {
|
||||
HttpServletResponse response = (HttpServletResponse)interceptorContext.allArguments()[1];
|
||||
AbstractSpan span = ContextManager.activeSpan();
|
||||
Tags.STATUS_CODE.set(span, response.getStatus());
|
||||
|
||||
if (response.getStatus() != 200) {
|
||||
Tags.ERROR.set(span, true);
|
||||
}
|
||||
ContextManager.stopSpan();
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleMethodException(Throwable t, EnhancedClassInstanceContext context,
|
||||
InstanceMethodInvokeContext interceptorContext) {
|
||||
AbstractSpan span = ContextManager.activeSpan();
|
||||
span.log(t);
|
||||
Tags.ERROR.set(span, true);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,6 +38,11 @@ public class ResinV4Instrumentation extends ClassInstanceMethodsEnhancePluginDef
|
|||
public String getMethodsInterceptor() {
|
||||
return METHOD_INTERCET_CLASS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOverrideArgs() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -50,9 +50,9 @@ public class TomcatInterceptor implements InstanceMethodsAroundInterceptor {
|
|||
HttpServletResponse response = (HttpServletResponse)allArguments[1];
|
||||
|
||||
AbstractSpan span = ContextManager.activeSpan();
|
||||
if (response.getStatus() != 200) {
|
||||
if (response.getStatus() >= 400) {
|
||||
span.errorOccurred();
|
||||
Tags.STATUS_CODE.set(span, response.getStatus() + "");
|
||||
Tags.STATUS_CODE.set(span, Integer.toString(response.getStatus()));
|
||||
}
|
||||
ContextManager.stopSpan();
|
||||
return ret;
|
||||
|
|
|
|||
Loading…
Reference in New Issue