From 21cf6f89e4ad52f90f8f2d119a2df2502056b8cb Mon Sep 17 00:00:00 2001 From: wusheng Date: Thu, 23 Nov 2017 19:00:58 +0800 Subject: [PATCH 01/15] Make travis maven runs in quiet mode. --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 40ba9d4d5..5dab876a9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,8 +6,8 @@ services: language: java install: - jdk_switcher use oraclejdk8 - - mvn clean install + - mvn clean install --quiet after_success: - - mvn clean test jacoco:report coveralls:report + - mvn clean test --quiet jacoco:report coveralls:report - bash ./travis/push_image.sh From d35bcbabd68d8c24ed9d18a364ab0bee223c1f98 Mon Sep 17 00:00:00 2001 From: wusheng Date: Thu, 23 Nov 2017 19:43:07 +0800 Subject: [PATCH 02/15] Do the test report inside `mvn install`. --- .travis.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 5dab876a9..540b9e8f0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,8 +6,7 @@ services: language: java install: - jdk_switcher use oraclejdk8 - - mvn clean install --quiet + - mvn clean install --quiet jacoco:report coveralls:report after_success: - - mvn clean test --quiet jacoco:report coveralls:report - bash ./travis/push_image.sh From 931effb6486e844c46ef5d2ffa91cda538b69dea Mon Sep 17 00:00:00 2001 From: wu-sheng Date: Mon, 27 Nov 2017 16:32:51 +0800 Subject: [PATCH 03/15] Output all instrumented classes into physical files. --- .../apm/agent/core/conf/Config.java | 6 ++ .../apm/agent/InstrumentDebuggingClass.java | 92 +++++++++++++++++++ .../skywalking/apm/agent/SkyWalkingAgent.java | 15 ++- apm-sniffer/config/agent.config | 4 + 4 files changed, 112 insertions(+), 5 deletions(-) create mode 100644 apm-sniffer/apm-agent/src/main/java/org/skywalking/apm/agent/InstrumentDebuggingClass.java diff --git a/apm-sniffer/apm-agent-core/src/main/java/org/skywalking/apm/agent/core/conf/Config.java b/apm-sniffer/apm-agent-core/src/main/java/org/skywalking/apm/agent/core/conf/Config.java index 77ac2a807..a6f661eaf 100644 --- a/apm-sniffer/apm-agent-core/src/main/java/org/skywalking/apm/agent/core/conf/Config.java +++ b/apm-sniffer/apm-agent-core/src/main/java/org/skywalking/apm/agent/core/conf/Config.java @@ -52,6 +52,12 @@ public class Config { * memory cost estimated. */ public static int SPAN_LIMIT_PER_SEGMENT = 300; + + /** + * If true, skywalking agent will save all instrumented classes files. And you can send them to skywalking team, + * in order to resolve compatible problem. + */ + public static boolean IS_OPEN_DEBUGGING_CLASS = false; } public static class Collector { diff --git a/apm-sniffer/apm-agent/src/main/java/org/skywalking/apm/agent/InstrumentDebuggingClass.java b/apm-sniffer/apm-agent/src/main/java/org/skywalking/apm/agent/InstrumentDebuggingClass.java new file mode 100644 index 000000000..96173f5c5 --- /dev/null +++ b/apm-sniffer/apm-agent/src/main/java/org/skywalking/apm/agent/InstrumentDebuggingClass.java @@ -0,0 +1,92 @@ +/* + * 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.agent; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.dynamic.DynamicType; +import org.skywalking.apm.agent.core.boot.AgentPackageNotFoundException; +import org.skywalking.apm.agent.core.boot.AgentPackagePath; +import org.skywalking.apm.agent.core.conf.Config; +import org.skywalking.apm.agent.core.logging.api.ILog; +import org.skywalking.apm.agent.core.logging.api.LogManager; + +/** + * @author wu-sheng + */ +public enum InstrumentDebuggingClass { + INSTANCE; + + private static final ILog logger = LogManager.getLogger(InstrumentDebuggingClass.class); + private File debuggingClassesRootPath; + + public void log(TypeDescription typeDescription, DynamicType dynamicType) { + if (!Config.Agent.IS_OPEN_DEBUGGING_CLASS) { + return; + } + + /** + * try to do I/O things in synchronized way, to avoid unexpected situations. + */ + synchronized (INSTANCE) { + try { + if (debuggingClassesRootPath == null) { + try { + debuggingClassesRootPath = new File(AgentPackagePath.getPath(), "/debugging"); + if (!debuggingClassesRootPath.exists()) { + debuggingClassesRootPath.mkdir(); + } + } catch (AgentPackageNotFoundException e) { + logger.error(e, "Can't find the root path for creating /debugging folder."); + } + } + + File newClassFileFolder = new File(debuggingClassesRootPath, typeDescription.getPackage().getActualName().replaceAll("\\.", "/")); + if (!newClassFileFolder.exists()) { + newClassFileFolder.mkdirs(); + } + File newClassFile = new File(newClassFileFolder, typeDescription.getSimpleName() + ".class"); + FileOutputStream fos = null; + try { + if (newClassFile.exists()) { + newClassFile.delete(); + } + newClassFile.createNewFile(); + fos = new FileOutputStream(newClassFile); + fos.write(dynamicType.getBytes()); + fos.flush(); + } catch (IOException e) { + logger.error(e, "Can't save class {} to file." + typeDescription.getActualName()); + } finally { + if (fos != null) { + try { + fos.close(); + } catch (IOException e) { + + } + } + } + } catch (Throwable t) { + logger.error(t, "Save debugging classes fail."); + } + } + } +} diff --git a/apm-sniffer/apm-agent/src/main/java/org/skywalking/apm/agent/SkyWalkingAgent.java b/apm-sniffer/apm-agent/src/main/java/org/skywalking/apm/agent/SkyWalkingAgent.java index 766191c2e..7a75978e5 100644 --- a/apm-sniffer/apm-agent/src/main/java/org/skywalking/apm/agent/SkyWalkingAgent.java +++ b/apm-sniffer/apm-agent/src/main/java/org/skywalking/apm/agent/SkyWalkingAgent.java @@ -18,6 +18,8 @@ package org.skywalking.apm.agent; +import java.lang.instrument.Instrumentation; +import java.util.List; import net.bytebuddy.agent.builder.AgentBuilder; import net.bytebuddy.description.type.TypeDescription; import net.bytebuddy.dynamic.DynamicType; @@ -26,10 +28,11 @@ import org.skywalking.apm.agent.core.boot.ServiceManager; import org.skywalking.apm.agent.core.conf.SnifferConfigInitializer; import org.skywalking.apm.agent.core.logging.api.ILog; import org.skywalking.apm.agent.core.logging.api.LogManager; -import org.skywalking.apm.agent.core.plugin.*; - -import java.lang.instrument.Instrumentation; -import java.util.List; +import org.skywalking.apm.agent.core.plugin.AbstractClassEnhancePluginDefine; +import org.skywalking.apm.agent.core.plugin.EnhanceContext; +import org.skywalking.apm.agent.core.plugin.PluginBootstrap; +import org.skywalking.apm.agent.core.plugin.PluginException; +import org.skywalking.apm.agent.core.plugin.PluginFinder; /** * The main entrance of sky-waking agent, @@ -103,6 +106,8 @@ public class SkyWalkingAgent { if (logger.isDebugEnable()) { logger.debug("On Transformation class {}.", typeDescription.getName()); } + + InstrumentDebuggingClass.INSTANCE.log(typeDescription, dynamicType); } @Override @@ -113,7 +118,7 @@ public class SkyWalkingAgent { @Override public void onError(String typeName, ClassLoader classLoader, JavaModule module, boolean loaded, Throwable throwable) { - logger.error("Failed to enhance class " + typeName, throwable); + logger.error("Enhance class " + typeName + " error.", throwable); } @Override diff --git a/apm-sniffer/config/agent.config b/apm-sniffer/config/agent.config index d85abb433..252d013ff 100644 --- a/apm-sniffer/config/agent.config +++ b/apm-sniffer/config/agent.config @@ -12,6 +12,10 @@ agent.application_code=Your_ApplicationName # Ignore the segments if their operation names start with these suffix. # agent.ignore_suffix=.jpg,.jpeg,.js,.css,.png,.bmp,.gif,.ico,.mp3,.mp4,.html,.svg +# If true, skywalking agent will save all instrumented classes files. And you can send them to skywalking team, +# in order to resolve compatible problem. +# agent.is_open_debugging_class = true + # Server addresses. # Mapping to `agent_server/jetty/port` in `config/application.yml` of Collector. # Examples: From 6a4a18a721ae3b8ca9a3e9789b0336402cf30f2d Mon Sep 17 00:00:00 2001 From: wu-sheng Date: Mon, 27 Nov 2017 16:56:22 +0800 Subject: [PATCH 04/15] Add documents about new config item. --- apm-sniffer/config/agent.config | 4 ++-- docs/cn/Deploy-skywalking-agent-CN.md | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/apm-sniffer/config/agent.config b/apm-sniffer/config/agent.config index 252d013ff..8616a4b04 100644 --- a/apm-sniffer/config/agent.config +++ b/apm-sniffer/config/agent.config @@ -12,8 +12,8 @@ agent.application_code=Your_ApplicationName # Ignore the segments if their operation names start with these suffix. # agent.ignore_suffix=.jpg,.jpeg,.js,.css,.png,.bmp,.gif,.ico,.mp3,.mp4,.html,.svg -# If true, skywalking agent will save all instrumented classes files. And you can send them to skywalking team, -# in order to resolve compatible problem. +# If true, skywalking agent will save all instrumented classes files in `/debugging` folder. +# Skywalking team may ask for these files in order to resolve compatible problem. # agent.is_open_debugging_class = true # Server addresses. diff --git a/docs/cn/Deploy-skywalking-agent-CN.md b/docs/cn/Deploy-skywalking-agent-CN.md index d95db9c7a..976c0e503 100644 --- a/docs/cn/Deploy-skywalking-agent-CN.md +++ b/docs/cn/Deploy-skywalking-agent-CN.md @@ -38,6 +38,10 @@ agent.application_code=Your_ApplicationName # 默认配置如下 # agent.ignore_suffix=.jpg,.jpeg,.js,.css,.png,.bmp,.gif,.ico,.mp3,.mp4,.html,.svg +# 探针调试开关,如果设置为true,探针会将所有操作字节码的类输出到/debugging目录下 +# skywalking团队可能在调试,需要此文件 +# agent.is_open_debugging_class = true + # 对应Collector的config/application.yml配置文件中 agent_server/jetty/port 配置内容 # 例如: # 单节点配置:SERVERS="127.0.0.1:8080" From b53c178b498ef6dbe41053a49e931ac3ad8d4014 Mon Sep 17 00:00:00 2001 From: wu-sheng Date: Mon, 27 Nov 2017 16:57:55 +0800 Subject: [PATCH 05/15] Add comments for new config item. --- .../main/java/org/skywalking/apm/agent/core/conf/Config.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apm-sniffer/apm-agent-core/src/main/java/org/skywalking/apm/agent/core/conf/Config.java b/apm-sniffer/apm-agent-core/src/main/java/org/skywalking/apm/agent/core/conf/Config.java index a6f661eaf..2d6a755be 100644 --- a/apm-sniffer/apm-agent-core/src/main/java/org/skywalking/apm/agent/core/conf/Config.java +++ b/apm-sniffer/apm-agent-core/src/main/java/org/skywalking/apm/agent/core/conf/Config.java @@ -54,8 +54,8 @@ public class Config { public static int SPAN_LIMIT_PER_SEGMENT = 300; /** - * If true, skywalking agent will save all instrumented classes files. And you can send them to skywalking team, - * in order to resolve compatible problem. + * If true, skywalking agent will save all instrumented classes files in `/debugging` folder. + * Skywalking team may ask for these files in order to resolve compatible problem. */ public static boolean IS_OPEN_DEBUGGING_CLASS = false; } From f85878f7464deaf1869536b9244c988b8a989b07 Mon Sep 17 00:00:00 2001 From: wu-sheng Date: Tue, 28 Nov 2017 09:25:21 +0800 Subject: [PATCH 06/15] Use byte buddy saveIn API instead of my own implementation. --- .../apm/agent/InstrumentDebuggingClass.java | 23 +------------------ 1 file changed, 1 insertion(+), 22 deletions(-) diff --git a/apm-sniffer/apm-agent/src/main/java/org/skywalking/apm/agent/InstrumentDebuggingClass.java b/apm-sniffer/apm-agent/src/main/java/org/skywalking/apm/agent/InstrumentDebuggingClass.java index 96173f5c5..bd5afa8a8 100644 --- a/apm-sniffer/apm-agent/src/main/java/org/skywalking/apm/agent/InstrumentDebuggingClass.java +++ b/apm-sniffer/apm-agent/src/main/java/org/skywalking/apm/agent/InstrumentDebuggingClass.java @@ -19,7 +19,6 @@ package org.skywalking.apm.agent; import java.io.File; -import java.io.FileOutputStream; import java.io.IOException; import net.bytebuddy.description.type.TypeDescription; import net.bytebuddy.dynamic.DynamicType; @@ -59,30 +58,10 @@ public enum InstrumentDebuggingClass { } } - File newClassFileFolder = new File(debuggingClassesRootPath, typeDescription.getPackage().getActualName().replaceAll("\\.", "/")); - if (!newClassFileFolder.exists()) { - newClassFileFolder.mkdirs(); - } - File newClassFile = new File(newClassFileFolder, typeDescription.getSimpleName() + ".class"); - FileOutputStream fos = null; try { - if (newClassFile.exists()) { - newClassFile.delete(); - } - newClassFile.createNewFile(); - fos = new FileOutputStream(newClassFile); - fos.write(dynamicType.getBytes()); - fos.flush(); + dynamicType.saveIn(debuggingClassesRootPath); } catch (IOException e) { logger.error(e, "Can't save class {} to file." + typeDescription.getActualName()); - } finally { - if (fos != null) { - try { - fos.close(); - } catch (IOException e) { - - } - } } } catch (Throwable t) { logger.error(t, "Save debugging classes fail."); From f8a815c1e840c6ee1a02f428c23f7b374568392e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=90=B4=E6=99=9F=20Wu=20Sheng?= Date: Tue, 28 Nov 2017 10:09:36 +0800 Subject: [PATCH 07/15] Update Deploy-collector-in-standalone-mode-CN.md --- .../Deploy-collector-in-standalone-mode-CN.md | 25 ++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/docs/cn/Deploy-collector-in-standalone-mode-CN.md b/docs/cn/Deploy-collector-in-standalone-mode-CN.md index 358a74dd1..2f4cc6a7a 100644 --- a/docs/cn/Deploy-collector-in-standalone-mode-CN.md +++ b/docs/cn/Deploy-collector-in-standalone-mode-CN.md @@ -58,4 +58,27 @@ collector_inside: ## 使用Elastic Search代替H2存储 由于H2数据库性能的局限性,我们在单机模式下,也支持使用ElasticSearch 5.3作为存储。你需要安装对应的ElasticSearch 5.3,并取消 -- 在单机模式下除了支持内置的H2数据库运行,也支持其他的存储(当前已支持的ElasticSearch 5.3以及将会支持的ShardJdbc),安装storage注释,修改配置信息即可。 +- 在单机模式下除了支持内置的H2数据库运行,也支持其他的存储(当前已支持的ElasticSearch 5.3),安装storage注释,修改配置信息即可。取消Storage相关配置节的注释。 +```yaml +#storage: +# elasticsearch: +# cluster_name: CollectorDBCluster +# cluster_transport_sniffer: true +# cluster_nodes: localhost:9300 +# index_shards_number: 2 +# index_replicas_number: 0 +``` + +### 部署Elasticsearch +- 修改`elasticsearch.yml`文件 + - 设置 `cluster.name: CollectorDBCluster`。此名称需要和collector配置文件一致。 + - 设置 `node.name: anyname`, 可以设置为任意名字,如Elasticsearch为集群模式,则每个节点名称需要不同。 + - 增加如下配置 + +``` +# ES监听的ip地址 +network.host: 0.0.0.0 +thread_pool.bulk.queue_size: 1000 +``` + +- 启动Elasticsearch From 34ac6442c53f2942b9ccd54e81ffde04e369125b Mon Sep 17 00:00:00 2001 From: wu-sheng Date: Tue, 28 Nov 2017 11:23:13 +0800 Subject: [PATCH 08/15] Fix log file names. --- apm-collector/apm-collector-boot/src/main/assembly/log4j2.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apm-collector/apm-collector-boot/src/main/assembly/log4j2.xml b/apm-collector/apm-collector-boot/src/main/assembly/log4j2.xml index 9c73106af..f65696a35 100644 --- a/apm-collector/apm-collector-boot/src/main/assembly/log4j2.xml +++ b/apm-collector/apm-collector-boot/src/main/assembly/log4j2.xml @@ -22,8 +22,8 @@ ${sys:collector.logDir} - + %d - %c -%-4r [%t] %-5p %x - %m%n From ac6895d1c1af421c79eff6b785535da075d23568 Mon Sep 17 00:00:00 2001 From: ascrutae Date: Mon, 27 Nov 2017 23:38:30 +0800 Subject: [PATCH 09/15] fix no default constructor found issue --- ...towiredAnnotationProcessorInterceptor.java | 109 ++++++++++++++++++ ...redAnnotationProcessorInstrumentation.java | 79 +++++++++++++ .../src/main/resources/skywalking-plugin.def | 1 + 3 files changed, 189 insertions(+) create mode 100644 apm-sniffer/apm-sdk-plugin/spring-plugins/core-patch/src/main/java/org/skywalking/apm/plugin/spring/patch/AutowiredAnnotationProcessorInterceptor.java create mode 100644 apm-sniffer/apm-sdk-plugin/spring-plugins/core-patch/src/main/java/org/skywalking/apm/plugin/spring/patch/define/AutowiredAnnotationProcessorInstrumentation.java diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/core-patch/src/main/java/org/skywalking/apm/plugin/spring/patch/AutowiredAnnotationProcessorInterceptor.java b/apm-sniffer/apm-sdk-plugin/spring-plugins/core-patch/src/main/java/org/skywalking/apm/plugin/spring/patch/AutowiredAnnotationProcessorInterceptor.java new file mode 100644 index 000000000..3a6b48cf6 --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/core-patch/src/main/java/org/skywalking/apm/plugin/spring/patch/AutowiredAnnotationProcessorInterceptor.java @@ -0,0 +1,109 @@ +/* + * 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.spring.patch; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import org.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance; +import org.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceConstructorInterceptor; +import org.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor; +import org.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult; + +/** + * {@link AutowiredAnnotationProcessorInterceptor} return the correct constructor when the bean class is enhanced by + * skywalking. + * + * @author zhangxin + */ +public class AutowiredAnnotationProcessorInterceptor implements InstanceMethodsAroundInterceptor, InstanceConstructorInterceptor { + + @Override + public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class[] argumentsTypes, + MethodInterceptResult result) throws Throwable { + + } + + @Override + public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class[] argumentsTypes, + Object ret) throws Throwable { + Class beanClass = (Class)allArguments[0]; + if (EnhancedInstance.class.isAssignableFrom(beanClass)) { + Map, Constructor[]> candidateConstructorsCache = (Map, Constructor[]>)objInst.getSkyWalkingDynamicField(); + + Constructor[] candidateConstructors = candidateConstructorsCache.get(beanClass); + if (candidateConstructors == null) { + Constructor[] returnCandidateConstructors = (Constructor[])ret; + + /** + * The return for the method {@link org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor#determineCandidateConstructors(Class, String) + * contains three cases: + * 1. Constructors with annotation {@link org.springframework.beans.factory.annotation.Autowired}. + * 2. The bean class only has one constructor with parameters. + * 3. The bean has constructor without parameters. + * + * because of the manipulate mechanism generates another private constructor in the enhance class, all the class that constrcutor enhance by skywalking + * cannot go to case two, and it will go to case three. case one is not affected in the current manipulate mechanism situation. + * + * The interceptor fill out the private constructor when the class is enhanced by skywalking, and check if the remainder constructors size is equals one, + * if yes, return the constructor. or return constructor without parameters. + * + * @see org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor#determineCandidateConstructors(Class, String) + */ + if (returnCandidateConstructors == null) { + Constructor[] rawConstructor = beanClass.getDeclaredConstructors(); + List> candidateRawConstructors = new ArrayList>(); + for (Constructor constructor : rawConstructor) { + if (!Modifier.isPrivate(constructor.getModifiers())) { + candidateRawConstructors.add(constructor); + } + } + + if (candidateRawConstructors.size() == 1 && candidateRawConstructors.get(0).getParameterTypes().length > 0) { + candidateConstructors = new Constructor[] {candidateRawConstructors.get(0)}; + } else { + candidateConstructors = new Constructor[0]; + } + + } else { + candidateConstructors = returnCandidateConstructors; + } + + candidateConstructorsCache.put(beanClass, candidateConstructors); + } + + return candidateConstructors.length > 0 ? candidateConstructors : null; + } + return ret; + } + + @Override public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments, + Class[] argumentsTypes, Throwable t) { + + } + + @Override public void onConstruct(EnhancedInstance objInst, Object[] allArguments) { + Map, Constructor[]> candidateConstructorsCache = new ConcurrentHashMap, Constructor[]>(20); + objInst.setSkyWalkingDynamicField(candidateConstructorsCache); + } +} diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/core-patch/src/main/java/org/skywalking/apm/plugin/spring/patch/define/AutowiredAnnotationProcessorInstrumentation.java b/apm-sniffer/apm-sdk-plugin/spring-plugins/core-patch/src/main/java/org/skywalking/apm/plugin/spring/patch/define/AutowiredAnnotationProcessorInstrumentation.java new file mode 100644 index 000000000..6c26653dc --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/core-patch/src/main/java/org/skywalking/apm/plugin/spring/patch/define/AutowiredAnnotationProcessorInstrumentation.java @@ -0,0 +1,79 @@ +/* + * 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.spring.patch.define; + +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.any; +import static net.bytebuddy.matcher.ElementMatchers.named; +import static org.skywalking.apm.agent.core.plugin.match.NameMatch.byName; + +/** + * {@link AutowiredAnnotationProcessorInstrumentation} indicates a spring core class patch for making sure the + * determineCandidateConstructors method in the class {@link org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor} + * works in spring designed ways + * + * @author zhang xin + */ +public class AutowiredAnnotationProcessorInstrumentation extends ClassInstanceMethodsEnhancePluginDefine { + private static final String ENHANCE_CLASS = "org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor"; + private static final String ENHANCE_METHOD = "determineCandidateConstructors"; + private static final String INTERCEPTOR_CLASS = "org.skywalking.apm.plugin.spring.patch.AutowiredAnnotationProcessorInterceptor"; + + @Override protected ConstructorInterceptPoint[] getConstructorsInterceptPoints() { + return new ConstructorInterceptPoint[] { + new ConstructorInterceptPoint() { + @Override public ElementMatcher getConstructorMatcher() { + return any(); + } + + @Override public String getConstructorInterceptor() { + return INTERCEPTOR_CLASS; + } + } + }; + } + + @Override protected InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() { + return new InstanceMethodsInterceptPoint[] { + new InstanceMethodsInterceptPoint() { + @Override public ElementMatcher getMethodsMatcher() { + return named(ENHANCE_METHOD); + } + + @Override public String getMethodsInterceptor() { + return INTERCEPTOR_CLASS; + } + + @Override public boolean isOverrideArgs() { + return false; + } + } + }; + } + + @Override protected ClassMatch enhanceClass() { + return byName(ENHANCE_CLASS); + } +} diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/core-patch/src/main/resources/skywalking-plugin.def b/apm-sniffer/apm-sdk-plugin/spring-plugins/core-patch/src/main/resources/skywalking-plugin.def index 5caefb1d6..2d8504014 100644 --- a/apm-sniffer/apm-sdk-plugin/spring-plugins/core-patch/src/main/resources/skywalking-plugin.def +++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/core-patch/src/main/resources/skywalking-plugin.def @@ -1 +1,2 @@ spring-core-patch=org.skywalking.apm.plugin.spring.patch.define.AopProxyFactoryInstrumentation +spring-core-patch=org.skywalking.apm.plugin.spring.patch.define.AutowiredAnnotationProcessorInstrumentation From 2adfcc0d5545e5eaaa241b2f94869718314ccd8f Mon Sep 17 00:00:00 2001 From: wu-sheng Date: Tue, 28 Nov 2017 15:07:10 +0800 Subject: [PATCH 10/15] Correct the log4j config file. --- .../apm-collector-boot/src/main/assembly/log4j2.xml | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/apm-collector/apm-collector-boot/src/main/assembly/log4j2.xml b/apm-collector/apm-collector-boot/src/main/assembly/log4j2.xml index f65696a35..ffb1ef68e 100644 --- a/apm-collector/apm-collector-boot/src/main/assembly/log4j2.xml +++ b/apm-collector/apm-collector-boot/src/main/assembly/log4j2.xml @@ -17,7 +17,7 @@ ~ Project repository: https://github.com/OpenSkywalking/skywalking --> - + ${sys:collector.logDir} @@ -34,9 +34,11 @@ - - - + + + + + From 184269077d884bab9ae253c05db91be80fd9fb61 Mon Sep 17 00:00:00 2001 From: wu-sheng Date: Tue, 28 Nov 2017 15:49:31 +0800 Subject: [PATCH 11/15] Update the documents. --- .../cn/Deploy-collector-in-cluster-mode-CN.md | 39 ++++++++------ .../Deploy-collector-in-standalone-mode-CN.md | 53 ++----------------- docs/en/Deploy-collector-in-cluster-mode.md | 41 +++++++------- .../en/Deploy-collector-in-standalone-mode.md | 27 +++++++--- 4 files changed, 73 insertions(+), 87 deletions(-) diff --git a/docs/cn/Deploy-collector-in-cluster-mode-CN.md b/docs/cn/Deploy-collector-in-cluster-mode-CN.md index d62ae2f05..2fba44ea5 100644 --- a/docs/cn/Deploy-collector-in-cluster-mode-CN.md +++ b/docs/cn/Deploy-collector-in-cluster-mode-CN.md @@ -23,49 +23,58 @@ thread_pool.bulk.queue_size: 1000 ### 部署collector 1. 解压安装包`tar -xvf skywalking-collector.tar.gz`,windows用户可以选择zip包 -1. 运行`bin/startup.sh`启动。windows用户为.bat文件。 +2. 设置Collector集群模式 + +集群模式主要依赖Zookeeper的注册和应用发现能力。所以,你只需要调整 `config/application.yml`中的host和port配置,使用实际IP和端口,代替默认配置。 +其次,将storage的注释取消,并修改为Elasticsearch集群的节点地址信息。 + - `config/application.yml` ``` cluster: -# Zookeeper地址配置 +# 配置zookeeper集群信息 zookeeper: hostPort: localhost:2181 sessionTimeout: 100000 -# agent_server, agent_stream, ui, collector_inside中配置的IP都是Collector所使用的IP地址 -agent_server: +naming: +# 配置探针使用的host和port jetty: host: localhost - # The port used port: 10800 context_path: / -agent_stream: - grpc: +remote: + gRPC: host: localhost port: 11800 +agent_gRPC: + gRPC: + host: localhost + port: 11800 +agent_jetty: jetty: host: localhost port: 12800 context_path: / +agent_stream: + default: + buffer_file_path: ../buffer/ + buffer_offset_max_file_size: 10M + buffer_segment_max_file_size: 500M ui: jetty: host: localhost port: 12800 context_path: / -collector_inside: - grpc: - host: localhost - port: 11800 +# 配置 Elasticsearch 集群连接信息 storage: elasticsearch: cluster_name: CollectorDBCluster cluster_transport_sniffer: true - # Elastic Search地址信息 cluster_nodes: localhost:9300 index_shards_number: 2 index_replicas_number: 0 + ttl: 7 ``` -## Collector集群模式启动 -集群模式主要依赖Zookeeper的注册和应用发现能力。所以,你只需要调整 `config/application.yml`中,agent_server, agent_stream, ui, collector_inside这些配置项的ip信息,使用真实的IP地址或者hostname,Collector就会使用集群模式运行。 -其次,将elasticsearch的注释取消,并修改集群的节点地址信息。 + +3. 运行`bin/startup.sh`启动。windows用户为.bat文件。 diff --git a/docs/cn/Deploy-collector-in-standalone-mode-CN.md b/docs/cn/Deploy-collector-in-standalone-mode-CN.md index 2f4cc6a7a..b79305b57 100644 --- a/docs/cn/Deploy-collector-in-standalone-mode-CN.md +++ b/docs/cn/Deploy-collector-in-standalone-mode-CN.md @@ -1,5 +1,5 @@ -## 用途说明 -单机模式使用本地H2数据库,不支持集群部署。主要用于:预览、功能测试、演示和低压力系统。 +# 用途说明 +单机模式使用本地H2数据库,不支持集群部署。主要用于:预览、功能测试、演示和低压力系统。你可选择使用Elasticsearch作为 ## 所需的第三方软件 - JDK8+ @@ -10,55 +10,12 @@ ## Quick Start Collector单机模拟启动简单,提供和集群模式相同的功能,单机模式下除端口被占用的情况下,直接启动即可。 -### 部署collector +## 部署collector 1. 解压安装包`tar -xvf skywalking-collector.tar.gz`,windows用户可以选择zip包 1. 运行`bin/startup.sh`启动。windows用户为.bat文件。 -- `config/application.yml` -``` -# 单机模式下无需配置集群相关信息 -#cluster: -# zookeeper: -# hostPort: localhost:2181 -# sessionTimeout: 100000 -# agent_server, agent_stream, ui, collector_inside中配置的IP都是Collector所使用的IP地址 -agent_server: - jetty: - host: localhost - # The port used - port: 10800 - context_path: / -agent_stream: - grpc: - host: localhost - port: 11800 - jetty: - host: localhost - port: 12800 - context_path: / -ui: - jetty: - host: localhost - port: 12800 - context_path: / -collector_inside: - grpc: - host: localhost - port: 11800 - -#storage: -# elasticsearch: -# cluster_name: CollectorDBCluster -# cluster_transport_sniffer: true -# Elastic Search地址信息 -# cluster_nodes: localhost:9300 -# index_shards_number: 2 -# index_replicas_number: 0 -``` - ## 使用Elastic Search代替H2存储 -由于H2数据库性能的局限性,我们在单机模式下,也支持使用ElasticSearch 5.3作为存储。你需要安装对应的ElasticSearch 5.3,并取消 -- 在单机模式下除了支持内置的H2数据库运行,也支持其他的存储(当前已支持的ElasticSearch 5.3),安装storage注释,修改配置信息即可。取消Storage相关配置节的注释。 +- 在单机模式下除了支持内置的H2数据库运行,也支持其他的存储(当前已支持的ElasticSearch 5.3),取消Storage相关配置节的注释,并修改配置。 ```yaml #storage: # elasticsearch: @@ -69,7 +26,7 @@ collector_inside: # index_replicas_number: 0 ``` -### 部署Elasticsearch +## 部署Elasticsearch - 修改`elasticsearch.yml`文件 - 设置 `cluster.name: CollectorDBCluster`。此名称需要和collector配置文件一致。 - 设置 `node.name: anyname`, 可以设置为任意名字,如Elasticsearch为集群模式,则每个节点名称需要不同。 diff --git a/docs/en/Deploy-collector-in-cluster-mode.md b/docs/en/Deploy-collector-in-cluster-mode.md index 4ff29a0a1..bea5ca0b5 100644 --- a/docs/en/Deploy-collector-in-cluster-mode.md +++ b/docs/en/Deploy-collector-in-cluster-mode.md @@ -12,7 +12,7 @@ - Set `cluster.name: CollectorDBCluster` - Set `node.name: anyname`, this name can be any, it based on Elasticsearch. - Add the following configurations to - + ``` # The ip used for listening network.host: 0.0.0.0 @@ -21,53 +21,58 @@ thread_pool.bulk.queue_size: 1000 - Start Elasticsearch -## Single Node Mode Collector -Single Node collector is easy to deploy, and provides same features as cluster mode. You can use almost all default config to run in this mode. And attention, all the default configs of single node mode, depend on running the collector, traced application, ElasticSearch and Zookeeper in the same machine. - ### Deploy collector servers 1. Run `tar -xvf skywalking-collector.tar.gz` -1. Run `bin/startup.sh` +2. Config collector in cluster mode. + +Cluster mode depends on Zookeeper register and application discovery capabilities. So, you just need to adjust the IP config items in `config/application.yml`. Change IP and port configs of agent_server, agent_stream, ui, collector_inside, replace them to the real ip or hostname which you want to use for cluster. - `config/application.yml` ``` cluster: - # The address of Zookeeper +# The Zookeeper cluster for collector cluster management. zookeeper: hostPort: localhost:2181 sessionTimeout: 100000 -# IPs in agent_server, agent_stream, ui, collector_inside are addresses of Collector -agent_server: +naming: +# Host and port used for agent config jetty: host: localhost - # The port used port: 10800 context_path: / -agent_stream: - grpc: +remote: + gRPC: host: localhost port: 11800 +agent_gRPC: + gRPC: + host: localhost + port: 11800 +agent_jetty: jetty: host: localhost port: 12800 context_path: / +agent_stream: + default: + buffer_file_path: ../buffer/ + buffer_offset_max_file_size: 10M + buffer_segment_max_file_size: 500M ui: jetty: host: localhost port: 12800 context_path: / -collector_inside: - grpc: - host: localhost - port: 11800 +# Config Elasticsearch cluster connection info. storage: elasticsearch: cluster_name: CollectorDBCluster cluster_transport_sniffer: true - # The address of Elastic Search cluster_nodes: localhost:9300 index_shards_number: 2 index_replicas_number: 0 + ttl: 7 ``` -## Cluster Mode Collector -Cluster mode depends on Zookeeper register and application discovery capabilities. So, you just need to adjust the IP config items in `config/application.yml`. Change IP and port configs of agent_server, agent_stream, ui, collector_inside, replace them to the real ip or hostname which you want to use for cluster. + +3. Run `bin/startup.sh` diff --git a/docs/en/Deploy-collector-in-standalone-mode.md b/docs/en/Deploy-collector-in-standalone-mode.md index 9a53fdaa4..375374e1c 100644 --- a/docs/en/Deploy-collector-in-standalone-mode.md +++ b/docs/en/Deploy-collector-in-standalone-mode.md @@ -1,13 +1,15 @@ # Usage scenario -Standalong mode collector means don't support cluster. It uses H2 as storage layer implementation, suggest that use only for preview, test, demonstration, low throughputs and small scale system. +Default standalong mode collector means don't support cluster. It uses H2 as storage layer implementation, suggest that use only for preview, test, demonstration, low throughputs and small scale system. -# Requirements +If you are using skywalking in a low throughputs monitoring scenario, and don't want to deploy cluster, at least, swith the storage implementation from H2 to Elasticsearch. + +## Requirements * JDK 8+ -# Download +## Download * [Releases](https://github.com/OpenSkywalking/skywalking/releases) -# Quick start +## Quick start You can simplely tar/unzip and startup if ports 10800, 11800, 12800 are free. - `tar -xvf skywalking-collector.tar.gz` in Linux, or unzip in windows. @@ -15,6 +17,19 @@ You can simplely tar/unzip and startup if ports 10800, 11800, 12800 are free. You should keep the `config/application.yml` as default. -# Use Elastic Search instead of H2 as storage layer implementation -Even in standalone mode, collector can run with Elastic Search as storage. If so, uncomment the `storage` section in `application.yml`, set the config right. +## Use Elastic Search instead of H2 as storage layer implementation +Even in standalone mode, collector can run with Elastic Search as storage. If so, uncomment the `storage` section in `application.yml`, set the config right. The default configs fit for collector and Elasticsearch both running in same machine, and not cluster. +## Deploy Elasticsearch server +- Modify `elasticsearch.yml` + - Set `cluster.name: CollectorDBCluster` + - Set `node.name: anyname`, this name can be any, it based on Elasticsearch. + - Add the following configurations to + +``` +# The ip used for listening +network.host: 0.0.0.0 +thread_pool.bulk.queue_size: 1000 +``` + +- Start Elasticsearch From a715220f5042f719fb8f74c1925286400ecac96c Mon Sep 17 00:00:00 2001 From: wu-sheng Date: Tue, 28 Nov 2017 15:51:39 +0800 Subject: [PATCH 12/15] Remove document versions. --- docs/README.md | 1 - docs/README_ZH.md | 1 - 2 files changed, 2 deletions(-) diff --git a/docs/README.md b/docs/README.md index abd20fb8d..900c41c81 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,5 +1,4 @@ ## Documents -[![version](https://img.shields.io/badge/document--version-3.2.5--2017-green.svg)]() [![cn doc](https://img.shields.io/badge/document-中文-blue.svg)](README_ZH.md) * Getting Started diff --git a/docs/README_ZH.md b/docs/README_ZH.md index 601eb7cd8..205ae0ddb 100644 --- a/docs/README_ZH.md +++ b/docs/README_ZH.md @@ -1,5 +1,4 @@ ## 中文文档 -[![version](https://img.shields.io/badge/document--version-3.2.5--2017-green.svg)]() [![EN doc](https://img.shields.io/badge/document-English-blue.svg)](README.md) * [项目简介](/README_ZH.md) From 4cda90a685bf9381609ea15bf050bf36b88c711a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=90=B4=E6=99=9F=20Wu=20Sheng?= Date: Tue, 28 Nov 2017 16:03:42 +0800 Subject: [PATCH 13/15] Update Deploy-collector-in-standalone-mode-CN.md --- docs/cn/Deploy-collector-in-standalone-mode-CN.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/cn/Deploy-collector-in-standalone-mode-CN.md b/docs/cn/Deploy-collector-in-standalone-mode-CN.md index b79305b57..7eca7f8ac 100644 --- a/docs/cn/Deploy-collector-in-standalone-mode-CN.md +++ b/docs/cn/Deploy-collector-in-standalone-mode-CN.md @@ -1,5 +1,5 @@ # 用途说明 -单机模式使用本地H2数据库,不支持集群部署。主要用于:预览、功能测试、演示和低压力系统。你可选择使用Elasticsearch作为 +单机模式默认使用本地H2数据库,不支持集群部署。主要用于:预览、功能测试、演示和低压力系统。如果使用单机collector用于非演示环境,你可选择使用Elasticsearch作为存储实现。 ## 所需的第三方软件 - JDK8+ From 30ba5853e035852d6f19b2c3ece402f363ecb198 Mon Sep 17 00:00:00 2001 From: ascrutae Date: Wed, 29 Nov 2017 19:17:05 +0800 Subject: [PATCH 14/15] support the 3.0 and 3.1 version of spring mvc framework --- .../v3/HandlerMethodInvokerInterceptor.java | 53 +++++++++++++++ .../HandlerMethodInvokerInstrumentation.java | 66 +++++++++++++++++++ .../src/main/resources/skywalking-plugin.def | 1 + 3 files changed, 120 insertions(+) create mode 100644 apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-3.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/mvc/v3/HandlerMethodInvokerInterceptor.java create mode 100644 apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-3.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/mvc/v3/define/HandlerMethodInvokerInstrumentation.java diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-3.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/mvc/v3/HandlerMethodInvokerInterceptor.java b/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-3.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/mvc/v3/HandlerMethodInvokerInterceptor.java new file mode 100644 index 000000000..52dd64a32 --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-3.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/mvc/v3/HandlerMethodInvokerInterceptor.java @@ -0,0 +1,53 @@ +/* + * 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.spring.mvc.v3; + +import java.lang.reflect.Method; +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.springframework.web.context.request.NativeWebRequest; + +/** + * {@link HandlerMethodInvokerInterceptor} pass the {@link NativeWebRequest} object into the {@link + * org.springframework.stereotype.Controller} object. + * + * @author zhangxin + */ +public class HandlerMethodInvokerInterceptor implements InstanceMethodsAroundInterceptor { + @Override + public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class[] argumentsTypes, + MethodInterceptResult result) throws Throwable { + Object handler = allArguments[1]; + if (handler instanceof EnhancedInstance) { + ((EnhanceRequireObjectCache)((EnhancedInstance)handler).getSkyWalkingDynamicField()).setNativeWebRequest((NativeWebRequest)allArguments[2]); + } + } + + @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) { + + } +} diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-3.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/mvc/v3/define/HandlerMethodInvokerInstrumentation.java b/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-3.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/mvc/v3/define/HandlerMethodInvokerInstrumentation.java new file mode 100644 index 000000000..b708c4c6d --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-3.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/mvc/v3/define/HandlerMethodInvokerInstrumentation.java @@ -0,0 +1,66 @@ +/* + * 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.spring.mvc.v3.define; + +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.match.ClassMatch; + +import static net.bytebuddy.matcher.ElementMatchers.named; +import static org.skywalking.apm.agent.core.plugin.match.NameMatch.byName; + +/** + * {@link HandlerMethodInvokerInstrumentation} intercept the invokeHandlerMethod method in the + * org.springframework.web.bind.annotation.support.HandlerMethodInvoker class. + * + * @author zhangxin + */ +public class HandlerMethodInvokerInstrumentation extends AbstractSpring3Instrumentation { + private static final String ENHANCE_CLASS = "org.springframework.web.bind.annotation.support.HandlerMethodInvoker"; + private static final String ENHANCE_METHOD = "invokeHandlerMethod"; + private static final String INTERCEPTOR_CLASS = "org.skywalking.apm.plugin.spring.mvc.v3.HandlerMethodInvokerInterceptor"; + + @Override protected ConstructorInterceptPoint[] getConstructorsInterceptPoints() { + return new ConstructorInterceptPoint[0]; + } + + @Override protected InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() { + return new InstanceMethodsInterceptPoint[] { + new InstanceMethodsInterceptPoint() { + @Override public ElementMatcher getMethodsMatcher() { + return named(ENHANCE_METHOD); + } + + @Override public String getMethodsInterceptor() { + return INTERCEPTOR_CLASS; + } + + @Override public boolean isOverrideArgs() { + return false; + } + } + }; + } + + @Override protected ClassMatch enhanceClass() { + return byName(ENHANCE_CLASS); + } +} diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-3.x-plugin/src/main/resources/skywalking-plugin.def b/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-3.x-plugin/src/main/resources/skywalking-plugin.def index 86b7b7658..8f4010b67 100644 --- a/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-3.x-plugin/src/main/resources/skywalking-plugin.def +++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-3.x-plugin/src/main/resources/skywalking-plugin.def @@ -1,3 +1,4 @@ spring-mvc-annotation-3.x=org.skywalking.apm.plugin.spring.mvc.v3.define.ControllerInstrumentation spring-mvc-annotation-3.x=org.skywalking.apm.plugin.spring.mvc.v3.define.HandlerMethodInstrumentation spring-mvc-annotation-3.x=org.skywalking.apm.plugin.spring.mvc.v3.define.InvocableHandlerInstrumentation +spring-mvc-annotation-3.x=org.skywalking.apm.plugin.spring.mvc.v3.define.HandlerMethodInvokerInstrumentation From 5501387279490ea2f1e7406363dc59404da39ba7 Mon Sep 17 00:00:00 2001 From: wu-sheng Date: Thu, 30 Nov 2017 14:20:37 +0800 Subject: [PATCH 15/15] Change network protocol and refactor agent core. --- .../src/main/proto/TraceSegmentService.proto | 32 +++++++++---------- .../agent/core/context/ContextManager.java | 11 ++++--- .../agent/core/context/TracingContext.java | 7 +++- .../agent/core/context/trace/EntrySpan.java | 32 +++++++++++++++++-- .../core/context/trace/TraceSegment.java | 10 +++--- .../core/context/ContextManagerTest.java | 4 +-- .../remote/TraceSegmentServiceClientTest.java | 2 +- 7 files changed, 65 insertions(+), 33 deletions(-) diff --git a/apm-network/src/main/proto/TraceSegmentService.proto b/apm-network/src/main/proto/TraceSegmentService.proto index 95eb1de6b..daaf0aa00 100644 --- a/apm-network/src/main/proto/TraceSegmentService.proto +++ b/apm-network/src/main/proto/TraceSegmentService.proto @@ -22,11 +22,10 @@ message UniqueId { message TraceSegmentObject { UniqueId traceSegmentId = 1; - repeated TraceSegmentReference refs = 2; - repeated SpanObject spans = 3; - int32 applicationId = 4; - int32 applicationInstanceId = 5; - bool isSizeLimited = 6; + repeated SpanObject spans = 2; + int32 applicationId = 3; + int32 applicationInstanceId = 4; + bool isSizeLimited = 5; } message TraceSegmentReference { @@ -48,17 +47,18 @@ message SpanObject { int32 parentSpanId = 2; int64 startTime = 3; int64 endTime = 4; - int32 operationNameId = 5; - string operationName = 6; - int32 peerId = 7; - string peer = 8; - SpanType spanType = 9; - SpanLayer spanLayer = 10; - int32 componentId = 11; - string component = 12; - bool isError = 13; - repeated KeyWithStringValue tags = 14; - repeated LogMessage logs = 15; + repeated TraceSegmentReference refs = 5; + int32 operationNameId = 6; + string operationName = 7; + int32 peerId = 8; + string peer = 9; + SpanType spanType = 10; + SpanLayer spanLayer = 11; + int32 componentId = 12; + string component = 13; + bool isError = 14; + repeated KeyWithStringValue tags = 15; + repeated LogMessage logs = 16; } enum RefType { diff --git a/apm-sniffer/apm-agent-core/src/main/java/org/skywalking/apm/agent/core/context/ContextManager.java b/apm-sniffer/apm-agent-core/src/main/java/org/skywalking/apm/agent/core/context/ContextManager.java index 4598be9df..37c58c99c 100644 --- a/apm-sniffer/apm-agent-core/src/main/java/org/skywalking/apm/agent/core/context/ContextManager.java +++ b/apm-sniffer/apm-agent-core/src/main/java/org/skywalking/apm/agent/core/context/ContextManager.java @@ -25,17 +25,15 @@ import org.skywalking.apm.agent.core.conf.RemoteDownstreamConfig; import org.skywalking.apm.agent.core.context.trace.AbstractSpan; import org.skywalking.apm.agent.core.context.trace.TraceSegment; import org.skywalking.apm.agent.core.dictionary.DictionaryUtil; -import org.skywalking.apm.agent.core.sampling.SamplingService; import org.skywalking.apm.agent.core.logging.api.ILog; import org.skywalking.apm.agent.core.logging.api.LogManager; +import org.skywalking.apm.agent.core.sampling.SamplingService; import org.skywalking.apm.util.StringUtil; /** * {@link ContextManager} controls the whole context of {@link TraceSegment}. Any {@link TraceSegment} relates to * single-thread, so this context use {@link ThreadLocal} to maintain the context, and make sure, since a {@link - * TraceSegment} starts, all ChildOf spans are in the same context. - *

- * What is 'ChildOf'? {@see + * TraceSegment} starts, all ChildOf spans are in the same context.

What is 'ChildOf'? {@see * https://github.com/opentracing/specification/blob/master/specification.md#references-between-spans} * *

Also, {@link ContextManager} delegates to all {@link AbstractTracerContext}'s major methods. @@ -100,15 +98,18 @@ public class ContextManager implements TracingContextListener, BootService, Igno public static AbstractSpan createEntrySpan(String operationName, ContextCarrier carrier) { SamplingService samplingService = ServiceManager.INSTANCE.findService(SamplingService.class); + AbstractSpan span; AbstractTracerContext context; if (carrier != null && carrier.isValid()) { samplingService.forceSampled(); context = getOrCreate(operationName, true); + span = context.createEntrySpan(operationName); context.extract(carrier); } else { context = getOrCreate(operationName, false); + span = context.createEntrySpan(operationName); } - return context.createEntrySpan(operationName); + return span; } public static AbstractSpan createLocalSpan(String operationName) { diff --git a/apm-sniffer/apm-agent-core/src/main/java/org/skywalking/apm/agent/core/context/TracingContext.java b/apm-sniffer/apm-agent-core/src/main/java/org/skywalking/apm/agent/core/context/TracingContext.java index 39d06c449..3a10f1f0f 100644 --- a/apm-sniffer/apm-agent-core/src/main/java/org/skywalking/apm/agent/core/context/TracingContext.java +++ b/apm-sniffer/apm-agent-core/src/main/java/org/skywalking/apm/agent/core/context/TracingContext.java @@ -153,8 +153,13 @@ public class TracingContext implements AbstractTracerContext { */ @Override public void extract(ContextCarrier carrier) { - this.segment.ref(new TraceSegmentRef(carrier)); + TraceSegmentRef ref = new TraceSegmentRef(carrier); + this.segment.ref(ref); this.segment.relatedGlobalTraces(carrier.getDistributedTraceId()); + AbstractSpan span = this.activeSpan(); + if (span instanceof EntrySpan) { + ((EntrySpan)span).ref(ref); + } } /** diff --git a/apm-sniffer/apm-agent-core/src/main/java/org/skywalking/apm/agent/core/context/trace/EntrySpan.java b/apm-sniffer/apm-agent-core/src/main/java/org/skywalking/apm/agent/core/context/trace/EntrySpan.java index 22dde5e6a..eb1ed9607 100644 --- a/apm-sniffer/apm-agent-core/src/main/java/org/skywalking/apm/agent/core/context/trace/EntrySpan.java +++ b/apm-sniffer/apm-agent-core/src/main/java/org/skywalking/apm/agent/core/context/trace/EntrySpan.java @@ -18,7 +18,10 @@ package org.skywalking.apm.agent.core.context.trace; +import java.util.LinkedList; +import java.util.List; import org.skywalking.apm.agent.core.dictionary.DictionaryUtil; +import org.skywalking.apm.network.proto.SpanObject; import org.skywalking.apm.network.trace.component.Component; /** @@ -29,12 +32,18 @@ import org.skywalking.apm.network.trace.component.Component; * * But with the last EntrySpan's tags and logs, which have more details about a service provider. * - * Such as: Tomcat Embed -> Dubbox - * The EntrySpan represents the Dubbox span. + * Such as: Tomcat Embed -> Dubbox The EntrySpan represents the Dubbox span. * * @author wusheng */ public class EntrySpan extends StackBasedTracingSpan { + /** + * The refs of parent trace segments, except the primary one. For most RPC call, {@link #refs} contains only one + * element, but if this segment is a start span of batch process, the segment faces multi parents, at this moment, + * we use this {@link #refs} to link them. + */ + private List refs; + private int currentMaxDepth; public EntrySpan(int spanId, int parentSpanId, String operationName) { @@ -126,6 +135,25 @@ public class EntrySpan extends StackBasedTracingSpan { return false; } + @Override public SpanObject.Builder transform() { + SpanObject.Builder builder = super.transform(); + if (refs != null) { + for (TraceSegmentRef ref : refs) { + builder.addRefs(ref.transform()); + } + } + return builder; + } + + public void ref(TraceSegmentRef ref) { + if (refs == null) { + refs = new LinkedList(); + } + if (!refs.contains(ref)) { + refs.add(ref); + } + } + private void clearWhenRestart() { this.componentId = DictionaryUtil.nullValue(); this.componentName = null; diff --git a/apm-sniffer/apm-agent-core/src/main/java/org/skywalking/apm/agent/core/context/trace/TraceSegment.java b/apm-sniffer/apm-agent-core/src/main/java/org/skywalking/apm/agent/core/context/trace/TraceSegment.java index 244b5c62c..f33882832 100644 --- a/apm-sniffer/apm-agent-core/src/main/java/org/skywalking/apm/agent/core/context/trace/TraceSegment.java +++ b/apm-sniffer/apm-agent-core/src/main/java/org/skywalking/apm/agent/core/context/trace/TraceSegment.java @@ -46,6 +46,8 @@ public class TraceSegment { * The refs of parent trace segments, except the primary one. For most RPC call, {@link #refs} contains only one * element, but if this segment is a start span of batch process, the segment faces multi parents, at this moment, * we use this {@link #refs} to link them. + * + * This field will not be serialized. Keeping this field is only for quick accessing. */ private List refs; @@ -165,12 +167,8 @@ public class TraceSegment { * Trace Segment */ traceSegmentBuilder.setTraceSegmentId(this.traceSegmentId.transform()); - // TraceSegmentReference - if (this.refs != null) { - for (TraceSegmentRef ref : this.refs) { - traceSegmentBuilder.addRefs(ref.transform()); - } - } + // Don't serialize TraceSegmentReference + // SpanObject for (AbstractTracingSpan span : this.spans) { traceSegmentBuilder.addSpans(span.transform()); diff --git a/apm-sniffer/apm-agent-core/src/test/java/org/skywalking/apm/agent/core/context/ContextManagerTest.java b/apm-sniffer/apm-agent-core/src/test/java/org/skywalking/apm/agent/core/context/ContextManagerTest.java index 68d741da5..bb2db7252 100644 --- a/apm-sniffer/apm-agent-core/src/test/java/org/skywalking/apm/agent/core/context/ContextManagerTest.java +++ b/apm-sniffer/apm-agent-core/src/test/java/org/skywalking/apm/agent/core/context/ContextManagerTest.java @@ -255,14 +255,14 @@ public class ContextManagerTest { UpstreamSegment upstreamSegment = actualSegment.transform(); assertThat(upstreamSegment.getGlobalTraceIdsCount(), is(1)); TraceSegmentObject traceSegmentObject = TraceSegmentObject.parseFrom(upstreamSegment.getSegment()); - TraceSegmentReference reference = traceSegmentObject.getRefs(0); + TraceSegmentReference reference = traceSegmentObject.getSpans(1).getRefs(0); assertThat(reference.getEntryServiceName(), is("/portal/")); assertThat(reference.getNetworkAddress(), is("127.0.0.1:8080")); assertThat(reference.getParentSpanId(), is(3)); assertThat(traceSegmentObject.getApplicationId(), is(1)); - assertThat(traceSegmentObject.getRefsCount(), is(1)); + assertThat(traceSegmentObject.getSpans(1).getRefsCount(), is(1)); assertThat(traceSegmentObject.getSpansCount(), is(2)); diff --git a/apm-sniffer/apm-agent-core/src/test/java/org/skywalking/apm/agent/core/remote/TraceSegmentServiceClientTest.java b/apm-sniffer/apm-agent-core/src/test/java/org/skywalking/apm/agent/core/remote/TraceSegmentServiceClientTest.java index 84b9dfefc..2c5ea61d0 100644 --- a/apm-sniffer/apm-agent-core/src/test/java/org/skywalking/apm/agent/core/remote/TraceSegmentServiceClientTest.java +++ b/apm-sniffer/apm-agent-core/src/test/java/org/skywalking/apm/agent/core/remote/TraceSegmentServiceClientTest.java @@ -127,7 +127,7 @@ public class TraceSegmentServiceClientTest { UpstreamSegment upstreamSegment = upstreamSegments.get(0); assertThat(upstreamSegment.getGlobalTraceIdsCount(), is(1)); TraceSegmentObject traceSegmentObject = TraceSegmentObject.parseFrom(upstreamSegment.getSegment()); - assertThat(traceSegmentObject.getRefsCount(), is(0)); + assertThat(traceSegmentObject.getSpans(0).getRefsCount(), is(0)); assertThat(traceSegmentObject.getSpansCount(), is(1)); SpanObject spanObject = traceSegmentObject.getSpans(0);