-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add a dropwizard-metrics -> OTel metrics bridge (open-telemetry#6259)
* Add a dropwizard-metrics -> OTel metrics bridge * disable by default * enable metrics for test
- Loading branch information
Showing
13 changed files
with
781 additions
and
108 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
20 changes: 20 additions & 0 deletions
20
instrumentation/dropwizard/dropwizard-metrics-4.0/javaagent/build.gradle.kts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
plugins { | ||
id("otel.javaagent-instrumentation") | ||
} | ||
|
||
muzzle { | ||
pass { | ||
group.set("io.dropwizard.metrics") | ||
module.set("metrics-core") | ||
versions.set("[4.0.0,)") | ||
assertInverse.set(true) | ||
} | ||
} | ||
|
||
dependencies { | ||
library("io.dropwizard.metrics:metrics-core:4.0.0") | ||
} | ||
|
||
tasks.withType<Test>().configureEach { | ||
jvmArgs("-Dotel.instrumentation.dropwizard-metrics.enabled=true") | ||
} |
51 changes: 51 additions & 0 deletions
51
.../io/opentelemetry/javaagent/instrumentation/dropwizardmetrics/CounterInstrumentation.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
/* | ||
* Copyright The OpenTelemetry Authors | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
package io.opentelemetry.javaagent.instrumentation.dropwizardmetrics; | ||
|
||
import static io.opentelemetry.javaagent.instrumentation.dropwizardmetrics.DropwizardSingletons.metrics; | ||
import static net.bytebuddy.matcher.ElementMatchers.named; | ||
import static net.bytebuddy.matcher.ElementMatchers.takesArguments; | ||
|
||
import com.codahale.metrics.Counter; | ||
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; | ||
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; | ||
import net.bytebuddy.asm.Advice; | ||
import net.bytebuddy.description.type.TypeDescription; | ||
import net.bytebuddy.matcher.ElementMatcher; | ||
|
||
public class CounterInstrumentation implements TypeInstrumentation { | ||
|
||
@Override | ||
public ElementMatcher<TypeDescription> typeMatcher() { | ||
return named("com.codahale.metrics.Counter"); | ||
} | ||
|
||
@Override | ||
public void transform(TypeTransformer transformer) { | ||
transformer.applyAdviceToMethod( | ||
named("inc").and(takesArguments(long.class)), this.getClass().getName() + "$IncAdvice"); | ||
transformer.applyAdviceToMethod( | ||
named("dec").and(takesArguments(long.class)), this.getClass().getName() + "$DecAdvice"); | ||
} | ||
|
||
@SuppressWarnings("unused") | ||
public static class IncAdvice { | ||
|
||
@Advice.OnMethodEnter(suppress = Throwable.class) | ||
public static void onEnter(@Advice.This Counter counter, @Advice.Argument(0) long increment) { | ||
metrics().counterAdd(counter, increment); | ||
} | ||
} | ||
|
||
@SuppressWarnings("unused") | ||
public static class DecAdvice { | ||
|
||
@Advice.OnMethodEnter(suppress = Throwable.class) | ||
public static void onEnter(@Advice.This Counter counter, @Advice.Argument(0) long decrement) { | ||
metrics().counterAdd(counter, -decrement); | ||
} | ||
} | ||
} |
174 changes: 174 additions & 0 deletions
174
...o/opentelemetry/javaagent/instrumentation/dropwizardmetrics/DropwizardMetricsAdapter.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,174 @@ | ||
/* | ||
* Copyright The OpenTelemetry Authors | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
package io.opentelemetry.javaagent.instrumentation.dropwizardmetrics; | ||
|
||
import com.codahale.metrics.Counter; | ||
import com.codahale.metrics.Gauge; | ||
import com.codahale.metrics.Histogram; | ||
import com.codahale.metrics.Meter; | ||
import com.codahale.metrics.MetricRegistryListener; | ||
import com.codahale.metrics.Timer; | ||
import io.opentelemetry.api.OpenTelemetry; | ||
import io.opentelemetry.api.metrics.DoubleHistogram; | ||
import io.opentelemetry.api.metrics.LongCounter; | ||
import io.opentelemetry.api.metrics.LongHistogram; | ||
import io.opentelemetry.api.metrics.LongUpDownCounter; | ||
import io.opentelemetry.api.metrics.ObservableDoubleGauge; | ||
import io.opentelemetry.instrumentation.api.util.VirtualField; | ||
import java.util.Map; | ||
import java.util.concurrent.ConcurrentHashMap; | ||
import java.util.concurrent.TimeUnit; | ||
|
||
public final class DropwizardMetricsAdapter implements MetricRegistryListener { | ||
|
||
private static final double NANOS_PER_MS = TimeUnit.MILLISECONDS.toNanos(1); | ||
|
||
private static final VirtualField<Counter, LongUpDownCounter> otelUpDownCounterField = | ||
VirtualField.find(Counter.class, LongUpDownCounter.class); | ||
private static final VirtualField<Histogram, LongHistogram> otelHistogramField = | ||
VirtualField.find(Histogram.class, LongHistogram.class); | ||
private static final VirtualField<Meter, LongCounter> otelCounterField = | ||
VirtualField.find(Meter.class, LongCounter.class); | ||
private static final VirtualField<Timer, DoubleHistogram> otelDoubleHistogramField = | ||
VirtualField.find(Timer.class, DoubleHistogram.class); | ||
|
||
private final io.opentelemetry.api.metrics.Meter otelMeter; | ||
|
||
private final Map<String, DoubleHistogram> otelDoubleHistograms = new ConcurrentHashMap<>(); | ||
private final Map<String, LongCounter> otelCounters = new ConcurrentHashMap<>(); | ||
private final Map<String, LongHistogram> otelHistograms = new ConcurrentHashMap<>(); | ||
private final Map<String, LongUpDownCounter> otelUpDownCounters = new ConcurrentHashMap<>(); | ||
private final Map<String, ObservableDoubleGauge> otelGauges = new ConcurrentHashMap<>(); | ||
|
||
private final Map<String, Counter> dropwizardCounters = new ConcurrentHashMap<>(); | ||
private final Map<String, Histogram> dropwizardHistograms = new ConcurrentHashMap<>(); | ||
private final Map<String, Meter> dropwizardMeters = new ConcurrentHashMap<>(); | ||
private final Map<String, Timer> dropwizardTimers = new ConcurrentHashMap<>(); | ||
|
||
public DropwizardMetricsAdapter(OpenTelemetry openTelemetry) { | ||
this.otelMeter = openTelemetry.getMeter("io.opentelemetry.dropwizard-metrics-4.0"); | ||
} | ||
|
||
@Override | ||
public void onGaugeAdded(String name, Gauge<?> gauge) { | ||
ObservableDoubleGauge otelGauge = | ||
otelMeter | ||
.gaugeBuilder(name) | ||
.buildWithCallback( | ||
measurement -> { | ||
Object val = gauge.getValue(); | ||
if (val instanceof Number) { | ||
measurement.record(((Number) val).doubleValue()); | ||
} | ||
}); | ||
otelGauges.put(name, otelGauge); | ||
} | ||
|
||
@Override | ||
public void onGaugeRemoved(String name) { | ||
ObservableDoubleGauge otelGauge = otelGauges.remove(name); | ||
if (otelGauge != null) { | ||
otelGauge.close(); | ||
} | ||
} | ||
|
||
@Override | ||
public void onCounterAdded(String name, Counter dropwizardCounter) { | ||
dropwizardCounters.put(name, dropwizardCounter); | ||
LongUpDownCounter otelCounter = | ||
otelUpDownCounters.computeIfAbsent(name, n -> otelMeter.upDownCounterBuilder(n).build()); | ||
otelUpDownCounterField.set(dropwizardCounter, otelCounter); | ||
} | ||
|
||
@Override | ||
public void onCounterRemoved(String name) { | ||
Counter dropwizardCounter = dropwizardCounters.remove(name); | ||
otelUpDownCounters.remove(name); | ||
if (dropwizardCounter != null) { | ||
otelUpDownCounterField.set(dropwizardCounter, null); | ||
} | ||
} | ||
|
||
public void counterAdd(Counter dropwizardCounter, long increment) { | ||
LongUpDownCounter otelCounter = otelUpDownCounterField.get(dropwizardCounter); | ||
if (otelCounter != null) { | ||
otelCounter.add(increment); | ||
} | ||
} | ||
|
||
@Override | ||
public void onHistogramAdded(String name, Histogram dropwizardHistogram) { | ||
dropwizardHistograms.put(name, dropwizardHistogram); | ||
LongHistogram otelHistogram = | ||
otelHistograms.computeIfAbsent(name, n -> otelMeter.histogramBuilder(n).ofLongs().build()); | ||
otelHistogramField.set(dropwizardHistogram, otelHistogram); | ||
} | ||
|
||
@Override | ||
public void onHistogramRemoved(String name) { | ||
Histogram dropwizardHistogram = dropwizardHistograms.remove(name); | ||
otelHistograms.remove(name); | ||
if (dropwizardHistogram != null) { | ||
otelHistogramField.set(dropwizardHistogram, null); | ||
} | ||
} | ||
|
||
public void histogramUpdate(Histogram dropwizardHistogram, long value) { | ||
LongHistogram otelHistogram = otelHistogramField.get(dropwizardHistogram); | ||
if (otelHistogram != null) { | ||
otelHistogram.record(value); | ||
} | ||
} | ||
|
||
@Override | ||
public void onMeterAdded(String name, Meter dropwizardMeter) { | ||
dropwizardMeters.put(name, dropwizardMeter); | ||
LongCounter otelCounter = | ||
otelCounters.computeIfAbsent(name, n -> otelMeter.counterBuilder(n).build()); | ||
otelCounterField.set(dropwizardMeter, otelCounter); | ||
} | ||
|
||
@Override | ||
public void onMeterRemoved(String name) { | ||
Meter dropwizardMeter = dropwizardMeters.remove(name); | ||
otelCounters.remove(name); | ||
if (dropwizardMeter != null) { | ||
otelCounterField.set(dropwizardMeter, null); | ||
} | ||
} | ||
|
||
public void meterMark(Meter dropwizardMeter, long increment) { | ||
LongCounter otelCounter = otelCounterField.get(dropwizardMeter); | ||
if (otelCounter != null) { | ||
otelCounter.add(increment); | ||
} | ||
} | ||
|
||
@Override | ||
public void onTimerAdded(String name, Timer dropwizardTimer) { | ||
dropwizardTimers.put(name, dropwizardTimer); | ||
DoubleHistogram otelHistogram = | ||
otelDoubleHistograms.computeIfAbsent( | ||
name, n -> otelMeter.histogramBuilder(n).setUnit("ms").build()); | ||
otelDoubleHistogramField.set(dropwizardTimer, otelHistogram); | ||
} | ||
|
||
@Override | ||
public void onTimerRemoved(String name) { | ||
Timer dropwizardTimer = dropwizardTimers.remove(name); | ||
otelDoubleHistograms.remove(name); | ||
if (dropwizardTimer != null) { | ||
otelDoubleHistogramField.set(dropwizardTimer, null); | ||
} | ||
} | ||
|
||
public void timerUpdate(Timer dropwizardTimer, long nanos) { | ||
DoubleHistogram otelHistogram = otelDoubleHistogramField.get(dropwizardTimer); | ||
if (otelHistogram != null) { | ||
otelHistogram.record(nanos / NANOS_PER_MS); | ||
} | ||
} | ||
} |
48 changes: 48 additions & 0 deletions
48
...y/javaagent/instrumentation/dropwizardmetrics/DropwizardMetricsInstrumentationModule.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
/* | ||
* Copyright The OpenTelemetry Authors | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
package io.opentelemetry.javaagent.instrumentation.dropwizardmetrics; | ||
|
||
import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.hasClassesNamed; | ||
import static java.util.Arrays.asList; | ||
import static net.bytebuddy.matcher.ElementMatchers.not; | ||
|
||
import com.google.auto.service.AutoService; | ||
import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule; | ||
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; | ||
import java.util.List; | ||
import net.bytebuddy.matcher.ElementMatcher; | ||
|
||
@AutoService(InstrumentationModule.class) | ||
public class DropwizardMetricsInstrumentationModule extends InstrumentationModule { | ||
|
||
public DropwizardMetricsInstrumentationModule() { | ||
super("dropwizard-metrics", "dropwizard-metrics-4.0"); | ||
} | ||
|
||
@Override | ||
public ElementMatcher.Junction<ClassLoader> classLoaderMatcher() { | ||
// removed in 4.0 | ||
return not(hasClassesNamed("com.codahale.metrics.LongAdder")); | ||
} | ||
|
||
@Override | ||
public boolean defaultEnabled() { | ||
// the Dropwizard metrics API does not have a concept of metric labels/tags/attributes, thus the | ||
// data produced by this integration might be of very low quality, depending on how the API is | ||
// used in the instrumented application | ||
return false; | ||
} | ||
|
||
@Override | ||
public List<TypeInstrumentation> typeInstrumentations() { | ||
return asList( | ||
new MetricRegistryInstrumentation(), | ||
new CounterInstrumentation(), | ||
new HistogramInstrumentation(), | ||
new MeterInstrumentation(), | ||
new TimerInstrumentation()); | ||
} | ||
} |
20 changes: 20 additions & 0 deletions
20
...va/io/opentelemetry/javaagent/instrumentation/dropwizardmetrics/DropwizardSingletons.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
/* | ||
* Copyright The OpenTelemetry Authors | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
package io.opentelemetry.javaagent.instrumentation.dropwizardmetrics; | ||
|
||
import io.opentelemetry.api.GlobalOpenTelemetry; | ||
|
||
public final class DropwizardSingletons { | ||
|
||
private static final DropwizardMetricsAdapter METRICS = | ||
new DropwizardMetricsAdapter(GlobalOpenTelemetry.get()); | ||
|
||
public static DropwizardMetricsAdapter metrics() { | ||
return METRICS; | ||
} | ||
|
||
private DropwizardSingletons() {} | ||
} |
41 changes: 41 additions & 0 deletions
41
...o/opentelemetry/javaagent/instrumentation/dropwizardmetrics/HistogramInstrumentation.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
/* | ||
* Copyright The OpenTelemetry Authors | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
package io.opentelemetry.javaagent.instrumentation.dropwizardmetrics; | ||
|
||
import static io.opentelemetry.javaagent.instrumentation.dropwizardmetrics.DropwizardSingletons.metrics; | ||
import static net.bytebuddy.matcher.ElementMatchers.named; | ||
import static net.bytebuddy.matcher.ElementMatchers.takesArguments; | ||
|
||
import com.codahale.metrics.Histogram; | ||
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; | ||
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; | ||
import net.bytebuddy.asm.Advice; | ||
import net.bytebuddy.description.type.TypeDescription; | ||
import net.bytebuddy.matcher.ElementMatcher; | ||
|
||
public class HistogramInstrumentation implements TypeInstrumentation { | ||
|
||
@Override | ||
public ElementMatcher<TypeDescription> typeMatcher() { | ||
return named("com.codahale.metrics.Histogram"); | ||
} | ||
|
||
@Override | ||
public void transform(TypeTransformer transformer) { | ||
transformer.applyAdviceToMethod( | ||
named("update").and(takesArguments(long.class)), | ||
this.getClass().getName() + "$UpdateAdvice"); | ||
} | ||
|
||
@SuppressWarnings("unused") | ||
public static class UpdateAdvice { | ||
|
||
@Advice.OnMethodEnter(suppress = Throwable.class) | ||
public static void onEnter(@Advice.This Histogram histogram, @Advice.Argument(0) long value) { | ||
metrics().histogramUpdate(histogram, value); | ||
} | ||
} | ||
} |
Oops, something went wrong.