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