diff --git a/apm-collector/apm-collector-core/src/main/java/org/skywalking/apm/collector/core/module/ModuleConfigLoader.java b/apm-collector/apm-collector-core/src/main/java/org/skywalking/apm/collector/core/module/ModuleConfigLoader.java index afda1299f3c0a440cc7ee1f274b29e8d4edf8e9e..42238dc8466f4d55e8a8f68a2c2d7041c6fb16a6 100644 --- a/apm-collector/apm-collector-core/src/main/java/org/skywalking/apm/collector/core/module/ModuleConfigLoader.java +++ b/apm-collector/apm-collector-core/src/main/java/org/skywalking/apm/collector/core/module/ModuleConfigLoader.java @@ -19,7 +19,7 @@ package org.skywalking.apm.collector.core.module; import java.io.FileNotFoundException; -import java.io.FileReader; +import java.io.Reader; import java.util.Map; import org.skywalking.apm.collector.core.config.ConfigLoader; import org.skywalking.apm.collector.core.framework.DefineException; @@ -39,8 +39,8 @@ public class ModuleConfigLoader implements ConfigLoader> { Yaml yaml = new Yaml(); try { try { - FileReader applicationFileReader = ResourceUtils.read("application.yml"); - return (Map)yaml.load(applicationFileReader); + Reader applicationReader = ResourceUtils.read("application.yml"); + return (Map)yaml.load(applicationReader); } catch (FileNotFoundException e) { logger.info("Could not found application.yml file, use default"); return (Map)yaml.load(ResourceUtils.read("application-default.yml")); diff --git a/apm-collector/apm-collector-core/src/main/java/org/skywalking/apm/collector/core/util/ResourceUtils.java b/apm-collector/apm-collector-core/src/main/java/org/skywalking/apm/collector/core/util/ResourceUtils.java index 3c86ac494670027042aa542258127e64fbe46112..0ec0f83a4baf14df54e730f32f8449c665e0085a 100644 --- a/apm-collector/apm-collector-core/src/main/java/org/skywalking/apm/collector/core/util/ResourceUtils.java +++ b/apm-collector/apm-collector-core/src/main/java/org/skywalking/apm/collector/core/util/ResourceUtils.java @@ -18,9 +18,10 @@ package org.skywalking.apm.collector.core.util; -import java.io.File; import java.io.FileNotFoundException; -import java.io.FileReader; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; import java.net.URL; /** @@ -28,12 +29,12 @@ import java.net.URL; */ public class ResourceUtils { - public static FileReader read(String fileName) throws FileNotFoundException { + public static Reader read(String fileName) throws FileNotFoundException { URL url = ResourceUtils.class.getClassLoader().getResource(fileName); if (url == null) { throw new FileNotFoundException("file not found: " + fileName); } - File file = new File(ResourceUtils.class.getClassLoader().getResource(fileName).getFile()); - return new FileReader(file); + InputStream inputStream = ResourceUtils.class.getClassLoader().getResourceAsStream(fileName); + return new InputStreamReader(inputStream); } } diff --git a/apm-collector/apm-collector-core/src/test/java/org/skywalking/apm/collector/core/module/ModuleConfigLoaderTestCase.java b/apm-collector/apm-collector-core/src/test/java/org/skywalking/apm/collector/core/module/ModuleConfigLoaderTestCase.java new file mode 100644 index 0000000000000000000000000000000000000000..546e39dcd359d324e68c7293fbab66ee401ec093 --- /dev/null +++ b/apm-collector/apm-collector-core/src/test/java/org/skywalking/apm/collector/core/module/ModuleConfigLoaderTestCase.java @@ -0,0 +1,40 @@ +/* + * Copyright 2017, OpenSkywalking Organization All rights reserved. + * + * Licensed 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 repository: https://github.com/OpenSkywalking/skywalking + */ + +package org.skywalking.apm.collector.core.module; + +import java.util.Map; + +import org.junit.Assert; +import org.junit.Test; +import org.skywalking.apm.collector.core.framework.DefineException; + +/** + * @author neeuq + */ +public class ModuleConfigLoaderTestCase { + + @SuppressWarnings({ "rawtypes" }) + @Test + public void testLoad() throws DefineException { + ModuleConfigLoader configLoader = new ModuleConfigLoader(); + Map configuration = configLoader.load(); + Assert.assertNotNull(configuration.get("cluster")); + Assert.assertNotNull(configuration.get("cluster").get("zookeeper")); + } +} diff --git a/apm-collector/apm-collector-core/src/test/java/org/skywalking/apm/collector/core/utils/ResourceUtilsTestCase.java b/apm-collector/apm-collector-core/src/test/java/org/skywalking/apm/collector/core/utils/ResourceUtilsTestCase.java new file mode 100644 index 0000000000000000000000000000000000000000..851050c1175fbe9d146adc3ead54f3c29060bb37 --- /dev/null +++ b/apm-collector/apm-collector-core/src/test/java/org/skywalking/apm/collector/core/utils/ResourceUtilsTestCase.java @@ -0,0 +1,40 @@ +/* + * Copyright 2017, OpenSkywalking Organization All rights reserved. + * + * Licensed 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 repository: https://github.com/OpenSkywalking/skywalking + */ + +package org.skywalking.apm.collector.core.utils; + +import java.io.IOException; +import java.io.Reader; + +import org.junit.Assert; +import org.junit.Test; +import org.skywalking.apm.collector.core.util.ResourceUtils; + +/** + * @author neeuq + */ +public class ResourceUtilsTestCase { + + @Test + public void testRead() throws IOException { + Reader reader = ResourceUtils.read("application.yml"); + Assert.assertNotNull(reader); + reader.close(); + } + +} diff --git a/apm-sniffer/apm-agent/pom.xml b/apm-sniffer/apm-agent/pom.xml index 8047e216183e0a2a018a2f1b5d83b50b57767982..0291c0377fb67818862b17f6377092d1a3ad1de0 100644 --- a/apm-sniffer/apm-agent/pom.xml +++ b/apm-sniffer/apm-agent/pom.xml @@ -153,6 +153,11 @@ apm-sharding-jdbc-1.5.x-plugin ${project.version} + + org.skywalking + apm-xmemcached-2.x-plugin + ${project.version} + diff --git a/apm-sniffer/apm-sdk-plugin/pom.xml b/apm-sniffer/apm-sdk-plugin/pom.xml index 84ccc21931d6400f536ad2faf3b564f42d9bfb8a..57ac581413913c28cd3faeacb920c552cc1b19af 100644 --- a/apm-sniffer/apm-sdk-plugin/pom.xml +++ b/apm-sniffer/apm-sdk-plugin/pom.xml @@ -46,6 +46,7 @@ jetty-plugin spymemcached-2.x-plugin sharding-jdbc-1.5.x-plugin + xmemcached-2.x-plugin pom diff --git a/apm-sniffer/apm-sdk-plugin/xmemcached-2.x-plugin/pom.xml b/apm-sniffer/apm-sdk-plugin/xmemcached-2.x-plugin/pom.xml new file mode 100644 index 0000000000000000000000000000000000000000..69a4eea0756c60fd802aab4d9b19baea16173b84 --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/xmemcached-2.x-plugin/pom.xml @@ -0,0 +1,52 @@ + + + + 4.0.0 + + org.skywalking + apm-sdk-plugin + 3.2.3-2017 + + + apm-xmemcached-2.x-plugin + xmemcached-2.x-plugin + jar + + + UTF-8 + 2.0.0 + + + + + com.googlecode.xmemcached + xmemcached + ${xmemcached.version} + provided + + + org.apache.logging.log4j + log4j-core + 2.4.1 + test + + + \ No newline at end of file diff --git a/apm-sniffer/apm-sdk-plugin/xmemcached-2.x-plugin/src/main/java/org/skywalking/apm/plugin/xmemcached/v2/XMemcachedConstructorWithComplexArgInterceptor.java b/apm-sniffer/apm-sdk-plugin/xmemcached-2.x-plugin/src/main/java/org/skywalking/apm/plugin/xmemcached/v2/XMemcachedConstructorWithComplexArgInterceptor.java new file mode 100644 index 0000000000000000000000000000000000000000..491f6a9b0c48896be906d922eb1351e5d95d7cac --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/xmemcached-2.x-plugin/src/main/java/org/skywalking/apm/plugin/xmemcached/v2/XMemcachedConstructorWithComplexArgInterceptor.java @@ -0,0 +1,74 @@ +/* + * Copyright 2017, OpenSkywalking Organization All rights reserved. + * + * Licensed 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 repository: https://github.com/OpenSkywalking/skywalking + */ + +package org.skywalking.apm.plugin.xmemcached.v2; + +import java.net.InetSocketAddress; +import java.util.Map; +import java.util.Map.Entry; + +import org.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance; +import org.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceConstructorInterceptor; + +/** + * {@link XMemcachedConstructorWithComplexArgInterceptor} intercept constructor of + * {@link XMemcachedClient(MemcachedSessionLocator locator,BufferAllocator allocator, Configuration conf, + * Map socketOptions, CommandFactory commandFactory, Transcoder transcoder, + * Map addressMap, List stateListeners, + * Map map, int poolSize, long connectTimeout, String name, boolean failureMode)} or + * {@link XMemcachedClient(MemcachedSessionLocator locator, BufferAllocator allocator, Configuration conf, + * Map socketOptions, CommandFactory commandFactory, Transcoder transcoder, + * Map addressMap, int[] weights, List stateListeners, + * Map infoMap, int poolSize, long connectTimeout, final String name, boolean failureMode)}. + * For parameter addressMap, every k-v is a master standby mode. + * + * @author IluckySi + */ +public class XMemcachedConstructorWithComplexArgInterceptor implements InstanceConstructorInterceptor { + + @Override + public void onConstruct(EnhancedInstance objInst, Object[] allArguments) { + StringBuilder memcachConnInfo = new StringBuilder(); + @SuppressWarnings("unchecked") + Map inetSocketAddressMap = (Map)allArguments[6]; + for (Entry entry : inetSocketAddressMap.entrySet()) { + memcachConnInfo = append(memcachConnInfo, entry.getKey()); + memcachConnInfo = append(memcachConnInfo, entry.getValue()); + } + Integer length = memcachConnInfo.length(); + if (length > 1) { + memcachConnInfo = new StringBuilder(memcachConnInfo.substring(0, length - 1)); + } + objInst.setSkyWalkingDynamicField(memcachConnInfo.toString()); + } + + /** + * Parse InetSocketAddress in specified format + * @param sb + * @param inetSocketAddress + * @return + */ + private StringBuilder append(StringBuilder sb, InetSocketAddress inetSocketAddress) { + if (inetSocketAddress != null) { + String host = inetSocketAddress.getAddress().getHostAddress(); + int port = inetSocketAddress.getPort(); + sb.append(host).append(":").append(port).append(";"); + } + return sb; + } +} diff --git a/apm-sniffer/apm-sdk-plugin/xmemcached-2.x-plugin/src/main/java/org/skywalking/apm/plugin/xmemcached/v2/XMemcachedConstructorWithHostPortArgInterceptor.java b/apm-sniffer/apm-sdk-plugin/xmemcached-2.x-plugin/src/main/java/org/skywalking/apm/plugin/xmemcached/v2/XMemcachedConstructorWithHostPortArgInterceptor.java new file mode 100644 index 0000000000000000000000000000000000000000..c2f63fe79a1f8d0f1fb5d2df437c00b296d127dc --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/xmemcached-2.x-plugin/src/main/java/org/skywalking/apm/plugin/xmemcached/v2/XMemcachedConstructorWithHostPortArgInterceptor.java @@ -0,0 +1,39 @@ +/* + * Copyright 2017, OpenSkywalking Organization All rights reserved. + * + * Licensed 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 repository: https://github.com/OpenSkywalking/skywalking + */ + +package org.skywalking.apm.plugin.xmemcached.v2; + +import org.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance; +import org.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceConstructorInterceptor; + +/** + * {@link XMemcachedConstructorWithHostPortArgInterceptor} intercept constructor of + * {@link XMemcachedClient(final String host, final int port)} or + * {@link XMemcachedClient(final String host, final int port, int weight)}. + * + * @author IluckySi + */ +public class XMemcachedConstructorWithHostPortArgInterceptor implements InstanceConstructorInterceptor { + + @Override + public void onConstruct(EnhancedInstance objInst, Object[] allArguments) { + Object host = allArguments[0]; + Object port = allArguments[1]; + objInst.setSkyWalkingDynamicField(host + ":" + port); + } +} \ No newline at end of file diff --git a/apm-sniffer/apm-sdk-plugin/xmemcached-2.x-plugin/src/main/java/org/skywalking/apm/plugin/xmemcached/v2/XMemcachedConstructorWithInetSocketAddressArgInterceptor.java b/apm-sniffer/apm-sdk-plugin/xmemcached-2.x-plugin/src/main/java/org/skywalking/apm/plugin/xmemcached/v2/XMemcachedConstructorWithInetSocketAddressArgInterceptor.java new file mode 100644 index 0000000000000000000000000000000000000000..023fa944539897a0571fc6915c3cdd254697fab8 --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/xmemcached-2.x-plugin/src/main/java/org/skywalking/apm/plugin/xmemcached/v2/XMemcachedConstructorWithInetSocketAddressArgInterceptor.java @@ -0,0 +1,42 @@ +/* + * Copyright 2017, OpenSkywalking Organization All rights reserved. + * + * Licensed 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 repository: https://github.com/OpenSkywalking/skywalking + */ + +package org.skywalking.apm.plugin.xmemcached.v2; + +import java.net.InetSocketAddress; + +import org.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance; +import org.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceConstructorInterceptor; + +/** + * {@link XMemcachedConstructorWithInetSocketAddressArgInterceptor} intercept constructor of + * {@link XMemcachedClient(final InetSocketAddress inetSocketAddress)} or + * {@link XMemcachedClient(final InetSocketAddress inetSocketAddress, int weight)}. + * + * @author IluckySi + */ +public class XMemcachedConstructorWithInetSocketAddressArgInterceptor implements InstanceConstructorInterceptor { + + @Override + public void onConstruct(EnhancedInstance objInst, Object[] allArguments) { + InetSocketAddress inetSocketAddress = (InetSocketAddress)allArguments[0]; + String host = inetSocketAddress.getAddress().getHostAddress(); + int port = inetSocketAddress.getPort(); + objInst.setSkyWalkingDynamicField(host + ":" + port); + } +} \ No newline at end of file diff --git a/apm-sniffer/apm-sdk-plugin/xmemcached-2.x-plugin/src/main/java/org/skywalking/apm/plugin/xmemcached/v2/XMemcachedConstructorWithInetSocketAddressListArgInterceptor.java b/apm-sniffer/apm-sdk-plugin/xmemcached-2.x-plugin/src/main/java/org/skywalking/apm/plugin/xmemcached/v2/XMemcachedConstructorWithInetSocketAddressListArgInterceptor.java new file mode 100644 index 0000000000000000000000000000000000000000..a38111b980345720c3fe737d1f5e345ccd5de99c --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/xmemcached-2.x-plugin/src/main/java/org/skywalking/apm/plugin/xmemcached/v2/XMemcachedConstructorWithInetSocketAddressListArgInterceptor.java @@ -0,0 +1,51 @@ +/* + * Copyright 2017, OpenSkywalking Organization All rights reserved. + * + * Licensed 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 repository: https://github.com/OpenSkywalking/skywalking + */ + +package org.skywalking.apm.plugin.xmemcached.v2; + +import java.net.InetSocketAddress; +import java.util.List; + +import org.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance; +import org.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceConstructorInterceptor; + +/** + * {@link XMemcachedConstructorWithInetSocketAddressListArgInterceptor} intercept constructor of + * {@link XMemcachedClient(List addressList). + * + * @author IluckySi + */ +public class XMemcachedConstructorWithInetSocketAddressListArgInterceptor implements InstanceConstructorInterceptor { + + @Override + public void onConstruct(EnhancedInstance objInst, Object[] allArguments) { + StringBuilder memcachConnInfo = new StringBuilder(); + @SuppressWarnings("unchecked") + List inetSocketAddressList = (List)allArguments[0]; + for (InetSocketAddress inetSocketAddress : inetSocketAddressList) { + String host = inetSocketAddress.getAddress().getHostAddress(); + int port = inetSocketAddress.getPort(); + memcachConnInfo.append(host).append(":").append(port).append(";"); + } + int length = memcachConnInfo.length(); + if (length > 1) { + memcachConnInfo = new StringBuilder(memcachConnInfo.substring(0, length - 1)); + } + objInst.setSkyWalkingDynamicField(memcachConnInfo.toString()); + } +} \ No newline at end of file diff --git a/apm-sniffer/apm-sdk-plugin/xmemcached-2.x-plugin/src/main/java/org/skywalking/apm/plugin/xmemcached/v2/XMemcachedMethodInterceptor.java b/apm-sniffer/apm-sdk-plugin/xmemcached-2.x-plugin/src/main/java/org/skywalking/apm/plugin/xmemcached/v2/XMemcachedMethodInterceptor.java new file mode 100644 index 0000000000000000000000000000000000000000..77fb444406ae9ff354d4f399dcb979d4edf2c80e --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/xmemcached-2.x-plugin/src/main/java/org/skywalking/apm/plugin/xmemcached/v2/XMemcachedMethodInterceptor.java @@ -0,0 +1,64 @@ +/* + * Copyright 2017, OpenSkywalking Organization All rights reserved. + * + * Licensed 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 repository: https://github.com/OpenSkywalking/skywalking + */ + +package org.skywalking.apm.plugin.xmemcached.v2; + +import java.lang.reflect.Method; + +import org.skywalking.apm.agent.core.context.ContextManager; +import org.skywalking.apm.agent.core.context.tag.Tags; +import org.skywalking.apm.agent.core.context.trace.AbstractSpan; +import org.skywalking.apm.agent.core.context.trace.SpanLayer; +import org.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance; +import org.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor; +import org.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult; +import org.skywalking.apm.network.trace.component.ComponentsDefine; + +/** + * {@link XMemcachedMethodInterceptor} intercept the operation method, + * record the memcached host, operation name and the key of the operation. + * + * @author IluckySi + */ +public class XMemcachedMethodInterceptor implements InstanceMethodsAroundInterceptor { + + private static final String XMEMCACHED = "XMemcached/"; + + @Override public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, + Class[] argumentsTypes, MethodInterceptResult result) throws Throwable { + String peer = String.valueOf(objInst.getSkyWalkingDynamicField()); + AbstractSpan span = ContextManager.createExitSpan(XMEMCACHED + method.getName(), peer); + span.setComponent(ComponentsDefine.MEMCACHED); + Tags.DB_TYPE.set(span, ComponentsDefine.MEMCACHED.getName()); + SpanLayer.asDB(span); + Tags.DB_STATEMENT.set(span, method.getName() + " " + allArguments[0]); + } + + @Override public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, + Class[] argumentsTypes, Object ret) throws Throwable { + ContextManager.stopSpan(); + return ret; + } + + @Override public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments, + Class[] argumentsTypes, Throwable t) { + AbstractSpan span = ContextManager.activeSpan(); + span.errorOccurred(); + span.log(t); + } +} diff --git a/apm-sniffer/apm-sdk-plugin/xmemcached-2.x-plugin/src/main/java/org/skywalking/apm/plugin/xmemcached/v2/define/XMemcachedInstrumentation.java b/apm-sniffer/apm-sdk-plugin/xmemcached-2.x-plugin/src/main/java/org/skywalking/apm/plugin/xmemcached/v2/define/XMemcachedInstrumentation.java new file mode 100644 index 0000000000000000000000000000000000000000..8a6fb3ea5d7de3b90fc6c35a09723e31dec5ad1e --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/xmemcached-2.x-plugin/src/main/java/org/skywalking/apm/plugin/xmemcached/v2/define/XMemcachedInstrumentation.java @@ -0,0 +1,135 @@ +/* + * Copyright 2017, OpenSkywalking Organization All rights reserved. + * + * Licensed 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 repository: https://github.com/OpenSkywalking/skywalking + */ + +package org.skywalking.apm.plugin.xmemcached.v2.define; + +import java.net.InetSocketAddress; +import java.util.List; +import java.util.Map; + +import net.bytebuddy.description.method.MethodDescription; +import net.bytebuddy.matcher.ElementMatcher; +import org.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint; +import org.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint; +import org.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine; +import org.skywalking.apm.agent.core.plugin.match.ClassMatch; + +import static net.bytebuddy.matcher.ElementMatchers.named; +import static net.bytebuddy.matcher.ElementMatchers.takesArgument; +import static net.bytebuddy.matcher.ElementMatchers.takesArguments; +import static org.skywalking.apm.agent.core.plugin.match.NameMatch.byName; + +/** + * {@link MemcachedInstrumentation} presents that skywalking intercept all constructors and methods of + * {@link net.rubyeye.xmemcached.XMemcachedClient}. + * {@link XMemcachedConstructorWithHostPortArgInterceptor} intercepts the constructor with + * ip and port arguments. + * {@link XMemcachedConstructorWithInetSocketAddressArgInterceptor} intercepts the constructor with + * argument {@link java.net.InetSocketAddress}. + * {@link XMemcachedConstructorWithInetSocketAddressListArgInterceptor} intercepts the constructor with + * argument {@link java.net.InetSocketAddress}. + * {@link XMemcachedConstructorWithComplexArgInterceptor} intercepts the constructor with complex arguments. + * + * @author IluckySi + */ +public class XMemcachedInstrumentation extends ClassInstanceMethodsEnhancePluginDefine { + + private static final String ENHANCE_CLASS = "net.rubyeye.xmemcached.XMemcachedClient"; + private static final String CONSTRUCTOR_WITH_HOSTPORT_ARG_INTERCEPT_CLASS = "org.skywalking.apm.plugin.xmemcached.v2.XMemcachedConstructorWithHostPortArgInterceptor"; + private static final String CONSTRUCTOR_WITH_INETSOCKETADDRESS_ARG_INTERCEPT_CLASS = "org.skywalking.apm.plugin.xmemcached.v2.XMemcachedConstructorWithInetSocketAddressArgInterceptor"; + private static final String CONSTRUCTOR_WITH_INETSOCKETADDRESS_LIST_ARG_INTERCEPT_CLASS = "org.skywalking.apm.plugin.xmemcached.v2.XMemcachedConstructorWithInetSocketAddressListArgInterceptor"; + private static final String CONSTRUCTOR_WITH_COMPLEX_ARG_INTERCEPT_CLASS = "org.skywalking.apm.plugin.xmemcached.v2.XMemcachedConstructorWithComplexArgInterceptor"; + private static final String METHOD_INTERCEPT_CLASS = "org.skywalking.apm.plugin.xmemcached.v2.XMemcachedMethodInterceptor"; + + @Override + public ClassMatch enhanceClass() { + return byName(ENHANCE_CLASS); + } + @Override + protected ConstructorInterceptPoint[] getConstructorsInterceptPoints() { + return new ConstructorInterceptPoint[] { + new ConstructorInterceptPoint() { + @Override + public ElementMatcher getConstructorMatcher() { + return takesArguments(String.class, int.class); + } + + @Override + public String getConstructorInterceptor() { + return CONSTRUCTOR_WITH_HOSTPORT_ARG_INTERCEPT_CLASS; + } + }, + new ConstructorInterceptPoint() { + @Override + public ElementMatcher getConstructorMatcher() { + return takesArgument(0, InetSocketAddress.class); + } + + @Override + public String getConstructorInterceptor() { + return CONSTRUCTOR_WITH_INETSOCKETADDRESS_ARG_INTERCEPT_CLASS; + } + }, + new ConstructorInterceptPoint() { + @Override + public ElementMatcher getConstructorMatcher() { + return takesArgument(0, List.class); + } + + @Override + public String getConstructorInterceptor() { + return CONSTRUCTOR_WITH_INETSOCKETADDRESS_LIST_ARG_INTERCEPT_CLASS; + } + }, + new ConstructorInterceptPoint() { + @Override + public ElementMatcher getConstructorMatcher() { + return takesArgument(6, Map.class); + } + + @Override + public String getConstructorInterceptor() { + return CONSTRUCTOR_WITH_COMPLEX_ARG_INTERCEPT_CLASS; + } + } + }; + } + + @Override + protected InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() { + return new InstanceMethodsInterceptPoint[] { + new InstanceMethodsInterceptPoint() { + @Override + public ElementMatcher getMethodsMatcher() { + return named("get").or(named("set")) .or(named("add")).or(named("replace")).or(named("gets")) + .or(named("append")) .or(named("prepend")).or(named("cas")).or(named("delete")).or(named("touch")). + or(named("getAndTouch")).or(named("incr")) .or(named("decr")); + } + + @Override + public String getMethodsInterceptor() { + return METHOD_INTERCEPT_CLASS; + } + + @Override public boolean isOverrideArgs() { + return false; + } + } + }; + } +} diff --git a/apm-sniffer/apm-sdk-plugin/xmemcached-2.x-plugin/src/main/resources/skywalking-plugin.def b/apm-sniffer/apm-sdk-plugin/xmemcached-2.x-plugin/src/main/resources/skywalking-plugin.def new file mode 100644 index 0000000000000000000000000000000000000000..c04b8817ba5a3fd072f92ba3449b81e5e51cb81e --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/xmemcached-2.x-plugin/src/main/resources/skywalking-plugin.def @@ -0,0 +1 @@ +memcache-2.x=org.skywalking.apm.plugin.xmemcached.v2.define.XMemcachedInstrumentation \ No newline at end of file diff --git a/apm-sniffer/apm-sdk-plugin/xmemcached-2.x-plugin/src/test/java/org/skywalking/apm/plugin/xmemcached/v2/XMemcachedConstructorWithComplexArgInterceptorTest.java b/apm-sniffer/apm-sdk-plugin/xmemcached-2.x-plugin/src/test/java/org/skywalking/apm/plugin/xmemcached/v2/XMemcachedConstructorWithComplexArgInterceptorTest.java new file mode 100644 index 0000000000000000000000000000000000000000..6615eee2f742aef5823c9fe7a84a92cbd7ac7cb5 --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/xmemcached-2.x-plugin/src/test/java/org/skywalking/apm/plugin/xmemcached/v2/XMemcachedConstructorWithComplexArgInterceptorTest.java @@ -0,0 +1,56 @@ +/* + * Copyright 2017, OpenSkywalking Organization All rights reserved. + * + * Licensed 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 repository: https://github.com/OpenSkywalking/skywalking + */ + +package org.skywalking.apm.plugin.xmemcached.v2; + +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +import java.net.InetSocketAddress; +import java.util.HashMap; +import java.util.Map; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.runners.MockitoJUnitRunner; +import org.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance; + +@RunWith(MockitoJUnitRunner.class) +public class XMemcachedConstructorWithComplexArgInterceptorTest { + + private XMemcachedConstructorWithComplexArgInterceptor interceptor; + + @Mock + private EnhancedInstance enhancedInstance; + + @Before + public void setUp() throws Exception { + interceptor = new XMemcachedConstructorWithComplexArgInterceptor(); + } + + @Test + public void onConstructWithComplex() { + Map inetSocketAddressMap = new HashMap(); + inetSocketAddressMap.put(new InetSocketAddress("127.0.0.1", 11211), new InetSocketAddress("127.0.0.2", 11211)); + interceptor.onConstruct(enhancedInstance, new Object[]{null, null, null, null, null, null, inetSocketAddressMap}); + + verify(enhancedInstance, times(1)).setSkyWalkingDynamicField("127.0.0.1:11211;127.0.0.2:11211"); + } +} \ No newline at end of file diff --git a/apm-sniffer/apm-sdk-plugin/xmemcached-2.x-plugin/src/test/java/org/skywalking/apm/plugin/xmemcached/v2/XMemcachedConstructorWithHostPortArgInterceptorTest.java b/apm-sniffer/apm-sdk-plugin/xmemcached-2.x-plugin/src/test/java/org/skywalking/apm/plugin/xmemcached/v2/XMemcachedConstructorWithHostPortArgInterceptorTest.java new file mode 100644 index 0000000000000000000000000000000000000000..ae8101e19a4efb5f188e698be4bd7f7e8aff9985 --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/xmemcached-2.x-plugin/src/test/java/org/skywalking/apm/plugin/xmemcached/v2/XMemcachedConstructorWithHostPortArgInterceptorTest.java @@ -0,0 +1,50 @@ +/* + * Copyright 2017, OpenSkywalking Organization All rights reserved. + * + * Licensed 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 repository: https://github.com/OpenSkywalking/skywalking + */ + +package org.skywalking.apm.plugin.xmemcached.v2; + +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.runners.MockitoJUnitRunner; +import org.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance; + +@RunWith(MockitoJUnitRunner.class) +public class XMemcachedConstructorWithHostPortArgInterceptorTest { + + private XMemcachedConstructorWithHostPortArgInterceptor interceptor; + + @Mock + private EnhancedInstance enhancedInstance; + + @Before + public void setUp() throws Exception { + interceptor = new XMemcachedConstructorWithHostPortArgInterceptor(); + } + + @Test + public void onConstructWithHostPort() { + interceptor.onConstruct(enhancedInstance, new Object[]{"127.0.0.1", 11211}); + + verify(enhancedInstance, times(1)).setSkyWalkingDynamicField("127.0.0.1:11211"); + } +} \ No newline at end of file diff --git a/apm-sniffer/apm-sdk-plugin/xmemcached-2.x-plugin/src/test/java/org/skywalking/apm/plugin/xmemcached/v2/XMemcachedConstructorWithInetSocketAddressArgInterceptorTest.java b/apm-sniffer/apm-sdk-plugin/xmemcached-2.x-plugin/src/test/java/org/skywalking/apm/plugin/xmemcached/v2/XMemcachedConstructorWithInetSocketAddressArgInterceptorTest.java new file mode 100644 index 0000000000000000000000000000000000000000..f83178ba9261f5acb58b5c52125743d3df941969 --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/xmemcached-2.x-plugin/src/test/java/org/skywalking/apm/plugin/xmemcached/v2/XMemcachedConstructorWithInetSocketAddressArgInterceptorTest.java @@ -0,0 +1,52 @@ +/* + * Copyright 2017, OpenSkywalking Organization All rights reserved. + * + * Licensed 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 repository: https://github.com/OpenSkywalking/skywalking + */ + +package org.skywalking.apm.plugin.xmemcached.v2; + +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +import java.net.InetSocketAddress; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.runners.MockitoJUnitRunner; +import org.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance; + +@RunWith(MockitoJUnitRunner.class) +public class XMemcachedConstructorWithInetSocketAddressArgInterceptorTest { + + private XMemcachedConstructorWithInetSocketAddressArgInterceptor interceptor; + + @Mock + private EnhancedInstance enhancedInstance; + + @Before + public void setUp() throws Exception { + interceptor = new XMemcachedConstructorWithInetSocketAddressArgInterceptor(); + } + + @Test + public void onConstructWithInetSocketAddress() { + interceptor.onConstruct(enhancedInstance, new Object[]{new InetSocketAddress("127.0.0.1", 11211)}); + + verify(enhancedInstance, times(1)).setSkyWalkingDynamicField("127.0.0.1:11211"); + } +} \ No newline at end of file diff --git a/apm-sniffer/apm-sdk-plugin/xmemcached-2.x-plugin/src/test/java/org/skywalking/apm/plugin/xmemcached/v2/XMemcachedConstructorWithInetSocketAddressListArgInterceptorTest.java b/apm-sniffer/apm-sdk-plugin/xmemcached-2.x-plugin/src/test/java/org/skywalking/apm/plugin/xmemcached/v2/XMemcachedConstructorWithInetSocketAddressListArgInterceptorTest.java new file mode 100644 index 0000000000000000000000000000000000000000..0e4a96ca67428982093b4c302269a71b932df36c --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/xmemcached-2.x-plugin/src/test/java/org/skywalking/apm/plugin/xmemcached/v2/XMemcachedConstructorWithInetSocketAddressListArgInterceptorTest.java @@ -0,0 +1,57 @@ +/* + * Copyright 2017, OpenSkywalking Organization All rights reserved. + * + * Licensed 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 repository: https://github.com/OpenSkywalking/skywalking + */ + +package org.skywalking.apm.plugin.xmemcached.v2; + +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +import java.net.InetSocketAddress; +import java.util.ArrayList; +import java.util.List; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.runners.MockitoJUnitRunner; +import org.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance; + +@RunWith(MockitoJUnitRunner.class) +public class XMemcachedConstructorWithInetSocketAddressListArgInterceptorTest { + + private XMemcachedConstructorWithInetSocketAddressListArgInterceptor interceptor; + + @Mock + private EnhancedInstance enhancedInstance; + + @Before + public void setUp() throws Exception { + interceptor = new XMemcachedConstructorWithInetSocketAddressListArgInterceptor(); + } + + @Test + public void onConstructWithInetSocketAddressList() { + List inetSocketAddressList = new ArrayList(); + inetSocketAddressList.add(new InetSocketAddress("127.0.0.1", 11211)); + inetSocketAddressList.add(new InetSocketAddress("127.0.0.2", 11211)); + interceptor.onConstruct(enhancedInstance, new Object[]{inetSocketAddressList}); + + verify(enhancedInstance, times(1)).setSkyWalkingDynamicField("127.0.0.1:11211;127.0.0.2:11211"); + } +} \ No newline at end of file diff --git a/apm-sniffer/apm-sdk-plugin/xmemcached-2.x-plugin/src/test/java/org/skywalking/apm/plugin/xmemcached/v2/XMemcachedMethodInterceptorTest.java b/apm-sniffer/apm-sdk-plugin/xmemcached-2.x-plugin/src/test/java/org/skywalking/apm/plugin/xmemcached/v2/XMemcachedMethodInterceptorTest.java new file mode 100644 index 0000000000000000000000000000000000000000..96f66d25ee62f9595926b5d2e3ffd185103b7c12 --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/xmemcached-2.x-plugin/src/test/java/org/skywalking/apm/plugin/xmemcached/v2/XMemcachedMethodInterceptorTest.java @@ -0,0 +1,131 @@ +/* + * Copyright 2017, OpenSkywalking Organization All rights reserved. + * + * Licensed 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 repository: https://github.com/OpenSkywalking/skywalking + */ + +package org.skywalking.apm.plugin.xmemcached.v2; + +import static junit.framework.TestCase.assertNotNull; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.mockito.Mockito.when; + +import java.lang.reflect.Method; +import java.util.List; + +import org.hamcrest.CoreMatchers; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.powermock.modules.junit4.PowerMockRunner; +import org.powermock.modules.junit4.PowerMockRunnerDelegate; +import org.skywalking.apm.agent.core.context.trace.AbstractTracingSpan; +import org.skywalking.apm.agent.core.context.trace.LogDataEntity; +import org.skywalking.apm.agent.core.context.trace.SpanLayer; +import org.skywalking.apm.agent.core.context.trace.TraceSegment; +import org.skywalking.apm.agent.core.context.util.KeyValuePair; +import org.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance; +import org.skywalking.apm.agent.test.helper.SegmentHelper; +import org.skywalking.apm.agent.test.helper.SpanHelper; +import org.skywalking.apm.agent.test.tools.AgentServiceRule; +import org.skywalking.apm.agent.test.tools.SegmentStorage; +import org.skywalking.apm.agent.test.tools.SegmentStoragePoint; +import org.skywalking.apm.agent.test.tools.TracingSegmentRunner; + +import net.rubyeye.xmemcached.XMemcachedClient; + +@RunWith(PowerMockRunner.class) +@PowerMockRunnerDelegate(TracingSegmentRunner.class) +public class XMemcachedMethodInterceptorTest { + + @SegmentStoragePoint + private SegmentStorage segmentStorage; + + @Rule + public AgentServiceRule serviceRule = new AgentServiceRule(); + + @Mock + private EnhancedInstance enhancedInstance; + private XMemcachedMethodInterceptor interceptor; + + private Object[] allArgument; + private Class[] argumentType; + + @Before + public void setUp() throws Exception { + allArgument = new Object[] {"OperationKey", "OperationValue"}; + argumentType = new Class[] {String.class, String.class}; + + interceptor = new XMemcachedMethodInterceptor(); + when(enhancedInstance.getSkyWalkingDynamicField()).thenReturn("127.0.0.1:11211"); + } + + @Test + public void testIntercept() throws Throwable { + interceptor.beforeMethod(enhancedInstance, getMockSetMethod(), allArgument, argumentType, null); + interceptor.afterMethod(enhancedInstance, getMockGetMethod(), allArgument, argumentType, null); + + TraceSegment traceSegment = segmentStorage.getTraceSegments().get(0); + List spans = SegmentHelper.getSpans(traceSegment); + assertThat(spans.size(), is(1)); + assertMemcacheSpan(spans.get(0)); + } + + @Test + public void testInterceptWithException() throws Throwable { + interceptor.beforeMethod(enhancedInstance, getMockSetMethod(), allArgument, argumentType, null); + interceptor.handleMethodException(enhancedInstance, getMockSetMethod(), allArgument, argumentType, new RuntimeException()); + interceptor.afterMethod(enhancedInstance, getMockSetMethod(), allArgument, argumentType, null); + + TraceSegment traceSegment = segmentStorage.getTraceSegments().get(0); + List spans = SegmentHelper.getSpans(traceSegment); + assertThat(spans.size(), is(1)); + assertMemcacheSpan(spans.get(0)); + + assertLogData(SpanHelper.getLogs(spans.get(0))); + } + + private void assertLogData(List logDataEntities) { + assertThat(logDataEntities.size(), is(1)); + LogDataEntity logData = logDataEntities.get(0); + Assert.assertThat(logData.getLogs().size(), is(4)); + Assert.assertThat(logData.getLogs().get(0).getValue(), CoreMatchers.is("error")); + Assert.assertThat(logData.getLogs().get(1).getValue(), CoreMatchers.is(RuntimeException.class.getName())); + Assert.assertNull(logData.getLogs().get(2).getValue()); + assertNotNull(logData.getLogs().get(3).getValue()); + } + + private void assertMemcacheSpan(AbstractTracingSpan span) { + assertThat(span.getOperationName(), is("XMemcached/set")); + assertThat(span.isExit(), is(true)); + assertThat(SpanHelper.getComponentId(span), is(20)); + List tags = SpanHelper.getTags(span); + assertThat(tags.get(0).getValue(), is("Memcached")); + assertThat(tags.get(1).getValue(), is("set OperationKey")); + assertThat(SpanHelper.getLayer(span), is(SpanLayer.DB)); + } + + private Method getMockSetMethod() throws Exception { + return XMemcachedClient.class.getMethod("set", String.class, int.class, Object.class); + } + + private Method getMockGetMethod() throws Exception { + return XMemcachedClient.class.getMethod("get", String.class); + } +} \ No newline at end of file