diff --git a/apm-sniffer/apm-agent-core/pom.xml b/apm-sniffer/apm-agent-core/pom.xml index 566500edc..d57fdde5d 100644 --- a/apm-sniffer/apm-agent-core/pom.xml +++ b/apm-sniffer/apm-agent-core/pom.xml @@ -36,15 +36,11 @@ 9.4.2.v20170220 1.14.0 20.0 - 1.9.16 - 3.3.6 + 1.10.1 2.6.0 2.0.7.Final 1.4.1.Final org.apache.skywalking.apm.dependencies - com.lmax.disruptor - ${shade.package}.${shade.com.lmax.disruptor.source} - com.google ${shade.package}.${shade.com.google.source} io.grpc @@ -72,11 +68,6 @@ byte-buddy ${bytebuddy.version} - - com.lmax - disruptor - ${disruptor.version} - io.grpc grpc-netty @@ -180,10 +171,6 @@ - - ${shade.com.lmax.disruptor.source} - ${shade.com.lmax.disruptor.target} - ${shade.com.google.source} ${shade.com.google.target} diff --git a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/logging/core/FileWriter.java b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/logging/core/FileWriter.java index a885b0dcb..1b0c6ef21 100644 --- a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/logging/core/FileWriter.java +++ b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/logging/core/FileWriter.java @@ -19,35 +19,33 @@ package org.apache.skywalking.apm.agent.core.logging.core; -import com.lmax.disruptor.EventFactory; -import com.lmax.disruptor.EventHandler; -import com.lmax.disruptor.RingBuffer; -import com.lmax.disruptor.dsl.Disruptor; -import com.lmax.disruptor.util.DaemonThreadFactory; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.text.SimpleDateFormat; +import java.util.ArrayList; import java.util.Date; +import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.Callable; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; +import org.apache.skywalking.apm.agent.core.boot.DefaultNamedThreadFactory; import org.apache.skywalking.apm.agent.core.conf.Config; import org.apache.skywalking.apm.agent.core.conf.Constants; +import org.apache.skywalking.apm.util.RunnableWithExceptionProtection; /** * The FileWriter support async file output, by using a queue as buffer. * * @author wusheng */ -public class FileWriter implements IWriter, EventHandler { +public class FileWriter implements IWriter { private static FileWriter INSTANCE; private static final Object CREATE_LOCK = new Object(); - private Disruptor disruptor; - private RingBuffer buffer; private FileOutputStream fileOutputStream; - private volatile boolean started = false; + private ArrayBlockingQueue logBuffer; private volatile int fileSize; - private volatile int lineNum; public static FileWriter get() { if (INSTANCE == null) { @@ -61,44 +59,45 @@ public class FileWriter implements IWriter, EventHandler { } private FileWriter() { - disruptor = new Disruptor(new EventFactory() { - @Override - public LogMessageHolder newInstance() { - return new LogMessageHolder(); + logBuffer = new ArrayBlockingQueue(1024); + final ArrayList outputLogs = new ArrayList(200); + Executors + .newSingleThreadScheduledExecutor(new DefaultNamedThreadFactory("LogFileWriter")) + .scheduleAtFixedRate(new RunnableWithExceptionProtection(new Runnable() { + @Override public void run() { + logBuffer.drainTo(outputLogs); + for (String log : outputLogs) { + writeToFile(log + Constants.LINE_SEPARATOR); + } + try { + fileOutputStream.flush(); + } catch (IOException e) { + e.printStackTrace(); + } + } + }, new RunnableWithExceptionProtection.CallbackWhenException() { + @Override public void handle(Throwable t) { + } } - }, 1024, DaemonThreadFactory.INSTANCE); - disruptor.handleEventsWith(this); - buffer = disruptor.getRingBuffer(); - lineNum = 0; - disruptor.start(); + ), 0, 1, TimeUnit.SECONDS); } - @Override - public void onEvent(LogMessageHolder event, long sequence, boolean endOfBatch) throws Exception { - if (hasWriteStream()) { + /** + * @param message to be written into the file. + */ + private void writeToFile(String message) { + if (prepareWriteStream()) { try { - lineNum++; - write(event.getMessage() + Constants.LINE_SEPARATOR, endOfBatch); + fileOutputStream.write(message.getBytes()); + fileSize += message.length(); + } catch (IOException e) { + e.printStackTrace(); } finally { - event.setMessage(null); + switchFile(); } } } - private void write(String message, boolean forceFlush) { - try { - fileOutputStream.write(message.getBytes()); - fileSize += message.length(); - if (forceFlush || lineNum % 20 == 0) { - fileOutputStream.flush(); - } - } catch (IOException e) { - e.printStackTrace(); - } finally { - switchFile(); - } - } - private void switchFile() { if (fileSize > Config.Logging.MAX_FILE_SIZE) { forceExecute(new Callable() { @@ -128,7 +127,6 @@ public class FileWriter implements IWriter, EventHandler { @Override public Object call() throws Exception { fileOutputStream = null; - started = false; return null; } }); @@ -143,37 +141,40 @@ public class FileWriter implements IWriter, EventHandler { } } - private boolean hasWriteStream() { + /** + * @return true if stream is prepared ready. + */ + private boolean prepareWriteStream() { if (fileOutputStream != null) { return true; } - if (!started) { - File logFilePath = new File(Config.Logging.DIR); - if (!logFilePath.exists()) { - logFilePath.mkdirs(); - } else if (!logFilePath.isDirectory()) { - System.err.println("Log dir(" + Config.Logging.DIR + ") is not a directory."); - } - try { - fileOutputStream = new FileOutputStream(new File(logFilePath, Config.Logging.FILE_NAME), true); - fileSize = Long.valueOf(new File(logFilePath, Config.Logging.FILE_NAME).length()).intValue(); - } catch (FileNotFoundException e) { - e.printStackTrace(); - } - started = true; + File logFilePath = new File(Config.Logging.DIR); + if (!logFilePath.exists()) { + logFilePath.mkdirs(); + } else if (!logFilePath.isDirectory()) { + System.err.println("Log dir(" + Config.Logging.DIR + ") is not a directory."); + } + try { + fileOutputStream = new FileOutputStream(new File(logFilePath, Config.Logging.FILE_NAME), true); + fileSize = Long.valueOf(new File(logFilePath, Config.Logging.FILE_NAME).length()).intValue(); + } catch (FileNotFoundException e) { + e.printStackTrace(); } return fileOutputStream != null; } - @Override - public void write(String message) { - long next = buffer.next(); + /** + * Write log to the queue. + * W/ performance trade off, set 2ms timeout for the log OP. + * + * @param message to log + */ + @Override public void write(String message) { try { - LogMessageHolder messageHolder = buffer.get(next); - messageHolder.setMessage(message); - } finally { - buffer.publish(next); + logBuffer.offer(message, 2, TimeUnit.MILLISECONDS); + } catch (InterruptedException e) { + e.printStackTrace(); } } } diff --git a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/ByteBuddyCoreClasses.java b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/ByteBuddyCoreClasses.java new file mode 100644 index 000000000..ee7324839 --- /dev/null +++ b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/ByteBuddyCoreClasses.java @@ -0,0 +1,38 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.skywalking.apm.agent.core.plugin; + +/** + * All ByteBuddy core classes required to expose, including open edge for JDK 9+ module, or Bootstrap instrumentation. + * + * @author wusheng + */ +public class ByteBuddyCoreClasses { + private static final String SHADE_PACKAGE = "org.apache.skywalking.apm.dependencies."; + + public static final String[] CLASSES = { + SHADE_PACKAGE + "net.bytebuddy.implementation.bind.annotation.RuntimeType", + SHADE_PACKAGE + "net.bytebuddy.implementation.bind.annotation.This", + SHADE_PACKAGE + "net.bytebuddy.implementation.bind.annotation.AllArguments", + SHADE_PACKAGE + "net.bytebuddy.implementation.bind.annotation.AllArguments$Assignment", + SHADE_PACKAGE + "net.bytebuddy.implementation.bind.annotation.SuperCall", + SHADE_PACKAGE + "net.bytebuddy.implementation.bind.annotation.Origin", + SHADE_PACKAGE + "net.bytebuddy.implementation.bind.annotation.Morph", + }; +} diff --git a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/bootstrap/BootstrapInstrumentBoost.java b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/bootstrap/BootstrapInstrumentBoost.java index 00aa7f6d8..ebb403514 100644 --- a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/bootstrap/BootstrapInstrumentBoost.java +++ b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/bootstrap/BootstrapInstrumentBoost.java @@ -35,12 +35,14 @@ import net.bytebuddy.pool.TypePool; import org.apache.skywalking.apm.agent.core.logging.api.ILog; import org.apache.skywalking.apm.agent.core.logging.api.LogManager; import org.apache.skywalking.apm.agent.core.plugin.AbstractClassEnhancePluginDefine; +import org.apache.skywalking.apm.agent.core.plugin.ByteBuddyCoreClasses; import org.apache.skywalking.apm.agent.core.plugin.InstrumentDebuggingClass; import org.apache.skywalking.apm.agent.core.plugin.PluginException; import org.apache.skywalking.apm.agent.core.plugin.PluginFinder; import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint; import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint; import org.apache.skywalking.apm.agent.core.plugin.interceptor.StaticMethodsInterceptPoint; +import org.apache.skywalking.apm.agent.core.plugin.jdk9module.JDK9ModuleExporter; import org.apache.skywalking.apm.agent.core.plugin.loader.AgentClassLoader; import static net.bytebuddy.matcher.ElementMatchers.named; @@ -53,32 +55,26 @@ import static net.bytebuddy.matcher.ElementMatchers.named; */ public class BootstrapInstrumentBoost { private static final ILog logger = LogManager.getLogger(BootstrapInstrumentBoost.class); - private static final String SHADE_PACKAGE = "org.apache.skywalking.apm.dependencies."; + private static final String[] HIGH_PRIORITY_CLASSES = { - "org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance", "org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.BootstrapInterRuntimeAssist", "org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor", "org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceConstructorInterceptor", "org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.StaticMethodsAroundInterceptor", - "org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult", - "org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.OverrideCallable", "org.apache.skywalking.apm.agent.core.plugin.bootstrap.IBootstrapLog", - SHADE_PACKAGE + "net.bytebuddy.implementation.bind.annotation.RuntimeType", - SHADE_PACKAGE + "net.bytebuddy.implementation.bind.annotation.This", - SHADE_PACKAGE + "net.bytebuddy.implementation.bind.annotation.AllArguments", - SHADE_PACKAGE + "net.bytebuddy.implementation.bind.annotation.AllArguments$Assignment", - SHADE_PACKAGE + "net.bytebuddy.implementation.bind.annotation.SuperCall", - SHADE_PACKAGE + "net.bytebuddy.implementation.bind.annotation.Origin", - SHADE_PACKAGE + "net.bytebuddy.implementation.bind.annotation.Morph" + "org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance", + "org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.OverrideCallable", + "org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult" }; + private static String INSTANCE_METHOD_DELEGATE_TEMPLATE = "org.apache.skywalking.apm.agent.core.plugin.bootstrap.template.InstanceMethodInterTemplate"; private static String INSTANCE_METHOD_WITH_OVERRIDE_ARGS_DELEGATE_TEMPLATE = "org.apache.skywalking.apm.agent.core.plugin.bootstrap.template.InstanceMethodInterWithOverrideArgsTemplate"; private static String CONSTRUCTOR_DELEGATE_TEMPLATE = "org.apache.skywalking.apm.agent.core.plugin.bootstrap.template.ConstructorInterTemplate"; private static String STATIC_METHOD_DELEGATE_TEMPLATE = "org.apache.skywalking.apm.agent.core.plugin.bootstrap.template.StaticMethodInterTemplate"; private static String STATIC_METHOD_WITH_OVERRIDE_ARGS_DELEGATE_TEMPLATE = "org.apache.skywalking.apm.agent.core.plugin.bootstrap.template.StaticMethodInterWithOverrideArgsTemplate"; - public static AgentBuilder inject(PluginFinder pluginFinder, AgentBuilder agentBuilder, - Instrumentation instrumentation) throws PluginException { + public static AgentBuilder inject(PluginFinder pluginFinder, Instrumentation instrumentation, AgentBuilder agentBuilder, + JDK9ModuleExporter.EdgeClasses edgeClasses) throws PluginException { Map classesTypeMap = new HashMap(); if (!prepareJREInstrumentation(pluginFinder, classesTypeMap)) { @@ -88,36 +84,25 @@ public class BootstrapInstrumentBoost { for (String highPriorityClass : HIGH_PRIORITY_CLASSES) { loadHighPriorityClass(classesTypeMap, highPriorityClass); } + for (String highPriorityClass : ByteBuddyCoreClasses.CLASSES) { + loadHighPriorityClass(classesTypeMap, highPriorityClass); + } + + /** + * Prepare to open edge of necessary classes. + */ + for (String generatedClass : classesTypeMap.keySet()) { + edgeClasses.add(generatedClass); + } /** * Inject the classes into bootstrap class loader by using Unsafe Strategy. * ByteBuddy adapts the sun.misc.Unsafe and jdk.internal.misc.Unsafe automatically. */ - ClassInjector.UsingUnsafe.ofBootLoader().injectRaw(classesTypeMap); - agentBuilder = agentBuilder.enableUnsafeBootstrapInjection(); + ClassInjector.UsingUnsafe.Factory factory = ClassInjector.UsingUnsafe.Factory.resolve(instrumentation); + factory.make(null, null).injectRaw(classesTypeMap); + agentBuilder = agentBuilder.with(new AgentBuilder.InjectionStrategy.UsingUnsafe.OfFactory(factory)); - /** - * Assures that all modules of the supplied types are read by the module of any instrumented type. - * JDK Module system was introduced since JDK9. - * - * The following codes work only JDK Module system exist. - */ - for (String highPriorityClass : HIGH_PRIORITY_CLASSES) { - try { - agentBuilder = agentBuilder.assureReadEdgeTo(instrumentation, Class.forName(highPriorityClass)); - } catch (ClassNotFoundException e) { - logger.error(e, "Fail to open the high priority class " + highPriorityClass + " to public access in JDK9+"); - throw new UnsupportedOperationException("Fail to open the high priority class " + highPriorityClass + " to public access in JDK9+", e); - } - } - for (String generatedClass : classesTypeMap.keySet()) { - try { - agentBuilder = agentBuilder.assureReadEdgeTo(instrumentation, Class.forName(generatedClass)); - } catch (ClassNotFoundException e) { - logger.error(e, "Fail to open the high generated class " + generatedClass + " to public access in JDK9+"); - throw new UnsupportedOperationException("Fail to open the high generated class " + generatedClass + " to public access in JDK9+", e); - } - } return agentBuilder; } diff --git a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/jdk9module/JDK9ModuleExporter.java b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/jdk9module/JDK9ModuleExporter.java new file mode 100644 index 000000000..92943af10 --- /dev/null +++ b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/jdk9module/JDK9ModuleExporter.java @@ -0,0 +1,89 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.skywalking.apm.agent.core.plugin.jdk9module; + +import java.lang.instrument.Instrumentation; +import java.util.ArrayList; +import java.util.List; +import net.bytebuddy.agent.builder.AgentBuilder; +import org.apache.skywalking.apm.agent.core.logging.api.ILog; +import org.apache.skywalking.apm.agent.core.logging.api.LogManager; +import org.apache.skywalking.apm.agent.core.plugin.ByteBuddyCoreClasses; + +/** + * Since JDK 9, module concept has been introduced. By supporting that, agent core needs to open the + * + * @author wusheng + */ +public class JDK9ModuleExporter { + private static final ILog logger = LogManager.getLogger(JDK9ModuleExporter.class); + + private static final String[] HIGH_PRIORITY_CLASSES = { + "org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance", + "org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult", + "org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.OverrideCallable", + "org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ConstructorInter", + "org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstMethodsInter", + "org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstMethodsInterWithOverrideArgs", + "org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.StaticMethodsInter", + "org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.StaticMethodsInterWithOverrideArgs", + }; + + /** + * Assures that all modules of the supplied types are read by the module of any instrumented type. JDK Module system + * was introduced since JDK9. + * + * The following codes work only JDK Module system exist. + */ + public static AgentBuilder openReadEdge(Instrumentation instrumentation, AgentBuilder agentBuilder, + EdgeClasses classes) { + for (String className : classes.classes) { + try { + agentBuilder = agentBuilder.assureReadEdgeFromAndTo(instrumentation, Class.forName(className)); + } catch (ClassNotFoundException e) { + throw new UnsupportedOperationException("Fail to open read edge for class " + className + " to public access in JDK9+", e); + } + } + for (String className : HIGH_PRIORITY_CLASSES) { + try { + agentBuilder = agentBuilder.assureReadEdgeFromAndTo(instrumentation, Class.forName(className)); + } catch (ClassNotFoundException e) { + throw new UnsupportedOperationException("Fail to open read edge for class " + className + " to public access in JDK9+", e); + } + } + + return agentBuilder; + } + + public static class EdgeClasses { + private List classes = new ArrayList(); + + public EdgeClasses() { + for (String className : ByteBuddyCoreClasses.CLASSES) { + add(className); + } + } + + public void add(String className) { + if (!classes.contains(className)) { + classes.add(className); + } + } + } +} diff --git a/apm-sniffer/apm-agent/pom.xml b/apm-sniffer/apm-agent/pom.xml index 8b1ca5177..3ee933412 100644 --- a/apm-sniffer/apm-agent/pom.xml +++ b/apm-sniffer/apm-agent/pom.xml @@ -76,7 +76,6 @@ - com.lmax:* *:gson io.grpc:* io.netty:* diff --git a/apm-sniffer/apm-agent/src/main/java/org/apache/skywalking/apm/agent/SkyWalkingAgent.java b/apm-sniffer/apm-agent/src/main/java/org/apache/skywalking/apm/agent/SkyWalkingAgent.java index b880d2bbe..b86ba541b 100644 --- a/apm-sniffer/apm-agent/src/main/java/org/apache/skywalking/apm/agent/SkyWalkingAgent.java +++ b/apm-sniffer/apm-agent/src/main/java/org/apache/skywalking/apm/agent/SkyWalkingAgent.java @@ -44,6 +44,7 @@ import org.apache.skywalking.apm.agent.core.plugin.PluginBootstrap; import org.apache.skywalking.apm.agent.core.plugin.PluginException; import org.apache.skywalking.apm.agent.core.plugin.PluginFinder; import org.apache.skywalking.apm.agent.core.plugin.bootstrap.BootstrapInstrumentBoost; +import org.apache.skywalking.apm.agent.core.plugin.jdk9module.JDK9ModuleExporter; import static net.bytebuddy.matcher.ElementMatchers.nameContains; import static net.bytebuddy.matcher.ElementMatchers.nameStartsWith; @@ -97,13 +98,21 @@ public class SkyWalkingAgent { .or(allSkyWalkingAgentExcludeToolkit()) .or(ElementMatchers.isSynthetic())); + JDK9ModuleExporter.EdgeClasses edgeClasses = new JDK9ModuleExporter.EdgeClasses(); try { - agentBuilder = BootstrapInstrumentBoost.inject(pluginFinder, agentBuilder, instrumentation); + agentBuilder = BootstrapInstrumentBoost.inject(pluginFinder, instrumentation, agentBuilder, edgeClasses); } catch (Exception e) { logger.error(e, "SkyWalking agent inject bootstrap instrumentation failure. Shutting down."); return; } + try { + agentBuilder = JDK9ModuleExporter.openReadEdge(instrumentation, agentBuilder, edgeClasses); + } catch (Exception e) { + logger.error(e, "SkyWalking agent open read edge in JDK 9+ failure. Shutting down."); + return; + } + agentBuilder .type(pluginFinder.buildMatch()) .transform(new Transformer(pluginFinder))