Skip to content

Commit

Permalink
Bring in micrometer shim (#4258)
Browse files Browse the repository at this point in the history
* Move in micrometer-shim

* Finish

* micrometer1

* Tweak

* micrometer1 module

* Fix build file

* Merge
  • Loading branch information
anuraaga authored Mar 16, 2022
1 parent 85b33d4 commit 338966e
Show file tree
Hide file tree
Showing 35 changed files with 3,326 additions and 0 deletions.
1 change: 1 addition & 0 deletions dependencyManagement/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ val DEPENDENCY_BOMS = listOf(
"com.linecorp.armeria:armeria-bom:1.14.0",
"com.squareup.okhttp3:okhttp-bom:4.9.3",
"io.grpc:grpc-bom:1.44.0",
"io.micrometer:micrometer-bom:1.8.3",
"io.zipkin.brave:brave-bom:5.13.7",
"io.zipkin.reporter2:zipkin-reporter-bom:2.16.3",
"org.junit:junit-bom:5.8.2",
Expand Down
54 changes: 54 additions & 0 deletions micrometer1-shim/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
plugins {
id("otel.java-conventions")
id("otel.publish-conventions")
}

description = "OpenTelemetry Micrometer Bridge"
otelJava.moduleName.set("io.opentelemetry.micrometer1shim")

dependencies {
api(project(":api:all"))

api("io.micrometer:micrometer-core")

testImplementation(project(":sdk:metrics-testing"))
testImplementation(project(":sdk:testing"))
}

testing {
suites {
// Test older LTS versions
val testMicrometer15 by registering(JvmTestSuite::class) {
sources {
java {
setSrcDirs(listOf("src/test/java"))
}
}
dependencies {
implementation(project(":sdk:metrics-testing"))
implementation(project(":sdk:testing"))

implementation(project.dependencies.enforcedPlatform("io.micrometer:micrometer-bom:1.5.17"))
}
}
val testMicrometer16 by registering(JvmTestSuite::class) {
sources {
java {
setSrcDirs(listOf("src/test/java"))
}
}
dependencies {
implementation(project(":sdk:metrics-testing"))
implementation(project(":sdk:testing"))

implementation(project.dependencies.enforcedPlatform("io.micrometer:micrometer-bom:1.6.13"))
}
}
}
}

tasks {
check {
dependsOn(testing.suites)
}
}
1 change: 1 addition & 0 deletions micrometer1-shim/gradle.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
otel.release=alpha
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.micrometer1shim;

import io.micrometer.core.instrument.Meter;
import io.micrometer.core.instrument.Statistic;
import io.micrometer.core.instrument.Tag;
import io.micrometer.core.instrument.config.NamingConvention;
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.api.common.AttributesBuilder;

final class Bridging {

static Attributes tagsAsAttributes(Meter.Id id, NamingConvention namingConvention) {
Iterable<Tag> tags = id.getTagsAsIterable();
if (!tags.iterator().hasNext()) {
return Attributes.empty();
}
AttributesBuilder builder = Attributes.builder();
for (Tag tag : tags) {
String tagKey = namingConvention.tagKey(tag.getKey());
String tagValue = namingConvention.tagValue(tag.getValue());
builder.put(tagKey, tagValue);
}
return builder.build();
}

static String name(Meter.Id id, NamingConvention namingConvention) {
return namingConvention.name(id.getName(), id.getType(), id.getBaseUnit());
}

static String description(Meter.Id id) {
String description = id.getDescription();
return description != null ? description : "";
}

static String baseUnit(Meter.Id id) {
String baseUnit = id.getBaseUnit();
return baseUnit == null ? "1" : baseUnit;
}

static String statisticInstrumentName(
Meter.Id id, Statistic statistic, NamingConvention namingConvention) {
String prefix = id.getName() + ".";
// use "total_time" instead of "total" to avoid clashing with Statistic.TOTAL
String statisticStr =
statistic == Statistic.TOTAL_TIME ? "total_time" : statistic.getTagValueRepresentation();
return namingConvention.name(prefix + statisticStr, id.getType(), id.getBaseUnit());
}

private Bridging() {}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.micrometer1shim;

import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.api.metrics.ObservableDoubleMeasurement;
import java.lang.ref.WeakReference;
import java.util.function.Consumer;
import java.util.function.ToDoubleFunction;
import javax.annotation.Nullable;

final class DoubleMeasurementRecorder<T> implements Consumer<ObservableDoubleMeasurement> {

// using a weak reference here so that the existence of the micrometer Meter does not block the
// measured object from being GC'd; e.g. a Gauge (or any other async instrument) must not block
// garbage collection of the object that it measures
private final WeakReference<T> objWeakRef;
private final ToDoubleFunction<T> metricFunction;
private final Attributes attributes;

DoubleMeasurementRecorder(
@Nullable T obj, ToDoubleFunction<T> metricFunction, Attributes attributes) {
this.objWeakRef = new WeakReference<>(obj);
this.metricFunction = metricFunction;
this.attributes = attributes;
}

@Override
public void accept(ObservableDoubleMeasurement measurement) {
T obj = objWeakRef.get();
if (obj != null) {
measurement.record(metricFunction.applyAsDouble(obj), attributes);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.micrometer1shim;

import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.api.metrics.ObservableLongMeasurement;
import java.lang.ref.WeakReference;
import java.util.function.Consumer;
import java.util.function.ToLongFunction;
import javax.annotation.Nullable;

final class LongMeasurementRecorder<T> implements Consumer<ObservableLongMeasurement> {

// using a weak reference here so that the existence of the micrometer Meter does not block the
// measured object from being GC'd; e.g. a Gauge (or any other async instrument) must not block
// garbage collection of the object that it measures
private final WeakReference<T> objWeakRef;
private final ToLongFunction<T> metricFunction;
private final Attributes attributes;

LongMeasurementRecorder(
@Nullable T obj, ToLongFunction<T> metricFunction, Attributes attributes) {
this.objWeakRef = new WeakReference<>(obj);
this.metricFunction = metricFunction;
this.attributes = attributes;
}

@Override
public void accept(ObservableLongMeasurement measurement) {
T obj = objWeakRef.get();
if (obj != null) {
measurement.record(metricFunction.applyAsLong(obj), attributes);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.micrometer1shim;

import static io.opentelemetry.micrometer1shim.Bridging.baseUnit;
import static io.opentelemetry.micrometer1shim.Bridging.name;
import static io.opentelemetry.micrometer1shim.Bridging.tagsAsAttributes;

import io.micrometer.core.instrument.Counter;
import io.micrometer.core.instrument.Measurement;
import io.micrometer.core.instrument.config.NamingConvention;
import io.micrometer.core.instrument.util.MeterEquivalence;
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.api.metrics.DoubleCounter;
import io.opentelemetry.api.metrics.Meter;
import java.util.Collections;
import javax.annotation.Nullable;

@SuppressWarnings("HashCodeToString")
final class OpenTelemetryCounter implements Counter, RemovableMeter {

private final Id id;
// TODO: use bound instruments when they're available
private final DoubleCounter otelCounter;
private final Attributes attributes;

private volatile boolean removed = false;

OpenTelemetryCounter(Id id, NamingConvention namingConvention, Meter otelMeter) {
this.id = id;

this.attributes = tagsAsAttributes(id, namingConvention);
String conventionName = name(id, namingConvention);
this.otelCounter =
otelMeter
.counterBuilder(conventionName)
.setDescription(Bridging.description(id))
.setUnit(baseUnit(id))
.ofDoubles()
.build();
}

@Override
public void increment(double v) {
if (removed) {
return;
}
otelCounter.add(v, attributes);
}

@Override
public double count() {
UnsupportedReadLogger.logWarning();
return Double.NaN;
}

@Override
public Iterable<Measurement> measure() {
UnsupportedReadLogger.logWarning();
return Collections.emptyList();
}

@Override
public Id getId() {
return id;
}

@Override
public void onRemove() {
removed = true;
}

@SuppressWarnings("EqualsWhichDoesntCheckParameterClass")
@Override
public boolean equals(@Nullable Object o) {
return MeterEquivalence.equals(this, o);
}

@Override
public int hashCode() {
return MeterEquivalence.hashCode(this);
}
}
Loading

0 comments on commit 338966e

Please sign in to comment.