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.Metric; 015import com.codahale.metrics.graphite.Graphite; 016import com.codahale.metrics.graphite.GraphiteReporter; 017import com.codahale.metrics.graphite.GraphiteSender; 018import com.codahale.metrics.graphite.PickledGraphite; 019import com.nimbusds.common.config.ConfigurationException; 020import com.nimbusds.common.config.MonitorConfiguration; 021import com.nimbusds.common.monitor.MonitorRegistries; 022import org.apache.logging.log4j.LogManager; 023import org.apache.logging.log4j.Logger; 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 is configured.</li> 033 * <li>Starts Graphite reporting is 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 Properties props; 071 072 try { 073 props = ResourceRetriever.getProperties( 074 sce.getServletContext(), 075 CONFIG_CTX_PARAMETER_NAME, 076 log); 077 078 } catch (Exception e) { 079 log.error(e.getMessage(), e); 080 throw new RuntimeException(e.getMessage(), e); 081 } 082 083 // Override with system properties 084 props.putAll(System.getProperties()); 085 086 final MonitorConfiguration config; 087 088 try { 089 config = new MonitorConfiguration(props); 090 091 } catch (ConfigurationException e) { 092 log.error(e.getMessage(), e); 093 throw e; 094 } 095 096 // Log configuration params 097 config.log(); 098 099 // Start JMX reporting if configured 100 if (config.enableJMX) { 101 jmxReporter = JmxReporter.forRegistry(MonitorRegistries.getMetricRegistry()).build(); 102 jmxReporter.start(); 103 log.info("[CM7100] Started JMX reporting with {} metrics", MonitorRegistries.getMetricRegistry().getNames().size()); 104 } else { 105 log.info("[CM7101] JMX metrics reporting disabled"); 106 } 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 if (jmxReporter != null) { 158 jmxReporter.stop(); 159 String msg = "[CM7104] Stopped JMX metrics reporting"; 160 System.out.println(msg); 161 log.info(msg); 162 } 163 164 if (graphiteReporter != null) { 165 graphiteReporter.stop(); 166 String msg = "[CM7105] Stopped Graphite metrics reporting"; 167 System.out.println(msg); 168 log.info(msg); 169 } 170 } 171}