package org.stagemonitor.core; import com.codahale.metrics.MetricRegistry; import com.codahale.metrics.SharedMetricRegistries; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.stagemonitor.configuration.ConfigurationRegistry; import org.stagemonitor.configuration.source.ConfigurationSource; import org.stagemonitor.core.instrument.AgentAttacher; import org.stagemonitor.core.metrics.metrics2.Metric2Registry; import org.stagemonitor.core.util.ClassUtils; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.ServiceLoader; import java.util.concurrent.CopyOnWriteArrayList; public final class Stagemonitor { public static final String STAGEMONITOR_PASSWORD = "stagemonitor.password"; private static Logger logger = LoggerFactory.getLogger(Stagemonitor.class); private static ConfigurationRegistry configuration; private static volatile boolean started; private static volatile boolean disabled; private static volatile MeasurementSession measurementSession; private static List<String> pathsOfWidgetMetricTabPlugins = Collections.emptyList(); private static List<String> pathsOfWidgetTabPlugins = Collections.emptyList(); private static Iterable<StagemonitorPlugin> plugins; private static List<Runnable> onShutdownActions = new CopyOnWriteArrayList<Runnable>(); private static Metric2Registry metric2Registry = new Metric2Registry(SharedMetricRegistries.getOrCreate("stagemonitor")); static { try { reset(); } catch (Throwable e) { logger.error(e.getMessage(), e); throw new RuntimeException(e); } } private Stagemonitor() { } /** * Just makes sure the static initializer is executed */ public static void init() { // intentionally left blank } public static synchronized void setMeasurementSession(MeasurementSession measurementSession) { if (!getPlugin(CorePlugin.class).isStagemonitorActive()) { logger.info("stagemonitor is deactivated"); disabled = true; } if (started || disabled) { return; } Stagemonitor.measurementSession = measurementSession; } public static void startMonitoring() { doStartMonitoring(); } public static synchronized void startMonitoring(MeasurementSession measurementSession) { setMeasurementSession(measurementSession); startMonitoring(); } private static synchronized void doStartMonitoring() { if (started) { return; } if (measurementSession.isInitialized()) { logger.info("Measurement Session is initialized: " + measurementSession); try { start(); } catch (RuntimeException e) { logger.warn("Error while trying to start monitoring. (this exception is ignored)", e); } } else { logger.debug("Measurement Session is not initialized: {}", measurementSession); logger.debug("make sure the properties 'stagemonitor.instanceName' and 'stagemonitor.applicationName' " + "are set and stagemonitor.properties is available in the classpath"); } } private static void start() { initializePlugins(); started = true; // don't register a shutdown hook for web applications as this causes a memory leak if (ClassUtils.isNotPresent("javax.servlet.Servlet")) { // in case the application does not directly call shutDown Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() { public void run() { shutDown(); } })); } } private static void initializePlugins() { final CorePlugin corePlugin = getPlugin(CorePlugin.class); final Collection<String> disabledPlugins = corePlugin.getDisabledPlugins(); pathsOfWidgetMetricTabPlugins = new CopyOnWriteArrayList<String>(); pathsOfWidgetTabPlugins = new CopyOnWriteArrayList<String>(); for (StagemonitorPlugin stagemonitorPlugin : plugins) { final String pluginName = stagemonitorPlugin.getClass().getSimpleName(); if (disabledPlugins.contains(pluginName)) { logger.info("Not initializing disabled plugin {}", pluginName); } else { initializePlugin(stagemonitorPlugin, pluginName); } } } private static void initializePlugin(final StagemonitorPlugin stagemonitorPlugin, String pluginName) { logger.info("Initializing plugin {}", pluginName); try { stagemonitorPlugin.initializePlugin(new StagemonitorPlugin.InitArguments(metric2Registry, getConfiguration(), measurementSession)); stagemonitorPlugin.initialized = true; for (Runnable onInitCallback : stagemonitorPlugin.onInitCallbacks) { onInitCallback.run(); } stagemonitorPlugin.registerWidgetTabPlugins(new StagemonitorPlugin.WidgetTabPluginsRegistry(pathsOfWidgetTabPlugins)); stagemonitorPlugin.registerWidgetMetricTabPlugins(new StagemonitorPlugin.WidgetMetricTabPluginsRegistry(pathsOfWidgetMetricTabPlugins)); } catch (Exception e) { logger.warn("Error while initializing plugin " + pluginName + " (this exception is ignored)", e); } } /** * Should be called when the server is shutting down. * Calls the {@link StagemonitorPlugin#onShutDown()} method of all plugins */ public static synchronized void shutDown() { if (measurementSession.getEndTimestamp() != null) { // shutDown has already been called return; } measurementSession.setEndTimestamp(System.currentTimeMillis()); for (Runnable onShutdownAction : onShutdownActions) { try { onShutdownAction.run(); } catch (RuntimeException e) { logger.warn(e.getMessage(), e); } } for (StagemonitorPlugin plugin : plugins) { try { plugin.onShutDown(); } catch (Exception e) { logger.warn(e.getMessage(), e); } } configuration.close(); } /** * @deprecated use {@link #getMetric2Registry()} */ @Deprecated public static MetricRegistry getMetricRegistry() { return metric2Registry.getMetricRegistry(); } public static Metric2Registry getMetric2Registry() { return metric2Registry; } public static ConfigurationRegistry getConfiguration() { return configuration; } public static <T extends StagemonitorPlugin> T getPlugin(Class<T> plugin) { return configuration.getConfig(plugin); } /** * @deprecated use {@link #getPlugin(Class)} */ @Deprecated public static <T extends StagemonitorPlugin> T getConfiguration(Class<T> plugin) { return getPlugin(plugin); } static void setConfiguration(ConfigurationRegistry configuration) { Stagemonitor.configuration = configuration; } public static MeasurementSession getMeasurementSession() { return measurementSession; } public static boolean isStarted() { return started; } static boolean isDisabled() { return disabled; } static void setLogger(Logger logger) { Stagemonitor.logger = logger; } /** * @see StagemonitorPlugin#getPathsOfWidgetTabPlugins() */ public static List<String> getPathsOfWidgetTabPlugins() { return Collections.unmodifiableList(pathsOfWidgetTabPlugins); } /** * @see org.stagemonitor.core.StagemonitorPlugin#getPathsOfWidgetMetricTabPlugins() */ public static List<String> getPathsOfWidgetMetricTabPlugins() { return Collections.unmodifiableList(pathsOfWidgetMetricTabPlugins); } /** * Should only be used outside of this class by the internal unit tests */ public static void reset() { started = false; disabled = false; measurementSession = new MeasurementSession(null, null, null); if (configuration == null) { reloadPluginsAndConfiguration(); } tryStartMonitoring(); onShutdownActions.add(AgentAttacher.performRuntimeAttachment()); } private static void tryStartMonitoring() { CorePlugin corePlugin = getPlugin(CorePlugin.class); MeasurementSession session = new MeasurementSession(corePlugin.getApplicationName(), corePlugin.getHostName(), corePlugin.getInstanceName()); startMonitoring(session); } private static void reloadPluginsAndConfiguration() { List<ConfigurationSource> configurationSources = new ArrayList<ConfigurationSource>(); for (StagemonitorConfigurationSourceInitializer initializer : ServiceLoader.load(StagemonitorConfigurationSourceInitializer.class, Stagemonitor.class.getClassLoader())) { initializer.modifyConfigurationSources(new StagemonitorConfigurationSourceInitializer.ModifyArguments(configurationSources)); } configurationSources.remove(null); plugins = ServiceLoader.load(StagemonitorPlugin.class, Stagemonitor.class.getClassLoader()); configuration = new ConfigurationRegistry(plugins, configurationSources, STAGEMONITOR_PASSWORD); try { for (StagemonitorConfigurationSourceInitializer initializer : ServiceLoader.load(StagemonitorConfigurationSourceInitializer.class, Stagemonitor.class.getClassLoader())) { initializer.onConfigurationInitialized(new StagemonitorConfigurationSourceInitializer.ConfigInitializedArguments(configuration)); } } catch (Exception e) { logger.error(e.getMessage(), e); logger.error("Stagemonitor will be deactivated!"); disabled = true; } } }