龙空技术网

聊聊skywalking的mysql-plugin

码匠乱炖 140

前言:

目前同学们对“mysqldynamic”大约比较看重,你们都需要学习一些“mysqldynamic”的相关资讯。那么小编也在网络上搜集了一些对于“mysqldynamic””的相关资讯,希望你们能喜欢,咱们一起来学习一下吧!

本文主要研究一下skywalking的mysql-plugin

skywalking-plugin.def

skywalking-6.6.0/apm-sniffer/apm-sdk-plugin/mysql-8.x-plugin/src/main/resources/skywalking-plugin.def

mysql-8.x=org.apache.skywalking.apm.plugin.jdbc.mysql.v8.define.ConnectionImplCreateInstrumentationmysql-8.x=org.apache.skywalking.apm.plugin.jdbc.mysql.v8.define.ConnectionInstrumentationmysql-8.x=org.apache.skywalking.apm.plugin.jdbc.mysql.v8.define.CallableInstrumentationmysql-8.x=org.apache.skywalking.apm.plugin.jdbc.mysql.v8.define.PreparedStatementInstrumentationmysql-8.x=org.apache.skywalking.apm.plugin.jdbc.mysql.v8.define.StatementInstrumentationmysql-8.x=org.apache.skywalking.apm.plugin.jdbc.mysql.v8.define.PreparedStatementSetterInstrumentationmysql-8.x=org.apache.skywalking.apm.plugin.jdbc.mysql.v8.define.PreparedStatementNullSetterInstrumentationmysql-8.x=org.apache.skywalking.apm.plugin.jdbc.mysql.v8.define.PreparedStatementIgnoredSetterInstrumentation
skywalking的mysql-plugin提供了ConnectionImplCreateInstrumentation、ConnectionInstrumentation、CallableInstrumentation、PreparedStatementInstrumentation、StatementInstrumentation、PreparedStatementSetterInstrumentation、PreparedStatementNullSetterInstrumentation、PreparedStatementIgnoredSetterInstrumentation这几个增强AbstractMysqlInstrumentation

skywalking-6.6.0/apm-sniffer/apm-sdk-plugin/mysql-8.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jdbc/mysql/v8/define/AbstractMysqlInstrumentation.java

public abstract class AbstractMysqlInstrumentation extends ClassEnhancePluginDefine {​    @Override    public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {        return null;    }    @Override    public StaticMethodsInterceptPoint[] getStaticMethodsInterceptPoints() {        return null;    }​    @Override    public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {        return null;    }​​    @Override    protected String[] witnessClasses() {        return new String[]{Constants.WITNESS_MYSQL_8X_CLASS};    }}
AbstractMysqlInstrumentation继承了ClassEnhancePluginDefine,其witnessClasses返回的是com.mysql.cj.interceptors.QueryInterceptorConnectionImplCreateInstrumentation

skywalking-6.6.0/apm-sniffer/apm-sdk-plugin/mysql-8.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jdbc/mysql/v8/define/ConnectionImplCreateInstrumentation.java

public class ConnectionImplCreateInstrumentation extends AbstractMysqlInstrumentation {​    private static final String JDBC_ENHANCE_CLASS = "com.mysql.cj.jdbc.ConnectionImpl";​    private static final String CONNECT_METHOD = "getInstance";​​    @Override    public StaticMethodsInterceptPoint[] getStaticMethodsInterceptPoints() {        return new StaticMethodsInterceptPoint[] {            new StaticMethodsInterceptPoint() {                @Override                public ElementMatcher<MethodDescription> getMethodsMatcher() {                    return named(CONNECT_METHOD);                }​                @Override                public String getMethodsInterceptor() {                    return "org.apache.skywalking.apm.plugin.jdbc.mysql.v8.ConnectionCreateInterceptor";                }​                @Override                public boolean isOverrideArgs() {                    return false;                }            }        };    }​    @Override    protected ClassMatch enhanceClass() {        return byName(JDBC_ENHANCE_CLASS);    }}
ConnectionImplCreateInstrumentation继承了AbstractMysqlInstrumentation;它使用org.apache.skywalking.apm.plugin.jdbc.mysql.v8.ConnectionCreateInterceptor增强了com.mysql.cj.jdbc.ConnectionImpl的getInstance方法ConnectionCreateInterceptor

skywalking-6.6.0/apm-sniffer/apm-sdk-plugin/mysql-8.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jdbc/mysql/v8/ConnectionCreateInterceptor.java

public class ConnectionCreateInterceptor implements StaticMethodsAroundInterceptor {​​    @Override    public void beforeMethod(Class clazz, Method method, Object[] allArguments, Class<?>[] parameterTypes, MethodInterceptResult result) {​    }​    @Override    public Object afterMethod(Class clazz, Method method, Object[] allArguments, Class<?>[] parameterTypes, Object ret) {        if (ret instanceof EnhancedInstance) {            final HostInfo hostInfo = (HostInfo) allArguments[0];            ConnectionInfo connectionInfo = URLParser.parser(hostInfo.getDatabaseUrl());            ((EnhancedInstance) ret).setSkyWalkingDynamicField(connectionInfo);        }        return ret;    }​    @Override    public void handleMethodException(Class clazz, Method method, Object[] allArguments, Class<?>[] parameterTypes, Throwable t) {​    }}
ConnectionCreateInterceptor实现了StaticMethodsAroundInterceptor接口,其afterMethod方法提取hostInfo解析为connectionInfo然后设置给ret的skyWalkingDynamicFieldConnectionInstrumentation

skywalking-6.6.0/apm-sniffer/apm-sdk-plugin/mysql-8.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jdbc/mysql/v8/define/ConnectionInstrumentation.java

public class ConnectionInstrumentation extends AbstractMysqlInstrumentation {​    @Override public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {        return new ConstructorInterceptPoint[0];    }​    @Override public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {        return new InstanceMethodsInterceptPoint[] {            new InstanceMethodsInterceptPoint() {                @Override public ElementMatcher<MethodDescription> getMethodsMatcher() {                    return named(org.apache.skywalking.apm.plugin.jdbc.define.Constants.PREPARE_STATEMENT_METHOD_NAME);                }​                @Override public String getMethodsInterceptor() {                    return org.apache.skywalking.apm.plugin.jdbc.mysql.Constants.CREATE_PREPARED_STATEMENT_INTERCEPTOR;                }​                @Override public boolean isOverrideArgs() {                    return false;                }            },            new InstanceMethodsInterceptPoint() {                @Override public ElementMatcher<MethodDescription> getMethodsMatcher() {                    return named(org.apache.skywalking.apm.plugin.jdbc.define.Constants.PREPARE_CALL_METHOD_NAME);                }​                @Override public String getMethodsInterceptor() {                    return org.apache.skywalking.apm.plugin.jdbc.mysql.Constants.CREATE_CALLABLE_STATEMENT_INTERCEPTOR;                }​                @Override public boolean isOverrideArgs() {                    return false;                }            },            new InstanceMethodsInterceptPoint() {                @Override public ElementMatcher<MethodDescription> getMethodsMatcher() {                    return named(org.apache.skywalking.apm.plugin.jdbc.define.Constants.CREATE_STATEMENT_METHOD_NAME).and(takesArguments(2));                }​                @Override public String getMethodsInterceptor() {                    return org.apache.skywalking.apm.plugin.jdbc.mysql.Constants.CREATE_STATEMENT_INTERCEPTOR;                }​                @Override public boolean isOverrideArgs() {                    return false;                }            },            new InstanceMethodsInterceptPoint() {                @Override public ElementMatcher<MethodDescription> getMethodsMatcher() {                    return named(org.apache.skywalking.apm.plugin.jdbc.define.Constants.COMMIT_METHOD_NAME).or(named(org.apache.skywalking.apm.plugin.jdbc.define.Constants.ROLLBACK_METHOD_NAME)).or(named(org.apache.skywalking.apm.plugin.jdbc.define.Constants.CLOSE_METHOD_NAME)).or(named(org.apache.skywalking.apm.plugin.jdbc.define.Constants.RELEASE_SAVE_POINT_METHOD_NAME));                }​                @Override public String getMethodsInterceptor() {                    return org.apache.skywalking.apm.plugin.jdbc.define.Constants.SERVICE_METHOD_INTERCEPT_CLASS;                }​                @Override public boolean isOverrideArgs() {                    return false;                }            },            new InstanceMethodsInterceptPoint() {                @Override public ElementMatcher<MethodDescription> getMethodsMatcher() {                    return named("setCatalog");                }​                @Override public String getMethodsInterceptor() {                    return org.apache.skywalking.apm.plugin.jdbc.mysql.Constants.SET_CATALOG_INTERCEPTOR;                }​                @Override public boolean isOverrideArgs() {                    return false;                }            }        };​    }​​    @Override protected ClassMatch enhanceClass() {        return byName("com.mysql.cj.jdbc.ConnectionImpl");    }​}
ConnectionInstrumentation继承了AbstractMysqlInstrumentation,它增强的是com.mysql.cj.jdbc.ConnectionImpl类;它使用org.apache.skywalking.apm.plugin.jdbc.mysql.CreatePreparedStatementInterceptor增强其prepareStatement方法;它使用org.apache.skywalking.apm.plugin.jdbc.mysql.CreateCallableStatementInterceptor增强其prepareCall方法;它使用org.apache.skywalking.apm.plugin.jdbc.mysql.CreateStatementInterceptor增强其createStatement方法;它使用org.apache.skywalking.apm.plugin.jdbc.ConnectionServiceMethodInterceptor增强其commit、rollback、close、releaseSavepoint方法;它使用org.apache.skywalking.apm.plugin.jdbc.mysql.SetCatalogInterceptor增强其setCatalog方法CreatePreparedStatementInterceptor

skywalking-6.6.0/apm-sniffer/apm-sdk-plugin/mysql-common/src/main/java/org/apache/skywalking/apm/plugin/jdbc/mysql/CreatePreparedStatementInterceptor.java

public class CreatePreparedStatementInterceptor implements InstanceMethodsAroundInterceptor {    @Override    public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes,        MethodInterceptResult result) throws Throwable {    }​    @Override    public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes,        Object ret) throws Throwable {        if (ret instanceof EnhancedInstance) {            ((EnhancedInstance)ret).setSkyWalkingDynamicField(new StatementEnhanceInfos((ConnectionInfo)objInst.getSkyWalkingDynamicField(), (String)allArguments[0], "PreparedStatement"));        }        return ret;    }​    @Override public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments,        Class<?>[] argumentsTypes, Throwable t) {​    }}
CreatePreparedStatementInterceptor实现了InstanceMethodsAroundInterceptor接口,其afterMethod方法会将StatementEnhanceInfos设置给ret的skyWalkingDynamicFieldCreateCallableStatementInterceptor

skywalking-6.6.0/apm-sniffer/apm-sdk-plugin/mysql-common/src/main/java/org/apache/skywalking/apm/plugin/jdbc/mysql/CreateCallableStatementInterceptor.java

public class CreateCallableStatementInterceptor implements InstanceMethodsAroundInterceptor {    @Override    public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes,        MethodInterceptResult result) throws Throwable {​    }​    @Override    public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes,        Object ret) throws Throwable {        if (ret instanceof EnhancedInstance) {            ((EnhancedInstance)ret).setSkyWalkingDynamicField(new StatementEnhanceInfos((ConnectionInfo)objInst.getSkyWalkingDynamicField(), (String)allArguments[0], "CallableStatement"));        }        return ret;    }​    @Override public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments,        Class<?>[] argumentsTypes, Throwable t) {​    }}
CreateCallableStatementInterceptor实现了InstanceMethodsAroundInterceptor接口,其afterMethod方法将StatementEnhanceInfos设置给ret的skyWalkingDynamicFieldCreateStatementInterceptor

skywalking-6.6.0/apm-sniffer/apm-sdk-plugin/mysql-common/src/main/java/org/apache/skywalking/apm/plugin/jdbc/mysql/CreateStatementInterceptor.java

public class CreateStatementInterceptor implements InstanceMethodsAroundInterceptor {    @Override    public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes,        MethodInterceptResult result) throws Throwable {​    }​    @Override    public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes,        Object ret) throws Throwable {        if (ret instanceof EnhancedInstance) {            ((EnhancedInstance)ret).setSkyWalkingDynamicField(new StatementEnhanceInfos((ConnectionInfo)objInst.getSkyWalkingDynamicField(), "", "Statement"));        }        return ret;    }​    @Override public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments,        Class<?>[] argumentsTypes, Throwable t) {​    }}
CreateStatementInterceptor实现了InstanceMethodsAroundInterceptor接口,其afterMethod方法将StatementEnhanceInfos设置给ret的skyWalkingDynamicFieldConnectionServiceMethodInterceptor

skywalking-6.6.0/apm-sniffer/apm-sdk-plugin/jdbc-commons/src/main/java/org/apache/skywalking/apm/plugin/jdbc/ConnectionServiceMethodInterceptor.java

public class ConnectionServiceMethodInterceptor implements InstanceMethodsAroundInterceptor {​    @Override    public final void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments,        Class<?>[] argumentsTypes,        MethodInterceptResult result) throws Throwable {        ConnectionInfo connectInfo = (ConnectionInfo)objInst.getSkyWalkingDynamicField();        if (connectInfo != null) {            AbstractSpan span = ContextManager.createExitSpan(connectInfo.getDBType() + "/JDBI/Connection/" + method.getName(), connectInfo.getDatabasePeer());            Tags.DB_TYPE.set(span, "sql");            Tags.DB_INSTANCE.set(span, connectInfo.getDatabaseName());            Tags.DB_STATEMENT.set(span, "");            span.setComponent(connectInfo.getComponent());            SpanLayer.asDB(span);        }    }​    @Override    public final Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments,        Class<?>[] argumentsTypes,        Object ret) throws Throwable {        ConnectionInfo connectInfo = (ConnectionInfo)objInst.getSkyWalkingDynamicField();        if (connectInfo != null) {            ContextManager.stopSpan();        }        return ret;    }​    @Override public final void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments,        Class<?>[] argumentsTypes, Throwable t) {        ContextManager.activeSpan().errorOccurred().log(t);    }​}
ConnectionServiceMethodInterceptor实现了InstanceMethodsAroundInterceptor接口,其beforeMethod方法设置DB_TYPE、DB_INSTANCE、DB_STATEMENT;其afterMethod方法在connectInfo不为null时执行ContextManager.stopSpan();其handleMethodException方法执行ContextManager.activeSpan().errorOccurred().log(t)SetCatalogInterceptor

skywalking-6.6.0/apm-sniffer/apm-sdk-plugin/mysql-common/src/main/java/org/apache/skywalking/apm/plugin/jdbc/mysql/SetCatalogInterceptor.java

public class SetCatalogInterceptor implements InstanceMethodsAroundInterceptor {    @Override    public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes,        MethodInterceptResult result) throws Throwable {        Object dynamicField = objInst.getSkyWalkingDynamicField();        if (dynamicField instanceof ConnectionInfo) {            ((ConnectionInfo)dynamicField).setDatabaseName(String.valueOf(allArguments[0]));        }    }​    @Override    public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes,        Object ret) throws Throwable {        return ret;    }​    @Override public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments,        Class<?>[] argumentsTypes, Throwable t) {    }}
SetCatalogInterceptor实现了InstanceMethodsAroundInterceptor接口,其beforeMethod方法给类型为ConnectionInfo的dynamicField设置databaseNameCallableInstrumentation

skywalking-6.6.0/apm-sniffer/apm-sdk-plugin/mysql-8.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jdbc/mysql/v8/define/CallableInstrumentation.java

public class CallableInstrumentation extends AbstractMysqlInstrumentation {    private static final String ENHANCE_CLASS = "com.mysql.cj.jdbc.CallableStatement";    private static final String SERVICE_METHOD_INTERCEPTOR = org.apache.skywalking.apm.plugin.jdbc.mysql.Constants.PREPARED_STATEMENT_EXECUTE_METHODS_INTERCEPTOR;​    @Override public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {        return new ConstructorInterceptPoint[0];    }​    @Override public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {        return new InstanceMethodsInterceptPoint[] {            new InstanceMethodsInterceptPoint() {                @Override public ElementMatcher<MethodDescription> getMethodsMatcher() {                    return named("execute")                        .or(named("executeQuery"))                        .or(named("executeUpdate"));                }​                @Override public String getMethodsInterceptor() {                    return SERVICE_METHOD_INTERCEPTOR;                }​                @Override public boolean isOverrideArgs() {                    return false;                }            }        };    }​    @Override protected ClassMatch enhanceClass() {        return byName(ENHANCE_CLASS);    }​}
CallableInstrumentation继承了AbstractMysqlInstrumentation,它使用org.apache.skywalking.apm.plugin.jdbc.mysql.PreparedStatementExecuteMethodsInterceptor增强了com.mysql.cj.jdbc.CallableStatement的execute、executeQuery、executeUpdate方法PreparedStatementExecuteMethodsInterceptor

skywalking-6.6.0/apm-sniffer/apm-sdk-plugin/mysql-common/src/main/java/org/apache/skywalking/apm/plugin/jdbc/mysql/PreparedStatementExecuteMethodsInterceptor.java

public class PreparedStatementExecuteMethodsInterceptor 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();        /**         * For avoid NPE. In this particular case, Execute sql inside the {@link com.mysql.jdbc.ConnectionImpl} constructor,         * before the interceptor sets the connectionInfo.         *         * @see JDBCDriverInterceptor#afterMethod(EnhancedInstance, Method, Object[], Class[], Object)         */        if (connectInfo != null) {​            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());            Tags.DB_STATEMENT.set(span, cacheObject.getSql());            span.setComponent(connectInfo.getComponent());​            if (Config.Plugin.MySQL.TRACE_SQL_PARAMETERS) {                final Object[] parameters = cacheObject.getParameters();                if (parameters != null && parameters.length > 0) {                    int maxIndex = cacheObject.getMaxIndex();                    String parameterString = buildParameterString(parameters, maxIndex);                    int sqlParametersMaxLength = Config.Plugin.MySQL.SQL_PARAMETERS_MAX_LENGTH;                    if (sqlParametersMaxLength > 0 && parameterString.length() > sqlParametersMaxLength) {                        parameterString = parameterString.substring(0, sqlParametersMaxLength) + "...";                    }                    SQL_PARAMETERS.set(span, parameterString);                }            }​            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) {            ContextManager.stopSpan();        }        return ret;    }​    @Override public final void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments,        Class<?>[] argumentsTypes, Throwable t) {        StatementEnhanceInfos cacheObject = (StatementEnhanceInfos)objInst.getSkyWalkingDynamicField();        if (cacheObject.getConnectionInfo() != null) {            ContextManager.activeSpan().errorOccurred().log(t);        }    }​    private String buildOperationName(ConnectionInfo connectionInfo, String methodName, String statementName) {        return connectionInfo.getDBType() + "/JDBI/" + statementName + "/" + methodName;    }​    private String buildParameterString(Object[] parameters, int maxIndex) {        String parameterString = "[";        boolean first = true;        for (int i = 0; i < maxIndex; i++) {            Object parameter = parameters[i];            if (!first) {                parameterString += ",";            }            parameterString += parameter;            first = false;        }        parameterString += "]";        return parameterString;    }}
PreparedStatementExecuteMethodsInterceptor实现了InstanceMethodsAroundInterceptor接口,其beforeMethod方法设置DB_TYPE、DB_INSTANCE、DB_STATEMENT、SQL_PARAMETERS(Config.Plugin.MySQL.TRACE_SQL_PARAMETERS为true的话);其afterMethod方法在cacheObject.getConnectionInfo()不为null时执行ContextManager.stopSpan();其handleMethodException方法在cacheObject.getConnectionInfo()不为null时执行ContextManager.activeSpan().errorOccurred().log(t)PreparedStatementInstrumentation

skywalking-6.6.0/apm-sniffer/apm-sdk-plugin/mysql-8.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jdbc/mysql/v8/define/PreparedStatementInstrumentation.java

public class PreparedStatementInstrumentation extends AbstractMysqlInstrumentation {​    private static final String PREPARED_STATEMENT_CLASS_NAME = "com.mysql.cj.jdbc.ClientPreparedStatement";    private static final String PREPARED_STATEMENT_SERVER_SIDE_CLASS_NAME = "com.mysql.cj.jdbc.ServerPreparedStatement";​    private static final String SERVICE_METHOD_INTERCEPTOR =  Constants.PREPARED_STATEMENT_EXECUTE_METHODS_INTERCEPTOR;​    @Override public final ConstructorInterceptPoint[] getConstructorsInterceptPoints() {        return new ConstructorInterceptPoint[0];    }​    @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"));                }​                @Override public String getMethodsInterceptor() {                    return SERVICE_METHOD_INTERCEPTOR;                }​                @Override public boolean isOverrideArgs() {                    return false;                }            }        };    }​    @Override protected ClassMatch enhanceClass() {        return byMultiClassMatch(PREPARED_STATEMENT_CLASS_NAME, PREPARED_STATEMENT_SERVER_SIDE_CLASS_NAME);    }}
PreparedStatementInstrumentation继承了AbstractMysqlInstrumentation,它使用org.apache.skywalking.apm.plugin.jdbc.mysql.PreparedStatementExecuteMethodsInterceptor增强了com.mysql.cj.jdbc.ClientPreparedStatement的execute、executeQuery、executeUpdate、executeLargeUpdate方法StatementInstrumentation

skywalking-6.6.0/apm-sniffer/apm-sdk-plugin/mysql-8.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jdbc/mysql/v8/define/StatementInstrumentation.java

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";​    @Override public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {        return new ConstructorInterceptPoint[0];    }​    @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);    }}
StatementInstrumentation继承了AbstractMysqlInstrumentation,它使用org.apache.skywalking.apm.plugin.jdbc.mysql.StatementExecuteMethodsInterceptor增强了com.mysql.cj.jdbc.StatementImpl的execute、executeQuery、executeUpdate、executeLargeUpdate、executeBatchInternal、executeUpdateInternal、executeQuery、executeBatch方法StatementExecuteMethodsInterceptor

skywalking-6.6.0/apm-sniffer/apm-sdk-plugin/mysql-common/src/main/java/org/apache/skywalking/apm/plugin/jdbc/mysql/StatementExecuteMethodsInterceptor.java

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();        /**         * To protected the code occur NullPointException. because mysql execute system sql when constructor method in         * {@link com.mysql.jdbc.ConnectionImpl} class executed. but the interceptor set the connection Info after         * the constructor method executed.         *         * @see JDBCDriverInterceptor#afterMethod(EnhancedInstance, Method, Object[], Class[], Object)         */        if (connectInfo != null) {​            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());​            /**             * The first argument of all intercept method in `com.mysql.jdbc.StatementImpl` class is SQL, except the             * `executeBatch` method that the jdbc plugin need to trace, because of this method argument size is zero.             */            String sql = "";            if (allArguments.length > 0) {                sql = (String)allArguments[0];            }​            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) {            ContextManager.stopSpan();        }        return ret;    }​    @Override public final void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments,        Class<?>[] argumentsTypes, Throwable t) {        StatementEnhanceInfos cacheObject = (StatementEnhanceInfos)objInst.getSkyWalkingDynamicField();        if (cacheObject.getConnectionInfo() != null) {            ContextManager.activeSpan().errorOccurred().log(t);        }    }​    private String buildOperationName(ConnectionInfo connectionInfo, String methodName, String statementName) {        return connectionInfo.getDBType() + "/JDBI/" + statementName + "/" + methodName;    }}
StatementExecuteMethodsInterceptor实现了InstanceMethodsAroundInterceptor接口,其beforeMethod方法设置DB_TYPE、DB_INSTANCE、DB_STATEMENT;其afterMethod方法在cacheObject.getConnectionInfo()不为null时执行ContextManager.stopSpan();其handleMethodException方法在cacheObject.getConnectionInfo()不为null时执行ContextManager.activeSpan().errorOccurred().log(t)PreparedStatementSetterInstrumentation

skywalking-6.6.0/apm-sniffer/apm-sdk-plugin/mysql-8.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jdbc/mysql/v8/define/PreparedStatementSetterInstrumentation.java

public class PreparedStatementSetterInstrumentation extends PreparedStatementInstrumentation {​    @Override    public final InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {        return new InstanceMethodsInterceptPoint[] {            new PSSetterDefinitionOfJDBCInstrumentation(false)        };    }​}
PreparedStatementSetterInstrumentation继承了PreparedStatementInstrumentation,其getInstanceMethodsInterceptPoints方法返回的是PSSetterDefinitionOfJDBCInstrumentation(false)PSSetterDefinitionOfJDBCInstrumentation

skywalking-6.6.0/apm-sniffer/apm-sdk-plugin/jdbc-commons/src/main/java/org/apache/skywalking/apm/plugin/jdbc/PSSetterDefinitionOfJDBCInstrumentation.java

public class PSSetterDefinitionOfJDBCInstrumentation implements InstanceMethodsInterceptPoint {    private final boolean ignorable;​    public PSSetterDefinitionOfJDBCInstrumentation(boolean ignorable) {        this.ignorable = ignorable;    }​    @Override    public ElementMatcher<MethodDescription> getMethodsMatcher() {        ElementMatcher.Junction<MethodDescription> matcher = none();​        if (Config.Plugin.MySQL.TRACE_SQL_PARAMETERS || Config.Plugin.POSTGRESQL.TRACE_SQL_PARAMETERS) {            final Set<String> setters = ignorable ? PS_IGNORABLE_SETTERS : PS_SETTERS;            for (String setter : setters) {                matcher = matcher.or(named(setter));            }        }​        return matcher;    }​    @Override    public String getMethodsInterceptor() {        return ignorable            ? Constants.PREPARED_STATEMENT_IGNORABLE_SETTER_METHODS_INTERCEPTOR            : Constants.PREPARED_STATEMENT_SETTER_METHODS_INTERCEPTOR;    }​    @Override    public boolean isOverrideArgs() {        return false;    }}
PSSetterDefinitionOfJDBCInstrumentation实现了InstanceMethodsInterceptPoint接口,其getMethodsMatcher方法根据ignorable使用PS_IGNORABLE_SETTERS还是PS_SETTERS去构造matcher以及methodsInterceptorPreparedStatementNullSetterInstrumentation

skywalking-6.6.0/apm-sniffer/apm-sdk-plugin/mysql-8.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jdbc/mysql/v8/define/PreparedStatementNullSetterInstrumentation.java

public class PreparedStatementNullSetterInstrumentation extends PreparedStatementInstrumentation {​    @Override    public final InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {        return new InstanceMethodsInterceptPoint[] {            new JDBCPreparedStatementNullSetterInstanceMethodsInterceptPoint()        };    }​}
PreparedStatementNullSetterInstrumentation继承了PreparedStatementInstrumentation,其getInstanceMethodsInterceptPoints方法返回的是JDBCPreparedStatementNullSetterInstanceMethodsInterceptPointJDBCPreparedStatementNullSetterInstanceMethodsInterceptPoint

skywalking-6.6.0/apm-sniffer/apm-sdk-plugin/jdbc-commons/src/main/java/org/apache/skywalking/apm/plugin/jdbc/JDBCPreparedStatementNullSetterInstanceMethodsInterceptPoint.java

public final class JDBCPreparedStatementNullSetterInstanceMethodsInterceptPoint implements InstanceMethodsInterceptPoint {    @Override    public ElementMatcher<MethodDescription> getMethodsMatcher() {        return named("setNull");    }​    @Override    public String getMethodsInterceptor() {        return Constants.PREPARED_STATEMENT_NULL_SETTER_METHODS_INTERCEPTOR;    }​    @Override    public boolean isOverrideArgs() {        return false;    }}
JDBCPreparedStatementNullSetterInstanceMethodsInterceptPoint实现了InstanceMethodsInterceptPoint接口,它使用org.apache.skywalking.apm.plugin.jdbc.JDBCPreparedStatementNullSetterInterceptor增强setNull方法PreparedStatementIgnoredSetterInstrumentation

skywalking-6.6.0/apm-sniffer/apm-sdk-plugin/mysql-8.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jdbc/mysql/v8/define/PreparedStatementIgnoredSetterInstrumentation.java

public class PreparedStatementIgnoredSetterInstrumentation extends PreparedStatementInstrumentation {​    @Override    public final InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {        return new InstanceMethodsInterceptPoint[] {            new PSSetterDefinitionOfJDBCInstrumentation(true)        };    }​}
PreparedStatementIgnoredSetterInstrumentation继承了PreparedStatementInstrumentation,其getInstanceMethodsInterceptPoints方法返回的是PSSetterDefinitionOfJDBCInstrumentation(true)小结

skywalking的mysql-plugin提供了ConnectionImplCreateInstrumentation、ConnectionInstrumentation、CallableInstrumentation、PreparedStatementInstrumentation、StatementInstrumentation、PreparedStatementSetterInstrumentation、PreparedStatementNullSetterInstrumentation、PreparedStatementIgnoredSetterInstrumentation这几个增强

docConnectionImplCreateInstrumentationConnectionInstrumentationCallableInstrumentationPreparedStatementInstrumentationStatementInstrumentationPreparedStatementSetterInstrumentationPreparedStatementNullSetterInstrumentationPreparedStatementIgnoredSetterInstrumentation

标签: #mysqldynamic