Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for dw-metrics 4.x #1228

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@
<module>prometheus-metrics-instrumentation-caffeine</module>
<module>prometheus-metrics-instrumentation-jvm</module>
<module>prometheus-metrics-instrumentation-dropwizard5</module>
<module>prometheus-metrics-instrumentation-dropwizard</module>
<module>prometheus-metrics-instrumentation-guava</module>
<module>prometheus-metrics-simpleclient-bridge</module>
</modules>
Expand Down
79 changes: 79 additions & 0 deletions prometheus-metrics-instrumentation-dropwizard/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
<?xml version="1.0" encoding="UTF-8"?>
<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">
<modelVersion>4.0.0</modelVersion>

<parent>
<groupId>io.prometheus</groupId>
<artifactId>client_java</artifactId>
<version>10.0.0-SNAPSHOT</version>
</parent>

<artifactId>prometheus-metrics-instrumentation-dropwizard</artifactId>
<packaging>bundle</packaging>

<name>Prometheus Metrics Instrumentation - Dropwizard 4.x</name>
<description>
Instrumentation library for Dropwizard metrics 4.x
</description>

<properties>
<automatic.module.name>io.prometheus.metrics.instrumentation.dropwizard</automatic.module.name>
</properties>

<licenses>
<license>
<name>The Apache Software License, Version 2.0</name>
<url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
<distribution>repo</distribution>
</license>
</licenses>
<developers>
<developer>
<id>kingster</id>
<name>Kinshuk Bairagi</name>
<email>[email protected]</email>
</developer>

</developers>

<dependencies>
<dependency>
<groupId>io.prometheus</groupId>
<artifactId>prometheus-metrics-core</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>io.dropwizard.metrics</groupId>
<artifactId>metrics-core</artifactId>
<version>4.2.0</version>
<scope>provided</scope>
</dependency>

<dependency>
<groupId>io.prometheus</groupId>
<artifactId>prometheus-metrics-exporter-httpserver</artifactId>
<version>${project.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.prometheus</groupId>
<artifactId>prometheus-metrics-exposition-textformats</artifactId>
<version>${project.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.prometheus</groupId>
<artifactId>prometheus-metrics-instrumentation-dropwizard5</artifactId>
<version>${project.version}</version>
<scope>compile</scope>
<exclusions>
<exclusion>
<groupId>io.dropwizard.metrics5</groupId>
<artifactId>metrics-core</artifactId>
</exclusion>
</exclusions>
</dependency>

</dependencies>

</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,274 @@
package io.prometheus.metrics.instrumentation.dropwizard;

import com.codahale.metrics.Counter;
import com.codahale.metrics.Gauge;
import com.codahale.metrics.Histogram;
import com.codahale.metrics.Meter;
import com.codahale.metrics.Metric;
import com.codahale.metrics.MetricFilter;
import com.codahale.metrics.MetricRegistry;
import com.codahale.metrics.Snapshot;
import com.codahale.metrics.Timer;
import io.prometheus.metrics.instrumentation.dropwizard5.labels.CustomLabelMapper;
import io.prometheus.metrics.model.registry.MultiCollector;
import io.prometheus.metrics.model.registry.PrometheusRegistry;
import io.prometheus.metrics.model.snapshots.CounterSnapshot;
import io.prometheus.metrics.model.snapshots.GaugeSnapshot;
import io.prometheus.metrics.model.snapshots.MetricMetadata;
import io.prometheus.metrics.model.snapshots.MetricSnapshot;
import io.prometheus.metrics.model.snapshots.MetricSnapshots;
import io.prometheus.metrics.model.snapshots.PrometheusNaming;
import io.prometheus.metrics.model.snapshots.Quantiles;
import io.prometheus.metrics.model.snapshots.SummarySnapshot;
import java.util.Collections;
import java.util.Optional;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;

/** Collect Dropwizard metrics from a MetricRegistry. */
public class DropwizardExports implements MultiCollector {
private static final Logger logger = Logger.getLogger(DropwizardExports.class.getName());
private final MetricRegistry registry;
private final MetricFilter metricFilter;
private final Optional<CustomLabelMapper> labelMapper;

/**
* Creates a new DropwizardExports and {@link MetricFilter#ALL}.
*
* @param registry a metric registry to export in prometheus.
*/
public DropwizardExports(MetricRegistry registry) {
super();
this.registry = registry;
this.metricFilter = MetricFilter.ALL;
this.labelMapper = Optional.empty();
}

/**
* Creates a new DropwizardExports with a custom {@link MetricFilter}.
*
* @param registry a metric registry to export in prometheus.
* @param metricFilter a custom metric filter.
*/
public DropwizardExports(MetricRegistry registry, MetricFilter metricFilter) {
this.registry = registry;
this.metricFilter = metricFilter;
this.labelMapper = Optional.empty();
}

/**
* @param registry a metric registry to export in prometheus.
* @param metricFilter a custom metric filter.
* @param labelMapper a labelMapper to use to map labels.
*/
public DropwizardExports(
MetricRegistry registry, MetricFilter metricFilter, CustomLabelMapper labelMapper) {
this.registry = registry;
this.metricFilter = metricFilter;
this.labelMapper = Optional.ofNullable(labelMapper);
}

private static String getHelpMessage(String metricName, Metric metric) {
return String.format(
"Generated from Dropwizard metric import (metric=%s, type=%s)",
metricName, metric.getClass().getName());
}

private MetricMetadata getMetricMetaData(String metricName, Metric metric) {
String name = labelMapper.isPresent() ? labelMapper.get().getName(metricName) : metricName;
return new MetricMetadata(
PrometheusNaming.sanitizeMetricName(name), getHelpMessage(metricName, metric));
}

/**
* Export counter as Prometheus <a
* href="https://prometheus.io/docs/concepts/metric_types/#gauge">Gauge</a>.
*/
MetricSnapshot fromCounter(String dropwizardName, Counter counter) {
MetricMetadata metadata = getMetricMetaData(dropwizardName, counter);
CounterSnapshot.CounterDataPointSnapshot.Builder dataPointBuilder =
CounterSnapshot.CounterDataPointSnapshot.builder()
.value(Long.valueOf(counter.getCount()).doubleValue());
labelMapper.ifPresent(
mapper ->
dataPointBuilder.labels(
mapper.getLabels(
dropwizardName, Collections.emptyList(), Collections.emptyList())));
return new CounterSnapshot(metadata, Collections.singletonList(dataPointBuilder.build()));
}

/** Export gauge as a prometheus gauge. */
MetricSnapshot fromGauge(String dropwizardName, Gauge<?> gauge) {
Object obj = gauge.getValue();
double value;
if (obj instanceof Number) {
value = ((Number) obj).doubleValue();
} else if (obj instanceof Boolean) {
value = ((Boolean) obj) ? 1 : 0;
} else {
logger.log(
Level.FINE,
String.format(
"Invalid type for Gauge %s: %s",
PrometheusNaming.sanitizeMetricName(dropwizardName),
obj == null ? "null" : obj.getClass().getName()));
return null;
}
MetricMetadata metadata = getMetricMetaData(dropwizardName, gauge);
GaugeSnapshot.GaugeDataPointSnapshot.Builder dataPointBuilder =
GaugeSnapshot.GaugeDataPointSnapshot.builder().value(value);
labelMapper.ifPresent(
mapper ->
dataPointBuilder.labels(
mapper.getLabels(
dropwizardName, Collections.emptyList(), Collections.emptyList())));
return new GaugeSnapshot(metadata, Collections.singletonList(dataPointBuilder.build()));
}

/**
* Export a histogram snapshot as a prometheus SUMMARY.
*
* @param dropwizardName metric name.
* @param snapshot the histogram snapshot.
* @param count the total sample count for this snapshot.
* @param factor a factor to apply to histogram values.
*/
MetricSnapshot fromSnapshotAndCount(
String dropwizardName, Snapshot snapshot, long count, double factor, String helpMessage) {
Quantiles quantiles =
Quantiles.builder()
.quantile(0.5, snapshot.getMedian() * factor)
.quantile(0.75, snapshot.get75thPercentile() * factor)
.quantile(0.95, snapshot.get95thPercentile() * factor)
.quantile(0.98, snapshot.get98thPercentile() * factor)
.quantile(0.99, snapshot.get99thPercentile() * factor)
.quantile(0.999, snapshot.get999thPercentile() * factor)
.build();

MetricMetadata metadata =
new MetricMetadata(PrometheusNaming.sanitizeMetricName(dropwizardName), helpMessage);
SummarySnapshot.SummaryDataPointSnapshot.Builder dataPointBuilder =
SummarySnapshot.SummaryDataPointSnapshot.builder().quantiles(quantiles).count(count);
labelMapper.ifPresent(
mapper ->
dataPointBuilder.labels(
mapper.getLabels(
dropwizardName, Collections.emptyList(), Collections.emptyList())));
return new SummarySnapshot(metadata, Collections.singletonList(dataPointBuilder.build()));
}

/** Convert histogram snapshot. */
MetricSnapshot fromHistogram(String dropwizardName, Histogram histogram) {
return fromSnapshotAndCount(
dropwizardName,
histogram.getSnapshot(),
histogram.getCount(),
1.0,
getHelpMessage(dropwizardName, histogram));
}

/** Export Dropwizard Timer as a histogram. Use TIME_UNIT as time unit. */
MetricSnapshot fromTimer(String dropwizardName, Timer timer) {
return fromSnapshotAndCount(
dropwizardName,
timer.getSnapshot(),
timer.getCount(),
1.0D / TimeUnit.SECONDS.toNanos(1L),
getHelpMessage(dropwizardName, timer));
}

/** Export a Meter as a prometheus COUNTER. */
MetricSnapshot fromMeter(String dropwizardName, Meter meter) {
MetricMetadata metadata = getMetricMetaData(dropwizardName + "_total", meter);
CounterSnapshot.CounterDataPointSnapshot.Builder dataPointBuilder =
CounterSnapshot.CounterDataPointSnapshot.builder().value(meter.getCount());
labelMapper.ifPresent(
mapper ->
dataPointBuilder.labels(
mapper.getLabels(
dropwizardName, Collections.emptyList(), Collections.emptyList())));
return new CounterSnapshot(metadata, Collections.singletonList(dataPointBuilder.build()));
}

@Override
public MetricSnapshots collect() {
MetricSnapshots.Builder metricSnapshots = MetricSnapshots.builder();

registry
.getGauges(metricFilter)
.forEach(
(name, gauge) -> {
MetricSnapshot snapshot = fromGauge(name, gauge);
if (snapshot != null) {
metricSnapshots.metricSnapshot(snapshot);
}
});

registry
.getCounters(metricFilter)
.forEach((name, counter) -> metricSnapshots.metricSnapshot(fromCounter(name, counter)));
registry
.getHistograms(metricFilter)
.forEach(
(name, histogram) -> metricSnapshots.metricSnapshot(fromHistogram(name, histogram)));
registry
.getTimers(metricFilter)
.forEach((name, timer) -> metricSnapshots.metricSnapshot(fromTimer(name, timer)));
registry
.getMeters(metricFilter)
.forEach((name, meter) -> metricSnapshots.metricSnapshot(fromMeter(name, meter)));

return metricSnapshots.build();
}

public static Builder builder() {
return new Builder();
}

// Builder class for DropwizardExports
public static class Builder {
private MetricRegistry registry;
private MetricFilter metricFilter;
private CustomLabelMapper labelMapper;

private Builder() {
this.metricFilter = MetricFilter.ALL;
}

public Builder dropwizardRegistry(MetricRegistry registry) {
this.registry = registry;
return this;
}

public Builder metricFilter(MetricFilter metricFilter) {
this.metricFilter = metricFilter;
return this;
}

public Builder customLabelMapper(CustomLabelMapper labelMapper) {
this.labelMapper = labelMapper;
return this;
}

DropwizardExports build() {
if (registry == null) {
throw new IllegalArgumentException("MetricRegistry must be set");
}
if (labelMapper == null) {
return new DropwizardExports(registry, metricFilter);
} else {
return new DropwizardExports(registry, metricFilter, labelMapper);
}
}

public void register() {
register(PrometheusRegistry.defaultRegistry);
}

public void register(PrometheusRegistry registry) {
DropwizardExports dropwizardExports = build();
registry.register(dropwizardExports);
}
}
}
Loading