From 931effb6486e844c46ef5d2ffa91cda538b69dea Mon Sep 17 00:00:00 2001 From: wu-sheng Date: Mon, 27 Nov 2017 16:32:51 +0800 Subject: [PATCH 1/4] 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 2/4] 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 3/4] 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 4/4] 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.");