001package com.nimbusds.common.servlet; 002 003 004import java.util.LinkedList; 005import java.util.List; 006import java.util.Map; 007import java.util.Properties; 008import java.util.concurrent.TimeUnit; 009import java.util.stream.Collectors; 010import javax.servlet.ServletContextEvent; 011import javax.servlet.ServletContextListener; 012 013import com.codahale.metrics.JmxReporter; 014import com.codahale.metrics.graphite.Graphite; 015import com.codahale.metrics.graphite.GraphiteReporter; 016import com.codahale.metrics.graphite.GraphiteSender; 017import com.codahale.metrics.graphite.PickledGraphite; 018import com.nimbusds.common.config.ConfigurationException; 019import com.nimbusds.common.config.MonitorConfiguration; 020import com.nimbusds.common.monitor.MonitorRegistries; 021import org.apache.logging.log4j.LogManager; 022import org.apache.logging.log4j.Logger; 023 024 025/** 026 * Monitor launcher. 027 * 028 * <ul> 029 * <li>Exports the shared {@link com.nimbusds.common.monitor.MonitorRegistries} 030 * into the servlet context.</li> 031 * <li>Starts JMX reporting is configured.</li> 032 * <li>Starts Graphite reporting is configured.</li> 033 * </ul> 034 */ 035public class MonitorLauncher implements ServletContextListener { 036 037 038 /** 039 * The name of the servlet context parameter that specifies the 040 * configuration file location. 041 */ 042 public static final String CONFIG_CTX_PARAMETER_NAME = "monitor.configurationFile"; 043 044 045 /** 046 * The JMX reporter. 047 */ 048 protected JmxReporter jmxReporter; 049 050 051 /** 052 * The Graphite reporter. 053 */ 054 protected GraphiteReporter graphiteReporter; 055 056 057 @Override 058 public void contextInitialized(final ServletContextEvent sce) { 059 060 Logger log = LogManager.getLogger("MAIN"); 061 062 sce.getServletContext().setAttribute( 063 "com.codahale.metrics.servlets.MetricsServlet.registry", 064 MonitorRegistries.getMetricRegistry()); 065 066 sce.getServletContext().setAttribute("com.codahale.metrics.servlets.HealthCheckServlet.registry", 067 MonitorRegistries.getHealthCheckRegistry()); 068 069 log.info("[CM7106] Started Dropwizard metrics and health checks"); 070 071 Properties props; 072 073 try { 074 props = ResourceRetriever.getProperties( 075 sce.getServletContext(), 076 CONFIG_CTX_PARAMETER_NAME, 077 log); 078 079 } catch (Exception e) { 080 log.error(e.getMessage(), e); 081 throw new RuntimeException(e.getMessage(), e); 082 } 083 084 // Override with system properties 085 props.putAll(System.getProperties()); 086 087 final MonitorConfiguration config; 088 089 try { 090 config = new MonitorConfiguration(props); 091 092 } catch (ConfigurationException e) { 093 log.error(e.getMessage(), e); 094 throw e; 095 } 096 097 // Log configuration params 098 config.log(); 099 100 // Start JMX reporting if configured 101 if (config.enableJMX) { 102 jmxReporter = JmxReporter.forRegistry(MonitorRegistries.getMetricRegistry()).build(); 103 jmxReporter.start(); 104 log.info("[CM7100] Started JMX reporting with {} metrics", MonitorRegistries.getMetricRegistry().getNames().size()); 105 } else { 106 log.info("[CM7101] JMX metrics reporting disabled"); 107 } 108 109 110 // Start Graphite reporting if configured 111 if (config.graphite.enable) { 112 final GraphiteSender graphite; 113 if (config.graphite.batchSize > 0) { 114 // With batching (recommended) 115 graphite = new PickledGraphite(config.graphite.host, config.graphite.port, config.graphite.batchSize); 116 } else { 117 // No batching 118 graphite = new Graphite(config.graphite.host, config.graphite.port); 119 } 120 121 GraphiteReporter.Builder builder = GraphiteReporter.forRegistry(MonitorRegistries.getMetricRegistry()); 122 123 if (config.graphite.prefix != null && ! config.graphite.prefix.isEmpty()) { 124 builder = builder.prefixedWith(config.graphite.prefix); 125 } 126 127 graphiteReporter = builder.convertRatesTo(config.graphite.ratesTimeUnit) 128 .convertDurationsTo(config.graphite.durationsTimeUnit) 129 .filter(config.graphite.filter) 130 .build(graphite); 131 132 graphiteReporter.start(config.graphite.reportInterval, TimeUnit.SECONDS); 133 134 List<String> filteredNames = MonitorRegistries.getMetricRegistry() 135 .getMetrics() 136 .entrySet() 137 .stream() 138 .filter(entry -> config.graphite.filter.matches(entry.getKey(), entry.getValue())) 139 .map(Map.Entry::getKey) 140 .collect(Collectors.toCollection(LinkedList::new)); 141 142 if (filteredNames.size() > 0) { 143 log.info("[CM7102] Started Graphite reporting with {} metrics: {}", filteredNames.size(), filteredNames); 144 } else { 145 log.warn("[CM7102] Started Graphite reporting, but filter matches zero metrics"); 146 } 147 } else { 148 log.info("[CM7103] Graphite metrics reporting disabled"); 149 } 150 } 151 152 153 @Override 154 public void contextDestroyed(final ServletContextEvent sce) { 155 156 Logger log = LogManager.getLogger("MAIN"); 157 158 MonitorRegistries.getHealthCheckRegistry().shutdown(); 159 160 log.info("[CM7107] Stopped Dropwizard health checks"); 161 162 if (jmxReporter != null) { 163 jmxReporter.stop(); 164 String msg = "[CM7104] Stopped JMX metrics reporting"; 165 System.out.println(msg); 166 log.info(msg); 167 } 168 169 if (graphiteReporter != null) { 170 graphiteReporter.stop(); 171 String msg = "[CM7105] Stopped Graphite metrics reporting"; 172 System.out.println(msg); 173 log.info(msg); 174 } 175 } 176}