All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.heroku.agent.metrics.Poller Maven / Gradle / Ivy

Go to download

This artifact is for use with the JVM Runtime Metrics features. It is a lightweight Java agent that uses a Prometheus Java client to report metrics.

There is a newer version: 4.0.3
Show newest version
package com.heroku.agent.metrics;

import java.io.IOException;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import io.prometheus.client.Collector;
import io.prometheus.client.CollectorRegistry;

/**
 * @author Joe Kutner on 11/1/17.
 *         Twitter: @codefinger
 */
public class Poller {

  private CollectorRegistry registry;

  private final Timer timer;

  private Map previousCounters = new ConcurrentHashMap<>();

  public Poller() {
    this.timer = new Timer("heroku-java-metrics-agent",true);
    this.registry = CollectorRegistry.defaultRegistry;
  }

  public void poll(final Callback callback) throws IOException {
    timer.scheduleAtFixedRate(new TimerTask() {
      @Override
      public void run() {
        Map counters = new ConcurrentHashMap<>();
        ObjectMapper mapper = new ObjectMapper();
        ObjectNode metricsJson = mapper.createObjectNode();
        ObjectNode gaugesJson = metricsJson.putObject("gauges");
        ObjectNode countersJson = metricsJson.putObject("counters");

        Enumeration samples = registry.metricFamilySamples();
        while (samples.hasMoreElements()) {
          Collector.MetricFamilySamples metricFamilySamples = samples.nextElement();
          switch (metricFamilySamples.type) {
            case GAUGE:
              for (Metric m : collectSamples(metricFamilySamples.samples)) {
                gaugesJson.put(m.getKey(), m.getValue());
              }
              break;
            case COUNTER:
              for (Metric m : collectSamples(metricFamilySamples.samples)) {
                countersJson.put(m.getKey(), m.getDerivedValue(previousCounters.get(m.getKey())));
                counters.put(m.getKey(), m);
              }
              break;
            case SUMMARY:
              for (Metric m : collectSamples(metricFamilySamples.samples)) {
                countersJson.put(m.getKey(), m.getDerivedValue(previousCounters.get(m.getKey())));
                counters.put(m.getKey(), m);
              }
              break;
          }
        }
        previousCounters = counters;
        callback.apply(mapper, metricsJson);
      }
    }, 5, 5);
  }

  public void cancel() {
    this.timer.cancel();
  }

  public static abstract class Callback {
    public abstract void apply(ObjectMapper mapper, ObjectNode metricsJson);
  }

  private List collectSamples(List samples) {
    List metrics = new ArrayList<>();
    for (Collector.MetricFamilySamples.Sample sample : samples) {
      StringBuilder key = new StringBuilder(sample.name);
      for (int i = 0; i < sample.labelNames.size(); i++) {
        key.append(".").append(massageLabel(sample.labelNames.get(i) + "_" + sample.labelValues.get(i)));
      }
      metrics.add(new Metric(key.toString(), sample.value));
    }
    return metrics;
  }

  private String massageLabel(String rune) {
    return rune.replaceAll("[^0-9a-zA-Z.,-]", "_");
  }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy