/* * Copyright 2014 NAVER Corp. * 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. */ package com.navercorp.pinpoint.bootstrap; import java.lang.instrument.Instrumentation; import java.net.URL; import java.util.ArrayList; import java.util.List; import java.util.Map; import com.navercorp.pinpoint.ProductInfo; import com.navercorp.pinpoint.bootstrap.config.DefaultProfilerConfig; import com.navercorp.pinpoint.bootstrap.config.ProfilerConfig; import com.navercorp.pinpoint.common.Version; import com.navercorp.pinpoint.common.service.AnnotationKeyRegistryService; import com.navercorp.pinpoint.common.service.DefaultAnnotationKeyRegistryService; import com.navercorp.pinpoint.common.service.DefaultServiceTypeRegistryService; import com.navercorp.pinpoint.common.service.DefaultTraceMetadataLoaderService; import com.navercorp.pinpoint.common.service.ServiceTypeRegistryService; import com.navercorp.pinpoint.common.service.TraceMetadataLoaderService; import com.navercorp.pinpoint.common.util.PinpointThreadFactory; import com.navercorp.pinpoint.common.util.SimpleProperty; import com.navercorp.pinpoint.common.util.SystemProperty; import com.navercorp.pinpoint.common.util.logger.CommonLoggerFactory; import com.navercorp.pinpoint.common.util.logger.StdoutCommonLoggerFactory; /** * @author Jongho Moon * */ class PinpointStarter { private final BootLogger logger = BootLogger.getLogger(PinpointStarter.class.getName()); public static final String AGENT_TYPE = "AGENT_TYPE"; public static final String DEFAULT_AGENT = "DEFAULT_AGENT"; public static final String BOOT_CLASS = "com.navercorp.pinpoint.profiler.DefaultAgent"; public static final String PLUGIN_TEST_AGENT = "PLUGIN_TEST"; public static final String PLUGIN_TEST_BOOT_CLASS = "com.navercorp.pinpoint.test.PluginTestAgent"; private SimpleProperty systemProperty = SystemProperty.INSTANCE; private final Map<String, String> agentArgs; private final BootstrapJarFile bootstrapJarFile; private final ClassPathResolver classPathResolver; private final Instrumentation instrumentation; public PinpointStarter(Map<String, String> agentArgs, BootstrapJarFile bootstrapJarFile, ClassPathResolver classPathResolver, Instrumentation instrumentation) { if (agentArgs == null) { throw new NullPointerException("agentArgs must not be null"); } if (bootstrapJarFile == null) { throw new NullPointerException("bootstrapJarFile must not be null"); } if (classPathResolver == null) { throw new NullPointerException("classPathResolver must not be null"); } if (instrumentation == null) { throw new NullPointerException("instrumentation must not be null"); } this.agentArgs = agentArgs; this.bootstrapJarFile = bootstrapJarFile; this.classPathResolver = classPathResolver; this.instrumentation = instrumentation; } boolean start() { final IdValidator idValidator = new IdValidator(); final String agentId = idValidator.getAgentId(); if (agentId == null) { return false; } final String applicationName = idValidator.getApplicationName(); if (applicationName == null) { return false; } URL[] pluginJars = classPathResolver.resolvePlugins(); // TODO using PLogger instead of CommonLogger CommonLoggerFactory loggerFactory = StdoutCommonLoggerFactory.INSTANCE; TraceMetadataLoaderService typeLoaderService = new DefaultTraceMetadataLoaderService(pluginJars, loggerFactory); ServiceTypeRegistryService serviceTypeRegistryService = new DefaultServiceTypeRegistryService(typeLoaderService, loggerFactory); AnnotationKeyRegistryService annotationKeyRegistryService = new DefaultAnnotationKeyRegistryService(typeLoaderService, loggerFactory); String configPath = getConfigPath(classPathResolver); if (configPath == null) { return false; } // set the path of log file as a system property saveLogFilePath(classPathResolver); savePinpointVersion(); try { // Is it right to load the configuration in the bootstrap? ProfilerConfig profilerConfig = DefaultProfilerConfig.load(configPath); // this is the library list that must be loaded List<URL> libUrlList = resolveLib(classPathResolver); AgentClassLoader agentClassLoader = new AgentClassLoader(libUrlList.toArray(new URL[libUrlList.size()])); final String bootClass = getBootClass(); agentClassLoader.setBootClass(bootClass); logger.info("pinpoint agent [" + bootClass + "] starting..."); AgentOption option = createAgentOption(agentId, applicationName, profilerConfig, instrumentation, pluginJars, bootstrapJarFile, serviceTypeRegistryService, annotationKeyRegistryService); Agent pinpointAgent = agentClassLoader.boot(option); pinpointAgent.start(); registerShutdownHook(pinpointAgent); logger.info("pinpoint agent started normally."); } catch (Exception e) { // unexpected exception that did not be checked above logger.warn(ProductInfo.NAME + " start failed.", e); return false; } return true; } private String getBootClass() { final String agentType = getAgentType().toUpperCase(); if (PLUGIN_TEST_AGENT.equals(agentType)) { return PLUGIN_TEST_BOOT_CLASS; } return BOOT_CLASS; } private String getAgentType() { String agentType = agentArgs.get(AGENT_TYPE); if (agentType == null) { return DEFAULT_AGENT; } return agentType; } private AgentOption createAgentOption(String agentId, String applicationName, ProfilerConfig profilerConfig, Instrumentation instrumentation, URL[] pluginJars, BootstrapJarFile bootstrapJarFile, ServiceTypeRegistryService serviceTypeRegistryService, AnnotationKeyRegistryService annotationKeyRegistryService) { List<String> bootstrapJarPaths = bootstrapJarFile.getJarNameList(); return new DefaultAgentOption(instrumentation, agentId, applicationName, profilerConfig, pluginJars, bootstrapJarPaths, serviceTypeRegistryService, annotationKeyRegistryService); } // for test void setSystemProperty(SimpleProperty systemProperty) { this.systemProperty = systemProperty; } private void registerShutdownHook(final Agent pinpointAgent) { final Runnable stop = new Runnable() { @Override public void run() { pinpointAgent.stop(); } }; PinpointThreadFactory pinpointThreadFactory = new PinpointThreadFactory("Pinpoint-shutdown-hook"); Thread thread = pinpointThreadFactory.newThread(stop); Runtime.getRuntime().addShutdownHook(thread); } private void saveLogFilePath(ClassPathResolver classPathResolver) { String agentLogFilePath = classPathResolver.getAgentLogFilePath(); logger.info("logPath:" + agentLogFilePath); systemProperty.setProperty(ProductInfo.NAME + ".log", agentLogFilePath); } private void savePinpointVersion() { logger.info("pinpoint version:" + Version.VERSION); systemProperty.setProperty(ProductInfo.NAME + ".version", Version.VERSION); } private String getConfigPath(ClassPathResolver classPathResolver) { final String configName = ProductInfo.NAME + ".config"; String pinpointConfigFormSystemProperty = systemProperty.getProperty(configName); if (pinpointConfigFormSystemProperty != null) { logger.info(configName + " systemProperty found. " + pinpointConfigFormSystemProperty); return pinpointConfigFormSystemProperty; } String classPathAgentConfigPath = classPathResolver.getAgentConfigPath(); if (classPathAgentConfigPath != null) { logger.info("classpath " + configName + " found. " + classPathAgentConfigPath); return classPathAgentConfigPath; } logger.info(configName + " file not found."); return null; } private List<URL> resolveLib(ClassPathResolver classPathResolver) { // this method may handle only absolute path, need to handle relative path (./..agentlib/lib) String agentJarFullPath = classPathResolver.getAgentJarFullPath(); String agentLibPath = classPathResolver.getAgentLibPath(); List<URL> urlList = resolveLib(classPathResolver.resolveLib()); String agentConfigPath = classPathResolver.getAgentConfigPath(); if (logger.isInfoEnabled()) { logger.info("agent JarPath:" + agentJarFullPath); logger.info("agent LibDir:" + agentLibPath); for (URL url : urlList) { logger.info("agent Lib:" + url); } logger.info("agent config:" + agentConfigPath); } return urlList; } private List<URL> resolveLib(List<URL> urlList) { if (DEFAULT_AGENT.equals(getAgentType().toUpperCase())) { final List<URL> releaseLib = new ArrayList<URL>(urlList.size()); for (URL url : urlList) { // if (!url.toExternalForm().contains("pinpoint-profiler-test")) { releaseLib.add(url); } } return releaseLib; } else { logger.info("load " + PLUGIN_TEST_AGENT + " lib"); // plugin test return urlList; } } }