-
Notifications
You must be signed in to change notification settings - Fork 873
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
- Loading branch information
Mateusz Rzeszutek
committed
Jul 4, 2022
1 parent
4cfdd8f
commit 504d86b
Showing
12 changed files
with
663 additions
and
5 deletions.
There are no files selected for viewing
16 changes: 16 additions & 0 deletions
16
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,16 @@ | ||
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") | ||
} |
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); | ||
} | ||
} | ||
} |
40 changes: 40 additions & 0 deletions
40
...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,40 @@ | ||
/* | ||
* 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 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); | ||
} | ||
} | ||
} |
40 changes: 40 additions & 0 deletions
40
...va/io/opentelemetry/javaagent/instrumentation/dropwizardmetrics/MeterInstrumentation.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,40 @@ | ||
/* | ||
* 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.Meter; | ||
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 MeterInstrumentation implements TypeInstrumentation { | ||
|
||
@Override | ||
public ElementMatcher<TypeDescription> typeMatcher() { | ||
return named("com.codahale.metrics.Meter"); | ||
} | ||
|
||
@Override | ||
public void transform(TypeTransformer transformer) { | ||
transformer.applyAdviceToMethod( | ||
named("mark").and(takesArguments(long.class)), this.getClass().getName() + "$MarkAdvice"); | ||
} | ||
|
||
@SuppressWarnings("unused") | ||
public static class MarkAdvice { | ||
|
||
@Advice.OnMethodEnter(suppress = Throwable.class) | ||
public static void onEnter(@Advice.This Meter meter, @Advice.Argument(0) long increment) { | ||
metrics().meterMark(meter, increment); | ||
} | ||
} | ||
} |
Oops, something went wrong.