未验证 提交 e471b107 编写于 作者: B Brandon Fergerson 提交者: GitHub

Merge branch 'master' into qualified-spring-mvc-endpoints

......@@ -23,6 +23,9 @@ import org.apache.skywalking.apm.agent.core.context.trace.TraceSegment;
import org.apache.skywalking.apm.agent.core.logging.core.LogLevel;
import org.apache.skywalking.apm.agent.core.logging.core.WriterFactory;
import java.util.HashMap;
import java.util.Map;
/**
* This is the core config in sniffer agent.
*
......@@ -164,6 +167,19 @@ public class Config {
public static boolean TRACE_DSL = false;
}
public static class Customize {
/**
* Custom enhancement class configuration file path, recommended to use an absolute path.
*/
public static String ENHANCE_FILE = "";
/**
* Some information after custom enhancements, this configuration is used by the custom enhancement plugin.
* And using Map CONTEXT for avoiding classloader isolation issue.
*/
public static Map<String, Object> CONTEXT = new HashMap<String, Object>();
}
public static class SpringMVC {
/**
* If true, the fully qualified method name will be used as the endpoint name instead of the request URL, default is false.
......@@ -177,5 +193,4 @@ public class Config {
*/
public static boolean USE_QUALIFIED_NAME_AS_ENDPOINT_NAME = false;
}
}
}
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.skywalking.apm.agent.core.plugin;
import org.apache.skywalking.apm.agent.core.plugin.loader.AgentClassLoader;
import org.apache.skywalking.apm.agent.core.plugin.loader.InstrumentationLoader;
import java.util.ArrayList;
import java.util.List;
import java.util.ServiceLoader;
/**
* The plugin can be inserted into the kernel by implementing this spi return PluginDefine list.
*
* @author zhaoyuguang
*/
public enum DynamicPluginLoader {
INSTANCE;
public List<AbstractClassEnhancePluginDefine> load(AgentClassLoader classLoader) {
List<AbstractClassEnhancePluginDefine> all = new ArrayList<AbstractClassEnhancePluginDefine>();
for (InstrumentationLoader instrumentationLoader : ServiceLoader.load(InstrumentationLoader.class, classLoader)) {
List<AbstractClassEnhancePluginDefine> plugins = instrumentationLoader.load(classLoader);
if (plugins != null && !plugins.isEmpty()) {
all.addAll(plugins);
}
}
return all;
}
}
......@@ -16,7 +16,6 @@
*
*/
package org.apache.skywalking.apm.agent.core.plugin;
import java.net.URL;
......@@ -78,6 +77,8 @@ public class PluginBootstrap {
}
}
plugins.addAll(DynamicPluginLoader.INSTANCE.load(AgentClassLoader.getDefault()));
return plugins;
}
......
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.skywalking.apm.agent.core.plugin.loader;
import org.apache.skywalking.apm.agent.core.plugin.AbstractClassEnhancePluginDefine;
import java.util.List;
/**
* the spi of the InstrumentationLoader.
*
* @author : zhaoyuguang
*/
public interface InstrumentationLoader {
List<AbstractClassEnhancePluginDefine> load(AgentClassLoader classLoader);
}
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.skywalking.apm.agent.core.util;
import java.lang.reflect.Method;
/**
* According to the input parameter,
* return the OperationName for the span record,
* It can determine the unique method
*
* @author zhaoyuguang
*/
public class MethodUtil {
public static String generateOperationName(Method method) {
StringBuilder operationName = new StringBuilder(method.getDeclaringClass().getName() + "." + method.getName() + "(");
Class<?>[] parameterTypes = method.getParameterTypes();
for (int i = 0; i < parameterTypes.length; i++) {
operationName.append(parameterTypes[i].getName());
if (i < (parameterTypes.length - 1)) {
operationName.append(",");
}
}
operationName.append(")");
return operationName.toString();
}
}
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.skywalking.apm.agent.core.util;
import org.junit.Assert;
import org.junit.Test;
import java.lang.reflect.Method;
/**
* @author zhaoyuguang
*/
public class MethodUtilTest {
@Test
public void testClassForName() throws NoSuchMethodException {
Assert.assertTrue(MethodUtil.generateOperationName(MethodUtil.class.getMethod("generateOperationName", Method.class))
.equals("org.apache.skywalking.apm.agent.core.util.MethodUtil.generateOperationName(java.lang.reflect.Method)"));
}
}
......@@ -32,7 +32,7 @@
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<mysql-connector-java.version>5.1.36</mysql-connector-java.version>
<mysql-connector-java.version>5.1.44</mysql-connector-java.version>
</properties>
<dependencies>
......@@ -45,7 +45,7 @@
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>[5.1.22,6.0.6]</version>
<version>${mysql-connector-java.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
......@@ -54,6 +54,12 @@
<version>${project.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.skywalking</groupId>
<artifactId>apm-mysql-commons</artifactId>
<version>${project.version}</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
......
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.skywalking.apm.plugin.jdbc.mysql.v5;
import org.apache.skywalking.apm.plugin.jdbc.trace.ConnectionInfo;
import org.apache.skywalking.apm.util.StringUtil;
import java.util.concurrent.ConcurrentHashMap;
/**
* @author: dingshaocheng
*/
public class ConnectionCache {
private static ConcurrentHashMap<String, ConnectionInfo> CONNECTIONS_MAP = new ConcurrentHashMap<String, ConnectionInfo>();
private static String CONNECTION_SPLIT_STR = ",";
public static ConnectionInfo get(String host, String port) {
final String connStr = String.format("%s:%s", host, port);
return CONNECTIONS_MAP.get(connStr);
}
public static void save(ConnectionInfo connectionInfo) {
for (String conn : connectionInfo.getDatabasePeer().split(CONNECTION_SPLIT_STR)) {
if (!StringUtil.isEmpty(conn)) {
CONNECTIONS_MAP.putIfAbsent(conn, connectionInfo);
}
}
}
}
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.skywalking.apm.plugin.jdbc.mysql.v5;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.StaticMethodsAroundInterceptor;
import org.apache.skywalking.apm.plugin.jdbc.connectionurl.parser.URLParser;
import org.apache.skywalking.apm.plugin.jdbc.trace.ConnectionInfo;
import java.lang.reflect.Method;
/**
* ConnectionImpl#getInstance in mysql-5.x has 5 parameters such as
* getInstance(String hostToConnectTo, int portToConnectTo, Properties info, String databaseToConnectTo, String url)
*
* @author: dingshaocheng
*/
public class ConnectionCreate5xInterceptor 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) {
ConnectionInfo connectionInfo = ConnectionCache.get(allArguments[0].toString(), allArguments[1].toString());
if (connectionInfo == null) {
connectionInfo = URLParser.parser(allArguments[4].toString());
}
((EnhancedInstance) ret).setSkyWalkingDynamicField(connectionInfo);
}
return ret;
}
@Override
public void handleMethodException(Class clazz, Method method, Object[] allArguments, Class<?>[] parameterTypes, Throwable t) {
}
}
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.skywalking.apm.plugin.jdbc.mysql.v5;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
import org.apache.skywalking.apm.plugin.jdbc.connectionurl.parser.URLParser;
import java.lang.reflect.Method;
/**
* @author: dingshaocheng
*/
public class DriverConnectInterceptor implements InstanceMethodsAroundInterceptor {
@Override
public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes, MethodInterceptResult result) throws Throwable {
ConnectionCache.save(URLParser.parser(allArguments[0].toString()));
}
@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) {
}
}
......@@ -17,21 +17,20 @@
*/
package org.apache.skywalking.apm.plugin.jdbc.mysql.define;
package org.apache.skywalking.apm.plugin.jdbc.mysql.v5.define;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.matcher.ElementMatcher;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
import org.apache.skywalking.apm.plugin.jdbc.define.Constants;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
import org.apache.skywalking.apm.plugin.jdbc.define.Constants;
import static net.bytebuddy.matcher.ElementMatchers.named;
import static net.bytebuddy.matcher.ElementMatchers.takesArguments;
/**
* {@link ConnectionInstrumentation} intercepts the following methods that the class which extend
* {@link AbstractConnectionInstrumentation} intercepts the following methods that the class which extend
* com.mysql.jdbc.ConnectionImpl.
*
* 1. Enhance <code>prepareStatement</code> by <code>org.apache.skywalking.apm.plugin.jdbc.define.JDBCPrepareStatementInterceptor</code>
......@@ -41,7 +40,7 @@ import static net.bytebuddy.matcher.ElementMatchers.takesArguments;
*
* @author zhangxin
*/
public abstract class ConnectionInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
public abstract class AbstractConnectionInstrumentation extends AbstractMysqlInstrumentation {
@Override protected ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
return new ConstructorInterceptPoint[0];
......@@ -55,7 +54,7 @@ public abstract class ConnectionInstrumentation extends ClassInstanceMethodsEnha
}
@Override public String getMethodsInterceptor() {
return "org.apache.skywalking.apm.plugin.jdbc.mysql.CreatePreparedStatementInterceptor";
return org.apache.skywalking.apm.plugin.jdbc.mysql.Constants.CREATE_PREPARED_STATEMENT_INTERCEPTOR;
}
@Override public boolean isOverrideArgs() {
......@@ -68,7 +67,7 @@ public abstract class ConnectionInstrumentation extends ClassInstanceMethodsEnha
}
@Override public String getMethodsInterceptor() {
return "org.apache.skywalking.apm.plugin.jdbc.mysql.CreateCallableStatementInterceptor";
return org.apache.skywalking.apm.plugin.jdbc.mysql.Constants.CREATE_CALLABLE_STATEMENT_INTERCEPTOR;
}
@Override public boolean isOverrideArgs() {
......@@ -81,7 +80,7 @@ public abstract class ConnectionInstrumentation extends ClassInstanceMethodsEnha
}
@Override public String getMethodsInterceptor() {
return "org.apache.skywalking.apm.plugin.jdbc.mysql.CreateStatementInterceptor";
return org.apache.skywalking.apm.plugin.jdbc.mysql.Constants.CREATE_STATEMENT_INTERCEPTOR;
}
@Override public boolean isOverrideArgs() {
......@@ -107,7 +106,7 @@ public abstract class ConnectionInstrumentation extends ClassInstanceMethodsEnha
}
@Override public String getMethodsInterceptor() {
return "org.apache.skywalking.apm.plugin.jdbc.mysql.SetCatalogInterceptor";
return org.apache.skywalking.apm.plugin.jdbc.mysql.Constants.SET_CATALOG_INTERCEPTOR;
}
@Override public boolean isOverrideArgs() {
......
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.skywalking.apm.plugin.jdbc.mysql.v5.define;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.StaticMethodsInterceptPoint;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassEnhancePluginDefine;
/**
* @author: dingshaocheng
*/
public abstract class AbstractMysqlInstrumentation extends ClassEnhancePluginDefine {
@Override
protected ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
return null;
}
@Override
protected StaticMethodsInterceptPoint[] getStaticMethodsInterceptPoints() {
return null;
}
@Override
protected InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
return null;
}
@Override
protected String[] witnessClasses() {
return new String[]{Constants.WITNESS_MYSQL_5X_CLASS};
}
}
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.skywalking.apm.plugin.jdbc.mysql.v5.define;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.matcher.ElementMatcher;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
import static net.bytebuddy.matcher.ElementMatchers.named;
import static org.apache.skywalking.apm.agent.core.plugin.match.MultiClassNameMatch.byMultiClassMatch;
/**
* @author: dingshaocheng
*/
public class CacheIpsInstrumentation extends AbstractMysqlInstrumentation {
private static final String ENHANCE_CLASS_NON_REG_REP = "com.mysql.jdbc.NonRegisteringReplicationDriver";
private static final String ENHANCE_CLASS = "com.mysql.jdbc.Driver";
private static final String ENHANCE_CLASS_NON_REG = "com.mysql.jdbc.NonRegisteringDriver";
private static final String METHOD_INTERCEPTOR_CLASS = "org.apache.skywalking.apm.plugin.jdbc.mysql.v5.DriverConnectInterceptor";
@Override
protected ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
return new ConstructorInterceptPoint[0];
}
@Override
protected InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
return new InstanceMethodsInterceptPoint[] {
new InstanceMethodsInterceptPoint() {
@Override
public ElementMatcher<MethodDescription> getMethodsMatcher() {
return named("connect");
}
@Override
public String getMethodsInterceptor() {
return METHOD_INTERCEPTOR_CLASS;
}
@Override
public boolean isOverrideArgs() {
return false;
}
}
};
}
@Override
protected ClassMatch enhanceClass() {
return byMultiClassMatch(ENHANCE_CLASS,ENHANCE_CLASS_NON_REG,ENHANCE_CLASS_NON_REG_REP);
}
}
......@@ -17,17 +17,16 @@
*/
package org.apache.skywalking.apm.plugin.jdbc.mysql.define;
package org.apache.skywalking.apm.plugin.jdbc.mysql.v5.define;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.matcher.ElementMatcher;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
import static net.bytebuddy.matcher.ElementMatchers.named;
import static org.apache.skywalking.apm.agent.core.plugin.match.MultiClassNameMatch.byMultiClassMatch;
import static org.apache.skywalking.apm.agent.core.plugin.match.NameMatch.byName;
/**
* {@link CallableInstrumentation} define that the mysql-2.x plugin intercepts the following methods in the
......@@ -38,9 +37,9 @@ import static org.apache.skywalking.apm.agent.core.plugin.match.MultiClassNameMa
*
* @author zhangxin
*/
public class CallableInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
public class CallableInstrumentation extends AbstractMysqlInstrumentation {
private static final String ENHANCE_CLASS = "com.mysql.jdbc.CallableStatement";
private static final String SERVICE_METHOD_INTERCEPTOR = "org.apache.skywalking.apm.plugin.jdbc.mysql.PreparedStatementExecuteMethodsInterceptor";
private static final String SERVICE_METHOD_INTERCEPTOR = org.apache.skywalking.apm.plugin.jdbc.mysql.Constants.PREPARED_STATEMENT_EXECUTE_METHODS_INTERCEPTOR;
@Override protected ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
return new ConstructorInterceptPoint[0];
......@@ -67,6 +66,7 @@ public class CallableInstrumentation extends ClassInstanceMethodsEnhancePluginDe
}
@Override protected ClassMatch enhanceClass() {
return byMultiClassMatch(ENHANCE_CLASS, "com.mysql.jdbc.cj.CallableStatement");
return byName(ENHANCE_CLASS);
}
}
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.skywalking.apm.plugin.jdbc.mysql.v5.define;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.matcher.ElementMatcher;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.StaticMethodsInterceptPoint;
import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
import static net.bytebuddy.matcher.ElementMatchers.named;
import static org.apache.skywalking.apm.agent.core.plugin.match.NameMatch.byName;
public class ConnectionImplCreateInstrumentation extends AbstractMysqlInstrumentation {
private static final String JDBC_ENHANCE_CLASS = "com.mysql.jdbc.ConnectionImpl";
private static final String CONNECT_METHOD = "getInstance";
@Override
protected 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.v5.ConnectionCreate5xInterceptor";
}
@Override
public boolean isOverrideArgs() {
return false;
}
}
};
}
@Override
protected ClassMatch enhanceClass() {
return byName(JDBC_ENHANCE_CLASS);
}
}
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.skywalking.apm.plugin.jdbc.mysql.v5.define;
/**
*
* @author: dingshaocheng
*/
public class Constants {
public static final String WITNESS_MYSQL_5X_CLASS = "com.mysql.jdbc.ConnectionImpl";
}
......@@ -17,7 +17,7 @@
*/
package org.apache.skywalking.apm.plugin.jdbc.mysql.define;
package org.apache.skywalking.apm.plugin.jdbc.mysql.v5.define;
import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
......@@ -29,7 +29,7 @@ import static org.apache.skywalking.apm.agent.core.plugin.match.NameMatch.byName
*
* @author zhangxin
*/
public class Mysql50ConnectionInstrumentation extends ConnectionInstrumentation {
public class Mysql50ConnectionInstrumentation extends AbstractConnectionInstrumentation {
@Override
protected ClassMatch enhanceClass() {
return byName("com.mysql.jdbc.Connection");
......
......@@ -17,24 +17,23 @@
*/
package org.apache.skywalking.apm.plugin.jdbc.mysql.define;
package org.apache.skywalking.apm.plugin.jdbc.mysql.v5.define;
import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
import static org.apache.skywalking.apm.agent.core.plugin.match.MultiClassNameMatch.byMultiClassMatch;
import static org.apache.skywalking.apm.agent.core.plugin.match.NameMatch.byName;
/**
* {@link Mysql5xConnectionInstrumentation } interceptor {@link com.mysql.cj.jdbc.ConnectionImpl} and
* {@link Mysql5xConnectionInstrumentation } interceptor {@link com.mysql.jdbc.ConnectionImpl} and
* com.mysql.jdbc.ConnectionImpl in mysql jdbc driver 5.1 and 5.1+
*
* @author zhangxin
*/
public class Mysql5xConnectionInstrumentation extends ConnectionInstrumentation {
public class Mysql5xConnectionInstrumentation extends AbstractConnectionInstrumentation {
public static final String ENHANCE_CLASS = "com.mysql.jdbc.ConnectionImpl";
public static final String CJ_JDBC_ENHANCE_CLASS = "com.mysql.cj.jdbc.ConnectionImpl";
@Override protected ClassMatch enhanceClass() {
return byMultiClassMatch(ENHANCE_CLASS, CJ_JDBC_ENHANCE_CLASS);
return byName(ENHANCE_CLASS);
}
}
......@@ -17,14 +17,14 @@
*/
package org.apache.skywalking.apm.plugin.jdbc.mysql.define;
package org.apache.skywalking.apm.plugin.jdbc.mysql.v5.define;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.matcher.ElementMatcher;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
import org.apache.skywalking.apm.plugin.jdbc.mysql.Constants;
import static net.bytebuddy.matcher.ElementMatchers.named;
import static org.apache.skywalking.apm.agent.core.plugin.match.MultiClassNameMatch.byMultiClassMatch;
......@@ -41,11 +41,10 @@ import static org.apache.skywalking.apm.agent.core.plugin.match.MultiClassNameMa
*
* @author zhangxin
*/
public class PreparedStatementInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
public class PreparedStatementInstrumentation extends AbstractMysqlInstrumentation {
private static final String PREPARED_STATEMENT_CLASS_NAME = "com.mysql.jdbc.PreparedStatement";
private static final String SERVICE_METHOD_INTERCEPTOR = "org.apache.skywalking.apm.plugin.jdbc.mysql.PreparedStatementExecuteMethodsInterceptor";
public static final String MYSQL6_PREPARED_STATEMENT_CLASS_NAME = "com.mysql.cj.jdbc.PreparedStatement";
private static final String SERVICE_METHOD_INTERCEPTOR = Constants.PREPARED_STATEMENT_EXECUTE_METHODS_INTERCEPTOR;
public static final String MYSQL_PREPARED_STATEMENT_CLASS_NAME = "com.mysql.jdbc.PreparedStatement";
public static final String JDBC42_PREPARED_STATEMENT_CLASS_NAME = "com.mysql.jdbc.JDBC42PreparedStatement";
@Override protected final ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
......@@ -74,6 +73,7 @@ public class PreparedStatementInstrumentation extends ClassInstanceMethodsEnhanc
}
@Override protected ClassMatch enhanceClass() {
return byMultiClassMatch(PREPARED_STATEMENT_CLASS_NAME, MYSQL6_PREPARED_STATEMENT_CLASS_NAME, JDBC42_PREPARED_STATEMENT_CLASS_NAME);
return byMultiClassMatch(MYSQL_PREPARED_STATEMENT_CLASS_NAME,JDBC42_PREPARED_STATEMENT_CLASS_NAME);
}
}
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.skywalking.apm.plugin.jdbc.mysql.v5.define;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.matcher.ElementMatcher;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
import static net.bytebuddy.matcher.ElementMatchers.named;
import static org.apache.skywalking.apm.agent.core.plugin.match.NameMatch.byName;
/**
* {@link StatementInstrumentation} intercepts the following methods in the
* com.mysql.jdbc.StatementImpl and com.mysql.cj.jdbc.StatementImpl class.
* 1. execute
* 2. executeQuery
* 3. executeUpdate
* 4. executeLargeUpdate
* 5. addBatch
* 6. executeBatchInternal
* 7. executeUpdateInternal
* 8. executeQuery
* 9. executeBatch
*
* @author zhangxin
*/
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 MYSQL_STATEMENT_CLASS_NAME = "com.mysql.jdbc.StatementImpl";
@Override protected ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
return new ConstructorInterceptPoint[0];
}
@Override protected 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(MYSQL_STATEMENT_CLASS_NAME);
}
}
......@@ -14,12 +14,10 @@
# See the License for the specific language governing permissions and
# limitations under the License.
mysql-5.x=org.apache.skywalking.apm.plugin.jdbc.mysql.define.DriverInstrumentation
mysql-5.x=org.apache.skywalking.apm.plugin.jdbc.mysql.define.Mysql5xConnectionInstrumentation
mysql-5.x=org.apache.skywalking.apm.plugin.jdbc.mysql.define.Mysql50ConnectionInstrumentation
mysql-5.x=org.apache.skywalking.apm.plugin.jdbc.mysql.define.CallableInstrumentation
mysql-5.x=org.apache.skywalking.apm.plugin.jdbc.mysql.define.PreparedStatementInstrumentation
mysql-5.x=org.apache.skywalking.apm.plugin.jdbc.mysql.define.StatementInstrumentation
mysql-5.x=org.apache.skywalking.apm.plugin.jdbc.mysql.define.FailoverConnectionProxyInstrumentation
mysql-5.x=org.apache.skywalking.apm.plugin.jdbc.mysql.define.LoadBalancedConnectionProxyInstrumentation
mysql-5.x=org.apache.skywalking.apm.plugin.jdbc.mysql.define.ReplicationConnectionProxyInstrumentation
mysql-5.x=org.apache.skywalking.apm.plugin.jdbc.mysql.v5.define.Mysql5xConnectionInstrumentation
mysql-5.x=org.apache.skywalking.apm.plugin.jdbc.mysql.v5.define.Mysql50ConnectionInstrumentation
mysql-5.x=org.apache.skywalking.apm.plugin.jdbc.mysql.v5.define.CallableInstrumentation
mysql-5.x=org.apache.skywalking.apm.plugin.jdbc.mysql.v5.define.PreparedStatementInstrumentation
mysql-5.x=org.apache.skywalking.apm.plugin.jdbc.mysql.v5.define.StatementInstrumentation
mysql-5.x=org.apache.skywalking.apm.plugin.jdbc.mysql.v5.define.CacheIpsInstrumentation
mysql-5.x=org.apache.skywalking.apm.plugin.jdbc.mysql.v5.define.ConnectionImplCreateInstrumentation
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.skywalking.apm.plugin.jdbc.mysql.v5;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Matchers;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import static org.mockito.Mockito.verify;
import static org.mockito.internal.verification.VerificationModeFactory.times;
/**
*
* @author: dingshaocheng
*/
@RunWith(MockitoJUnitRunner.class)
public class ConnectionImplCreateInterceptorTest {
private ConnectionCreate5xInterceptor interceptor;
@Mock
private EnhancedInstance objectInstance;
@Before
public void setUp() {
interceptor = new ConnectionCreate5xInterceptor();
}
@Test
public void testResultIsEnhanceInstance() throws Throwable {
interceptor.afterMethod(null,null,new Object[]{"localhost",3360,null,"test","jdbc:mysql:replication://localhost:3360,localhost:3360,localhost:3360/test?useUnicode=true&characterEncoding=utf8&useSSL=false&roundRobinLoadBalance=true"},null,objectInstance);
verify(objectInstance,times(1)).setSkyWalkingDynamicField(Matchers.any());
}
}
\ No newline at end of file
<!--
~ Licensed to the Apache Software Foundation (ASF) under one or more
~ contributor license agreements. See the NOTICE file distributed with
~ this work for additional information regarding copyright ownership.
~ The ASF licenses this file to You under the Apache License, Version 2.0
~ (the "License"); you may not use this file except in compliance with
~ the License. You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
~
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>apm-sdk-plugin</artifactId>
<groupId>org.apache.skywalking</groupId>
<version>6.1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>apm-mysql-6.x-plugin</artifactId>
<packaging>jar</packaging>
<name>mysql-6.x-plugin</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<mysql-connector-java.version>6.0.6</mysql-connector-java.version>
</properties>
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql-connector-java.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql-connector-java.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.skywalking</groupId>
<artifactId>apm-jdbc-commons</artifactId>
<version>${project.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.skywalking</groupId>
<artifactId>apm-mysql-commons</artifactId>
<version>${project.version}</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
......@@ -15,7 +15,7 @@
* limitations under the License.
*/
package org.apache.skywalking.apm.plugin.jdbc.mysql;
package org.apache.skywalking.apm.plugin.jdbc.mysql.v6;
import com.mysql.cj.api.jdbc.JdbcConnection;
import com.mysql.cj.core.conf.url.ConnectionUrl;
......@@ -24,7 +24,7 @@ import java.lang.reflect.Method;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.StaticMethodsAroundInterceptor;
import org.apache.skywalking.apm.network.trace.component.ComponentsDefine;
import org.apache.skywalking.apm.plugin.jdbc.mysql.wrapper.JdbcConnectionWrapper;
import org.apache.skywalking.apm.plugin.jdbc.mysql.v6.wrapper.JdbcConnectionWrapper;
import org.apache.skywalking.apm.plugin.jdbc.trace.ConnectionInfo;
public class CreateJdbcConnectionProxyInstanceInterceptor implements StaticMethodsAroundInterceptor {
......
......@@ -15,7 +15,7 @@
* limitations under the License.
*/
package org.apache.skywalking.apm.plugin.jdbc.mysql;
package org.apache.skywalking.apm.plugin.jdbc.mysql.v6;
import com.mysql.cj.api.jdbc.ha.LoadBalancedConnection;
import com.mysql.cj.core.conf.url.ConnectionUrl;
......@@ -24,7 +24,7 @@ import java.lang.reflect.Method;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.StaticMethodsAroundInterceptor;
import org.apache.skywalking.apm.network.trace.component.ComponentsDefine;
import org.apache.skywalking.apm.plugin.jdbc.mysql.wrapper.LoadBalancedConnectionWrapper;
import org.apache.skywalking.apm.plugin.jdbc.mysql.v6.wrapper.LoadBalancedConnectionWrapper;
import org.apache.skywalking.apm.plugin.jdbc.trace.ConnectionInfo;
public class CreateLoadBalancedConnectionProxyInstanceInterceptor implements StaticMethodsAroundInterceptor {
......
......@@ -15,7 +15,7 @@
* limitations under the License.
*/
package org.apache.skywalking.apm.plugin.jdbc.mysql;
package org.apache.skywalking.apm.plugin.jdbc.mysql.v6;
import com.mysql.cj.api.jdbc.ha.ReplicationConnection;
import com.mysql.cj.core.conf.url.ConnectionUrl;
......@@ -24,7 +24,7 @@ import java.lang.reflect.Method;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.StaticMethodsAroundInterceptor;
import org.apache.skywalking.apm.network.trace.component.ComponentsDefine;
import org.apache.skywalking.apm.plugin.jdbc.mysql.wrapper.ReplicationConnectionWrapper;
import org.apache.skywalking.apm.plugin.jdbc.mysql.v6.wrapper.ReplicationConnectionWrapper;
import org.apache.skywalking.apm.plugin.jdbc.trace.ConnectionInfo;
public class CreateReplicationConnectionProxyInstanceInterceptor implements StaticMethodsAroundInterceptor {
......
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.skywalking.apm.plugin.jdbc.mysql.v6.define;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.StaticMethodsInterceptPoint;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassEnhancePluginDefine;
/**
* @author: dingshaocheng
*/
public abstract class AbstractMysqlInstrumentation extends ClassEnhancePluginDefine {
@Override
protected ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
return null;
}
@Override
protected StaticMethodsInterceptPoint[] getStaticMethodsInterceptPoints() {
return null;
}
@Override
protected InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
return null;
}
@Override
protected String[] witnessClasses() {
return new String[]{Constants.WITNESS_MYSQL_6X_CLASS};
}
}
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.skywalking.apm.plugin.jdbc.mysql.v6.define;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.matcher.ElementMatcher;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
import static net.bytebuddy.matcher.ElementMatchers.named;
import static org.apache.skywalking.apm.agent.core.plugin.match.NameMatch.byName;
/**
* {@link CallableInstrumentation} define that the mysql-2.x plugin intercepts the following methods in the
* com.mysql.jdbc.CallableStatement
* 1. execute
* 2. executeQuery
* 3. executeUpdate
*
* @author zhangxin
*/
public class CallableInstrumentation extends AbstractMysqlInstrumentation {
private static final String ENHANCE_CLASS = "com.mysql.jdbc.cj.CallableStatement";
private static final String SERVICE_METHOD_INTERCEPTOR = org.apache.skywalking.apm.plugin.jdbc.mysql.Constants.PREPARED_STATEMENT_EXECUTE_METHODS_INTERCEPTOR;
@Override protected ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
return new ConstructorInterceptPoint[0];
}
@Override protected 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);
}
}
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.skywalking.apm.plugin.jdbc.mysql.v6.define;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.matcher.ElementMatcher;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
import static net.bytebuddy.matcher.ElementMatchers.named;
import static net.bytebuddy.matcher.ElementMatchers.takesArguments;
import static org.apache.skywalking.apm.agent.core.plugin.match.NameMatch.byName;
public class ConnectionInstrumentation extends AbstractMysqlInstrumentation {
public static final String ENHANCE_CLASS = "com.mysql.cj.jdbc.ConnectionImpl";
@Override protected ClassMatch enhanceClass() {
return byName(ENHANCE_CLASS);
}
@Override protected ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
return new ConstructorInterceptPoint[0];
}
@Override protected InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
return new InstanceMethodsInterceptPoint[] {
new InstanceMethodsInterceptPoint() {
@Override public ElementMatcher<MethodDescription> getMethodsMatcher() {
return named(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;
}
}
};
}
}
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.skywalking.apm.plugin.jdbc.mysql.v6.define;
/**
*
* @author: dingshaocheng
*/
public class Constants {
public static final String WITNESS_MYSQL_6X_CLASS = "com.mysql.cj.api.MysqlConnection";
}
......@@ -17,7 +17,7 @@
*/
package org.apache.skywalking.apm.plugin.jdbc.mysql.define;
package org.apache.skywalking.apm.plugin.jdbc.mysql.v6.define;
import org.apache.skywalking.apm.plugin.jdbc.define.AbstractDriverInstrumentation;
import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
......@@ -34,4 +34,9 @@ public class DriverInstrumentation extends AbstractDriverInstrumentation {
protected ClassMatch enhanceClass() {
return byMultiClassMatch("com.mysql.jdbc.Driver", "com.mysql.cj.jdbc.Driver", "com.mysql.jdbc.NonRegisteringDriver");
}
@Override
protected String[] witnessClasses() {
return new String[] {Constants.WITNESS_MYSQL_6X_CLASS};
}
}
......@@ -15,20 +15,19 @@
* limitations under the License.
*/
package org.apache.skywalking.apm.plugin.jdbc.mysql.define;
package org.apache.skywalking.apm.plugin.jdbc.mysql.v6.define;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.matcher.ElementMatcher;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.StaticMethodsInterceptPoint;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassStaticMethodsEnhancePluginDefine;
import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
import static net.bytebuddy.matcher.ElementMatchers.named;
import static org.apache.skywalking.apm.agent.core.plugin.match.NameMatch.byName;
public class FailoverConnectionProxyInstrumentation extends ClassStaticMethodsEnhancePluginDefine {
public class FailoverConnectionProxyInstrumentation extends AbstractMysqlInstrumentation {
public static final String METHOD_INTERCEPTOR = "org.apache.skywalking.apm.plugin.jdbc.mysql.CreateJdbcConnectionProxyInstanceInterceptor";
public static final String METHOD_INTERCEPTOR = "org.apache.skywalking.apm.plugin.jdbc.mysql.v6.CreateJdbcConnectionProxyInstanceInterceptor";
public static final String INTERCEPT_CLASS = "com.mysql.cj.jdbc.ha.FailoverConnectionProxy";
@Override
......@@ -54,4 +53,5 @@ public class FailoverConnectionProxyInstrumentation extends ClassStaticMethodsEn
protected ClassMatch enhanceClass() {
return byName(INTERCEPT_CLASS);
}
}
......@@ -15,20 +15,19 @@
* limitations under the License.
*/
package org.apache.skywalking.apm.plugin.jdbc.mysql.define;
package org.apache.skywalking.apm.plugin.jdbc.mysql.v6.define;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.matcher.ElementMatcher;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.StaticMethodsInterceptPoint;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassStaticMethodsEnhancePluginDefine;
import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
import static net.bytebuddy.matcher.ElementMatchers.named;
import static org.apache.skywalking.apm.agent.core.plugin.match.NameMatch.byName;
public class LoadBalancedConnectionProxyInstrumentation extends ClassStaticMethodsEnhancePluginDefine {
public class LoadBalancedConnectionProxyInstrumentation extends AbstractMysqlInstrumentation {
public static final String METHOD_INTERCEPTOR = "org.apache.skywalking.apm.plugin.jdbc.mysql.CreateLoadBalancedConnectionProxyInstanceInterceptor";
public static final String METHOD_INTERCEPTOR = "org.apache.skywalking.apm.plugin.jdbc.mysql.v6.CreateLoadBalancedConnectionProxyInstanceInterceptor";
public static final String INTERCEPT_CLASS = "com.mysql.cj.jdbc.ha.LoadBalancedConnectionProxy";
@Override protected StaticMethodsInterceptPoint[] getStaticMethodsInterceptPoints() {
......@@ -52,4 +51,5 @@ public class LoadBalancedConnectionProxyInstrumentation extends ClassStaticMetho
@Override protected ClassMatch enhanceClass() {
return byName(INTERCEPT_CLASS);
}
}
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.skywalking.apm.plugin.jdbc.mysql.v6.define;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.matcher.ElementMatcher;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
import static net.bytebuddy.matcher.ElementMatchers.named;
import static org.apache.skywalking.apm.agent.core.plugin.match.NameMatch.byName;
/**
* {@link PreparedStatementInstrumentation} define that the mysql-2.x plugin intercepts the following methods in the
* com.mysql.jdbc.JDBC42PreparedStatement, com.mysql.jdbc.PreparedStatement and
* com.mysql.cj.jdbc.PreparedStatement class:
* 1. execute
* 2. executeQuery
* 3. executeUpdate
* 4. executeLargeUpdate
* 5. addBatch
*
* @author zhangxin
*/
public class PreparedStatementInstrumentation extends AbstractMysqlInstrumentation {
private static final String SERVICE_METHOD_INTERCEPTOR = org.apache.skywalking.apm.plugin.jdbc.mysql.Constants.PREPARED_STATEMENT_EXECUTE_METHODS_INTERCEPTOR;
public static final String MYSQL6_PREPARED_STATEMENT_CLASS_NAME = "com.mysql.cj.jdbc.PreparedStatement";
@Override protected final ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
return new ConstructorInterceptPoint[0];
}
@Override protected final 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 byName(MYSQL6_PREPARED_STATEMENT_CLASS_NAME);
}
}
......@@ -15,20 +15,19 @@
* limitations under the License.
*/
package org.apache.skywalking.apm.plugin.jdbc.mysql.define;
package org.apache.skywalking.apm.plugin.jdbc.mysql.v6.define;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.matcher.ElementMatcher;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.StaticMethodsInterceptPoint;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassStaticMethodsEnhancePluginDefine;
import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
import static net.bytebuddy.matcher.ElementMatchers.named;
import static org.apache.skywalking.apm.agent.core.plugin.match.NameMatch.byName;
public class ReplicationConnectionProxyInstrumentation extends ClassStaticMethodsEnhancePluginDefine {
public class ReplicationConnectionProxyInstrumentation extends AbstractMysqlInstrumentation {
public static final String METHOD_INTERCEPTOR = "org.apache.skywalking.apm.plugin.jdbc.mysql.CreateReplicationConnectionProxyInstanceInterceptor";
public static final String METHOD_INTERCEPTOR = "org.apache.skywalking.apm.plugin.jdbc.mysql.v6.CreateReplicationConnectionProxyInstanceInterceptor";
public static final String INTERCEPT_CLASS = "com.mysql.cj.jdbc.ha.ReplicationConnectionProxy";
@Override protected StaticMethodsInterceptPoint[] getStaticMethodsInterceptPoints() {
......
......@@ -17,17 +17,16 @@
*/
package org.apache.skywalking.apm.plugin.jdbc.mysql.define;
package org.apache.skywalking.apm.plugin.jdbc.mysql.v6.define;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.matcher.ElementMatcher;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
import static net.bytebuddy.matcher.ElementMatchers.named;
import static org.apache.skywalking.apm.agent.core.plugin.match.MultiClassNameMatch.byMultiClassMatch;
import static org.apache.skywalking.apm.agent.core.plugin.match.NameMatch.byName;
/**
* {@link StatementInstrumentation} intercepts the following methods in the
......@@ -44,9 +43,8 @@ import static org.apache.skywalking.apm.agent.core.plugin.match.MultiClassNameMa
*
* @author zhangxin
*/
public class StatementInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
private static final String STATEMENT_CLASS_NAME = "com.mysql.jdbc.StatementImpl";
private static final String SERVICE_METHOD_INTERCEPTOR = "org.apache.skywalking.apm.plugin.jdbc.mysql.StatementExecuteMethodsInterceptor";
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 MYSQL6_STATEMENT_CLASS_NAME = "com.mysql.cj.jdbc.StatementImpl";
@Override protected ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
......@@ -79,6 +77,7 @@ public class StatementInstrumentation extends ClassInstanceMethodsEnhancePluginD
}
@Override protected ClassMatch enhanceClass() {
return byMultiClassMatch(STATEMENT_CLASS_NAME, MYSQL6_STATEMENT_CLASS_NAME);
return byName(MYSQL6_STATEMENT_CLASS_NAME);
}
}
......@@ -15,7 +15,7 @@
* limitations under the License.
*/
package org.apache.skywalking.apm.plugin.jdbc.mysql.wrapper;
package org.apache.skywalking.apm.plugin.jdbc.mysql.v6.wrapper;
import java.io.InputStream;
import java.io.Reader;
......
......@@ -15,7 +15,7 @@
* limitations under the License.
*/
package org.apache.skywalking.apm.plugin.jdbc.mysql.wrapper;
package org.apache.skywalking.apm.plugin.jdbc.mysql.v6.wrapper;
import com.mysql.cj.api.exceptions.ExceptionInterceptor;
import com.mysql.cj.api.jdbc.ClientInfoProvider;
......
......@@ -15,7 +15,7 @@
* limitations under the License.
*/
package org.apache.skywalking.apm.plugin.jdbc.mysql.wrapper;
package org.apache.skywalking.apm.plugin.jdbc.mysql.v6.wrapper;
import com.mysql.cj.api.jdbc.ha.LoadBalancedConnection;
import java.sql.SQLException;
......
......@@ -15,7 +15,7 @@
* limitations under the License.
*/
package org.apache.skywalking.apm.plugin.jdbc.mysql.wrapper;
package org.apache.skywalking.apm.plugin.jdbc.mysql.v6.wrapper;
import java.io.InputStream;
import java.io.Reader;
......
......@@ -15,7 +15,7 @@
* limitations under the License.
*/
package org.apache.skywalking.apm.plugin.jdbc.mysql.wrapper;
package org.apache.skywalking.apm.plugin.jdbc.mysql.v6.wrapper;
import com.mysql.cj.api.jdbc.JdbcConnection;
import com.mysql.cj.api.jdbc.ha.ReplicationConnection;
......
......@@ -15,7 +15,7 @@
* limitations under the License.
*/
package org.apache.skywalking.apm.plugin.jdbc.mysql.wrapper;
package org.apache.skywalking.apm.plugin.jdbc.mysql.v6.wrapper;
import java.sql.Connection;
import java.sql.ResultSet;
......
......@@ -15,7 +15,7 @@
* limitations under the License.
*/
package org.apache.skywalking.apm.plugin.jdbc.mysql.wrapper;
package org.apache.skywalking.apm.plugin.jdbc.mysql.v6.wrapper;
import java.sql.SQLException;
import org.apache.skywalking.apm.agent.core.context.ContextManager;
......
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
mysql-6.x=org.apache.skywalking.apm.plugin.jdbc.mysql.v6.define.DriverInstrumentation
mysql-6.x=org.apache.skywalking.apm.plugin.jdbc.mysql.v6.define.ConnectionInstrumentation
mysql-6.x=org.apache.skywalking.apm.plugin.jdbc.mysql.v6.define.CallableInstrumentation
mysql-6.x=org.apache.skywalking.apm.plugin.jdbc.mysql.v6.define.PreparedStatementInstrumentation
mysql-6.x=org.apache.skywalking.apm.plugin.jdbc.mysql.v6.define.StatementInstrumentation
mysql-6.x=org.apache.skywalking.apm.plugin.jdbc.mysql.v6.define.FailoverConnectionProxyInstrumentation
mysql-6.x=org.apache.skywalking.apm.plugin.jdbc.mysql.v6.define.LoadBalancedConnectionProxyInstrumentation
mysql-6.x=org.apache.skywalking.apm.plugin.jdbc.mysql.v6.define.ReplicationConnectionProxyInstrumentation
<!--
~ Licensed to the Apache Software Foundation (ASF) under one or more
~ contributor license agreements. See the NOTICE file distributed with
~ this work for additional information regarding copyright ownership.
~ The ASF licenses this file to You under the Apache License, Version 2.0
~ (the "License"); you may not use this file except in compliance with
~ the License. You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
~
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>apm-sdk-plugin</artifactId>
<groupId>org.apache.skywalking</groupId>
<version>6.1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>apm-mysql-8.x-plugin</artifactId>
<packaging>jar</packaging>
<name>mysql-8.x-plugin</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<mysql-connector-java.version>8.0.13</mysql-connector-java.version>
</properties>
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql-connector-java.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql-connector-java.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.skywalking</groupId>
<artifactId>apm-jdbc-commons</artifactId>
<version>${project.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.skywalking</groupId>
<artifactId>apm-mysql-commons</artifactId>
<version>${project.version}</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.skywalking.apm.plugin.jdbc.mysql.v8;
import com.mysql.cj.conf.HostInfo;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.StaticMethodsAroundInterceptor;
import org.apache.skywalking.apm.plugin.jdbc.connectionurl.parser.URLParser;
import org.apache.skywalking.apm.plugin.jdbc.trace.ConnectionInfo;
import java.lang.reflect.Method;
/**
* @author: dingshaocheng
*/
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) {
}
}
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.skywalking.apm.plugin.jdbc.mysql.v8.define;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.StaticMethodsInterceptPoint;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassEnhancePluginDefine;
/**
* @author: dingshaocheng
*/
public abstract class AbstractMysqlInstrumentation extends ClassEnhancePluginDefine {
@Override
protected ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
return null;
}
@Override
protected StaticMethodsInterceptPoint[] getStaticMethodsInterceptPoints() {
return null;
}
@Override
protected InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
return null;
}
@Override
protected String[] witnessClasses() {
return new String[]{Constants.WITNESS_MYSQL_8X_CLASS};
}
}
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.skywalking.apm.plugin.jdbc.mysql.v8.define;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.matcher.ElementMatcher;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
import static net.bytebuddy.matcher.ElementMatchers.named;
import static org.apache.skywalking.apm.agent.core.plugin.match.NameMatch.byName;
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 protected ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
return new ConstructorInterceptPoint[0];
}
@Override protected 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);
}
}
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.skywalking.apm.plugin.jdbc.mysql.v8.define;
import com.mysql.cj.conf.HostInfo;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.matcher.ElementMatcher;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.StaticMethodsInterceptPoint;
import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
import java.util.Properties;
import static net.bytebuddy.matcher.ElementMatchers.named;
import static org.apache.skywalking.apm.agent.core.plugin.match.NameMatch.byName;
/**
* interceptor the method {@link com.mysql.cj.jdbc.ConnectionImpl#getInstance(HostInfo)}
* instead of {@link com.mysql.cj.jdbc.Driver#connect(String, Properties)}
* @author: dingshaocheng
*/
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
protected 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);
}
}
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.skywalking.apm.plugin.jdbc.mysql.v8.define;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.matcher.ElementMatcher;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
import static net.bytebuddy.matcher.ElementMatchers.named;
import static net.bytebuddy.matcher.ElementMatchers.takesArguments;
import static org.apache.skywalking.apm.agent.core.plugin.match.NameMatch.byName;
public class ConnectionInstrumentation extends AbstractMysqlInstrumentation {
@Override protected ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
return new ConstructorInterceptPoint[0];
}
@Override protected 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");
}
}
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.skywalking.apm.plugin.jdbc.mysql.v8.define;
public class Constants {
public static final String WITNESS_MYSQL_8X_CLASS = "com.mysql.cj.interceptors.QueryInterceptor";
}
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.skywalking.apm.plugin.jdbc.mysql.v8.define;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.matcher.ElementMatcher;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
import org.apache.skywalking.apm.plugin.jdbc.mysql.Constants;
import static net.bytebuddy.matcher.ElementMatchers.named;
import static org.apache.skywalking.apm.agent.core.plugin.match.MultiClassNameMatch.byMultiClassMatch;
public class PreparedStatementInstrumentation extends AbstractMysqlInstrumentation {
private static final String PREPARED_STATEMENT_CLASS_NAME = "com.mysql.cj.jdbc.ClientPreparedStatement";
private static final String PREPARED_STATEMENT_SERVERSIDE_CLASS_NAME = "com.mysql.cj.jdbc.ServerPreparedStatement";
private static final String SERVICE_METHOD_INTERCEPTOR = Constants.PREPARED_STATEMENT_EXECUTE_METHODS_INTERCEPTOR;
@Override protected final ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
return new ConstructorInterceptPoint[0];
}
@Override protected final 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_SERVERSIDE_CLASS_NAME);
}
}
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.skywalking.apm.plugin.jdbc.mysql.v8.define;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.matcher.ElementMatcher;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
import static net.bytebuddy.matcher.ElementMatchers.named;
import static org.apache.skywalking.apm.agent.core.plugin.match.NameMatch.byName;
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 protected ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
return new ConstructorInterceptPoint[0];
}
@Override protected 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);
}
}
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
mysql-8.x=org.apache.skywalking.apm.plugin.jdbc.mysql.v8.define.ConnectionImplCreateInstrumentation
mysql-8.x=org.apache.skywalking.apm.plugin.jdbc.mysql.v8.define.ConnectionInstrumentation
mysql-8.x=org.apache.skywalking.apm.plugin.jdbc.mysql.v8.define.CallableInstrumentation
mysql-8.x=org.apache.skywalking.apm.plugin.jdbc.mysql.v8.define.PreparedStatementInstrumentation
mysql-8.x=org.apache.skywalking.apm.plugin.jdbc.mysql.v8.define.StatementInstrumentation
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.skywalking.apm.plugin.jdbc.mysql.v8;
import com.mysql.cj.conf.ConnectionUrlParser;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Matchers;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import static org.mockito.Mockito.verify;
import static org.mockito.internal.verification.VerificationModeFactory.times;
/**
*
* @author: dingshaocheng
*/
@RunWith(MockitoJUnitRunner.class)
public class ConnectionImplCreateInterceptorTest {
private ConnectionCreateInterceptor interceptor;
@Mock
private EnhancedInstance objectInstance;
@Before
public void setUp() {
interceptor = new ConnectionCreateInterceptor();
}
@Test
public void testResultIsEnhanceInstance() throws Throwable {
final ConnectionUrlParser connectionUrlParser = ConnectionUrlParser.parseConnectionString("jdbc:mysql:replication://localhost:3360,localhost:3360,localhost:3360/test?useUnicode=true&characterEncoding=utf8&useSSL=false&roundRobinLoadBalance=true");
interceptor.afterMethod(null,null,connectionUrlParser.getHosts().toArray(),null,objectInstance);
verify(objectInstance,times(1)).setSkyWalkingDynamicField(Matchers.any());
}
}
\ No newline at end of file
<!--
~ Licensed to the Apache Software Foundation (ASF) under one or more
~ contributor license agreements. See the NOTICE file distributed with
~ this work for additional information regarding copyright ownership.
~ The ASF licenses this file to You under the Apache License, Version 2.0
~ (the "License"); you may not use this file except in compliance with
~ the License. You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
~
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>apm-sdk-plugin</artifactId>
<groupId>org.apache.skywalking</groupId>
<version>6.1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>apm-mysql-commons</artifactId>
<packaging>jar</packaging>
<name>apm-mysql-commons</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<mysql-connector-java.version>8.0.13</mysql-connector-java.version>
</properties>
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql-connector-java.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.skywalking</groupId>
<artifactId>apm-jdbc-commons</artifactId>
<version>${project.version}</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.skywalking.apm.plugin.jdbc.mysql;
/**
* @author: dingshaocheng
*/
public class Constants {
public static final String CREATE_CALLABLE_STATEMENT_INTERCEPTOR = "org.apache.skywalking.apm.plugin.jdbc.mysql.CreateCallableStatementInterceptor";
public static final String CREATE_PREPARED_STATEMENT_INTERCEPTOR = "org.apache.skywalking.apm.plugin.jdbc.mysql.CreatePreparedStatementInterceptor";
public static final String CREATE_STATEMENT_INTERCEPTOR = "org.apache.skywalking.apm.plugin.jdbc.mysql.CreateStatementInterceptor";
public static final String PREPARED_STATEMENT_EXECUTE_METHODS_INTERCEPTOR = "org.apache.skywalking.apm.plugin.jdbc.mysql.PreparedStatementExecuteMethodsInterceptor";
public static final String SET_CATALOG_INTERCEPTOR = "org.apache.skywalking.apm.plugin.jdbc.mysql.SetCatalogInterceptor";
public static final String STATEMENT_EXECUTE_METHODS_INTERCEPTOR = "org.apache.skywalking.apm.plugin.jdbc.mysql.StatementExecuteMethodsInterceptor";
}
......@@ -19,16 +19,14 @@
package org.apache.skywalking.apm.plugin.jdbc.mysql;
import java.lang.reflect.Method;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
import org.apache.skywalking.apm.plugin.jdbc.define.StatementEnhanceInfos;
import org.apache.skywalking.apm.plugin.jdbc.trace.ConnectionInfo;
/**
* @author zhangxin
*/
import java.lang.reflect.Method;
public class CreateCallableStatementInterceptor implements InstanceMethodsAroundInterceptor {
@Override
public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes,
......
......@@ -18,21 +18,18 @@
package org.apache.skywalking.apm.plugin.jdbc.mysql;
import java.lang.reflect.Method;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
import org.apache.skywalking.apm.plugin.jdbc.define.StatementEnhanceInfos;
import org.apache.skywalking.apm.plugin.jdbc.trace.ConnectionInfo;
/**
* @author zhangxin
*/
import java.lang.reflect.Method;
public class CreatePreparedStatementInterceptor implements InstanceMethodsAroundInterceptor {
@Override
public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes,
MethodInterceptResult result) throws Throwable {
}
@Override
......
......@@ -19,16 +19,15 @@
package org.apache.skywalking.apm.plugin.jdbc.mysql;
import java.lang.reflect.Method;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
import org.apache.skywalking.apm.plugin.jdbc.define.StatementEnhanceInfos;
import org.apache.skywalking.apm.plugin.jdbc.trace.ConnectionInfo;
/**
* @author zhangxin
*/
import java.lang.reflect.Method;
public class CreateStatementInterceptor implements InstanceMethodsAroundInterceptor {
@Override
public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes,
......
......@@ -18,7 +18,6 @@
package org.apache.skywalking.apm.plugin.jdbc.mysql;
import java.lang.reflect.Method;
import org.apache.skywalking.apm.agent.core.context.ContextManager;
import org.apache.skywalking.apm.agent.core.context.tag.Tags;
import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan;
......@@ -29,9 +28,8 @@ import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInt
import org.apache.skywalking.apm.plugin.jdbc.define.StatementEnhanceInfos;
import org.apache.skywalking.apm.plugin.jdbc.trace.ConnectionInfo;
/**
* @author zhang xin
*/
import java.lang.reflect.Method;
public class PreparedStatementExecuteMethodsInterceptor implements InstanceMethodsAroundInterceptor {
@Override
......
......@@ -18,12 +18,13 @@
package org.apache.skywalking.apm.plugin.jdbc.mysql;
import java.lang.reflect.Method;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
import org.apache.skywalking.apm.plugin.jdbc.trace.ConnectionInfo;
import java.lang.reflect.Method;
public class SetCatalogInterceptor implements InstanceMethodsAroundInterceptor {
@Override
public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes,
......
......@@ -18,7 +18,6 @@
package org.apache.skywalking.apm.plugin.jdbc.mysql;
import java.lang.reflect.Method;
import org.apache.skywalking.apm.agent.core.context.ContextManager;
import org.apache.skywalking.apm.agent.core.context.tag.Tags;
import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan;
......@@ -29,11 +28,9 @@ import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInt
import org.apache.skywalking.apm.plugin.jdbc.define.StatementEnhanceInfos;
import org.apache.skywalking.apm.plugin.jdbc.trace.ConnectionInfo;
/**
* {@link StatementExecuteMethodsInterceptor} create the exit span when the client call the interceptor methods.
*
* @author zhangxin
*/
import java.lang.reflect.Method;
public class StatementExecuteMethodsInterceptor implements InstanceMethodsAroundInterceptor {
@Override
public final void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments,
......
......@@ -19,14 +19,14 @@
package org.apache.skywalking.apm.plugin.jdbc.mysql;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
import org.apache.skywalking.apm.plugin.jdbc.trace.ConnectionInfo;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Matchers;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
import org.apache.skywalking.apm.plugin.jdbc.trace.ConnectionInfo;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
......
......@@ -19,14 +19,14 @@
package org.apache.skywalking.apm.plugin.jdbc.mysql;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
import org.apache.skywalking.apm.plugin.jdbc.trace.ConnectionInfo;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Matchers;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
import org.apache.skywalking.apm.plugin.jdbc.trace.ConnectionInfo;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
......
......@@ -20,13 +20,13 @@
package org.apache.skywalking.apm.plugin.jdbc.mysql;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
import org.apache.skywalking.apm.plugin.jdbc.trace.ConnectionInfo;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Matchers;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import org.apache.skywalking.apm.plugin.jdbc.trace.ConnectionInfo;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
......
......@@ -18,14 +18,15 @@
package org.apache.skywalking.apm.plugin.jdbc.mysql;
import java.lang.reflect.Method;
import org.apache.skywalking.apm.agent.core.context.trace.AbstractTracingSpan;
import org.apache.skywalking.apm.agent.core.context.trace.SpanLayer;
import org.apache.skywalking.apm.agent.core.context.trace.TraceSegment;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
import org.apache.skywalking.apm.agent.test.helper.SegmentHelper;
import org.apache.skywalking.apm.agent.test.tools.SegmentStorage;
import org.apache.skywalking.apm.agent.test.tools.SegmentStoragePoint;
import org.apache.skywalking.apm.agent.test.tools.SpanAssert;
import org.apache.skywalking.apm.agent.test.tools.*;
import org.apache.skywalking.apm.network.trace.component.ComponentsDefine;
import org.apache.skywalking.apm.plugin.jdbc.define.StatementEnhanceInfos;
import org.apache.skywalking.apm.plugin.jdbc.trace.ConnectionInfo;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
......@@ -33,12 +34,8 @@ import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.powermock.modules.junit4.PowerMockRunner;
import org.powermock.modules.junit4.PowerMockRunnerDelegate;
import org.apache.skywalking.apm.agent.core.context.trace.AbstractTracingSpan;
import org.apache.skywalking.apm.agent.core.context.trace.TraceSegment;
import org.apache.skywalking.apm.agent.test.tools.AgentServiceRule;
import org.apache.skywalking.apm.agent.test.tools.TracingSegmentRunner;
import org.apache.skywalking.apm.network.trace.component.ComponentsDefine;
import org.apache.skywalking.apm.plugin.jdbc.trace.ConnectionInfo;
import java.lang.reflect.Method;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
......
......@@ -47,6 +47,9 @@
<module>xmemcached-2.x-plugin</module>
<module>grpc-1.x-plugin</module>
<module>mysql-5.x-plugin</module>
<module>mysql-6.x-plugin</module>
<module>mysql-8.x-plugin</module>
<module>mysql-common</module>
<module>h2-1.x-plugin</module>
<module>postgresql-8.x-plugin</module>
<module>rocketMQ-3.x-plugin</module>
......
......@@ -26,6 +26,7 @@ import org.apache.skywalking.apm.agent.core.context.ContextManager;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
import org.apache.skywalking.apm.agent.core.util.MethodUtil;
/**
* {@link TraceAnnotationMethodInterceptor} create a local span and set the operation name which fetch from
......@@ -41,25 +42,12 @@ public class TraceAnnotationMethodInterceptor implements InstanceMethodsAroundIn
Trace trace = method.getAnnotation(Trace.class);
String operationName = trace.operationName();
if (operationName.length() == 0 || Config.Plugin.Toolkit.USE_QUALIFIED_NAME_AS_ENDPOINT_NAME) {
operationName = generateOperationName(method);
operationName = MethodUtil.generateOperationName(method);
}
ContextManager.createLocalSpan(operationName);
}
private String generateOperationName(Method method) {
StringBuilder operationName = new StringBuilder(method.getDeclaringClass().getName() + "." + method.getName() + "(");
Class<?>[] parameterTypes = method.getParameterTypes();
for (int i = 0; i < parameterTypes.length; i++) {
operationName.append(parameterTypes[i].getName());
if (i < (parameterTypes.length - 1)) {
operationName.append(",");
}
}
operationName.append(")");
return operationName.toString();
}
@Override
public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes,
Object ret) throws Throwable {
......
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Licensed to the Apache Software Foundation (ASF) under one or more
~ contributor license agreements. See the NOTICE file distributed with
~ this work for additional information regarding copyright ownership.
~ The ASF licenses this file to You under the Apache License, Version 2.0
~ (the "License"); you may not use this file except in compliance with
~ the License. You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
~
-->
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>org.apache.skywalking</groupId>
<artifactId>optional-plugins</artifactId>
<version>6.1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>apm-customize-enhance-plugin</artifactId>
<name>customize-enhance-plugin</name>
<packaging>jar</packaging>
</project>
\ No newline at end of file
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.skywalking.apm.plugin.customize.conf;
import net.bytebuddy.matcher.ElementMatcher;
import org.apache.skywalking.apm.agent.core.conf.Config;
import org.apache.skywalking.apm.agent.core.logging.api.ILog;
import org.apache.skywalking.apm.agent.core.logging.api.LogManager;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassEnhancePluginDefine;
import org.apache.skywalking.apm.plugin.customize.constants.Constants;
import org.apache.skywalking.apm.plugin.customize.util.CustomizeUtil;
import org.apache.skywalking.apm.agent.core.util.MethodUtil;
import org.apache.skywalking.apm.util.StringUtil;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.*;
import static net.bytebuddy.matcher.ElementMatchers.*;
import static org.apache.skywalking.apm.agent.core.plugin.bytebuddy.ArgumentTypeNameMatch.takesArgumentWithType;
/**
* The CustomizeConfiguration class is the core class for
* parsing custom enhanced configuration files,
* parsing configuration files,
* and converting content into plugins for loading into the kernel.
*
* @author zhaoyuguang
*/
public enum CustomizeConfiguration {
INSTANCE;
private static final ILog logger = LogManager.getLogger(CustomizeConfiguration.class);
/**
* The load method is resolver configuration file,
* and parse it to kernel.
*/
public void load() {
try {
parse(resolver());
} catch (Exception e) {
logger.error("CustomizeConfiguration load fail", e);
}
}
/**
* Resolver custom enhancement file method total entry.
*
* @return configurations is a bridge resolver method and parse method,
* mainly used for decoupling.
* @throws ParserConfigurationException link {@link ParserConfigurationException}
* @throws IOException link {@link IOException}
* @throws SAXException link {@link SAXException}
*/
private List<Map<String, Object>> resolver() throws ParserConfigurationException, IOException, SAXException {
List<Map<String, Object>> customizeMethods = new ArrayList<Map<String, Object>>();
File file = new File(Config.Plugin.Customize.ENHANCE_FILE);
if (file.exists() && file.isFile()) {
NodeList classNodeList = resolverFileClassDesc(file);
resolverClassNodeList(classNodeList, customizeMethods);
}
return customizeMethods;
}
/**
* According to the custom enhancement file, return lass description nodes in the file.
*
* @param file the custom enhanced files
* @return all class description nodes
* @throws ParserConfigurationException link {@link ParserConfigurationException}
* @throws IOException link {@link IOException}
* @throws SAXException link {@link SAXException}
*/
private NodeList resolverFileClassDesc(File file) throws ParserConfigurationException, IOException, SAXException {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document doc = builder.parse(file);
return doc.getElementsByTagName(Constants.XML_ELEMENT_CLASS);
}
/**
* Resolver all class description nodes to customizeMethods.
*
* @param classNodeList all class description nodes.
* @param customizeMethods of memory address, the element {@link MethodConfiguration}.
*/
private void resolverClassNodeList(NodeList classNodeList, List<Map<String, Object>> customizeMethods) {
for (int ec = 0; ec < classNodeList.getLength(); ec++) {
Node classDesc = classNodeList.item(ec);
NodeList methodNodeList = classDesc.getChildNodes();
for (int ms = 0; ms < methodNodeList.getLength(); ms++) {
Node methodDesc = methodNodeList.item(ms);
if (methodDesc.getNodeType() == Node.ELEMENT_NODE) {
String className = classDesc.getAttributes().getNamedItem(Constants.XML_ELEMENT_CLASS_NAME).getNodeValue();
Map<String, Object> configuration = resolverMethodNodeDesc(className, methodDesc);
if (configuration != null) {
customizeMethods.add(configuration);
}
}
}
}
}
/**
* Resolver according to the description of the method under the current class node.
*
* @param className class name.
* @param methodDesc method node.
* @return configurations is a bridge resolver method and parse method,
* mainly used for decoupling.
*/
private Map<String, Object> resolverMethodNodeDesc(String className, Node methodDesc) {
Map<String, Object> configuration = new HashMap<String, Object>();
if (methodDesc.getAttributes().getNamedItem(Constants.XML_ELEMENT_OPERATION_NAME) != null) {
MethodConfiguration.setOperationName(configuration, methodDesc.getAttributes().getNamedItem(Constants.XML_ELEMENT_OPERATION_NAME).getNodeValue());
}
if (methodDesc.getAttributes().getNamedItem(Constants.XML_ELEMENT_CLOSE_BEFORE_METHOD) != null) {
MethodConfiguration.setCloseBeforeMethod(configuration, Boolean.valueOf(methodDesc.getAttributes().getNamedItem(Constants.XML_ELEMENT_CLOSE_BEFORE_METHOD).getNodeValue()));
} else {
MethodConfiguration.setCloseBeforeMethod(configuration, false);
}
if (methodDesc.getAttributes().getNamedItem(Constants.XML_ELEMENT_CLOSE_AFTER_METHOD) != null) {
MethodConfiguration.setCloseAfterMethod(configuration, Boolean.valueOf(methodDesc.getAttributes().getNamedItem(Constants.XML_ELEMENT_CLOSE_AFTER_METHOD).getNodeValue()));
} else {
MethodConfiguration.setCloseAfterMethod(configuration, false);
}
if (methodDesc.getAttributes().getNamedItem(Constants.XML_ELEMENT_METHOD_IS_STATIC) != null) {
MethodConfiguration.setStatic(configuration, Boolean.valueOf(methodDesc.getAttributes().getNamedItem(Constants.XML_ELEMENT_METHOD_IS_STATIC).getNodeValue()));
}
setAdvancedField(configuration, methodDesc);
return resolverClassAndMethod(className,
methodDesc.getAttributes().getNamedItem(Constants.XML_ELEMENT_METHOD).getNodeValue(),
configuration);
}
/**
* Add some private properties of the Advanced method configuration.
*
* @param configuration {@link MethodConfiguration}.
* @param methodNode method node.
*/
private void setAdvancedField(Map<String, Object> configuration, Node methodNode) {
NodeList methodContents = methodNode.getChildNodes();
for (int mc = 0; mc < methodContents.getLength(); mc++) {
Node methodContentNode = methodContents.item(mc);
if (methodContentNode.getNodeType() == Node.ELEMENT_NODE) {
if (Constants.XML_ELEMENT_OPERATION_NAME_SUFFIX.equals(methodContentNode.getNodeName())) {
MethodConfiguration.addOperationNameSuffixes(configuration, methodContentNode.getTextContent());
}
if (Constants.XML_ELEMENT_TAG.equals(methodContentNode.getNodeName())) {
MethodConfiguration.addTag(configuration, methodContentNode.getAttributes().getNamedItem(Constants.XML_ELEMENT_KEY).getNodeValue(), methodContentNode.getTextContent());
}
if (Constants.XML_ELEMENT_LOG.equals(methodContentNode.getNodeName())) {
MethodConfiguration.addLog(configuration, methodContentNode.getAttributes().getNamedItem(Constants.XML_ELEMENT_KEY).getNodeValue(), methodContentNode.getTextContent());
}
}
}
}
/**
* Parse class and method,
* if no error log is printed in this JVM, and return null.
* primitive desc impl by {@link CustomizeUtil}
* At the bottom, the default operation name is added.
*
* @param className class name.
* @param methodDesc method desc.
* @param configuration {@link MethodConfiguration}.
* @return configuration of method.
*/
private Map<String, Object> resolverClassAndMethod(String className, String methodDesc, Map<String, Object> configuration) {
try {
int openParen = methodDesc.indexOf(Constants.LEFT_PARENTHESIS);
int closeParen = methodDesc.indexOf(Constants.RIGHT_PARENTHESIS);
String methodName = methodDesc.substring(0, openParen);
String[] arguments = methodDesc.substring(openParen + 1, closeParen).split(Constants.COMMA);
MethodConfiguration.setClz(configuration, className);
MethodConfiguration.setMethod(configuration, CustomizeUtil.generateOperationName(className, methodName, arguments));
MethodConfiguration.setMethodName(configuration, methodName);
MethodConfiguration.setArguments(configuration, StringUtil.isEmpty(arguments[0]) ? new String[0] : arguments);
if (StringUtil.isEmpty(MethodConfiguration.getOperationName(configuration))) {
MethodConfiguration.setOperationName(configuration, MethodConfiguration.getMethod(configuration));
}
return configuration;
} catch (Exception e) {
logger.error(e, "Failed to resolver, className is {}, methodDesc is {}.", className, methodDesc);
}
return null;
}
/**
* Put the plugin configuration into the kernel according to the configuration.
*
* @param configurations is a bridge resolver method and parse method,
* mainly used for decoupling.
*/
private void parse(List<Map<String, Object>> configurations) {
init();
for (Map<String, Object> configuration : configurations) {
addContextMethodConfiguration(configuration);
addContextEnhanceClass(configuration);
}
}
/**
* In order to avoid the judgment of the useless null pointer exception.
*/
private void init() {
Config.Plugin.Customize.CONTEXT.put(Constants.CONTEXT_METHOD_CONFIGURATIONS, new HashMap<String, Map<String, Object>>());
Config.Plugin.Customize.CONTEXT.put(Constants.CONTEXT_ENHANCE_CLASSES, new HashMap<String, ElementMatcher>());
}
/**
* The configuration of each method is put into the kernel.
*
* @param configuration {@link MethodConfiguration}.
*/
private void addContextMethodConfiguration(Map<String, Object> configuration) {
getMethodConfigurations().put(MethodConfiguration.getMethod(configuration), configuration);
}
/**
* The private method for get the configuration of this method.
*
* @return all method configs.
*/
@SuppressWarnings("unchecked")
private Map<String, Map<String, Object>> getMethodConfigurations() {
return (Map<String, Map<String, Object>>) Config.Plugin.Customize.CONTEXT.get(Constants.CONTEXT_METHOD_CONFIGURATIONS);
}
/**
* The configuration of each class is put into the kernel.
*
* @param configuration {@link MethodConfiguration}
*/
private void addContextEnhanceClass(Map<String, Object> configuration) {
String key = CustomizeUtil.generateClassDesc(MethodConfiguration.getClz(configuration), MethodConfiguration.isStatic(configuration));
HashMap<String, ElementMatcher> enhanceClasses = getEnhanceClasses();
ElementMatcher matcher = enhanceClasses.get(key);
enhanceClasses.put(key, matcher == null ? parserMethodsMatcher(configuration) : ((ElementMatcher.Junction) matcher).or(parserMethodsMatcher(configuration)));
}
/**
* Parse each configuration to matcher.
*
* @param configuration {@link MethodConfiguration}.
* @return matcher {@link ElementMatcher}.
*/
private ElementMatcher parserMethodsMatcher(Map<String, Object> configuration) {
String[] arguments = MethodConfiguration.getArguments(configuration);
ElementMatcher matcher = named(MethodConfiguration.getMethodName(configuration)).and(takesArguments(arguments.length));
if (arguments.length > 0) {
for (int i = 0; i < arguments.length; i++) {
matcher = ((ElementMatcher.Junction) matcher).and(
CustomizeUtil.isJavaClass(arguments[i]) ?
takesArgument(i, CustomizeUtil.getJavaClass(arguments[i])) :
takesArgumentWithType(i, arguments[i]));
}
}
return matcher;
}
/**
* Get InterceptPoints, the input dimension is class and is static.
*
* @param enhanceClass Real enhancement class
* @param isStatic Is it static, because static or not,
* logic is different in the SkyWalking kernel,
* so this dimension is abstracted out.
* @return all the interceptPoints.
*/
public ElementMatcher getInterceptPoints(String enhanceClass, boolean isStatic) {
HashMap<String, ElementMatcher> enhanceClasses = getEnhanceClasses();
return enhanceClasses.get(CustomizeUtil.generateClassDesc(enhanceClass, isStatic));
}
/**
* Get all the instrumentation {@link ClassEnhancePluginDefine} that need custom enhancements.
*
* @return all the custom instrumentation.
*/
public Set<String> getInstrumentations() {
HashMap<String, ElementMatcher> enhanceClasses = getEnhanceClasses();
return enhanceClasses.keySet();
}
/**
* Get all the private methods of interceptPoints that need custom enhancements.
*
* @return all config of the custom instrumentation.
*/
@SuppressWarnings("unchecked")
private HashMap<String, ElementMatcher> getEnhanceClasses() {
return (HashMap<String, ElementMatcher>) Config.Plugin.Customize.CONTEXT.get(Constants.CONTEXT_ENHANCE_CLASSES);
}
public Map<String, Object> getConfiguration(Method method) {
return getMethodConfigurations().get(MethodUtil.generateOperationName(method));
}
}
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.skywalking.apm.plugin.customize.conf;
import org.apache.skywalking.apm.plugin.customize.constants.Constants;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Default custom enhancement configuration.
*
* @author zhaoyuguang
*/
public class MethodConfiguration {
static String getMethod(Map<String, Object> configuration) {
return (String) configuration.get(Constants.CONFIGURATION_ATTRIBUTE_METHOD);
}
static String getClz(Map<String, Object> configuration) {
return (String) configuration.get(Constants.CONFIGURATION_ATTRIBUTE_CLZ);
}
static Boolean isStatic(Map<String, Object> configuration) {
return (Boolean) configuration.get(Constants.CONFIGURATION_ATTRIBUTE_IS_STATIC);
}
static String getMethodName(Map<String, Object> configuration) {
return (String) configuration.get(Constants.CONFIGURATION_ATTRIBUTE_METHOD_NAME);
}
static String[] getArguments(Map<String, Object> configuration) {
return (String[]) configuration.get(Constants.CONFIGURATION_ATTRIBUTE_ARGUMENTS);
}
static void setOperationName(Map<String, Object> configuration, String operationName) {
configuration.put(Constants.CONFIGURATION_ATTRIBUTE_OPERATION_NAME, operationName);
}
static void setCloseBeforeMethod(Map<String, Object> configuration, Boolean closeBeforeMethod) {
configuration.put(Constants.CONFIGURATION_ATTRIBUTE_CLOSE_BEFORE_METHOD, closeBeforeMethod);
}
static void setCloseAfterMethod(Map<String, Object> configuration, Boolean closeAfterMethod) {
configuration.put(Constants.CONFIGURATION_ATTRIBUTE_CLOSE_AFTER_METHOD, closeAfterMethod);
}
static void setStatic(Map<String, Object> configuration, Boolean isStatic) {
configuration.put(Constants.CONFIGURATION_ATTRIBUTE_IS_STATIC, isStatic);
}
@SuppressWarnings("unchecked")
static void addOperationNameSuffixes(Map<String, Object> configuration, String suffix) {
List<String> suffixes = (List<String>) configuration.get(Constants.CONFIGURATION_ATTRIBUTE_OPERATION_NAME_SUFFIXES);
if (suffixes == null) {
suffixes = new ArrayList<String>();
suffixes.add(suffix);
configuration.put(Constants.CONFIGURATION_ATTRIBUTE_OPERATION_NAME_SUFFIXES, suffixes);
} else {
suffixes.add(suffix);
}
}
@SuppressWarnings("unchecked")
static void addTag(Map<String, Object> configuration, String key, String value) {
Map<String, String> tags = (Map<String, String>) configuration.get(Constants.CONFIGURATION_ATTRIBUTE_TAGS);
if (tags == null) {
tags = new HashMap<String, String>();
tags.put(key, value);
configuration.put(Constants.CONFIGURATION_ATTRIBUTE_TAGS, tags);
} else {
tags.put(key, value);
}
}
@SuppressWarnings("unchecked")
static void addLog(Map<String, Object> configuration, String key, String value) {
Map<String, String> logs = (Map<String, String>) configuration.get(Constants.CONFIGURATION_ATTRIBUTE_LOGS);
if (logs == null) {
logs = new HashMap<String, String>();
logs.put(key, value);
configuration.put(Constants.CONFIGURATION_ATTRIBUTE_LOGS, logs);
} else {
logs.put(key, value);
}
}
static void setClz(Map<String, Object> configuration, String className) {
configuration.put(Constants.CONFIGURATION_ATTRIBUTE_CLZ, className);
}
static void setMethod(Map<String, Object> configuration, String method) {
configuration.put(Constants.CONFIGURATION_ATTRIBUTE_METHOD, method);
}
static void setMethodName(Map<String, Object> configuration, String methodName) {
configuration.put(Constants.CONFIGURATION_ATTRIBUTE_METHOD_NAME, methodName);
}
static void setArguments(Map<String, Object> configuration, String[] arguments) {
configuration.put(Constants.CONFIGURATION_ATTRIBUTE_ARGUMENTS, arguments);
}
public static String getOperationName(Map<String, Object> configuration) {
return (String) configuration.get(Constants.CONFIGURATION_ATTRIBUTE_OPERATION_NAME);
}
public static boolean isCloseBeforeMethod(Map<String, Object> configuration) {
return (Boolean) configuration.get(Constants.CONFIGURATION_ATTRIBUTE_CLOSE_BEFORE_METHOD);
}
public static boolean isCloseAfterMethod(Map<String, Object> configuration) {
return (Boolean) configuration.get(Constants.CONFIGURATION_ATTRIBUTE_CLOSE_AFTER_METHOD);
}
@SuppressWarnings("unchecked")
public static Map<String, String> getTags(Map<String, Object> configuration) {
return (Map<String, String>) configuration.get(Constants.CONFIGURATION_ATTRIBUTE_TAGS);
}
@SuppressWarnings("unchecked")
public static Map<String, String> getLogs(Map<String, Object> configuration) {
return (Map<String, String>) configuration.get(Constants.CONFIGURATION_ATTRIBUTE_LOGS);
}
@SuppressWarnings("unchecked")
public static List<String> getOperationNameSuffixes(Map<String, Object> configuration) {
return (List<String>) configuration.get(Constants.CONFIGURATION_ATTRIBUTE_OPERATION_NAME_SUFFIXES);
}
}
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.skywalking.apm.plugin.customize.constants;
/**
* The constant of customize enhance.
*
* @author zhaoyuguang
*/
public class Constants {
public static final String OPERATION_NAME_SEPARATOR = "/";
public static final String COMMA = ",";
public static final String LEFT_PARENTHESIS = "(";
public static final String RIGHT_PARENTHESIS = ")";
public static final String XML_ELEMENT_CLASS = "class";
public static final String XML_ELEMENT_CLASS_NAME = "class_name";
public static final String XML_ELEMENT_METHOD = "method";
public static final String XML_ELEMENT_METHOD_IS_STATIC = "static";
public static final String XML_ELEMENT_OPERATION_NAME = "operation_name";
public static final String XML_ELEMENT_CLOSE_BEFORE_METHOD = "close_before_method";
public static final String XML_ELEMENT_CLOSE_AFTER_METHOD = "close_after_method";
public static final String XML_ELEMENT_OPERATION_NAME_SUFFIX = "operation_name_suffix";
public static final String XML_ELEMENT_TAG = "tag";
public static final String XML_ELEMENT_LOG = "log";
public static final String XML_ELEMENT_KEY = "key";
public static final String CONTEXT_METHOD_CONFIGURATIONS = "CONTEXT_METHOD_CONFIGURATIONS";
public static final String CONTEXT_ENHANCE_CLASSES = "CONTEXT_ENHANCE_CLASSES";
public static final String CONFIGURATION_ATTRIBUTE_METHOD = "CONFIGURATION_ATTRIBUTE_METHOD";
public static final String CONFIGURATION_ATTRIBUTE_METHOD_NAME = "CONFIGURATION_ATTRIBUTE_METHOD_NAME";
public static final String CONFIGURATION_ATTRIBUTE_ARGUMENTS = "CONFIGURATION_ATTRIBUTE_ARGUMENTS";
public static final String CONFIGURATION_ATTRIBUTE_IS_STATIC = "CONFIGURATION_ATTRIBUTE_IS_STATIC";
public static final String CONFIGURATION_ATTRIBUTE_CLZ = "CONFIGURATION_ATTRIBUTE_CLZ";
public static final String CONFIGURATION_ATTRIBUTE_OPERATION_NAME = "CONFIGURATION_ATTRIBUTE_OPERATION_NAME";
public static final String CONFIGURATION_ATTRIBUTE_CLOSE_BEFORE_METHOD = "CONFIGURATION_ATTRIBUTE_CLOSE_BEFORE_METHOD";
public static final String CONFIGURATION_ATTRIBUTE_CLOSE_AFTER_METHOD = "CONFIGURATION_ATTRIBUTE_CLOSE_AFTER_METHOD";
public static final String CONFIGURATION_ATTRIBUTE_OPERATION_NAME_SUFFIXES = "CONFIGURATION_ATTRIBUTE_OPERATION_NAME_SUFFIXES";
public static final String CONFIGURATION_ATTRIBUTE_TAGS = "CONFIGURATION_ATTRIBUTE_TAGS";
public static final String CONFIGURATION_ATTRIBUTE_LOGS = "CONFIGURATION_ATTRIBUTE_LOGS";
}
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.skywalking.apm.plugin.customize.define;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.matcher.ElementMatcher;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine;
import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
import org.apache.skywalking.apm.agent.core.plugin.match.NameMatch;
import org.apache.skywalking.apm.plugin.customize.conf.CustomizeConfiguration;
/**
* The instance of customize instrumentation.
*
* @author zhaoyuguang
*/
public class CustomizeInstanceInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
private String enhanceClass;
public CustomizeInstanceInstrumentation(String enhanceClass) {
this.enhanceClass = enhanceClass;
}
@Override
protected ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
return new ConstructorInterceptPoint[0];
}
@Override
protected InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
final ElementMatcher matcher = CustomizeConfiguration.INSTANCE.getInterceptPoints(enhanceClass, false);
if (matcher == null) {
return new InstanceMethodsInterceptPoint[0];
} else {
return new InstanceMethodsInterceptPoint[]{
new InstanceMethodsInterceptPoint() {
@Override
public ElementMatcher<MethodDescription> getMethodsMatcher() {
return matcher;
}
@Override
public String getMethodsInterceptor() {
return "org.apache.skywalking.apm.plugin.customize.interceptor.CustomizeInstanceInterceptor";
}
@Override
public boolean isOverrideArgs() {
return false;
}
}
};
}
}
@Override
protected ClassMatch enhanceClass() {
return NameMatch.byName(enhanceClass);
}
}
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.skywalking.apm.plugin.customize.define;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.matcher.ElementMatcher;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.StaticMethodsInterceptPoint;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassStaticMethodsEnhancePluginDefine;
import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
import org.apache.skywalking.apm.agent.core.plugin.match.NameMatch;
import org.apache.skywalking.apm.plugin.customize.conf.CustomizeConfiguration;
/**
* The static of customize instrumentation.
*
* @author zhaoyuguang
*/
public class CustomizeStaticInstrumentation extends ClassStaticMethodsEnhancePluginDefine {
private String enhanceClass;
public CustomizeStaticInstrumentation(String enhanceClass) {
this.enhanceClass = enhanceClass;
}
@Override
protected StaticMethodsInterceptPoint[] getStaticMethodsInterceptPoints() {
final ElementMatcher matcher = CustomizeConfiguration.INSTANCE.getInterceptPoints(enhanceClass, true);
if (matcher == null) {
return new StaticMethodsInterceptPoint[0];
} else {
return new StaticMethodsInterceptPoint[]{
new StaticMethodsInterceptPoint() {
@Override
public ElementMatcher<MethodDescription> getMethodsMatcher() {
return matcher;
}
@Override
public String getMethodsInterceptor() {
return "org.apache.skywalking.apm.plugin.customize.interceptor.CustomizeStaticInterceptor";
}
@Override
public boolean isOverrideArgs() {
return false;
}
}
};
}
}
@Override
protected ClassMatch enhanceClass() {
return NameMatch.byName(enhanceClass);
}
}
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.skywalking.apm.plugin.customize.interceptor;
import org.apache.skywalking.apm.agent.core.context.ContextManager;
import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan;
import org.apache.skywalking.apm.plugin.customize.conf.CustomizeConfiguration;
import org.apache.skywalking.apm.plugin.customize.conf.MethodConfiguration;
import org.apache.skywalking.apm.plugin.customize.constants.Constants;
import org.apache.skywalking.apm.plugin.customize.util.CustomizeExpression;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @author zhaoyuguang
*/
class BaseInterceptorMethods {
void beforeMethod(Method method, Object[] allArguments) {
Map<String, Object> configuration = CustomizeConfiguration.INSTANCE.getConfiguration(method);
if (!MethodConfiguration.isCloseBeforeMethod(configuration)) {
String operationName = MethodConfiguration.getOperationName(configuration);
Map<String, Object> context = CustomizeExpression.evaluationContext(allArguments);
if (context == null || context.isEmpty()) {
ContextManager.createLocalSpan(operationName);
} else {
Map<String, String> tags = MethodConfiguration.getTags(configuration);
Map<String, String> spanTags = new HashMap<String, String>();
Map<String, String> logs = MethodConfiguration.getLogs(configuration);
Map<String, String> spanLogs = new HashMap<String, String>();
List<String> operationNameSuffixes = MethodConfiguration.getOperationNameSuffixes(configuration);
StringBuilder operationNameSuffix = new StringBuilder();
if (operationNameSuffixes != null && !operationNameSuffixes.isEmpty()) {
for (String expression : operationNameSuffixes) {
operationNameSuffix.append(Constants.OPERATION_NAME_SEPARATOR);
operationNameSuffix.append(CustomizeExpression.parseExpression(expression, context));
}
}
if (tags != null && !tags.isEmpty()) {
for (String key : tags.keySet()) {
String expression = tags.get(key);
spanTags.put(key, CustomizeExpression.parseExpression(expression, context));
}
}
if (logs != null && !logs.isEmpty()) {
for (String key : logs.keySet()) {
String expression = logs.get(key);
spanLogs.put(key, CustomizeExpression.parseExpression(expression, context));
}
}
operationName = operationNameSuffix.insert(0, operationName).toString();
AbstractSpan span = ContextManager.createLocalSpan(operationName);
if (!spanTags.isEmpty()) {
for (Map.Entry<String, String> tag : spanTags.entrySet()) {
span.tag(tag.getKey(), tag.getValue());
}
}
if (!spanLogs.isEmpty()) {
span.log(System.currentTimeMillis(), spanLogs);
}
}
}
}
void afterMethod(Method method) {
if (!MethodConfiguration.isCloseAfterMethod(CustomizeConfiguration.INSTANCE.getConfiguration(method))) {
ContextManager.stopSpan();
}
}
void handleMethodException(Throwable t) {
if (ContextManager.activeSpan() != null) {
ContextManager.activeSpan().errorOccurred().log(t);
}
}
}
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.skywalking.apm.plugin.customize.interceptor;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
import java.lang.reflect.Method;
/**
* @author zhaoyuguang
*/
public class CustomizeInstanceInterceptor extends BaseInterceptorMethods implements InstanceMethodsAroundInterceptor {
@Override
public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes, MethodInterceptResult result) throws Throwable {
super.beforeMethod(method, allArguments);
}
@Override
public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes, Object ret) throws Throwable {
super.afterMethod(method);
return ret;
}
@Override
public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes, Throwable t) {
super.handleMethodException(t);
}
}
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.skywalking.apm.plugin.customize.interceptor;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.StaticMethodsAroundInterceptor;
import java.lang.reflect.Method;
/**
* @author zhaoyuguang
*/
public class CustomizeStaticInterceptor extends BaseInterceptorMethods implements StaticMethodsAroundInterceptor {
@Override
public void beforeMethod(Class clazz, Method method, Object[] allArguments, Class<?>[] parameterTypes, MethodInterceptResult result) {
super.beforeMethod(method, allArguments);
}
@Override
public Object afterMethod(Class clazz, Method method, Object[] allArguments, Class<?>[] parameterTypes, Object ret) {
super.afterMethod(method);
return ret;
}
@Override
public void handleMethodException(Class clazz, Method method, Object[] allArguments, Class<?>[] parameterTypes, Throwable t) {
super.handleMethodException(t);
}
}
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.skywalking.apm.plugin.customize.loader;
import org.apache.skywalking.apm.agent.core.logging.api.ILog;
import org.apache.skywalking.apm.agent.core.logging.api.LogManager;
import org.apache.skywalking.apm.agent.core.plugin.AbstractClassEnhancePluginDefine;
import org.apache.skywalking.apm.agent.core.plugin.loader.AgentClassLoader;
import org.apache.skywalking.apm.agent.core.plugin.loader.InstrumentationLoader;
import org.apache.skywalking.apm.plugin.customize.conf.CustomizeConfiguration;
import org.apache.skywalking.apm.plugin.customize.define.CustomizeInstanceInstrumentation;
import org.apache.skywalking.apm.plugin.customize.define.CustomizeStaticInstrumentation;
import org.apache.skywalking.apm.plugin.customize.util.CustomizeUtil;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
/**
* The customize instrumentation plugin loader,
* so implements {@link InstrumentationLoader}
*
* @author zhaoyuguang
*/
public class CustomizeInstrumentationLoader implements InstrumentationLoader {
private static final ILog logger = LogManager.getLogger(CustomizeConfiguration.class);
@Override
public List<AbstractClassEnhancePluginDefine> load(AgentClassLoader classLoader) {
List<AbstractClassEnhancePluginDefine> instrumentations = new ArrayList<AbstractClassEnhancePluginDefine>();
CustomizeConfiguration.INSTANCE.load();
Set<String> enhanceClasses = CustomizeConfiguration.INSTANCE.getInstrumentations();
try {
for (String enhanceClass : enhanceClasses) {
String[] classDesc = CustomizeUtil.getClassDesc(enhanceClass);
AbstractClassEnhancePluginDefine plugin = (AbstractClassEnhancePluginDefine) Class.forName(
Boolean.valueOf(classDesc[1]) ? CustomizeStaticInstrumentation.class.getName() : CustomizeInstanceInstrumentation.class.getName(),
true, classLoader).getConstructor(String.class).newInstance(classDesc[0]);
instrumentations.add(plugin);
}
} catch (Exception e) {
logger.error(e, "InstrumentationLoader loader is error, spi loader is {}", CustomizeInstrumentationLoader.class.getName());
}
return instrumentations;
}
}
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.skywalking.apm.plugin.customize.util;
import org.apache.skywalking.apm.agent.core.logging.api.ILog;
import org.apache.skywalking.apm.agent.core.logging.api.LogManager;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* a simple parsing expression
*
* @author zhaoyuguang
*/
public class CustomizeExpression {
private static final ILog logger = LogManager.getLogger(CustomizeExpression.class);
public static Map<String, Object> evaluationContext(Object[] allArguments) {
Map<String, Object> context = new HashMap<String, Object>();
for (int i = 0; i < allArguments.length; i++) {
context.put("arg[" + i + "]", allArguments[i]);
}
return context;
}
public static String parseExpression(String expression, Map<String, Object> context) {
try {
String[] es = expression.split("\\.");
Object o = context.get(es[0]);
return o == null ? "null" : String.valueOf(parse(es, o, 0));
} catch (Exception e) {
logger.debug("parse expression error, expression is {}, exception is {}", expression, e.getMessage());
}
return "null";
}
private static Object parse(String[] expressions, Object o, int i) {
int next = i + 1;
if (next == expressions.length) {
return o;
} else {
o = parse0(expressions[next], o);
return o == null ? "null" : parse(expressions, o, next);
}
}
private static Object parse0(String expression, Object o) {
if (o instanceof Map) {
return matcherMap(expression, o);
} else if (o instanceof List) {
return matcherList(expression, o);
} else if (o.getClass().isArray()) {
return matcherArray(expression, o);
} else {
return matcherDefault(expression, o);
}
}
private static Object matcherMap(String expression, Object o) {
String key = expression.replace("['", "").replace("']", "");
return ((Map) o).get(key);
}
private static Object matcherList(String expression, Object o) {
int index = Integer.valueOf(expression.replace("[", "").replace("]", ""));
List l = (List) o;
return l != null && l.size() > index ? l.get(index) : null;
}
private static Object matcherArray(String expression, Object o) {
int index = Integer.valueOf(expression.replace("[", "").replace("]", ""));
return o != null && Array.getLength(o) > index ? Array.get(o, index) : null;
}
private static Object matcherDefault(String expression, Object o) {
try {
if (expression.contains("()")) {
Method m = o.getClass().getMethod(expression.replace("()", ""), null);
return m.invoke(o, null);
} else {
Field f = o.getClass().getDeclaredField(expression);
f.setAccessible(true);
return f.get(o);
}
} catch (Exception e) {
logger.debug("matcher default error, expression is {}, object is {}, expression is {}", expression, o, e.getMessage());
}
return null;
}
}
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.skywalking.apm.plugin.customize.util;
import java.util.HashMap;
import java.util.Map;
/**
* @author zhaoyuguang
*/
public class CustomizeUtil {
private static final Map<String, Class> JAVA_CLASS = new HashMap<String, Class>();
static {
JAVA_CLASS.put("boolean.class", boolean.class);
JAVA_CLASS.put("char.class", char.class);
JAVA_CLASS.put("byte.class", byte.class);
JAVA_CLASS.put("short.class", short.class);
JAVA_CLASS.put("int.class", int.class);
JAVA_CLASS.put("long.class", long.class);
JAVA_CLASS.put("float.class", float.class);
JAVA_CLASS.put("double.class", double.class);
JAVA_CLASS.put("java.util.List", java.util.List.class);
JAVA_CLASS.put("java.util.Map", java.util.Map.class);
}
public static boolean isJavaClass(String className) {
return JAVA_CLASS.containsKey(className);
}
public static Class getJavaClass(String className) {
return JAVA_CLASS.get(className);
}
public static String generateOperationName(String className, String methodName, String[] parameterTypes) {
StringBuilder operationName = new StringBuilder(className + "." + methodName + "(");
for (int i = 0; i < parameterTypes.length; i++) {
operationName.append(CustomizeUtil.isJavaClass(parameterTypes[i]) ? CustomizeUtil.getJavaClass(parameterTypes[i]).getName() : parameterTypes[i]);
if (i < (parameterTypes.length - 1)) {
operationName.append(",");
}
}
operationName.append(")");
return operationName.toString();
}
public static String generateClassDesc(String className, boolean isStatic) {
return className + ":" + isStatic;
}
public static String[] getClassDesc(String enhanceClass) {
return enhanceClass.split(":");
}
}
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
#
org.apache.skywalking.apm.plugin.customize.loader.CustomizeInstrumentationLoader
\ No newline at end of file
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.skywalking.apm.plugin.customize.util;
import org.junit.Assert;
import org.junit.Test;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @author zhaoyuguang
*/
public class CustomizeExpressionTest {
@Test
public void testExpression() {
Object[] allArguments = init();
Map<String, Object> context = CustomizeExpression.evaluationContext(allArguments);
Assert.assertTrue("String_test".equals(CustomizeExpression.parseExpression("arg[0]", context)));
Assert.assertTrue("1024".equals(CustomizeExpression.parseExpression("arg[1]", context)));
Assert.assertTrue("v2_1".equals(CustomizeExpression.parseExpression("arg[2].['k2_1']", context)));
Assert.assertTrue("test1".equals(CustomizeExpression.parseExpression("arg[3].[1]", context)));
Assert.assertTrue("null".equals(CustomizeExpression.parseExpression("arg[3].[100]", context)));
Assert.assertTrue("100".equals(CustomizeExpression.parseExpression("arg[4].id", context)));
Assert.assertTrue("sw".equals(CustomizeExpression.parseExpression("arg[4].getName()", context)));
Assert.assertTrue("ext_v_1".equals(CustomizeExpression.parseExpression("arg[4].ext.['ext_k_1']", context)));
Assert.assertTrue("uuid".equals(CustomizeExpression.parseExpression("arg[5].uuid", context)));
Assert.assertTrue("c".equals(CustomizeExpression.parseExpression("arg[5].orderIds.[0]", context)));
Assert.assertTrue("2".equals(CustomizeExpression.parseExpression("arg[5].ids.[2]", context)));
Assert.assertTrue("3".equals(CustomizeExpression.parseExpression("arg[5].ids.[1]", context)));
Assert.assertTrue("open_id".equals(CustomizeExpression.parseExpression("arg[5].openId", context)));
Assert.assertTrue("ext_v_2".equals(CustomizeExpression.parseExpression("arg[5].user.ext.['ext_k_2']", context)));
}
private static Object[] init() {
Object[] allArguments = new Object[6];
allArguments[0] = "String_test";
allArguments[1] = 1024;
Map m0 = new HashMap();
m0.put("k2_1", "v2_1");
allArguments[2] = m0;
List l0 = new ArrayList();
l0.add("test0");
l0.add("test1");
allArguments[3] = l0;
Map m1 = new HashMap();
m1.put("ext_k_1", "ext_v_1");
allArguments[4] = new User(100, "sw", m1);
Map m2 = new HashMap();
m2.put("ext_k_2", "ext_v_2");
User user2 = new User(101, "sw0", m2);
List l1 = new ArrayList();
l1.add("c");
Order order = new Order(999, "uuid", l1, user2, "open_id", new Object[]{0, 3, "2"});
allArguments[5] = order;
return allArguments;
}
static class Order {
public Order(int id, String uuid, List orderIds, User user, String openId, Object[] ids) {
this.id = id;
this.uuid = uuid;
this.orderIds = orderIds;
this.user = user;
this.openId = openId;
this.ids = ids;
}
private int id;
private String uuid;
private List orderIds;
private User user;
public String openId;
private Object[] ids;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUuid() {
return uuid;
}
public void setUuid(String uuid) {
this.uuid = uuid;
}
public List getOrderIds() {
return orderIds;
}
public void setOrderIds(List orderIds) {
this.orderIds = orderIds;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public Object[] getIds() {
return ids;
}
public void setIds(Object[] ids) {
this.ids = ids;
}
}
static class User {
public User(int id, String name, Map ext) {
this.id = id;
this.name = name;
this.ext = ext;
}
private int id;
private String name;
private Map ext;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Map getExt() {
return ext;
}
public void setExt(Map ext) {
this.ext = ext;
}
}
}
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.skywalking.apm.plugin.customize.util;
import org.junit.Assert;
import org.junit.Test;
/**
* @author zhaoyuguang
*/
public class CustomizeUtilTest {
@Test
public void testClassForName() throws ClassNotFoundException {
Assert.assertTrue(CustomizeUtil.isJavaClass("boolean.class"));
Assert.assertTrue(CustomizeUtil.isJavaClass("char.class"));
Assert.assertTrue(CustomizeUtil.getJavaClass("byte.class") == byte.class);
Assert.assertTrue(CustomizeUtil.getJavaClass("short.class") == short.class);
Assert.assertTrue(CustomizeUtil.getJavaClass("int.class") == int.class);
Assert.assertTrue(CustomizeUtil.getJavaClass("long.class") == long.class);
Assert.assertTrue(CustomizeUtil.getJavaClass("float.class") == float.class);
}
}
......@@ -46,6 +46,7 @@
<module>gson-2.8.x-plugin</module>
<module>lettuce-5.x-plugin</module>
<module>zookeeper-3.4.x-plugin</module>
<module>customize-enhance-plugin</module>
</modules>
<dependencies>
......
## Support custom enhance
Here is an optional plugin `apm-customize-enhance-plugin`
## Introduce
SkyWalking has provided [Java agent plugin development guide](https://github.com/apache/incubator-skywalking/blob/master/docs/en/guides/Java-Plugin-Development-Guide.md) to help developers to build new plugin.
This plugin is not designed for replacement but for user convenience. The behaviour is very similar with [@Trace toolkit](Application-toolkit-trace.md), but without code change requirement, and more powerful, such as provide tag and log.
## How to configure
Implementing enhancements to custom classes requires two steps.
1. Active the plugin, move the `optional-plugins/apm-customize-enhance-plugin.jar` to `plugin/apm-customize-enhance-plugin.jar`.
2. Set `plugin.customize.enhance_file` in agent.config, which targets to rule file, such as `/absolute/path/to/customize_enhance.xml`.
3. Set enhancement rules in `customize_enhance.xml`.
```xml
<?xml version="1.0" encoding="UTF-8"?>
<enhanced>
<class class_name="test.apache.skywalking.testcase.customize.service.TestService1">
<method method="staticMethod()" operation_name="/is_static_method" static="true"/>
<method method="staticMethod(java.lang.String,int.class,java.util.Map,java.util.List,[Ljava.lang.Object;)" operation_name="/is_static_method_args" static="true">
<operation_name_suffix>arg[0]</operation_name_suffix>
<operation_name_suffix>arg[1]</operation_name_suffix>
<operation_name_suffix>arg[3].[0]</operation_name_suffix>
<tag key="tag_1">arg[2].['k1']</tag>
<tag key="tag_2">arg[4].[1]</tag>
<log key="log_1">arg[4].[2]</log>
</method>
<method method="method()" static="false"/>
<method method="method(java.lang.String,int.class)" operation_name="/method_2" static="false">
<operation_name_suffix>arg[0]</operation_name_suffix>
<tag key="tag_1">arg[0]</tag>
<log key="log_1">arg[1]</log>
</method>
<method method="method(test.apache.skywalking.testcase.customize.model.Model0,java.lang.String,int.class)" operation_name="/method_3" static="false">
<operation_name_suffix>arg[0].id</operation_name_suffix>
<operation_name_suffix>arg[0].model1.name</operation_name_suffix>
<operation_name_suffix>arg[0].model1.getId()</operation_name_suffix>
<tag key="tag_os">arg[0].os.[1]</tag>
<log key="log_map">arg[0].getM().['k1']</log>
</method>
</class>
<class class_name="test.apache.skywalking.testcase.customize.service.TestService2">
<method method="staticMethod(java.lang.String,int.class)" operation_name="/is_2_static_method" static="true">
<tag key="tag_2_1">arg[0]</tag>
<log key="log_1_1">arg[1]</log>
</method>
<method method="method([Ljava.lang.Object;)" operation_name="/method_4" static="false">
<tag key="tag_4_1">arg[0].[0]</tag>
</method>
<method method="method(java.util.List,int.class)" operation_name="/method_5" static="false">
<tag key="tag_5_1">arg[0].[0]</tag>
<log key="log_5_1">arg[1]</log>
</method>
</class>
</enhanced>
```
- Explanation of the configuration in the file
| configuration | explanation |
|:----------------- |:---------------|
| class_name | The enhanced class |
| method | The interceptor method of the class |
| operation_name | If fill it out, will use it instead of the default operation_name. |
| operation_name\_suffix | What it means adding dynamic data after the operation_name. |
| static | Is this method static. |
| tag | Will add a tag in local span. The value of key needs to be represented on the XML node. |
| log | Will add a log in local span. The value of key needs to be represented on the XML node. |
| arg[x] | What it means is to get the input arguments. such as arg[0] is means get first arguments. |
| .[x] | When the parsing object is Array or List, you can use it to get the object at the specified index. |
| .['key'] | When the parsing object is Map, you can get the map 'key' through it.|
......@@ -94,6 +94,7 @@ Now, we have the following known optional plugins.
* Gson serialization lib in optional plugin folder
* Lettuce 5.x(JRE1.8+) in optional plugin folder
* Zookeeper 3.4.x in optional plugin folder. The reason of being optional plugin is, many business irrelevant traces are generated, which cause extra payload to agents and backends. At the same time, those traces may be just heartbeat(s).
* [Customize enhance](Customize-enhance-trace.md) Trace methods based on description files, rather than write plugin or change source codes.
## Advanced Features
* Set the settings through system properties for config file override. Read [setting override](Setting-override.md).
......
......@@ -38,5 +38,11 @@
<groupId>io.kubernetes</groupId>
<artifactId>client-java</artifactId>
</dependency>
<dependency>
<groupId>org.apache.skywalking</groupId>
<artifactId>server-testing</artifactId>
<version>${project.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
\ No newline at end of file
......@@ -18,13 +18,9 @@
package org.apache.skywalking.oap.server.cluster.plugin.kubernetes;
import org.apache.skywalking.oap.server.cluster.plugin.kubernetes.dependencies.NamespacedPodListWatch;
import org.apache.skywalking.oap.server.cluster.plugin.kubernetes.dependencies.UidEnvSupplier;
import org.apache.skywalking.oap.server.core.cluster.ClusterModule;
import org.apache.skywalking.oap.server.core.cluster.ClusterNodesQuery;
import org.apache.skywalking.oap.server.core.cluster.ClusterRegister;
import org.apache.skywalking.oap.server.cluster.plugin.kubernetes.dependencies.*;
import org.apache.skywalking.oap.server.core.cluster.*;
import org.apache.skywalking.oap.server.library.module.*;
import org.apache.skywalking.oap.server.library.module.ModuleDefine;
/**
* Use kubernetes to manage all instances in Skywalking cluster.
......@@ -34,6 +30,7 @@ import org.apache.skywalking.oap.server.library.module.ModuleDefine;
public class ClusterModuleKubernetesProvider extends ModuleProvider {
private final ClusterModuleKubernetesConfig config;
private KubernetesCoordinator coordinator;
public ClusterModuleKubernetesProvider() {
super();
......@@ -53,7 +50,7 @@ public class ClusterModuleKubernetesProvider extends ModuleProvider {
}
@Override public void prepare() throws ServiceNotProvidedException {
KubernetesCoordinator coordinator = new KubernetesCoordinator(
coordinator = new KubernetesCoordinator(getManager(),
new NamespacedPodListWatch(config.getNamespace(), config.getLabelSelector(), config.getWatchTimeoutSeconds()),
new UidEnvSupplier(config.getUidEnvName()));
this.registerServiceImplementation(ClusterRegister.class, coordinator);
......@@ -65,7 +62,7 @@ public class ClusterModuleKubernetesProvider extends ModuleProvider {
}
@Override public void notifyAfterCompleted() {
coordinator.start();
}
@Override public String[] requiredModules() {
......
......@@ -18,20 +18,22 @@
package org.apache.skywalking.oap.server.cluster.plugin.kubernetes;
import com.google.common.collect.Lists;
import com.google.common.util.concurrent.*;
import java.util.*;
import java.util.concurrent.*;
import java.util.function.Supplier;
import javax.annotation.Nullable;
import org.apache.skywalking.oap.server.core.CoreModule;
import org.apache.skywalking.oap.server.core.cluster.*;
import org.apache.skywalking.oap.server.core.config.ConfigService;
import org.apache.skywalking.oap.server.core.remote.client.Address;
import org.apache.skywalking.oap.server.library.module.ModuleDefineHolder;
import org.apache.skywalking.oap.server.telemetry.api.TelemetryRelatedContext;
import org.slf4j.*;
/**
* Read collector pod info from api-server of kubernetes, then using all containerIp list to
* construct the list of {@link RemoteInstance}.
* Read collector pod info from api-server of kubernetes, then using all containerIp list to construct the list of
* {@link RemoteInstance}.
*
* @author gaohongtao
*/
......@@ -39,26 +41,33 @@ public class KubernetesCoordinator implements ClusterRegister, ClusterNodesQuery
private static final Logger logger = LoggerFactory.getLogger(KubernetesCoordinator.class);
private final ModuleDefineHolder manager;
private final String uid;
private final Map<String, RemoteInstance> cache = new ConcurrentHashMap<>();
private final ReusableWatch<Event> watch;
private int port;
private volatile int port = -1;
KubernetesCoordinator(final ReusableWatch<Event> watch, final Supplier<String> uidSupplier) {
KubernetesCoordinator(ModuleDefineHolder manager,
final ReusableWatch<Event> watch, final Supplier<String> uidSupplier) {
this.manager = manager;
this.watch = watch;
this.uid = uidSupplier.get();
TelemetryRelatedContext.INSTANCE.setId(uid);
}
@Override public void registerRemote(RemoteInstance remoteInstance) throws ServiceRegisterException {
this.port = remoteInstance.getAddress().getPort();
public void start() {
submitTask(MoreExecutors.listeningDecorator(Executors.newSingleThreadExecutor(new ThreadFactoryBuilder()
.setDaemon(true).setNameFormat("Kubernetes-ApiServer-%s").build())));
}
@Override public void registerRemote(RemoteInstance remoteInstance) throws ServiceRegisterException {
this.port = remoteInstance.getAddress().getPort();
}
private void submitTask(final ListeningExecutorService service) {
watch.initOrReset();
ListenableFuture<?> watchFuture = service.submit(newWatch());
......@@ -102,7 +111,19 @@ public class KubernetesCoordinator implements ClusterRegister, ClusterNodesQuery
}
@Override public List<RemoteInstance> queryRemoteNodes() {
logger.debug("Query kubernetes remote nodes: {}", cache);
return Lists.newArrayList(cache.values());
final List<RemoteInstance> list = new ArrayList<>();
cache.values().forEach(instance -> {
Address address = instance.getAddress();
if (port == -1) {
logger.debug("Query kubernetes remote, port hasn't init, try to init");
ConfigService service = manager.find(CoreModule.NAME).provider().getService(ConfigService.class);
port = service.getGRPCPort();
logger.debug("Query kubernetes remote, port is set at {}", port);
}
list.add(new RemoteInstance(new Address(address.getHost(), port, address.isSelf())));
});
logger.debug("Query kubernetes remote nodes: {}", list);
return list;
}
}
......@@ -19,12 +19,18 @@
package org.apache.skywalking.oap.server.cluster.plugin.kubernetes;
import org.apache.skywalking.oap.server.cluster.plugin.kubernetes.fixture.PlainWatch;
import org.apache.skywalking.oap.server.core.*;
import org.apache.skywalking.oap.server.core.cluster.RemoteInstance;
import org.apache.skywalking.oap.server.core.config.ConfigService;
import org.apache.skywalking.oap.server.core.remote.client.Address;
import org.apache.skywalking.oap.server.library.module.ModuleDefineHolder;
import org.apache.skywalking.oap.server.testing.module.*;
import org.junit.Test;
import org.mockito.Mockito;
import static org.hamcrest.core.Is.is;
import static org.junit.Assert.assertThat;
import static org.mockito.Mockito.when;
public class KubernetesCoordinatorTest {
......@@ -33,7 +39,8 @@ public class KubernetesCoordinatorTest {
@Test
public void assertAdded() throws InterruptedException {
PlainWatch watch = PlainWatch.create(2, "ADDED", "1", "10.0.0.1", "ADDED", "2", "10.0.0.2");
coordinator = new KubernetesCoordinator(watch, () -> "1");
coordinator = new KubernetesCoordinator(getManager(), watch, () -> "1");
coordinator.start();
coordinator.registerRemote(new RemoteInstance(new Address("0.0.0.0", 8454, true)));
watch.await();
assertThat(coordinator.queryRemoteNodes().size(), is(2));
......@@ -43,7 +50,8 @@ public class KubernetesCoordinatorTest {
@Test
public void assertModified() throws InterruptedException {
PlainWatch watch = PlainWatch.create(3, "ADDED", "1", "10.0.0.1", "ADDED", "2", "10.0.0.2", "MODIFIED", "1", "10.0.0.3");
coordinator = new KubernetesCoordinator(watch, () -> "1");
coordinator = new KubernetesCoordinator(getManager(), watch, () -> "1");
coordinator.start();
coordinator.registerRemote(new RemoteInstance(new Address("0.0.0.0", 8454, true)));
watch.await();
assertThat(coordinator.queryRemoteNodes().size(), is(2));
......@@ -53,7 +61,8 @@ public class KubernetesCoordinatorTest {
@Test
public void assertDeleted() throws InterruptedException {
PlainWatch watch = PlainWatch.create(3, "ADDED", "1", "10.0.0.1", "ADDED", "2", "10.0.0.2", "DELETED", "2", "10.0.0.2");
coordinator = new KubernetesCoordinator(watch, () -> "1");
coordinator = new KubernetesCoordinator(getManager(), watch, () -> "1");
coordinator.start();
coordinator.registerRemote(new RemoteInstance(new Address("0.0.0.0", 8454, true)));
watch.await();
assertThat(coordinator.queryRemoteNodes().size(), is(1));
......@@ -63,10 +72,52 @@ public class KubernetesCoordinatorTest {
@Test
public void assertError() throws InterruptedException {
PlainWatch watch = PlainWatch.create(3, "ADDED", "1", "10.0.0.1", "ERROR", "X", "10.0.0.2", "ADDED", "2", "10.0.0.2");
coordinator = new KubernetesCoordinator(watch, () -> "1");
coordinator = new KubernetesCoordinator(getManager(), watch, () -> "1");
coordinator.start();
coordinator.registerRemote(new RemoteInstance(new Address("0.0.0.0", 8454, true)));
watch.await();
assertThat(coordinator.queryRemoteNodes().size(), is(2));
assertThat(coordinator.queryRemoteNodes().stream().filter(instance -> instance.getAddress().isSelf()).findFirst().get().getAddress().getHost(), is("10.0.0.1"));
}
@Test
public void assertModifiedInReceiverRole() throws InterruptedException {
PlainWatch watch = PlainWatch.create(3, "ADDED", "1", "10.0.0.1", "ADDED", "2", "10.0.0.2", "MODIFIED", "1", "10.0.0.3");
coordinator = new KubernetesCoordinator(getManager(), watch, () -> "1");
coordinator.start();
watch.await();
assertThat(coordinator.queryRemoteNodes().size(), is(2));
assertThat(coordinator.queryRemoteNodes().stream().filter(instance -> instance.getAddress().isSelf()).findFirst().get().getAddress().getHost(), is("10.0.0.3"));
}
@Test
public void assertDeletedInReceiverRole() throws InterruptedException {
PlainWatch watch = PlainWatch.create(3, "ADDED", "1", "10.0.0.1", "ADDED", "2", "10.0.0.2", "DELETED", "2", "10.0.0.2");
coordinator = new KubernetesCoordinator(getManager(), watch, () -> "1");
coordinator.start();
watch.await();
assertThat(coordinator.queryRemoteNodes().size(), is(1));
assertThat(coordinator.queryRemoteNodes().stream().filter(instance -> instance.getAddress().isSelf()).findFirst().get().getAddress().getHost(), is("10.0.0.1"));
}
@Test
public void assertErrorInReceiverRole() throws InterruptedException {
PlainWatch watch = PlainWatch.create(3, "ADDED", "1", "10.0.0.1", "ERROR", "X", "10.0.0.2", "ADDED", "2", "10.0.0.2");
coordinator = new KubernetesCoordinator(getManager(), watch, () -> "1");
coordinator.start();
watch.await();
assertThat(coordinator.queryRemoteNodes().size(), is(2));
assertThat(coordinator.queryRemoteNodes().stream().filter(instance -> instance.getAddress().isSelf()).findFirst().get().getAddress().getHost(), is("10.0.0.1"));
}
public ModuleDefineHolder getManager() {
ModuleManagerTesting moduleManagerTesting = new ModuleManagerTesting();
ModuleDefineTesting coreModuleDefine = new ModuleDefineTesting();
moduleManagerTesting.put(CoreModule.NAME, coreModuleDefine);
CoreModuleConfig config = Mockito.mock(CoreModuleConfig.class);
when(config.getGRPCHost()).thenReturn("127.0.0.1");
when(config.getGRPCPort()).thenReturn(8454);
coreModuleDefine.provider().registerServiceImplementation(ConfigService.class, new ConfigService(config));
return moduleManagerTesting;
}
}
\ No newline at end of file
......@@ -28,9 +28,8 @@ import org.apache.skywalking.oap.server.core.remote.annotation.StreamDataClassGe
import org.apache.skywalking.oap.server.core.remote.client.RemoteClientManager;
import org.apache.skywalking.oap.server.core.server.*;
import org.apache.skywalking.oap.server.core.source.SourceReceiver;
import org.apache.skywalking.oap.server.core.storage.model.IModelGetter;
import org.apache.skywalking.oap.server.core.storage.model.IModelOverride;
import org.apache.skywalking.oap.server.library.module.*;
import org.apache.skywalking.oap.server.core.storage.model.*;
import org.apache.skywalking.oap.server.library.module.ModuleDefine;
/**
* @author peng-yongsheng
......@@ -45,6 +44,7 @@ public class CoreModule extends ModuleDefine {
@Override public Class[] services() {
List<Class> classes = new ArrayList<>();
classes.add(ConfigService.class);
classes.add(DownsamplingConfigService.class);
classes.add(IComponentLibraryCatalogService.class);
......
......@@ -27,7 +27,7 @@ import org.apache.skywalking.oap.server.library.module.ModuleConfig;
*/
@Getter
public class CoreModuleConfig extends ModuleConfig {
@Setter private String role;
@Setter private String role = "Mixed";
@Setter private String nameSpace;
@Setter private String restHost;
@Setter private int restPort;
......
......@@ -106,6 +106,7 @@ public class CoreModuleProvider extends ModuleProvider {
jettyServer = new JettyServer(moduleConfig.getRestHost(), moduleConfig.getRestPort(), moduleConfig.getRestContextPath(), moduleConfig.getJettySelectors());
jettyServer.initialize();
this.registerServiceImplementation(ConfigService.class, new ConfigService(moduleConfig));
this.registerServiceImplementation(DownsamplingConfigService.class, new DownsamplingConfigService(moduleConfig.getDownsampling()));
this.registerServiceImplementation(GRPCHandlerRegister.class, new GRPCHandlerRegisterImpl(grpcServer));
......@@ -176,7 +177,7 @@ public class CoreModuleProvider extends ModuleProvider {
throw new ModuleStartException(e.getMessage(), e);
}
if (CoreModuleConfig.Role.Mixed.name().equals(moduleConfig.getRole()) || CoreModuleConfig.Role.Aggregator.name().equals(moduleConfig.getRole())) {
if (CoreModuleConfig.Role.Mixed.name().equalsIgnoreCase(moduleConfig.getRole()) || CoreModuleConfig.Role.Aggregator.name().equalsIgnoreCase(moduleConfig.getRole())) {
RemoteInstance gRPCServerInstance = new RemoteInstance(new Address(moduleConfig.getGRPCHost(), moduleConfig.getGRPCPort(), true));
this.getManager().find(ClusterModule.NAME).provider().getService(ClusterRegister.class).registerRemote(gRPCServerInstance);
}
......
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.skywalking.oap.server.core.config;
import lombok.Getter;
import org.apache.skywalking.oap.server.core.CoreModuleConfig;
import org.apache.skywalking.oap.server.library.module.Service;
/**
* @author wusheng
*/
@Getter
public class ConfigService implements Service {
private String gRPCHost;
private int gRPCPort;
public ConfigService(CoreModuleConfig moduleConfig) {
this.gRPCHost = moduleConfig.getGRPCHost();
this.gRPCPort = moduleConfig.getGRPCPort();
}
}
......@@ -28,7 +28,7 @@ import org.apache.skywalking.oap.server.core.Const;
public class Address implements Comparable<Address> {
private final String host;
private final int port;
@Setter private boolean isSelf;
@Setter private volatile boolean isSelf;
public Address(String host, int port, boolean isSelf) {
this.host = host;
......
......@@ -66,10 +66,13 @@ public class MetricServiceGRPCHandler extends MetricsServiceGrpc.MetricsServiceI
private int serviceInstanceId = Const.NONE;
@Override public void onNext(StreamMetricsMessage message) {
if (logger.isDebugEnabled()) {
logger.debug("Received msg {}", message);
}
if (isFirst) {
isFirst = false;
StreamMetricsMessage.Identifier identifier = message.getIdentifier();
logger.debug("Received identifier msg {}", identifier);
Node node = identifier.getNode();
if (node != null) {
String nodeId = node.getId();
......@@ -110,6 +113,20 @@ public class MetricServiceGRPCHandler extends MetricsServiceGrpc.MetricsServiceI
timestamp = metric.getTimestampMs();
value = metric.getGauge().getValue();
if (timestamp > 1000000000000000000L) {
/**
* Several versions of envoy in istio.deps send timestamp in nanoseconds,
* instead of milliseconds(protocol says).
*
* Sadly, but have to fix it forcedly.
*
* An example of timestamp is '1552303033488741055', clearly it is not in milliseconds.
*
* This should be removed in the future.
*/
timestamp /= 1_000_000;
}
EnvoyInstanceMetric metricSource = new EnvoyInstanceMetric();
metricSource.setServiceId(serviceId);
metricSource.setServiceName(serviceName);
......
......@@ -20,7 +20,7 @@ package org.apache.skywalking.oap.server.starter;
import org.apache.skywalking.oap.server.core.RunningMode;
import org.apache.skywalking.oap.server.library.module.*;
import org.apache.skywalking.oap.server.starter.config.*;
import org.apache.skywalking.oap.server.starter.config.ApplicationConfigLoader;
import org.apache.skywalking.oap.server.telemetry.TelemetryModule;
import org.apache.skywalking.oap.server.telemetry.api.*;
import org.slf4j.*;
......@@ -45,14 +45,14 @@ public class OAPServerStartUp {
manager.find(TelemetryModule.NAME).provider().getService(MetricCreator.class).createGauge("uptime",
"oap server start up time", MetricTag.EMPTY_KEY, MetricTag.EMPTY_VALUE)
// Set uptime to second
.setValue(System.currentTimeMillis() / 1000);
.setValue(System.currentTimeMillis() / 1000d);
if (RunningMode.isInitMode()) {
logger.info("OAP starts up in init mode successfully, exit now...");
System.exit(0);
}
} catch (ConfigFileNotFoundException | ModuleNotFoundException | ProviderNotFoundException | ServiceNotProvidedException | ModuleConfigException | ModuleStartException e) {
logger.error(e.getMessage(), e);
} catch (Throwable t) {
logger.error(t.getMessage(), t);
System.exit(1);
}
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册