package com.levigo.jadice.webtoolkit.monitoring.client; import java.util.Collection; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import javax.servlet.ServletContext; import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener; import javax.servlet.ServletRegistration; import com.levigo.jadice.webtoolkit.monitoring.data.CounterData; import com.levigo.jadice.webtoolkit.monitoring.data.DataObject; import com.levigo.jadice.webtoolkit.monitoring.data.DurationData; import com.levigo.jadice.webtoolkit.monitoring.data.ReturnData; import io.prometheus.client.Collector; import io.prometheus.client.CollectorRegistry; import io.prometheus.client.Counter; import io.prometheus.client.Histogram; import io.prometheus.client.SimpleCollector; import io.prometheus.client.exporter.MetricsServlet; public class PrometheusAdapter implements MonitorClient, ServletContextListener { private static final String contextPath = "/metrics"; private CollectorRegistry collectorRegistry = CollectorRegistry.defaultRegistry; private Map<String, Collector> collectors = new ConcurrentHashMap<>(); @Override public void publish(DataObject<?> data) { String[] labelValues = mapToArray(data.getLabels().values()); if (data instanceof DurationData) { DurationData dd = (DurationData) data; // Gauge gauge = getCollector(Gauge.build(), dd); Histogram hist = getCollector(Histogram.build(), dd); if (dd.hasMetricLabel()) { // gauge.labels(dd.getMetricLabelValue()).set(dd.getValue()); hist.labels(labelValues).observe(dd.getValue()); } else { // gauge.set((dd.getValue())); hist.observe(dd.getValue()); } } else if (data instanceof CounterData) { CounterData cd = (CounterData) data; Counter counter = getCollector(Counter.build(), cd); counter.clear(); if (cd.hasMetricLabel()) { counter.labels(labelValues).inc(cd.getValue()); } else { counter.inc(cd.getValue()); } } else if (data instanceof ReturnData) { // not supported by Prometheus // https://prometheus.io/docs/concepts/metric_types/ } } @Override public void contextInitialized(ServletContextEvent sce) { ServletContext context = sce.getServletContext(); ServletRegistration.Dynamic dynamic = context.addServlet("MetricsServlet", new MetricsServlet(collectorRegistry)); dynamic.addMapping(contextPath); } @Override public void contextDestroyed(ServletContextEvent sce) { // nothing to do here } private String[] mapToArray(Collection<String> collection) { return collection.toArray(new String[collection.size()]); } private <C extends SimpleCollector<?>, B extends SimpleCollector.Builder<B, C>> C getCollector( SimpleCollector.Builder<B, C> builder, DataObject<?> data) { @SuppressWarnings("unchecked") C collector = (C) collectors.get(data.getMetricName()); String[] labelAttributes = mapToArray(data.getLabels().keySet()); if (null == collector) { if (data.hasMetricLabel()) { collector = builder.name(data.getMetricName()).help(data.getMetricDescription()).labelNames( labelAttributes).register(); } else { collector = builder.name(data.getMetricName()).help(data.getMetricDescription()).register(); } collectors.put(data.getMetricName(), collector); } return collector; } }