diff --git a/joylive-bootstrap/joylive-bootstrap-premain/src/main/java/com/jd/live/agent/bootstrap/LiveAgent.java b/joylive-bootstrap/joylive-bootstrap-premain/src/main/java/com/jd/live/agent/bootstrap/LiveAgent.java index 5ef6c9ba..d35346e9 100644 --- a/joylive-bootstrap/joylive-bootstrap-premain/src/main/java/com/jd/live/agent/bootstrap/LiveAgent.java +++ b/joylive-bootstrap/joylive-bootstrap-premain/src/main/java/com/jd/live/agent/bootstrap/LiveAgent.java @@ -29,9 +29,7 @@ import java.lang.reflect.Method; import java.net.URL; import java.net.URLClassLoader; -import java.util.HashMap; -import java.util.Map; -import java.util.Properties; +import java.util.*; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Function; import java.util.jar.JarFile; @@ -71,6 +69,12 @@ public class LiveAgent { private static final String SHUTDOWN_ON_ERROR = "agent.enhance.shutdownOnError"; + private static final String SUN_JAVA_COMMAND = "sun.java.command"; + + private static final String EXCLUDE_APP = "agent.enhance.excludeApp"; + + private static final String ARRAY_DELIMITER_PATTERN = "[;,]"; + private static Object lifecycle; private static URLClassLoader classLoader; @@ -120,307 +124,399 @@ public static void agentmain(String arguments, Instrumentation instrumentation) */ private static synchronized void launch(String arguments, Instrumentation instrumentation, boolean dynamic) { boolean shutdownOnError = true; - try { - // Parse the arguments and environment to prepare for the agent setup. - Map args = createArgs(arguments); - Map env = createEnv(); - File root = LivePath.getRootPath(env, args); - if (root != null) { - // Update the environment with the determined agent path. - env.put(LivePath.KEY_AGENT_PATH, root.getPath()); + InstallContext ctx = InstallContext.parse(arguments, instrumentation, dynamic); + shutdownOnError = ctx.shutdownOnError; + if (ctx.isExcludeApp()) { + logger.log(Level.INFO, "[LiveAgent] exit when excluding app " + ctx.mainClass); + return; } - File libDir = new File(root, LivePath.DIR_LIB); - File configDir = new File(root, LivePath.DIR_CONFIG); - Map bootstrapConfig = createBootstrapConfig(configDir); - File[] systemLibs = getLibs(new File(libDir, LivePath.DIR_LIB_SYSTEM), true); - File[] coreLibs = getLibs(new File(libDir, LivePath.DIR_LIB_CORE), false); - URL[] coreLibUrls = getUrls(coreLibs); - String command = (String) args.get(ARG_COMMAND); // Load system libraries and set up the class loader. if (status.compareAndSet(STATUS_INITIAL, STATUS_SYSTEM_LIB)) { - addSystemPath(instrumentation, systemLibs); + ctx.addSystemPath(); + ctx.configLogger(); } - - // Configure the agent based on the bootstrap configuration and environment. - ConfigResolver configuration = new ConfigResolver(bootstrapConfig, env); - shutdownOnError = isShutdownOnError(configuration); - // Install the agent by setting up the class loader and lifecycle manager. if (status.compareAndSet(STATUS_SYSTEM_LIB, STATUS_INSTALLING)) { - classLoader = createClassLoader(coreLibUrls, configDir, configuration); - lifecycle = install(instrumentation, dynamic, classLoader, env, bootstrapConfig); + classLoader = ctx.createClassLoader(); + lifecycle = ctx.install(classLoader); status.compareAndSet(STATUS_INSTALLING, lifecycle != null ? STATUS_INSTALL_SUCCESS : STATUS_INSTALL_FAILED); // If the installation failed and shutdownOnError is true, terminate the JVM. - if (status.get() == STATUS_INSTALL_FAILED && shutdownOnError) { - System.exit(1); - } - } - - // Execute the command if provided and the agent installation status allows it. - if (command != null && !command.isEmpty()) { - switch (status.get()) { - case STATUS_INSTALL_SUCCESS: - case STATUS_INSTALL_FAILED: - execute(lifecycle, command, args); - break; - default: - execute(null, command, args); + if (status.get() == STATUS_INSTALL_FAILED) { + onError(null, shutdownOnError); } } + ctx.execute(); } catch (Throwable e) { - // Log severe errors and shut down if required. - logger.log(Level.SEVERE, "Failed to install agent. caused by " + e.getMessage(), e); - if (shutdownOnError) { - System.exit(1); - } + onError(e, shutdownOnError); } } - /** - * Determines whether the agent should shut down the JVM on error based on the provided environment settings. - * - * @param env A function that retrieves environment settings based on a given key. - * @return A boolean indicating whether the JVM should be shut down on error. - */ - private static boolean isShutdownOnError(Function env) { - String value = (String) env.apply(SHUTDOWN_ON_ERROR); - if (value != null) { - try { - return Boolean.parseBoolean(value); - } catch (Exception ignore) { - // If there's an exception parsing the boolean value, ignore it and return the default value. - } + private static void onError(Throwable e, boolean shutdownOnError) { + if (e != null) { + logger.log(Level.SEVERE, "[LiveAgent] Failed to install agent. caused by " + e.getMessage(), e); + } else { + logger.log(Level.SEVERE, "[LiveAgent] Failed to install agent."); + } + if (shutdownOnError) { + System.exit(1); } - // Default to true if the value is not set or cannot be parsed. - return true; } /** - * Executes a command on the target object using reflection. + * Closes the specified URLClassLoader. * - * @param target The object on which the command is to be executed, or null if the agent is not installed. - * @param command The command to execute. - * @param args A map containing the arguments required to execute the command. + * @param classLoader The URLClassLoader to be closed. */ - private static void execute(Object target, String command, Map args) { - logger.info("executing command " + command); - if (target != null) { + private static void close(URLClassLoader classLoader) { + if (classLoader != null) { try { - // Reflectively obtain the method to execute the command. - Method execute = target.getClass().getDeclaredMethod(BOOTSTRAP_METHOD_EXECUTE, String.class, Map.class); - // Invoke the command with the provided arguments. - execute.invoke(target, command, args); - logger.info("success executing command " + command); - } catch (InvocationTargetException e) { - // Log the exception thrown by the method being invoked. - logger.log(Level.SEVERE, "failed to execute command " + command + ", caused by " + e.getTargetException().getMessage(), e.getTargetException()); - } catch (Throwable e) { - // Log other exceptions that occurred during reflection or invocation. - logger.log(Level.SEVERE, "failed to execute command " + command + ", caused by " + e.getMessage(), e); + classLoader.close(); + } catch (IOException ignore) { + // Ignoring IOException during class loader close operation. } - } else { - // If the agent is not installed, log a message indicating that execution cannot proceed. - logger.info("agent is not successfully installed, please retry later."); } } /** - * Installs the agent by loading the bootstrap class and invoking its install method. - * - * @param instrumentation The {@link Instrumentation} instance provided by the JVM. - * @param dynamic A flag indicating whether the agent is being loaded dynamically. - * @param classLoader The class loader to use for loading the agent's classes. - * @param env A map containing the environment configuration. - * @param config A map containing the agent configuration. - * @return An object representing the agent's lifecycle, or null if the installation fails. + * A class representing the arguments for installing and configuring the agent. */ - private static Object install(Instrumentation instrumentation, boolean dynamic, ClassLoader classLoader, - Map env, Map config) { - try { - logger.info("[LiveAgent] Installing agent."); - // Load the bootstrap class using the provided class loader. - Class type = classLoader.loadClass(BOOTSTRAP_CLASS); - // Get the constructor of the bootstrap class. - Constructor constructor = type.getConstructor(Instrumentation.class, boolean.class, Map.class, Map.class, Runnable.class); - // Instantiate the bootstrap class with the given parameters. - Object lifecycle = constructor.newInstance(instrumentation, dynamic, env, config, unLoader); - // Get the installation method from the bootstrap class. - Method install = type.getDeclaredMethod(BOOTSTRAP_METHOD_INSTALL); - // Invoke the installation method to complete the agent installation. - install.invoke(lifecycle); - // Return the lifecycle object for further operations. - return lifecycle; - } catch (InvocationTargetException e) { - // Log the exception thrown by the installation method and exit. - String message = e.getMessage(); - message = message == null ? e.getTargetException().getMessage() : message; - logger.log(Level.SEVERE, "Failed to install agent. caused by " + message); - System.exit(1); - } catch (Throwable e) { - // Log any other exceptions that occurred during the installation process and exit. - logger.log(Level.SEVERE, "Failed to install agent. caused by " + e.getMessage(), e); - System.exit(1); + private static class InstallContext { + private Instrumentation instrumentation; + private boolean dynamic; + private File root; + private Map args; + private File configDir; + private File libDir; + private File[] systemLibs; + private File[] coreLibs; + private URL[] coreLibUrls; + private Map env; + private Map bootstrapConfig; + private ConfigResolver configuration; + private String command; + private boolean shutdownOnError; + private String mainClass; + private Set excludeApps; + + /** + * Parses the installation arguments and returns an InstallArg object. + * + * @param arguments The installation arguments as a string. + * @param instrumentation The instrumentation object used for agent installation. + * @param dynamic Whether to perform dynamic instrumentation or not. + * @return An InstallArg object containing the parsed arguments. + * @throws IOException If there is an error parsing the arguments. + */ + public static InstallContext parse(String arguments, Instrumentation instrumentation, boolean dynamic) throws IOException { + InstallContext arg = new InstallContext(); + arg.instrumentation = instrumentation; + arg.dynamic = dynamic; + arg.args = createArgs(arguments); + arg.env = createEnv(); + arg.command = (String) arg.args.get(ARG_COMMAND); + arg.mainClass = System.getProperty(SUN_JAVA_COMMAND); + + arg.root = LivePath.getRootPath(arg.env, arg.args); + if (arg.root != null) { + // Update the environment with the determined agent path. + arg.env.put(LivePath.KEY_AGENT_PATH, arg.root.getPath()); + } + arg.configDir = new File(arg.root, LivePath.DIR_CONFIG); + arg.libDir = new File(arg.root, LivePath.DIR_LIB); + arg.systemLibs = getLibs(new File(arg.libDir, LivePath.DIR_LIB_SYSTEM), true); + arg.coreLibs = getLibs(new File(arg.libDir, LivePath.DIR_LIB_CORE), false); + arg.coreLibUrls = getUrls(arg.coreLibs); + + arg.bootstrapConfig = createBootstrapConfig(arg.configDir); + // Configure the agent based on the bootstrap configuration and environment. + arg.configuration = new ConfigResolver(arg.bootstrapConfig, arg.env); + arg.shutdownOnError = isShutdownOnError(arg.configuration); + + // Exclude apps + arg.excludeApps = getExcludeApps(arg.configuration); + return arg; + } + + /** + * Checks if the main class of the current application is excluded from monitoring. + * + * @return true if the main class is excluded, false otherwise. + */ + public boolean isExcludeApp() { + return mainClass != null && excludeApps.contains(mainClass); } - // If the installation fails, return null. - return null; - } - private static void addSystemPath(Instrumentation instrumentation, File[] files) throws IOException { - if (files != null) { - for (File file : files) { - try (JarFile jarFile = new JarFile(file)) { - instrumentation.appendToBootstrapClassLoaderSearch(jarFile); + /** + * Adds the system libraries to the bootstrap class loader search. + * + * @throws IOException If there is an error reading the system libraries. + */ + public void addSystemPath() throws IOException { + if (systemLibs != null) { + for (File file : systemLibs) { + try (JarFile jarFile = new JarFile(file)) { + instrumentation.appendToBootstrapClassLoaderSearch(jarFile); + } } } } - logger.setUseParentHandlers(false); - logger.addHandler(new LogHandler()); - } - /** - * Creates a class loader with specified URLs, configuration path, and a configuration function. - * - * @param urls An array of URLs from which to load classes and resources. - * @param configPath The path to the configuration directory. - * @param configFunc A function that provides configuration values based on a string key. - * @return A URLClassLoader instance that can load classes and resources from the specified URLs. - */ - private static URLClassLoader createClassLoader(URL[] urls, File configPath, Function configFunc) { - // Create a new ResourceConfig using the configuration function and a prefix. - ResourceConfig config = new ResourceConfig(configFunc, ResourceConfig.CORE_PREFIX); - // Instantiate a new CoreResourceFilter with the created configuration and the config path. - CoreResourceFilter filter = new CoreResourceFilter(config, configPath); - // Return a new instance of LiveClassLoader with the provided URLs and filter. - return new LiveClassLoader(urls, Thread.currentThread().getContextClassLoader(), ResourcerType.CORE, filter); - } + /** + * Configures the logger to use a custom log handler and disables the use of parent handlers. + */ + public void configLogger() { + logger.setUseParentHandlers(false); + logger.addHandler(new LogHandler()); + } - /** - * Parses a string of arguments into a map where each key-value pair is separated by an equal sign, - * and different pairs are separated by a semicolon. - * - * @param args The string containing the arguments to parse. - * @return A map with the parsed arguments. - */ - private static Map createArgs(String args) { - // Create a new HashMap to store the arguments. - Map result = new HashMap<>(); - if (args != null) { - // Split the input string into parts using the semicolon as a delimiter. - String[] parts = args.trim().split("[;,]"); - for (String arg : parts) { - // Find the index of the equal sign to separate key and value. - int index = arg.indexOf('='); - if (index > 0) { // Ensure that there is a key before the equal sign. - // Extract the key and value, trimming any whitespace. - String key = arg.substring(0, index).trim(); - String value = arg.substring(index + 1).trim(); - // If the value is not empty, put the key-value pair into the map. - if (!value.isEmpty()) { - result.put(key, value); + /** + * Executes a command if the agent installation status allows it. + */ + public void execute() { + // Execute the command if provided and the agent installation status allows it. + if (command != null && !command.isEmpty()) { + switch (status.get()) { + case STATUS_INSTALL_SUCCESS: + case STATUS_INSTALL_FAILED: + execute(lifecycle); + break; + default: + execute(null); + } + } + } + + /** + * Creates a class loader with specified URLs, configuration path, and a configuration function. + * + * @return A URLClassLoader instance that can load classes and resources from the specified URLs. + */ + public URLClassLoader createClassLoader() { + // Create a new ResourceConfig using the configuration function and a prefix. + ResourceConfig config = new ResourceConfig(configuration, ResourceConfig.CORE_PREFIX); + // Instantiate a new CoreResourceFilter with the created configuration and the config path. + CoreResourceFilter filter = new CoreResourceFilter(config, configDir); + // Return a new instance of LiveClassLoader with the provided URLs and filter. + return new LiveClassLoader(coreLibUrls, Thread.currentThread().getContextClassLoader(), ResourcerType.CORE, filter); + } + + /** + * Installs the agent by loading the bootstrap class and invoking its install method. + * + * @param classLoader The class loader to use for loading the agent's classes. + * @return An object representing the agent's lifecycle, or null if the installation fails. + */ + public Object install(ClassLoader classLoader) { + try { + logger.info("[LiveAgent] Installing agent."); + // Load the bootstrap class using the provided class loader. + Class type = classLoader.loadClass(BOOTSTRAP_CLASS); + // Get the constructor of the bootstrap class. + Constructor constructor = type.getConstructor(Instrumentation.class, boolean.class, Map.class, Map.class, Runnable.class); + // Instantiate the bootstrap class with the given parameters. + Object lifecycle = constructor.newInstance(instrumentation, dynamic, env, bootstrapConfig, unLoader); + // Get the installation method from the bootstrap class. + Method install = type.getDeclaredMethod(BOOTSTRAP_METHOD_INSTALL); + // Invoke the installation method to complete the agent installation. + install.invoke(lifecycle); + // Return the lifecycle object for further operations. + return lifecycle; + } catch (InvocationTargetException e) { + // Log the exception thrown by the installation method and exit. + String message = e.getMessage(); + message = message == null ? e.getTargetException().getMessage() : message; + logger.log(Level.SEVERE, "Failed to install agent. caused by " + message); + System.exit(1); + } catch (Throwable e) { + // Log any other exceptions that occurred during the installation process and exit. + logger.log(Level.SEVERE, "Failed to install agent. caused by " + e.getMessage(), e); + System.exit(1); + } + // If the installation fails, return null. + return null; + } + + /** + * Executes a command on the target object using reflection. + * + * @param target The object on which the command is to be executed, or null if the agent is not installed. + */ + private void execute(Object target) { + logger.info("executing command " + command); + if (target != null) { + try { + // Reflectively obtain the method to execute the command. + Method execute = target.getClass().getDeclaredMethod(BOOTSTRAP_METHOD_EXECUTE, String.class, Map.class); + // Invoke the command with the provided arguments. + execute.invoke(target, command, args); + logger.info("success executing command " + command); + } catch (InvocationTargetException e) { + // Log the exception thrown by the method being invoked. + logger.log(Level.SEVERE, "failed to execute command " + command + ", caused by " + e.getTargetException().getMessage(), e.getTargetException()); + } catch (Throwable e) { + // Log other exceptions that occurred during reflection or invocation. + logger.log(Level.SEVERE, "failed to execute command " + command + ", caused by " + e.getMessage(), e); + } + } else { + // If the agent is not installed, log a message indicating that execution cannot proceed. + logger.info("agent is not successfully installed, please retry later."); + } + } + + /** + * Parses a string of arguments into a map where each key-value pair is separated by an equal sign, + * and different pairs are separated by a semicolon. + * + * @param args The string containing the arguments to parse. + * @return A map with the parsed arguments. + */ + private static Map createArgs(String args) { + // Create a new HashMap to store the arguments. + Map result = new HashMap<>(); + if (args != null) { + // Split the input string into parts using the semicolon as a delimiter. + String[] parts = args.trim().split(ARRAY_DELIMITER_PATTERN); + for (String arg : parts) { + // Find the index of the equal sign to separate key and value. + int index = arg.indexOf('='); + if (index > 0) { // Ensure that there is a key before the equal sign. + // Extract the key and value, trimming any whitespace. + String key = arg.substring(0, index).trim(); + String value = arg.substring(index + 1).trim(); + // If the value is not empty, put the key-value pair into the map. + if (!value.isEmpty()) { + result.put(key, value); + } } } } + // Return the map with the parsed arguments. + return result; } - // Return the map with the parsed arguments. - return result; - } - /** - * Creates an environment map that contains all system properties and environment variables. - * - * @return A map with system properties and environment variables. - */ - private static Map createEnv() { - // Create a new HashMap to store the environment variables and system properties. - Map result = new HashMap<>(); - // Add all system properties to the map. - for (Map.Entry entry : System.getProperties().entrySet()) { - result.put(entry.getKey().toString(), entry.getValue()); + /** + * Creates an environment map that contains all system properties and environment variables. + * + * @return A map with system properties and environment variables. + */ + private static Map createEnv() { + // Create a new HashMap to store the environment variables and system properties. + Map result = new HashMap<>(); + // Add all system properties to the map. + for (Map.Entry entry : System.getProperties().entrySet()) { + result.put(entry.getKey().toString(), entry.getValue()); + } + // Add all environment variables to the map. + result.putAll(System.getenv()); + // Return the map containing both system properties and environment variables. + return result; } - // Add all environment variables to the map. - result.putAll(System.getenv()); - // Return the map containing both system properties and environment variables. - return result; - } - /** - * Creates a configuration map from a properties file located in the specified configuration directory. - * - * @param configDir The directory where the configuration properties file is located. - * @return A map with the configuration loaded from the properties file. - * @throws IOException If an I/O error occurs while reading the properties file. - */ - private static Map createBootstrapConfig(File configDir) throws IOException { - // Create a new HashMap to store the bootstrap configuration. - Map result = new HashMap<>(); - // Construct a file object for the bootstrap properties file. - File file = new File(configDir, BOOTSTRAP_PROPERTIES); - if (file.exists()) { - // If the file exists, read it using a FileReader wrapped in a BufferedReader. - try (Reader reader = new BufferedReader(new FileReader(file))) { - Properties properties = new Properties(); - // Load the properties from the reader. - properties.load(reader); - // Put all properties into the result map. - for (Map.Entry entry : properties.entrySet()) { - result.put(entry.getKey().toString(), entry.getValue()); + /** + * Creates a configuration map from a properties file located in the specified configuration directory. + * + * @param configDir The directory where the configuration properties file is located. + * @return A map with the configuration loaded from the properties file. + * @throws IOException If an I/O error occurs while reading the properties file. + */ + private static Map createBootstrapConfig(File configDir) throws IOException { + // Create a new HashMap to store the bootstrap configuration. + Map result = new HashMap<>(); + // Construct a file object for the bootstrap properties file. + File file = new File(configDir, BOOTSTRAP_PROPERTIES); + if (file.exists()) { + // If the file exists, read it using a FileReader wrapped in a BufferedReader. + try (Reader reader = new BufferedReader(new FileReader(file))) { + Properties properties = new Properties(); + // Load the properties from the reader. + properties.load(reader); + // Put all properties into the result map. + for (Map.Entry entry : properties.entrySet()) { + result.put(entry.getKey().toString(), entry.getValue()); + } } } + // Return the map containing the bootstrap configuration. + return result; } - // Return the map containing the bootstrap configuration. - return result; - } - /** - * Retrieves an array of JAR files located in a specified directory. - * - * @param dir The directory to search for JAR files. - * @param empty Whether the directory is allowed to be empty or not. - * @return An array of File objects representing the JAR files found in the directory. - * @throws IOException If the directory does not exist, is not a directory, or is empty (and empty is false). - */ - private static File[] getLibs(File dir, boolean empty) throws IOException { - if (!empty && !dir.exists() && !dir.isDirectory()) { - throw new IOException("Directory is not exists." + dir.getPath()); + /** + * Determines whether the agent should shut down the JVM on error based on the provided environment settings. + * + * @param env A function that retrieves environment settings based on a given key. + * @return A boolean indicating whether the JVM should be shut down on error. + */ + private static boolean isShutdownOnError(Function env) { + String value = (String) env.apply(SHUTDOWN_ON_ERROR); + if (value != null) { + try { + return Boolean.parseBoolean(value); + } catch (Exception ignore) { + // If there's an exception parsing the boolean value, ignore it and return the default value. + } + } + // Default to true if the value is not set or cannot be parsed. + return true; } - File[] files = dir.listFiles(pathname -> pathname.isFile() && pathname.getName().endsWith(".jar")); - if (!empty && (files == null || files.length == 0)) { - throw new IOException("Directory is empty. " + dir); + + /** + * Retrieves an array of JAR files located in a specified directory. + * + * @param dir The directory to search for JAR files. + * @param empty Whether the directory is allowed to be empty or not. + * @return An array of File objects representing the JAR files found in the directory. + * @throws IOException If the directory does not exist, is not a directory, or is empty (and empty is false). + */ + private static File[] getLibs(File dir, boolean empty) throws IOException { + if (!empty && !dir.exists() && !dir.isDirectory()) { + throw new IOException("Directory is not exists." + dir.getPath()); + } + File[] files = dir.listFiles(pathname -> pathname.isFile() && pathname.getName().endsWith(".jar")); + if (!empty && (files == null || files.length == 0)) { + throw new IOException("Directory is empty. " + dir); + } + return files; } - return files; - } - /** - * Converts an array of File objects into an array of URL objects. - * - * @param libs The array of File objects to be converted. - * @return An array of URL objects corresponding to the input File objects. - * @throws IOException If an error occurs while converting File to URL. - */ - private static URL[] getUrls(File[] libs) throws IOException { - URL[] urls = new URL[libs.length]; - for (int i = 0; i < libs.length; i++) { - urls[i] = libs[i].toURI().toURL(); + /** + * Converts an array of File objects into an array of URL objects. + * + * @param libs The array of File objects to be converted. + * @return An array of URL objects corresponding to the input File objects. + * @throws IOException If an error occurs while converting File to URL. + */ + private static URL[] getUrls(File[] libs) throws IOException { + URL[] urls = new URL[libs.length]; + for (int i = 0; i < libs.length; i++) { + urls[i] = libs[i].toURI().toURL(); + } + return urls; } - return urls; - } - /** - * Closes the specified URLClassLoader. - * - * @param classLoader The URLClassLoader to be closed. - */ - private static void close(URLClassLoader classLoader) { - if (classLoader != null) { - try { - classLoader.close(); - } catch (IOException ignore) { - // Ignoring IOException during class loader close operation. + /** + * Retrieves the set of excluded applications from the configuration. + * + * @param env The environment function used to retrieve configuration values. + * @return A set of strings representing the excluded applications. + */ + private static Set getExcludeApps(Function env) { + Set excludeApps = new HashSet<>(); + String config = (String) env.apply(EXCLUDE_APP); + if (config != null) { + String[] values = config.split(ARRAY_DELIMITER_PATTERN); + for (String value : values) { + value = value.trim(); + if (!value.isEmpty()) { + excludeApps.add(value.trim()); + } + } } + return excludeApps; } + } private static class LogHandler extends Handler { diff --git a/joylive-package/src/main/assembly/config/bootstrap.properties b/joylive-package/src/main/assembly/config/bootstrap.properties index 522fa5f8..65eb1af3 100644 --- a/joylive-package/src/main/assembly/config/bootstrap.properties +++ b/joylive-package/src/main/assembly/config/bootstrap.properties @@ -16,6 +16,7 @@ app.location.cell=${APPLICATION_LOCATION_CELL} app.location.laneSpaceId=${APPLICATION_LOCATION_LANESPACE_ID} app.location.lane=${APPLICATION_LOCATION_LANE} agent.enhance.shutdownOnError=${CONFIG_ENHANCE_SHUTDOWN_ON_ERROR:true} +agent.enhance.excludeApp=${CONFIG_ENHANCE_EXCLUDE_APPS:com.taobao.arthas.boot.Bootstrap} classloader.contextLoaderEnabled=${CLASSLOADER_CONTEXT_LOADER_ENABLED:true} classloader.core.configExtensions=yaml,yml,xml,json,properties #classloader.core.parentResources=