com.heroku.agent.metrics.Poller Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of heroku-java-metrics-agent Show documentation
Show all versions of heroku-java-metrics-agent Show documentation
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.
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.,-]", "_");
}
}