Skip to content

Commit 9dcefdd

Browse files
authored
Implement Metrics incubator APIs to accept advice (#1190)
1 parent 341421d commit 9dcefdd

25 files changed

+1628
-273
lines changed

micrometer-meter-provider/build.gradle.kts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,9 @@ otelJava.moduleName.set("io.opentelemetry.contrib.metrics.micrometer")
99
dependencies {
1010
api("io.opentelemetry:opentelemetry-api")
1111
api("io.opentelemetry:opentelemetry-sdk-metrics")
12+
api("io.opentelemetry:opentelemetry-extension-incubator")
1213

13-
compileOnly("io.micrometer:micrometer-core:1.1.0") // do not auto-update this version
14+
compileOnly("io.micrometer:micrometer-core:1.5.0") // do not auto-update this version
1415
compileOnly("io.opentelemetry:opentelemetry-sdk-extension-autoconfigure")
1516

1617
annotationProcessor("com.google.auto.service:auto-service")

micrometer-meter-provider/src/integrationTest/java/io/opentelemetry/contrib/metrics/micrometer/PrometheusIntegrationTest.java

Lines changed: 589 additions & 68 deletions
Large diffs are not rendered by default.

micrometer-meter-provider/src/main/java/io/opentelemetry/contrib/metrics/micrometer/internal/instruments/AbstractCounter.java

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,15 @@ protected final Counter counter(Attributes attributes) {
2727
.register(meterRegistry());
2828
}
2929

30-
protected final void record(double value, Attributes attributes) {
30+
protected final void increment(Attributes attributes, double value) {
31+
if (value >= 0.0) {
32+
counter(attributes).increment(value);
33+
}
34+
}
35+
36+
protected final void setMonotonically(Attributes attributes, double value) {
3137
counterMap
32-
.computeIfAbsent(attributesOrEmpty(attributes), this::createAsyncCounter)
38+
.computeIfAbsent(effectiveAttributes(attributes), this::createAsyncCounter)
3339
.setMonotonically(value);
3440
}
3541

micrometer-meter-provider/src/main/java/io/opentelemetry/contrib/metrics/micrometer/internal/instruments/AbstractGauge.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@ protected AbstractGauge(InstrumentState instrumentState) {
1818
super(instrumentState);
1919
}
2020

21-
protected final void record(double value, Attributes attributes) {
22-
gaugeMap.computeIfAbsent(attributesOrEmpty(attributes), this::createAsyncGauge).set(value);
21+
protected final void record(Attributes attributes, double value) {
22+
gaugeMap.computeIfAbsent(effectiveAttributes(attributes), this::createAsyncGauge).set(value);
2323
}
2424

2525
private AtomicDoubleCounter createAsyncGauge(Attributes attributes) {

micrometer-meter-provider/src/main/java/io/opentelemetry/contrib/metrics/micrometer/internal/instruments/AbstractHistogram.java

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,36 @@
88
import io.micrometer.core.instrument.DistributionSummary;
99
import io.opentelemetry.api.common.Attributes;
1010
import io.opentelemetry.contrib.metrics.micrometer.internal.state.InstrumentState;
11+
import java.util.List;
12+
import javax.annotation.Nullable;
1113

1214
abstract class AbstractHistogram extends AbstractInstrument {
15+
@Nullable private final List<? extends Number> explicitBucketBoundaries;
16+
1317
protected AbstractHistogram(InstrumentState instrumentState) {
1418
super(instrumentState);
19+
this.explicitBucketBoundaries = instrumentState.explicitBucketBoundariesAdvice();
1520
}
1621

1722
public DistributionSummary distribution(Attributes attributes) {
1823
return DistributionSummary.builder(name())
1924
.tags(attributesToTags(attributes))
2025
.description(description())
2126
.baseUnit(unit())
27+
.serviceLevelObjectives(serviceLevelObjectives(explicitBucketBoundaries))
2228
.register(meterRegistry());
2329
}
30+
31+
@Nullable
32+
private static double[] serviceLevelObjectives(
33+
@Nullable List<? extends Number> explicitBucketBoundaries) {
34+
if (explicitBucketBoundaries == null) {
35+
return null;
36+
}
37+
double[] slos = new double[explicitBucketBoundaries.size()];
38+
for (int i = 0; i < explicitBucketBoundaries.size(); i++) {
39+
slos[i] = explicitBucketBoundaries.get(i).doubleValue();
40+
}
41+
return slos;
42+
}
2443
}

micrometer-meter-provider/src/main/java/io/opentelemetry/contrib/metrics/micrometer/internal/instruments/AbstractInstrument.java

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,19 @@
77

88
import io.micrometer.core.instrument.MeterRegistry;
99
import io.micrometer.core.instrument.Tag;
10+
import io.opentelemetry.api.common.AttributeKey;
1011
import io.opentelemetry.api.common.Attributes;
1112
import io.opentelemetry.api.metrics.ObservableDoubleMeasurement;
1213
import io.opentelemetry.api.metrics.ObservableLongMeasurement;
1314
import io.opentelemetry.contrib.metrics.micrometer.CallbackRegistration;
1415
import io.opentelemetry.contrib.metrics.micrometer.internal.state.InstrumentState;
1516
import java.util.ArrayList;
1617
import java.util.Collections;
18+
import java.util.HashSet;
1719
import java.util.List;
1820
import java.util.Map;
1921
import java.util.Objects;
22+
import java.util.Set;
2023
import java.util.concurrent.ConcurrentHashMap;
2124
import java.util.function.Consumer;
2225
import java.util.logging.Level;
@@ -28,13 +31,20 @@ abstract class AbstractInstrument {
2831
private final Logger logger;
2932
private final Tag instrumentationNameTag;
3033
private final Tag instrumentationVersionTag;
34+
@Nullable private final Set<AttributeKey<?>> attributeKeySet;
3135
private final Map<Attributes, Iterable<Tag>> attributesTagsCache;
3236

3337
protected AbstractInstrument(InstrumentState instrumentState) {
3438
this.instrumentState = instrumentState;
3539
this.logger = Logger.getLogger(getClass().getName());
3640
this.instrumentationNameTag = instrumentState.instrumentationScopeNameTag();
3741
this.instrumentationVersionTag = instrumentState.instrumentationScopeVersionTag();
42+
List<AttributeKey<?>> attributes = instrumentState.attributesAdvice();
43+
if (attributes != null) {
44+
attributeKeySet = new HashSet<>(attributes);
45+
} else {
46+
attributeKeySet = null;
47+
}
3848
this.attributesTagsCache = new ConcurrentHashMap<>();
3949
}
4050

@@ -56,19 +66,27 @@ protected final String unit() {
5666
return instrumentState.unit();
5767
}
5868

59-
protected final Attributes attributesOrEmpty(@Nullable Attributes attributes) {
60-
return attributes != null ? attributes : Attributes.empty();
69+
protected final Attributes effectiveAttributes(@Nullable Attributes attributes) {
70+
if (attributes == null) {
71+
return Attributes.empty();
72+
}
73+
if (attributeKeySet == null) {
74+
return attributes;
75+
}
76+
return attributes.toBuilder().removeIf(key -> !attributeKeySet.contains(key)).build();
6177
}
6278

6379
@SuppressWarnings("PreferredInterfaceType")
6480
protected final Iterable<Tag> attributesToTags(Attributes attributes) {
65-
return attributesTagsCache.computeIfAbsent(attributesOrEmpty(attributes), this::calculateTags);
81+
return attributesTagsCache.computeIfAbsent(
82+
effectiveAttributes(attributes), this::calculateTags);
6683
}
6784

6885
@SuppressWarnings("PreferredInterfaceType")
6986
private Iterable<Tag> calculateTags(Attributes attributes) {
70-
List<Tag> list = new ArrayList<>(attributes.size() + 2);
71-
attributes.forEach(
87+
Attributes effectiveAttributes = effectiveAttributes(attributes);
88+
List<Tag> list = new ArrayList<>(effectiveAttributes.size() + 2);
89+
effectiveAttributes.forEach(
7290
(attributeKey, value) -> list.add(Tag.of(attributeKey.getKey(), Objects.toString(value))));
7391

7492
list.add(instrumentationNameTag);

micrometer-meter-provider/src/main/java/io/opentelemetry/contrib/metrics/micrometer/internal/instruments/AbstractInstrumentBuilder.java

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,30 +6,32 @@
66
package io.opentelemetry.contrib.metrics.micrometer.internal.instruments;
77

88
import com.google.errorprone.annotations.CanIgnoreReturnValue;
9+
import io.opentelemetry.api.common.AttributeKey;
910
import io.opentelemetry.contrib.metrics.micrometer.internal.state.InstrumentState;
1011
import io.opentelemetry.contrib.metrics.micrometer.internal.state.MeterSharedState;
12+
import java.util.List;
1113
import javax.annotation.Nullable;
1214

1315
abstract class AbstractInstrumentBuilder<BUILDER extends AbstractInstrumentBuilder<BUILDER>> {
1416
protected final MeterSharedState meterSharedState;
1517
protected final String name;
1618
@Nullable protected String description;
1719
@Nullable protected String unit;
20+
@Nullable protected List<AttributeKey<?>> attributes;
21+
@Nullable protected List<? extends Number> explicitBucketBoundaries;
1822

1923
protected AbstractInstrumentBuilder(MeterSharedState meterSharedState, String name) {
2024
this.meterSharedState = meterSharedState;
2125
this.name = name;
2226
}
2327

24-
protected AbstractInstrumentBuilder(
25-
MeterSharedState meterSharedState,
26-
String name,
27-
@Nullable String description,
28-
@Nullable String unit) {
29-
this.meterSharedState = meterSharedState;
30-
this.name = name;
31-
this.description = description;
32-
this.unit = unit;
28+
protected AbstractInstrumentBuilder(AbstractInstrumentBuilder<?> parent) {
29+
this.meterSharedState = parent.meterSharedState;
30+
this.name = parent.name;
31+
this.description = parent.description;
32+
this.unit = parent.unit;
33+
this.attributes = parent.attributes;
34+
this.explicitBucketBoundaries = parent.explicitBucketBoundaries;
3335
}
3436

3537
protected abstract BUILDER self();
@@ -46,7 +48,20 @@ public BUILDER setUnit(String unit) {
4648
return self();
4749
}
4850

51+
@CanIgnoreReturnValue
52+
public BUILDER setAttributesAdvice(List<AttributeKey<?>> attributes) {
53+
this.attributes = attributes;
54+
return self();
55+
}
56+
57+
@CanIgnoreReturnValue
58+
public BUILDER setExplicitBucketBoundaries(List<? extends Number> explicitBucketBoundaries) {
59+
this.explicitBucketBoundaries = explicitBucketBoundaries;
60+
return self();
61+
}
62+
4963
protected InstrumentState createInstrumentState() {
50-
return new InstrumentState(meterSharedState, name, description, unit);
64+
return new InstrumentState(
65+
meterSharedState, name, description, unit, attributes, explicitBucketBoundaries);
5166
}
5267
}

micrometer-meter-provider/src/main/java/io/opentelemetry/contrib/metrics/micrometer/internal/instruments/AbstractUpDownCounter.java

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,15 @@ protected AbstractUpDownCounter(InstrumentState instrumentState) {
1919
}
2020

2121
protected final void add(Attributes attributes, double value) {
22-
counterMap.computeIfAbsent(attributesOrEmpty(attributes), this::createCounter).increment(value);
22+
counter(attributes).increment(value);
2323
}
2424

25-
protected final void record(double value, Attributes attributes) {
26-
counterMap.computeIfAbsent(attributesOrEmpty(attributes), this::createCounter).set(value);
25+
protected final void record(Attributes attributes, double value) {
26+
counter(attributes).set(value);
27+
}
28+
29+
protected final AtomicDoubleCounter counter(Attributes attributes) {
30+
return counterMap.computeIfAbsent(effectiveAttributes(attributes), this::createCounter);
2731
}
2832

2933
private AtomicDoubleCounter createCounter(Attributes attributes) {

micrometer-meter-provider/src/main/java/io/opentelemetry/contrib/metrics/micrometer/internal/instruments/MicrometerDoubleCounter.java

Lines changed: 23 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -12,53 +12,49 @@
1212
import io.opentelemetry.api.metrics.ObservableDoubleMeasurement;
1313
import io.opentelemetry.context.Context;
1414
import io.opentelemetry.contrib.metrics.micrometer.internal.state.InstrumentState;
15-
import io.opentelemetry.contrib.metrics.micrometer.internal.state.MeterSharedState;
15+
import io.opentelemetry.extension.incubator.metrics.ExtendedDoubleCounterBuilder;
1616
import java.util.function.Consumer;
17-
import javax.annotation.Nullable;
1817

19-
final class MicrometerDoubleCounter extends AbstractCounter implements DoubleCounter {
18+
final class MicrometerDoubleCounter extends AbstractCounter
19+
implements DoubleCounter, ObservableDoubleMeasurement {
2020

2121
private MicrometerDoubleCounter(InstrumentState instrumentState) {
2222
super(instrumentState);
2323
}
2424

2525
@Override
2626
public void add(double value) {
27-
if (value >= 0.0) {
28-
counter(Attributes.empty()).increment(value);
29-
}
27+
increment(Attributes.empty(), value);
3028
}
3129

3230
@Override
3331
public void add(double value, Attributes attributes) {
34-
if (value >= 0.0) {
35-
counter(attributes).increment(value);
36-
}
32+
increment(attributes, value);
3733
}
3834

3935
@Override
4036
public void add(double value, Attributes attributes, Context context) {
41-
if (value >= 0.0) {
42-
counter(attributes).increment(value);
43-
}
37+
increment(attributes, value);
38+
}
39+
40+
@Override
41+
public void record(double value) {
42+
setMonotonically(Attributes.empty(), value);
4443
}
4544

46-
public static DoubleCounterBuilder builder(
47-
MeterSharedState meterSharedState,
48-
String name,
49-
@Nullable String description,
50-
@Nullable String unit) {
51-
return new Builder(meterSharedState, name, description, unit);
45+
@Override
46+
public void record(double value, Attributes attributes) {
47+
setMonotonically(attributes, value);
5248
}
5349

54-
private static class Builder extends AbstractInstrumentBuilder<Builder>
55-
implements DoubleCounterBuilder {
56-
private Builder(
57-
MeterSharedState meterSharedState,
58-
String name,
59-
@Nullable String description,
60-
@Nullable String unit) {
61-
super(meterSharedState, name, description, unit);
50+
public static DoubleCounterBuilder builder(MicrometerLongCounter.Builder parent) {
51+
return new Builder(parent);
52+
}
53+
54+
static final class Builder extends AbstractInstrumentBuilder<Builder>
55+
implements DoubleCounterBuilder, ExtendedDoubleCounterBuilder {
56+
private Builder(MicrometerLongCounter.Builder parent) {
57+
super(parent);
6258
}
6359

6460
@Override
@@ -75,19 +71,7 @@ public MicrometerDoubleCounter build() {
7571
public ObservableDoubleCounter buildWithCallback(
7672
Consumer<ObservableDoubleMeasurement> callback) {
7773
MicrometerDoubleCounter instrument = build();
78-
return instrument.registerDoubleCallback(
79-
callback,
80-
new ObservableDoubleMeasurement() {
81-
@Override
82-
public void record(double value) {
83-
record(value, Attributes.empty());
84-
}
85-
86-
@Override
87-
public void record(double value, Attributes attributes) {
88-
instrument.record(value, attributes);
89-
}
90-
});
74+
return instrument.registerDoubleCallback(callback, instrument);
9175
}
9276
}
9377
}

0 commit comments

Comments
 (0)