0
点赞
收藏
分享

微信扫一扫

skywalking源码分析第二十二篇一agent端实战之JDBC插件


文章目录

  • ​​源码分析一插件定义​​
  • ​​源码分析一方法拦截器定义​​
  • ​​总结​​

源码分析一插件定义

  • StatementInstrumentation插件拦截StatementImpl相关方法进行增强
  • jdbc含包含其他众多插件
  • 其中CONSTRUCTOR_INTERCEPTOR并非skywalking源码,其为笔者私有定制,用于全链路压测场景

public class StatementInstrumentation extends AbstractMysqlInstrumentation {
private static final String SERVICE_METHOD_INTERCEPTOR = org.apache.skywalking.apm.plugin.jdbc.mysql.Constants.STATEMENT_EXECUTE_METHODS_INTERCEPTOR;
public static final String MYSQL8_STATEMENT_CLASS_NAME = "com.mysql.cj.jdbc.StatementImpl";
private static final String CONSTRUCTOR_INTERCEPTOR = "org.apache.skywalking.apm.plugin.jdbc.mysql.v8.StatementCreateInterceptor";

@Override public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
return new ConstructorInterceptPoint[]{ new ConstructorInterceptPoint() {
@Override
public ElementMatcher<MethodDescription> getConstructorMatcher() {
return any();
}

@Override
public String getConstructorInterceptor() {
return CONSTRUCTOR_INTERCEPTOR;
}
}};
}

@Override public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
return new InstanceMethodsInterceptPoint[] {
new InstanceMethodsInterceptPoint() {
@Override public ElementMatcher<MethodDescription> getMethodsMatcher() {
return named("execute")
.or(named("executeQuery"))
.or(named("executeUpdate"))
.or(named("executeLargeUpdate"))
.or(named("executeBatchInternal"))
.or(named("executeUpdateInternal"))
.or(named("executeQuery"))
.or(named("executeBatch"));
}

@Override public String getMethodsInterceptor() {
return SERVICE_METHOD_INTERCEPTOR;
}

@Override public boolean isOverrideArgs() {
return false;
}
}
};
}

@Override protected ClassMatch enhanceClass() {
return byName(MYSQL8_STATEMENT_CLASS_NAME);
}
}

源码分析一方法拦截器定义

  • 设置数据库span的相关kv键值对
  • 包含sql语句等

public class StatementExecuteMethodsInterceptor implements InstanceMethodsAroundInterceptor {
@Override
public final void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments,
Class<?>[] argumentsTypes,
MethodInterceptResult result) throws Throwable {
StatementEnhanceInfos cacheObject = (StatementEnhanceInfos)objInst.getSkyWalkingDynamicField();
ConnectionInfo connectInfo = cacheObject.getConnectionInfo();
if (connectInfo != null) {
// 创建Exitspan
AbstractSpan span = ContextManager.createExitSpan(buildOperationName(connectInfo, method.getName(), cacheObject.getStatementName()), connectInfo.getDatabasePeer());
Tags.DB_TYPE.set(span, "sql");
// 设置数据库名称
Tags.DB_INSTANCE.set(span, connectInfo.getDatabaseName());
String sql = "";
if (allArguments.length > 0) {
sql = (String)allArguments[0];
}

为span设置sql语句
Tags.DB_STATEMENT.set(span, sql);
span.setComponent(connectInfo.getComponent());

SpanLayer.asDB(span);
}
}

@Override
public final Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments,
Class<?>[] argumentsTypes,
Object ret) throws Throwable {
StatementEnhanceInfos cacheObject = (StatementEnhanceInfos)objInst.getSkyWalkingDynamicField();
if (cacheObject.getConnectionInfo() != null) {
// 将TracerContext.activeSpanStack中的span弹栈加入Segment
ContextManager.stopSpan();
}
return ret;
}



private String buildOperationName(ConnectionInfo connectionInfo, String methodName, String statementName) {
return connectionInfo.getDBType() + "/JDBI/" + statementName + "/" + methodName;
}
}

总结

  • jdbc插件众多,本文分析的Statement是一个重点,其创建的span持有sql语句,查询参数等信息


举报

相关推荐

0 条评论