MetricsManager.java

  1. package emissary.core;

  2. import emissary.config.ConfigUtil;
  3. import emissary.config.Configurator;

  4. import com.codahale.metrics.Counter;
  5. import com.codahale.metrics.Gauge;
  6. import com.codahale.metrics.Histogram;
  7. import com.codahale.metrics.Meter;
  8. import com.codahale.metrics.MetricFilter;
  9. import com.codahale.metrics.MetricRegistry;
  10. import com.codahale.metrics.Slf4jReporter;
  11. import com.codahale.metrics.Timer;
  12. import com.codahale.metrics.graphite.Graphite;
  13. import com.codahale.metrics.graphite.GraphiteReporter;
  14. import com.codahale.metrics.health.HealthCheckRegistry;
  15. import com.codahale.metrics.health.jvm.ThreadDeadlockHealthCheck;
  16. import com.codahale.metrics.jmx.JmxReporter;
  17. import com.codahale.metrics.jvm.FileDescriptorRatioGauge;
  18. import com.codahale.metrics.jvm.GarbageCollectorMetricSet;
  19. import com.codahale.metrics.jvm.MemoryUsageGaugeSet;
  20. import com.codahale.metrics.jvm.ThreadStatesGaugeSet;
  21. import org.slf4j.Logger;
  22. import org.slf4j.LoggerFactory;

  23. import java.io.IOException;
  24. import java.net.InetSocketAddress;
  25. import java.util.Map;
  26. import java.util.SortedMap;
  27. import java.util.TreeMap;
  28. import java.util.concurrent.TimeUnit;

  29. /**
  30.  * Manages the interactions with CodaHale's Metrics package, including configuration
  31.  */
  32. public class MetricsManager {

  33.     public static final String DEFAULT_NAMESPACE_NAME = "MetricsManager";

  34.     @SuppressWarnings("rawtypes")
  35.     public static final SortedMap<String, Gauge> EMPTY_GUAGES = new TreeMap<>();
  36.     public static final SortedMap<String, Counter> EMPTY_COUNTERS = new TreeMap<>();
  37.     public static final SortedMap<String, Histogram> EMPTY_HISTOGRAMS = new TreeMap<>();
  38.     public static final SortedMap<String, Meter> EMPTY_METERS = new TreeMap<>();

  39.     protected static final Logger logger = LoggerFactory.getLogger(MetricsManager.class);

  40.     protected final MetricRegistry metrics = new MetricRegistry();
  41.     protected final HealthCheckRegistry healthChecks = new HealthCheckRegistry();

  42.     protected final Slf4jReporter reporter;
  43.     protected Configurator conf;

  44.     /**
  45.      * Lookup the default ResourceWatcher in the Namespace
  46.      */
  47.     public static MetricsManager lookup() throws NamespaceException {
  48.         return (MetricsManager) Namespace.lookup(DEFAULT_NAMESPACE_NAME);
  49.     }

  50.     public MetricsManager() {
  51.         configure();
  52.         init();
  53.         this.reporter = Slf4jReporter.forRegistry(this.metrics).build();
  54.     }

  55.     /**
  56.      * Create manager using specified configuration
  57.      *
  58.      * @param conf the configuration to use
  59.      */
  60.     public MetricsManager(final Configurator conf) {
  61.         this.conf = conf;
  62.         init();
  63.         this.reporter = Slf4jReporter.forRegistry(this.metrics).build();
  64.     }

  65.     public void logMetrics(final Map<String, Timer> stats) {
  66.         final SortedMap<String, Timer> m = new TreeMap<>();
  67.         m.putAll(stats);
  68.         this.reporter.report(EMPTY_GUAGES, EMPTY_COUNTERS, EMPTY_HISTOGRAMS, EMPTY_METERS, m);
  69.     }

  70.     public MetricRegistry getMetricRegistry() {
  71.         return this.metrics;
  72.     }

  73.     public HealthCheckRegistry getHealthCheckRegistry() {
  74.         return this.healthChecks;
  75.     }

  76.     protected void configure() {
  77.         try {
  78.             this.conf = ConfigUtil.getConfigInfo(MetricsManager.class);
  79.         } catch (IOException e) {
  80.             logger.warn("Cannot read MetricsManager.cfg, taking default values");
  81.         }
  82.     }

  83.     protected void init() {
  84.         Namespace.bind(DEFAULT_NAMESPACE_NAME, this);

  85.         if (this.conf == null) {
  86.             logger.warn("Configuration is null, skipping init()");
  87.         }

  88.         initMetrics();
  89.         initHealthChecks();
  90.         initJmxReporter();
  91.         initGraphiteReporter();
  92.         initSlf4jReporter();
  93.     }

  94.     protected void initHealthChecks() {
  95.         this.healthChecks.register(
  96.                 "healthcheck.filequeue",
  97.                 new FilePickUpPlaceHealthCheck(this.conf.findIntEntry("MAX_FILE_COUNT_BEFORE_UNHEALTHY", Integer.MAX_VALUE), this.conf.findLongEntry(
  98.                         "MAX_AGGREGATE_FIZE_SIZE_BEFORE_UNHEALTHY_BYTES", Long.MAX_VALUE)));
  99.         this.healthChecks.register("healthcheck.threaddeadlocks", new ThreadDeadlockHealthCheck());
  100.         this.healthChecks.register("healthcheck.agentpool", new AgentPoolHealthCheck());
  101.     }

  102.     protected void initMetrics() {
  103.         if (this.conf.findBooleanEntry("JVM_METRICS_ENABLED", false)) {
  104.             logger.debug("JVM Metrics are enabled");
  105.             this.metrics.registerAll(new MemoryUsageGaugeSet());
  106.             this.metrics.registerAll(new GarbageCollectorMetricSet());
  107.             this.metrics.registerAll(new ThreadStatesGaugeSet());
  108.             this.metrics.register("file.descriptor.info", new FileDescriptorRatioGauge());
  109.         } else {
  110.             logger.debug("JVM Metrics are disabled");
  111.         }
  112.     }

  113.     protected void initJmxReporter() {
  114.         if (!this.conf.findBooleanEntry("JMX_METRICS_ENABLED", false)) {
  115.             logger.debug("JMX Metrics are disabled");
  116.             return;
  117.         }

  118.         logger.debug("JMX Metrics are enabled");

  119.         final String domain = this.conf.findStringEntry("JMX_METRICS_DOMAIN", "emissary-metrics");
  120.         final TimeUnit rateUnit = TimeUnit.valueOf(this.conf.findStringEntry("JMX_METRICS_RATE_UNIT", TimeUnit.SECONDS.name()));
  121.         final TimeUnit durationUnit = TimeUnit.valueOf(this.conf.findStringEntry("JMX_METRICS_DURATION_UNIT", TimeUnit.MILLISECONDS.name()));


  122.         final JmxReporter jmxReporter =
  123.                 JmxReporter.forRegistry(this.metrics).inDomain(domain).convertRatesTo(rateUnit).convertDurationsTo(durationUnit).build();

  124.         jmxReporter.start();
  125.     }

  126.     protected void initSlf4jReporter() {
  127.         if (!this.conf.findBooleanEntry("SLF4J_METRICS_ENABLED", false)) {
  128.             logger.debug("Slf4j Metrics are disabled");
  129.             return;
  130.         }

  131.         logger.debug("Slf4j Metrics are enabled");

  132.         final String loggerStr = this.conf.findStringEntry("SLF4J_METRICS_LOGGER", "emissary.core.metrics");
  133.         final int interval = this.conf.findIntEntry("SL4J_METRICS_INTERVAL", -1);

  134.         final TimeUnit intervalUnit = TimeUnit.valueOf(this.conf.findStringEntry("SL4J_METRICS_INTERVAL_UNIT", TimeUnit.MINUTES.name()));
  135.         final TimeUnit rateUnit = TimeUnit.valueOf(this.conf.findStringEntry("SLF4J_METRICS_RATE_UNIT", TimeUnit.SECONDS.name()));
  136.         final TimeUnit durationUnit = TimeUnit.valueOf(this.conf.findStringEntry("SLF4J_METRICS_DURATION_UNIT", TimeUnit.MILLISECONDS.name()));

  137.         final Slf4jReporter slf4jReporter =
  138.                 Slf4jReporter.forRegistry(this.metrics).outputTo(LoggerFactory.getLogger(loggerStr)).convertRatesTo(rateUnit)
  139.                         .convertDurationsTo(durationUnit).build();

  140.         if (interval > 0) {
  141.             slf4jReporter.start(interval, intervalUnit);
  142.         }
  143.     }

  144.     protected void initGraphiteReporter() {
  145.         if (!this.conf.findBooleanEntry("GRAPHITE_METRICS_ENABLED", false)) {
  146.             logger.debug("Graphite Metrics are disabled");
  147.             return;
  148.         }

  149.         logger.debug("Graphite Metrics are enabled");

  150.         final String prefix = this.conf.findStringEntry("GRAPHITE_METRICS_PREFIX", "emissary");
  151.         final String host = this.conf.findStringEntry("GRAPHITE_METRICS_HOST", "localhost");
  152.         final int port = this.conf.findIntEntry("GRAPHITE_METRICS_PORT", 2003);
  153.         final int interval = this.conf.findIntEntry("GRAPHITE_METRICS_INTERVAL", -1);

  154.         final TimeUnit intervalUnit = TimeUnit.valueOf(this.conf.findStringEntry("GRAPHITE_METRICS_INTERVAL_UNIT", TimeUnit.MINUTES.name()));
  155.         final TimeUnit rateUnit = TimeUnit.valueOf(this.conf.findStringEntry("GRAPHITE_RATE_UNIT", TimeUnit.SECONDS.name()));
  156.         final TimeUnit durationUnit = TimeUnit.valueOf(this.conf.findStringEntry("GRAPHITE_DURATION_UNIT", TimeUnit.MILLISECONDS.name()));

  157.         final Graphite graphite = new Graphite(new InetSocketAddress(host, port));
  158.         final GraphiteReporter graphiteReporter =
  159.                 GraphiteReporter.forRegistry(this.metrics).prefixedWith(prefix).convertRatesTo(rateUnit).convertDurationsTo(durationUnit)
  160.                         .filter(MetricFilter.ALL).build(graphite);

  161.         if (interval > 0) {
  162.             graphiteReporter.start(interval, intervalUnit);
  163.         }
  164.     }

  165.     public void shutdown() {
  166.         this.healthChecks.shutdown();
  167.         this.metrics.getMetrics().keySet().forEach(metrics::remove);
  168.         this.metrics.getTimers().keySet().forEach(metrics::remove);
  169.         this.metrics.getCounters().keySet().forEach(metrics::remove);
  170.         this.metrics.getGauges().keySet().forEach(metrics::remove);
  171.         this.metrics.getHistograms().keySet().forEach(metrics::remove);
  172.         this.metrics.getMeters().keySet().forEach(metrics::remove);
  173.         Namespace.unbind(DEFAULT_NAMESPACE_NAME);
  174.     }
  175. }