Skip to content

Commit 5359ba3

Browse files
kingsterzeitlinger
andauthored
Add support for dw-metrics 4.x (#1228)
* Add support for dw-metrics 4.x Signed-off-by: Kinshuk Bairagi <[email protected]> * Update DropwizardExportsTest.java Signed-off-by: Kinshuk Bairagi <[email protected]> * cleanup Signed-off-by: Gregor Zeitlinger <[email protected]> --------- Signed-off-by: Kinshuk Bairagi <[email protected]> Signed-off-by: Gregor Zeitlinger <[email protected]> Co-authored-by: Gregor Zeitlinger <[email protected]>
1 parent 3d216b8 commit 5359ba3

File tree

5 files changed

+662
-0
lines changed

5 files changed

+662
-0
lines changed

pom.xml

+1
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@
7777
<module>prometheus-metrics-instrumentation-caffeine</module>
7878
<module>prometheus-metrics-instrumentation-jvm</module>
7979
<module>prometheus-metrics-instrumentation-dropwizard5</module>
80+
<module>prometheus-metrics-instrumentation-dropwizard</module>
8081
<module>prometheus-metrics-instrumentation-guava</module>
8182
<module>prometheus-metrics-simpleclient-bridge</module>
8283
</modules>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
3+
<modelVersion>4.0.0</modelVersion>
4+
5+
<parent>
6+
<groupId>io.prometheus</groupId>
7+
<artifactId>client_java</artifactId>
8+
<version>10.0.0-SNAPSHOT</version>
9+
</parent>
10+
11+
<artifactId>prometheus-metrics-instrumentation-dropwizard</artifactId>
12+
<packaging>bundle</packaging>
13+
14+
<name>Prometheus Metrics Instrumentation - Dropwizard 4.x</name>
15+
<description>
16+
Instrumentation library for Dropwizard metrics 4.x
17+
</description>
18+
19+
<properties>
20+
<automatic.module.name>io.prometheus.metrics.instrumentation.dropwizard</automatic.module.name>
21+
</properties>
22+
23+
<licenses>
24+
<license>
25+
<name>The Apache Software License, Version 2.0</name>
26+
<url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
27+
<distribution>repo</distribution>
28+
</license>
29+
</licenses>
30+
<developers>
31+
<developer>
32+
<id>kingster</id>
33+
<name>Kinshuk Bairagi</name>
34+
<email>[email protected]</email>
35+
</developer>
36+
37+
</developers>
38+
39+
<dependencies>
40+
<dependency>
41+
<groupId>io.prometheus</groupId>
42+
<artifactId>prometheus-metrics-core</artifactId>
43+
<version>${project.version}</version>
44+
</dependency>
45+
<dependency>
46+
<groupId>io.dropwizard.metrics</groupId>
47+
<artifactId>metrics-core</artifactId>
48+
<version>4.2.0</version>
49+
<scope>provided</scope>
50+
</dependency>
51+
52+
<dependency>
53+
<groupId>io.prometheus</groupId>
54+
<artifactId>prometheus-metrics-exporter-httpserver</artifactId>
55+
<version>${project.version}</version>
56+
<scope>test</scope>
57+
</dependency>
58+
<dependency>
59+
<groupId>io.prometheus</groupId>
60+
<artifactId>prometheus-metrics-exposition-textformats</artifactId>
61+
<version>${project.version}</version>
62+
<scope>test</scope>
63+
</dependency>
64+
<dependency>
65+
<groupId>io.prometheus</groupId>
66+
<artifactId>prometheus-metrics-instrumentation-dropwizard5</artifactId>
67+
<version>${project.version}</version>
68+
<scope>compile</scope>
69+
<exclusions>
70+
<exclusion>
71+
<groupId>io.dropwizard.metrics5</groupId>
72+
<artifactId>metrics-core</artifactId>
73+
</exclusion>
74+
</exclusions>
75+
</dependency>
76+
77+
</dependencies>
78+
79+
</project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,274 @@
1+
package io.prometheus.metrics.instrumentation.dropwizard;
2+
3+
import com.codahale.metrics.Counter;
4+
import com.codahale.metrics.Gauge;
5+
import com.codahale.metrics.Histogram;
6+
import com.codahale.metrics.Meter;
7+
import com.codahale.metrics.Metric;
8+
import com.codahale.metrics.MetricFilter;
9+
import com.codahale.metrics.MetricRegistry;
10+
import com.codahale.metrics.Snapshot;
11+
import com.codahale.metrics.Timer;
12+
import io.prometheus.metrics.instrumentation.dropwizard5.labels.CustomLabelMapper;
13+
import io.prometheus.metrics.model.registry.MultiCollector;
14+
import io.prometheus.metrics.model.registry.PrometheusRegistry;
15+
import io.prometheus.metrics.model.snapshots.CounterSnapshot;
16+
import io.prometheus.metrics.model.snapshots.GaugeSnapshot;
17+
import io.prometheus.metrics.model.snapshots.MetricMetadata;
18+
import io.prometheus.metrics.model.snapshots.MetricSnapshot;
19+
import io.prometheus.metrics.model.snapshots.MetricSnapshots;
20+
import io.prometheus.metrics.model.snapshots.PrometheusNaming;
21+
import io.prometheus.metrics.model.snapshots.Quantiles;
22+
import io.prometheus.metrics.model.snapshots.SummarySnapshot;
23+
import java.util.Collections;
24+
import java.util.Optional;
25+
import java.util.concurrent.TimeUnit;
26+
import java.util.logging.Level;
27+
import java.util.logging.Logger;
28+
29+
/** Collect Dropwizard metrics from a MetricRegistry. */
30+
public class DropwizardExports implements MultiCollector {
31+
private static final Logger logger = Logger.getLogger(DropwizardExports.class.getName());
32+
private final MetricRegistry registry;
33+
private final MetricFilter metricFilter;
34+
private final Optional<CustomLabelMapper> labelMapper;
35+
36+
/**
37+
* Creates a new DropwizardExports and {@link MetricFilter#ALL}.
38+
*
39+
* @param registry a metric registry to export in prometheus.
40+
*/
41+
public DropwizardExports(MetricRegistry registry) {
42+
super();
43+
this.registry = registry;
44+
this.metricFilter = MetricFilter.ALL;
45+
this.labelMapper = Optional.empty();
46+
}
47+
48+
/**
49+
* Creates a new DropwizardExports with a custom {@link MetricFilter}.
50+
*
51+
* @param registry a metric registry to export in prometheus.
52+
* @param metricFilter a custom metric filter.
53+
*/
54+
public DropwizardExports(MetricRegistry registry, MetricFilter metricFilter) {
55+
this.registry = registry;
56+
this.metricFilter = metricFilter;
57+
this.labelMapper = Optional.empty();
58+
}
59+
60+
/**
61+
* @param registry a metric registry to export in prometheus.
62+
* @param metricFilter a custom metric filter.
63+
* @param labelMapper a labelMapper to use to map labels.
64+
*/
65+
public DropwizardExports(
66+
MetricRegistry registry, MetricFilter metricFilter, CustomLabelMapper labelMapper) {
67+
this.registry = registry;
68+
this.metricFilter = metricFilter;
69+
this.labelMapper = Optional.ofNullable(labelMapper);
70+
}
71+
72+
private static String getHelpMessage(String metricName, Metric metric) {
73+
return String.format(
74+
"Generated from Dropwizard metric import (metric=%s, type=%s)",
75+
metricName, metric.getClass().getName());
76+
}
77+
78+
private MetricMetadata getMetricMetaData(String metricName, Metric metric) {
79+
String name = labelMapper.isPresent() ? labelMapper.get().getName(metricName) : metricName;
80+
return new MetricMetadata(
81+
PrometheusNaming.sanitizeMetricName(name), getHelpMessage(metricName, metric));
82+
}
83+
84+
/**
85+
* Export counter as Prometheus <a
86+
* href="https://prometheus.io/docs/concepts/metric_types/#gauge">Gauge</a>.
87+
*/
88+
MetricSnapshot fromCounter(String dropwizardName, Counter counter) {
89+
MetricMetadata metadata = getMetricMetaData(dropwizardName, counter);
90+
CounterSnapshot.CounterDataPointSnapshot.Builder dataPointBuilder =
91+
CounterSnapshot.CounterDataPointSnapshot.builder()
92+
.value(Long.valueOf(counter.getCount()).doubleValue());
93+
labelMapper.ifPresent(
94+
mapper ->
95+
dataPointBuilder.labels(
96+
mapper.getLabels(
97+
dropwizardName, Collections.emptyList(), Collections.emptyList())));
98+
return new CounterSnapshot(metadata, Collections.singletonList(dataPointBuilder.build()));
99+
}
100+
101+
/** Export gauge as a prometheus gauge. */
102+
MetricSnapshot fromGauge(String dropwizardName, Gauge<?> gauge) {
103+
Object obj = gauge.getValue();
104+
double value;
105+
if (obj instanceof Number) {
106+
value = ((Number) obj).doubleValue();
107+
} else if (obj instanceof Boolean) {
108+
value = ((Boolean) obj) ? 1 : 0;
109+
} else {
110+
logger.log(
111+
Level.FINE,
112+
String.format(
113+
"Invalid type for Gauge %s: %s",
114+
PrometheusNaming.sanitizeMetricName(dropwizardName),
115+
obj == null ? "null" : obj.getClass().getName()));
116+
return null;
117+
}
118+
MetricMetadata metadata = getMetricMetaData(dropwizardName, gauge);
119+
GaugeSnapshot.GaugeDataPointSnapshot.Builder dataPointBuilder =
120+
GaugeSnapshot.GaugeDataPointSnapshot.builder().value(value);
121+
labelMapper.ifPresent(
122+
mapper ->
123+
dataPointBuilder.labels(
124+
mapper.getLabels(
125+
dropwizardName, Collections.emptyList(), Collections.emptyList())));
126+
return new GaugeSnapshot(metadata, Collections.singletonList(dataPointBuilder.build()));
127+
}
128+
129+
/**
130+
* Export a histogram snapshot as a prometheus SUMMARY.
131+
*
132+
* @param dropwizardName metric name.
133+
* @param snapshot the histogram snapshot.
134+
* @param count the total sample count for this snapshot.
135+
* @param factor a factor to apply to histogram values.
136+
*/
137+
MetricSnapshot fromSnapshotAndCount(
138+
String dropwizardName, Snapshot snapshot, long count, double factor, String helpMessage) {
139+
Quantiles quantiles =
140+
Quantiles.builder()
141+
.quantile(0.5, snapshot.getMedian() * factor)
142+
.quantile(0.75, snapshot.get75thPercentile() * factor)
143+
.quantile(0.95, snapshot.get95thPercentile() * factor)
144+
.quantile(0.98, snapshot.get98thPercentile() * factor)
145+
.quantile(0.99, snapshot.get99thPercentile() * factor)
146+
.quantile(0.999, snapshot.get999thPercentile() * factor)
147+
.build();
148+
149+
MetricMetadata metadata =
150+
new MetricMetadata(PrometheusNaming.sanitizeMetricName(dropwizardName), helpMessage);
151+
SummarySnapshot.SummaryDataPointSnapshot.Builder dataPointBuilder =
152+
SummarySnapshot.SummaryDataPointSnapshot.builder().quantiles(quantiles).count(count);
153+
labelMapper.ifPresent(
154+
mapper ->
155+
dataPointBuilder.labels(
156+
mapper.getLabels(
157+
dropwizardName, Collections.emptyList(), Collections.emptyList())));
158+
return new SummarySnapshot(metadata, Collections.singletonList(dataPointBuilder.build()));
159+
}
160+
161+
/** Convert histogram snapshot. */
162+
MetricSnapshot fromHistogram(String dropwizardName, Histogram histogram) {
163+
return fromSnapshotAndCount(
164+
dropwizardName,
165+
histogram.getSnapshot(),
166+
histogram.getCount(),
167+
1.0,
168+
getHelpMessage(dropwizardName, histogram));
169+
}
170+
171+
/** Export Dropwizard Timer as a histogram. Use TIME_UNIT as time unit. */
172+
MetricSnapshot fromTimer(String dropwizardName, Timer timer) {
173+
return fromSnapshotAndCount(
174+
dropwizardName,
175+
timer.getSnapshot(),
176+
timer.getCount(),
177+
1.0D / TimeUnit.SECONDS.toNanos(1L),
178+
getHelpMessage(dropwizardName, timer));
179+
}
180+
181+
/** Export a Meter as a prometheus COUNTER. */
182+
MetricSnapshot fromMeter(String dropwizardName, Meter meter) {
183+
MetricMetadata metadata = getMetricMetaData(dropwizardName + "_total", meter);
184+
CounterSnapshot.CounterDataPointSnapshot.Builder dataPointBuilder =
185+
CounterSnapshot.CounterDataPointSnapshot.builder().value(meter.getCount());
186+
labelMapper.ifPresent(
187+
mapper ->
188+
dataPointBuilder.labels(
189+
mapper.getLabels(
190+
dropwizardName, Collections.emptyList(), Collections.emptyList())));
191+
return new CounterSnapshot(metadata, Collections.singletonList(dataPointBuilder.build()));
192+
}
193+
194+
@Override
195+
public MetricSnapshots collect() {
196+
MetricSnapshots.Builder metricSnapshots = MetricSnapshots.builder();
197+
198+
registry
199+
.getGauges(metricFilter)
200+
.forEach(
201+
(name, gauge) -> {
202+
MetricSnapshot snapshot = fromGauge(name, gauge);
203+
if (snapshot != null) {
204+
metricSnapshots.metricSnapshot(snapshot);
205+
}
206+
});
207+
208+
registry
209+
.getCounters(metricFilter)
210+
.forEach((name, counter) -> metricSnapshots.metricSnapshot(fromCounter(name, counter)));
211+
registry
212+
.getHistograms(metricFilter)
213+
.forEach(
214+
(name, histogram) -> metricSnapshots.metricSnapshot(fromHistogram(name, histogram)));
215+
registry
216+
.getTimers(metricFilter)
217+
.forEach((name, timer) -> metricSnapshots.metricSnapshot(fromTimer(name, timer)));
218+
registry
219+
.getMeters(metricFilter)
220+
.forEach((name, meter) -> metricSnapshots.metricSnapshot(fromMeter(name, meter)));
221+
222+
return metricSnapshots.build();
223+
}
224+
225+
public static Builder builder() {
226+
return new Builder();
227+
}
228+
229+
// Builder class for DropwizardExports
230+
public static class Builder {
231+
private MetricRegistry registry;
232+
private MetricFilter metricFilter;
233+
private CustomLabelMapper labelMapper;
234+
235+
private Builder() {
236+
this.metricFilter = MetricFilter.ALL;
237+
}
238+
239+
public Builder dropwizardRegistry(MetricRegistry registry) {
240+
this.registry = registry;
241+
return this;
242+
}
243+
244+
public Builder metricFilter(MetricFilter metricFilter) {
245+
this.metricFilter = metricFilter;
246+
return this;
247+
}
248+
249+
public Builder customLabelMapper(CustomLabelMapper labelMapper) {
250+
this.labelMapper = labelMapper;
251+
return this;
252+
}
253+
254+
DropwizardExports build() {
255+
if (registry == null) {
256+
throw new IllegalArgumentException("MetricRegistry must be set");
257+
}
258+
if (labelMapper == null) {
259+
return new DropwizardExports(registry, metricFilter);
260+
} else {
261+
return new DropwizardExports(registry, metricFilter, labelMapper);
262+
}
263+
}
264+
265+
public void register() {
266+
register(PrometheusRegistry.defaultRegistry);
267+
}
268+
269+
public void register(PrometheusRegistry registry) {
270+
DropwizardExports dropwizardExports = build();
271+
registry.register(dropwizardExports);
272+
}
273+
}
274+
}

0 commit comments

Comments
 (0)