Skip to content

Commit 555c03a

Browse files
committed
Add support for dw-metrics 4.x
1 parent e486e4d commit 555c03a

File tree

5 files changed

+625
-0
lines changed

5 files changed

+625
-0
lines changed

pom.xml

Lines changed: 1 addition & 0 deletions
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>
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
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>1.3.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+
<!-- Test Dependencies Follow -->
52+
<dependency>
53+
<groupId>junit</groupId>
54+
<artifactId>junit</artifactId>
55+
<version>4.13.2</version>
56+
<scope>test</scope>
57+
</dependency>
58+
<dependency>
59+
<groupId>org.assertj</groupId>
60+
<artifactId>assertj-core</artifactId>
61+
<version>3.25.3</version>
62+
<scope>test</scope>
63+
</dependency>
64+
<dependency>
65+
<groupId>org.mockito</groupId>
66+
<artifactId>mockito-core</artifactId>
67+
<version>5.11.0</version>
68+
<scope>test</scope>
69+
</dependency>
70+
71+
<dependency>
72+
<groupId>io.prometheus</groupId>
73+
<artifactId>prometheus-metrics-exporter-httpserver</artifactId>
74+
<version>${project.version}</version>
75+
<scope>test</scope>
76+
</dependency>
77+
<dependency>
78+
<groupId>io.prometheus</groupId>
79+
<artifactId>prometheus-metrics-exposition-formats</artifactId>
80+
<version>${project.version}</version>
81+
<scope>test</scope>
82+
</dependency>
83+
<dependency>
84+
<groupId>io.prometheus</groupId>
85+
<artifactId>prometheus-metrics-instrumentation-dropwizard5</artifactId>
86+
<version>${project.version}</version>
87+
<scope>compile</scope>
88+
<exclusions>
89+
<exclusion>
90+
<groupId>io.dropwizard.metrics5</groupId>
91+
<artifactId>metrics-core</artifactId>
92+
</exclusion>
93+
</exclusions>
94+
</dependency>
95+
96+
</dependencies>
97+
98+
</project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,222 @@
1+
package io.prometheus.metrics.instrumentation.dropwizard;
2+
3+
import com.codahale.metrics.Timer;
4+
import com.codahale.metrics.*;
5+
import io.prometheus.metrics.instrumentation.dropwizard5.labels.CustomLabelMapper;
6+
import io.prometheus.metrics.model.registry.MultiCollector;
7+
import io.prometheus.metrics.model.registry.PrometheusRegistry;
8+
import io.prometheus.metrics.model.snapshots.*;
9+
10+
import java.util.*;
11+
import java.util.concurrent.TimeUnit;
12+
import java.util.logging.Level;
13+
import java.util.logging.Logger;
14+
15+
/**
16+
* Collect Dropwizard metrics from a MetricRegistry.
17+
*/
18+
public class DropwizardExports implements MultiCollector {
19+
private static final Logger LOGGER = Logger.getLogger(DropwizardExports.class.getName());
20+
private final MetricRegistry registry;
21+
private final MetricFilter metricFilter;
22+
private final Optional<CustomLabelMapper> labelMapper;
23+
24+
/**
25+
* Creates a new DropwizardExports and {@link MetricFilter#ALL}.
26+
*
27+
* @param registry a metric registry to export in prometheus.
28+
*/
29+
public DropwizardExports(MetricRegistry registry) {
30+
super();
31+
this.registry = registry;
32+
this.metricFilter = MetricFilter.ALL;
33+
this.labelMapper = Optional.empty();
34+
}
35+
36+
/**
37+
* Creates a new DropwizardExports with a custom {@link MetricFilter}.
38+
*
39+
* @param registry a metric registry to export in prometheus.
40+
* @param metricFilter a custom metric filter.
41+
*/
42+
public DropwizardExports(MetricRegistry registry, MetricFilter metricFilter) {
43+
this.registry = registry;
44+
this.metricFilter = metricFilter;
45+
this.labelMapper = Optional.empty();
46+
}
47+
48+
/**
49+
* @param registry a metric registry to export in prometheus.
50+
* @param metricFilter a custom metric filter.
51+
* @param labelMapper a labelMapper to use to map labels.
52+
*/
53+
public DropwizardExports(MetricRegistry registry, MetricFilter metricFilter, CustomLabelMapper labelMapper) {
54+
this.registry = registry;
55+
this.metricFilter = metricFilter;
56+
this.labelMapper = Optional.ofNullable(labelMapper);
57+
}
58+
59+
private static String getHelpMessage(String metricName, Metric metric) {
60+
return String.format("Generated from Dropwizard metric import (metric=%s, type=%s)",
61+
metricName, metric.getClass().getName());
62+
}
63+
64+
private MetricMetadata getMetricMetaData(String metricName, Metric metric) {
65+
String name = labelMapper.isPresent() ? labelMapper.get().getName(metricName) : metricName;
66+
return new MetricMetadata(PrometheusNaming.sanitizeMetricName(name), getHelpMessage(metricName, metric));
67+
}
68+
69+
/**
70+
* Export counter as Prometheus <a href="https://prometheus.io/docs/concepts/metric_types/#gauge">Gauge</a>.
71+
*/
72+
MetricSnapshot fromCounter(String dropwizardName, Counter counter) {
73+
MetricMetadata metadata = getMetricMetaData(dropwizardName, counter);
74+
CounterSnapshot.CounterDataPointSnapshot.Builder dataPointBuilder = CounterSnapshot.CounterDataPointSnapshot.builder().value(Long.valueOf(counter.getCount()).doubleValue());
75+
labelMapper.map(mapper -> dataPointBuilder.labels(mapper.getLabels(dropwizardName, Collections.emptyList(), Collections.emptyList())));
76+
return new CounterSnapshot(metadata, Collections.singletonList(dataPointBuilder.build()));
77+
}
78+
79+
/**
80+
* Export gauge as a prometheus gauge.
81+
*/
82+
MetricSnapshot fromGauge(String dropwizardName, Gauge gauge) {
83+
Object obj = gauge.getValue();
84+
double value;
85+
if (obj instanceof Number) {
86+
value = ((Number) obj).doubleValue();
87+
} else if (obj instanceof Boolean) {
88+
value = ((Boolean) obj) ? 1 : 0;
89+
} else {
90+
LOGGER.log(Level.FINE, String.format("Invalid type for Gauge %s: %s", PrometheusNaming.sanitizeMetricName(dropwizardName),
91+
obj == null ? "null" : obj.getClass().getName()));
92+
return null;
93+
}
94+
MetricMetadata metadata = getMetricMetaData(dropwizardName, gauge);
95+
GaugeSnapshot.GaugeDataPointSnapshot.Builder dataPointBuilder = GaugeSnapshot.GaugeDataPointSnapshot.builder().value(value);
96+
labelMapper.map(mapper -> dataPointBuilder.labels(mapper.getLabels(dropwizardName, Collections.emptyList(), Collections.emptyList())));
97+
return new GaugeSnapshot(metadata, Collections.singletonList(dataPointBuilder.build()));
98+
}
99+
100+
/**
101+
* Export a histogram snapshot as a prometheus SUMMARY.
102+
*
103+
* @param dropwizardName metric name.
104+
* @param snapshot the histogram snapshot.
105+
* @param count the total sample count for this snapshot.
106+
* @param factor a factor to apply to histogram values.
107+
*/
108+
MetricSnapshot fromSnapshotAndCount(String dropwizardName, Snapshot snapshot, long count, double factor, String helpMessage) {
109+
Quantiles quantiles = Quantiles.builder()
110+
.quantile(0.5, snapshot.getMedian() * factor)
111+
.quantile(0.75, snapshot.get75thPercentile() * factor)
112+
.quantile(0.95, snapshot.get95thPercentile() * factor)
113+
.quantile(0.98, snapshot.get98thPercentile() * factor)
114+
.quantile(0.99, snapshot.get99thPercentile() * factor)
115+
.quantile(0.999, snapshot.get999thPercentile() * factor)
116+
.build();
117+
118+
MetricMetadata metadata = new MetricMetadata(PrometheusNaming.sanitizeMetricName(dropwizardName), helpMessage);
119+
SummarySnapshot.SummaryDataPointSnapshot.Builder dataPointBuilder = SummarySnapshot.SummaryDataPointSnapshot.builder().quantiles(quantiles).count(count);
120+
labelMapper.map(mapper -> dataPointBuilder.labels(mapper.getLabels(dropwizardName, Collections.emptyList(), Collections.emptyList())));
121+
return new SummarySnapshot(metadata, Collections.singletonList(dataPointBuilder.build()));
122+
}
123+
124+
/**
125+
* Convert histogram snapshot.
126+
*/
127+
MetricSnapshot fromHistogram(String dropwizardName, Histogram histogram) {
128+
return fromSnapshotAndCount(dropwizardName, histogram.getSnapshot(), histogram.getCount(), 1.0,
129+
getHelpMessage(dropwizardName, histogram));
130+
}
131+
132+
/**
133+
* Export Dropwizard Timer as a histogram. Use TIME_UNIT as time unit.
134+
*/
135+
MetricSnapshot fromTimer(String dropwizardName, Timer timer) {
136+
return fromSnapshotAndCount(dropwizardName, timer.getSnapshot(), timer.getCount(),
137+
1.0D / TimeUnit.SECONDS.toNanos(1L), getHelpMessage(dropwizardName, timer));
138+
}
139+
140+
/**
141+
* Export a Meter as a prometheus COUNTER.
142+
*/
143+
MetricSnapshot fromMeter(String dropwizardName, Meter meter) {
144+
MetricMetadata metadata = getMetricMetaData(dropwizardName + "_total", meter);
145+
CounterSnapshot.CounterDataPointSnapshot.Builder dataPointBuilder = CounterSnapshot.CounterDataPointSnapshot.builder().value(meter.getCount());
146+
labelMapper.map(mapper -> dataPointBuilder.labels(mapper.getLabels(dropwizardName, Collections.emptyList(), Collections.emptyList())));
147+
return new CounterSnapshot(metadata, Collections.singletonList(dataPointBuilder.build()));
148+
}
149+
150+
@Override
151+
public MetricSnapshots collect() {
152+
MetricSnapshots.Builder metricSnapshots = MetricSnapshots.builder();
153+
154+
for (SortedMap.Entry<String, Gauge> entry : registry.getGauges(metricFilter).entrySet()) {
155+
Optional.ofNullable(fromGauge(entry.getKey(), entry.getValue())).map(metricSnapshots::metricSnapshot);
156+
}
157+
for (SortedMap.Entry<String, Counter> entry : registry.getCounters(metricFilter).entrySet()) {
158+
metricSnapshots.metricSnapshot(fromCounter(entry.getKey(), entry.getValue()));
159+
}
160+
for (SortedMap.Entry<String, Histogram> entry : registry.getHistograms(metricFilter).entrySet()) {
161+
metricSnapshots.metricSnapshot(fromHistogram(entry.getKey(), entry.getValue()));
162+
}
163+
for (SortedMap.Entry<String, Timer> entry : registry.getTimers(metricFilter).entrySet()) {
164+
metricSnapshots.metricSnapshot(fromTimer(entry.getKey(), entry.getValue()));
165+
}
166+
for (SortedMap.Entry<String, Meter> entry : registry.getMeters(metricFilter).entrySet()) {
167+
metricSnapshots.metricSnapshot(fromMeter(entry.getKey(), entry.getValue()));
168+
}
169+
return metricSnapshots.build();
170+
}
171+
172+
public static Builder builder() {
173+
return new Builder();
174+
}
175+
176+
//Builder class for DropwizardExports
177+
public static class Builder {
178+
private MetricRegistry registry;
179+
private MetricFilter metricFilter;
180+
private CustomLabelMapper labelMapper;
181+
182+
private Builder() {
183+
this.metricFilter = MetricFilter.ALL;
184+
}
185+
186+
public Builder dropwizardRegistry(MetricRegistry registry) {
187+
this.registry = registry;
188+
return this;
189+
}
190+
191+
public Builder metricFilter(MetricFilter metricFilter) {
192+
this.metricFilter = metricFilter;
193+
return this;
194+
}
195+
196+
public Builder customLabelMapper(CustomLabelMapper labelMapper) {
197+
this.labelMapper = labelMapper;
198+
return this;
199+
}
200+
201+
DropwizardExports build() {
202+
if (registry == null) {
203+
throw new IllegalArgumentException("MetricRegistry must be set");
204+
}
205+
if (labelMapper == null) {
206+
return new DropwizardExports(registry, metricFilter);
207+
} else {
208+
return new DropwizardExports(registry, metricFilter, labelMapper);
209+
}
210+
}
211+
212+
public void register() {
213+
register(PrometheusRegistry.defaultRegistry);
214+
}
215+
216+
public void register(PrometheusRegistry registry) {
217+
DropwizardExports dropwizardExports = build();
218+
registry.register(dropwizardExports);
219+
}
220+
}
221+
222+
}

0 commit comments

Comments
 (0)