Skip to content

Commit ca89436

Browse files
authored
Workaround for temporality configuration not being possible (#610)
1 parent e0e0ecc commit ca89436

File tree

5 files changed

+86
-3
lines changed

5 files changed

+86
-3
lines changed

CHANGELOG.next-release.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
1+
* Fix `otel.exporter.otlp.metrics.temporality.preference` config option having no effect. - #610

custom/build.gradle.kts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,9 @@ dependencies {
3535
// test dependencies
3636
testImplementation(project(":testing-common"))
3737
testImplementation("io.opentelemetry:opentelemetry-sdk")
38+
testImplementation("io.opentelemetry:opentelemetry-sdk-extension-autoconfigure")
3839
testImplementation("io.opentelemetry:opentelemetry-sdk-extension-autoconfigure-spi")
40+
testImplementation("io.opentelemetry:opentelemetry-exporter-otlp")
3941
testImplementation("io.opentelemetry.javaagent:opentelemetry-javaagent-tooling") {
4042
//The following dependency isn't actually needed, but breaks the classpath when testing with Java 8
4143
exclude(group = "io.opentelemetry.javaagent", module = "opentelemetry-javaagent-tooling-java9")

custom/src/main/java/co/elastic/otel/ElasticUserAgentHeader.java

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,12 +47,23 @@ public static SpanExporter configureIfPossible(SpanExporter spanExporter) {
4747
}
4848

4949
public static MetricExporter configureIfPossible(MetricExporter metricExporter) {
50+
// TODO remove workaround for https://github.com/open-telemetry/opentelemetry-java/issues/7276
51+
// once fixed, setAggregationTemporalitySelector and setDefaultAggregationSelector can then be
52+
// removed
5053
if (metricExporter instanceof OtlpGrpcMetricExporter) {
5154
return ((OtlpGrpcMetricExporter) metricExporter)
52-
.toBuilder().addHeader(HEADER_NAME, GRPC_VALUE).build();
55+
.toBuilder()
56+
.setAggregationTemporalitySelector(metricExporter)
57+
.setDefaultAggregationSelector(metricExporter)
58+
.addHeader(HEADER_NAME, GRPC_VALUE)
59+
.build();
5360
} else if (metricExporter instanceof OtlpHttpMetricExporter) {
5461
return ((OtlpHttpMetricExporter) metricExporter)
55-
.toBuilder().addHeader(HEADER_NAME, HTTP_VALUE).build();
62+
.toBuilder()
63+
.setAggregationTemporalitySelector(metricExporter)
64+
.setDefaultAggregationSelector(metricExporter)
65+
.addHeader(HEADER_NAME, HTTP_VALUE)
66+
.build();
5667
}
5768
return metricExporter;
5869
}

custom/src/test/java/co/elastic/otel/ElasticAutoConfigurationCustomizerProviderTest.java

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,22 @@
2222
import static co.elastic.otel.ElasticAutoConfigurationCustomizerProvider.resourceProviders;
2323
import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat;
2424

25+
import co.elastic.otel.testing.OtelReflectionUtils;
26+
import io.opentelemetry.exporter.otlp.http.metrics.OtlpHttpMetricExporter;
2527
import io.opentelemetry.javaagent.tooling.EmptyConfigProperties;
28+
import io.opentelemetry.sdk.OpenTelemetrySdk;
29+
import io.opentelemetry.sdk.autoconfigure.AutoConfiguredOpenTelemetrySdk;
2630
import io.opentelemetry.sdk.autoconfigure.spi.internal.DefaultConfigProperties;
31+
import io.opentelemetry.sdk.metrics.InstrumentType;
32+
import io.opentelemetry.sdk.metrics.data.AggregationTemporality;
33+
import io.opentelemetry.sdk.metrics.export.AggregationTemporalitySelector;
34+
import io.opentelemetry.sdk.metrics.export.MetricExporter;
2735
import io.opentelemetry.sdk.resources.Resource;
2836
import io.opentelemetry.semconv.incubating.DeploymentIncubatingAttributes;
2937
import java.util.HashMap;
38+
import java.util.List;
3039
import java.util.Map;
40+
import org.assertj.core.api.Assertions;
3141
import org.junit.jupiter.api.Test;
3242

3343
class ElasticAutoConfigurationCustomizerProviderTest {
@@ -88,6 +98,50 @@ void customizeMetricTemporalityPreference() {
8898
assertThat(value).isEqualTo("LOWMEMORY");
8999
}
90100

101+
@Test
102+
void testTemporalityWorkaroundStilLRequired() {
103+
// Verifies that the workaround for
104+
// https://github.com/open-telemetry/opentelemetry-java/issues/7276
105+
// is still required. Once not needed anymore, fix the TODO in
106+
// co.elastic.otel.ElasticUserAgentHeader and remove this test
107+
108+
OtlpHttpMetricExporter original =
109+
OtlpHttpMetricExporter.builder()
110+
.setAggregationTemporalitySelector(AggregationTemporalitySelector.deltaPreferred())
111+
.build();
112+
Assertions.assertThat(original.getAggregationTemporality(InstrumentType.COUNTER))
113+
.isEqualTo(AggregationTemporality.DELTA);
114+
115+
OtlpHttpMetricExporter modified = original.toBuilder().build();
116+
117+
// The bug causes the temporality to become cumulative, though it should be delta
118+
assertThat(modified.getAggregationTemporality(InstrumentType.COUNTER))
119+
.isEqualTo(AggregationTemporality.CUMULATIVE);
120+
}
121+
122+
@Test
123+
void verifyDefaultTemporalityOverriddenToDelta() {
124+
try (OpenTelemetrySdk sdk =
125+
AutoConfiguredOpenTelemetrySdk.builder().build().getOpenTelemetrySdk()) {
126+
List<MetricExporter> metricExporters =
127+
OtelReflectionUtils.extractMetricExporters(sdk.getSdkMeterProvider());
128+
129+
assertThat(metricExporters).hasSize(1);
130+
131+
MetricExporter otlp = metricExporters.get(0);
132+
assertThat(otlp.getAggregationTemporality(InstrumentType.COUNTER))
133+
.isEqualTo(AggregationTemporality.DELTA);
134+
assertThat(otlp.getAggregationTemporality(InstrumentType.OBSERVABLE_COUNTER))
135+
.isEqualTo(AggregationTemporality.DELTA);
136+
assertThat(otlp.getAggregationTemporality(InstrumentType.HISTOGRAM))
137+
.isEqualTo(AggregationTemporality.DELTA);
138+
assertThat(otlp.getAggregationTemporality(InstrumentType.UP_DOWN_COUNTER))
139+
.isEqualTo(AggregationTemporality.CUMULATIVE);
140+
assertThat(otlp.getAggregationTemporality(InstrumentType.OBSERVABLE_UP_DOWN_COUNTER))
141+
.isEqualTo(AggregationTemporality.CUMULATIVE);
142+
}
143+
}
144+
91145
@Test
92146
void legacyDeploymentEnvironment() {
93147
Resource input =

testing-common/src/main/java/co/elastic/otel/testing/OtelReflectionUtils.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@
2222
import io.opentelemetry.api.OpenTelemetry;
2323
import io.opentelemetry.api.trace.TracerProvider;
2424
import io.opentelemetry.sdk.OpenTelemetrySdk;
25+
import io.opentelemetry.sdk.metrics.SdkMeterProvider;
26+
import io.opentelemetry.sdk.metrics.export.MetricExporter;
27+
import io.opentelemetry.sdk.metrics.export.PeriodicMetricReader;
28+
import io.opentelemetry.sdk.metrics.internal.export.RegisteredReader;
2529
import io.opentelemetry.sdk.trace.SdkTracerProvider;
2630
import io.opentelemetry.sdk.trace.SpanProcessor;
2731
import java.lang.reflect.Field;
@@ -119,4 +123,16 @@ private static Object readField(Class<?> clazz, Object instance, String fieldNam
119123
throw new IllegalStateException(e);
120124
}
121125
}
126+
127+
@SuppressWarnings("unchecked")
128+
public static List<MetricExporter> extractMetricExporters(SdkMeterProvider sdkMeterProvider) {
129+
List<RegisteredReader> readers =
130+
(List<RegisteredReader>) readField(sdkMeterProvider, "registeredReaders");
131+
132+
return readers.stream()
133+
.map(reader -> reader.getReader())
134+
.filter(reader -> reader instanceof PeriodicMetricReader)
135+
.map(periodicReader -> (MetricExporter) readField(periodicReader, "exporter"))
136+
.collect(Collectors.toList());
137+
}
122138
}

0 commit comments

Comments
 (0)