Skip to content

Commit 05f6702

Browse files
add scope schema URL and attributes to prom attributes (#7356)
Co-authored-by: jack-berg <[email protected]>
1 parent e949555 commit 05f6702

File tree

2 files changed

+50
-23
lines changed

2 files changed

+50
-23
lines changed

exporters/prometheus/src/main/java/io/opentelemetry/exporter/prometheus/Otel2PrometheusConverter.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,8 @@ final class Otel2PrometheusConverter {
7777
private static final ThrottlingLogger THROTTLING_LOGGER = new ThrottlingLogger(LOGGER);
7878
private static final String OTEL_SCOPE_NAME = "otel_scope_name";
7979
private static final String OTEL_SCOPE_VERSION = "otel_scope_version";
80+
private static final String OTEL_SCOPE_SCHEMA_URL = "otel_scope_schema_url";
81+
private static final String OTEL_SCOPE_ATTRIBUTE_PREFIX = "otel_scope_";
8082
private static final long NANOS_PER_MILLISECOND = TimeUnit.MILLISECONDS.toNanos(1);
8183
static final int MAX_CACHE_SIZE = 10;
8284

@@ -488,6 +490,16 @@ private Labels convertAttributes(
488490
if (scope.getVersion() != null) {
489491
labelNameToValue.putIfAbsent(OTEL_SCOPE_VERSION, scope.getVersion());
490492
}
493+
String schemaUrl = scope.getSchemaUrl();
494+
if (schemaUrl != null) {
495+
labelNameToValue.putIfAbsent(OTEL_SCOPE_SCHEMA_URL, schemaUrl);
496+
}
497+
scope
498+
.getAttributes()
499+
.forEach(
500+
(key, value) ->
501+
labelNameToValue.putIfAbsent(
502+
OTEL_SCOPE_ATTRIBUTE_PREFIX + key.getKey(), value.toString()));
491503
}
492504

493505
if (resource != null) {

exporters/prometheus/src/test/java/io/opentelemetry/exporter/prometheus/Otel2PrometheusConverterTest.java

Lines changed: 38 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,9 @@
3838
import io.opentelemetry.sdk.metrics.internal.data.ImmutableSummaryPointData;
3939
import io.opentelemetry.sdk.resources.Resource;
4040
import io.prometheus.metrics.expositionformats.ExpositionFormats;
41+
import io.prometheus.metrics.model.snapshots.CounterSnapshot;
4142
import io.prometheus.metrics.model.snapshots.Labels;
43+
import io.prometheus.metrics.model.snapshots.MetricSnapshot;
4244
import io.prometheus.metrics.model.snapshots.MetricSnapshots;
4345
import java.io.ByteArrayOutputStream;
4446
import java.io.IOException;
@@ -47,9 +49,9 @@
4749
import java.util.Arrays;
4850
import java.util.Collections;
4951
import java.util.List;
52+
import java.util.Optional;
5053
import java.util.concurrent.atomic.AtomicInteger;
5154
import java.util.function.Predicate;
52-
import java.util.regex.Matcher;
5355
import java.util.regex.Pattern;
5456
import java.util.stream.Collectors;
5557
import java.util.stream.Stream;
@@ -63,7 +65,9 @@ class Otel2PrometheusConverterTest {
6365

6466
private static final Pattern PATTERN =
6567
Pattern.compile(
66-
"# HELP (?<help>.*)\n# TYPE (?<type>.*)\n(?<metricName>.*)\\{otel_scope_name=\"scope\"}(.|\\n)*");
68+
"(.|\\n)*# HELP (?<help>.*)\n# TYPE (?<type>.*)\n(?<metricName>.*)\\{"
69+
+ "otel_scope_foo=\"bar\",otel_scope_name=\"scope\","
70+
+ "otel_scope_schema_url=\"schemaUrl\",otel_scope_version=\"version\"}(.|\\n)*");
6771
private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
6872

6973
private final Otel2PrometheusConverter converter =
@@ -79,16 +83,17 @@ void metricMetadata(
7983
ExpositionFormats.init().getPrometheusTextFormatWriter().write(out, snapshots);
8084
String expositionFormat = new String(out.toByteArray(), StandardCharsets.UTF_8);
8185

82-
// Uncomment to debug exposition format output
83-
// System.out.println(expositionFormat);
84-
85-
Matcher matcher = PATTERN.matcher(expositionFormat);
86-
assertThat(matcher.matches()).isTrue();
87-
assertThat(matcher.group("help")).isEqualTo(expectedHelp);
88-
assertThat(matcher.group("type")).isEqualTo(expectedType);
89-
// Note: Summaries and histograms produce output which matches METRIC_NAME_PATTERN multiple
90-
// times. The pattern ends up matching against the first.
91-
assertThat(matcher.group("metricName")).isEqualTo(expectedMetricName);
86+
assertThat(expositionFormat)
87+
.matchesSatisfying(
88+
PATTERN,
89+
matcher -> {
90+
assertThat(matcher.group("help")).isEqualTo(expectedHelp);
91+
assertThat(matcher.group("type")).isEqualTo(expectedType);
92+
// Note: Summaries and histograms produce output which matches METRIC_NAME_PATTERN
93+
// multiple
94+
// times. The pattern ends up matching against the first.
95+
assertThat(matcher.group("metricName")).isEqualTo(expectedMetricName);
96+
});
9297
}
9398

9499
private static Stream<Arguments> metricMetadataArgs() {
@@ -239,7 +244,7 @@ private static Stream<Arguments> resourceAttributesAdditionArgs() {
239244
: "my_metric_units",
240245

241246
// "cluster" attribute is added (due to reg expr specified) and only it
242-
"cluster=\"mycluster\",foo1=\"bar1\",foo2=\"bar2\",otel_scope_name=\"scope\""));
247+
"cluster=\"mycluster\",foo1=\"bar1\",foo2=\"bar2\",otel_scope_foo=\"bar\",otel_scope_name=\"scope\",otel_scope_schema_url=\"schemaUrl\",otel_scope_version=\"version\""));
243248
}
244249

245250
// Resource attributes which also exists in the metric labels are not added twice
@@ -258,7 +263,7 @@ private static Stream<Arguments> resourceAttributesAdditionArgs() {
258263

259264
// "cluster" attribute is present only once and the value is taken
260265
// from the metric attributes and not the resource attributes
261-
"cluster=\"mycluster2\",foo2=\"bar2\",otel_scope_name=\"scope\""));
266+
"cluster=\"mycluster2\",foo2=\"bar2\",otel_scope_foo=\"bar\",otel_scope_name=\"scope\",otel_scope_schema_url=\"schemaUrl\",otel_scope_version=\"version\""));
262267

263268
// Empty attributes
264269
arguments.add(
@@ -273,7 +278,7 @@ private static Stream<Arguments> resourceAttributesAdditionArgs() {
273278
stringKey("host"), "localhost", stringKey("cluster"), "mycluster"))),
274279
/* allowedResourceAttributesFilter= */ Predicates.startsWith("clu"),
275280
"my_metric_units",
276-
"cluster=\"mycluster\",otel_scope_name=\"scope\""));
281+
"cluster=\"mycluster\",otel_scope_foo=\"bar\",otel_scope_name=\"scope\",otel_scope_schema_url=\"schemaUrl\",otel_scope_version=\"version\""));
277282

278283
return arguments.stream();
279284
}
@@ -314,7 +319,11 @@ void labelValueSerialization(Attributes attributes) {
314319

315320
MetricSnapshots snapshots = converter.convert(Collections.singletonList(metricData));
316321

317-
Labels labels = snapshots.get(0).getDataPoints().get(0).getLabels();
322+
Optional<MetricSnapshot> metricSnapshot =
323+
snapshots.stream().filter(snapshot -> snapshot instanceof CounterSnapshot).findFirst();
324+
assertThat(metricSnapshot).isPresent();
325+
326+
Labels labels = metricSnapshot.get().getDataPoints().get(0).getLabels();
318327
attributes.forEach(
319328
(key, value) -> {
320329
String labelValue = labels.get(key.getKey());
@@ -368,11 +377,17 @@ static MetricData createSampleMetricData(
368377
Attributes attributesToUse = attributes == null ? Attributes.empty() : attributes;
369378
Resource resourceToUse = resource == null ? Resource.getDefault() : resource;
370379

380+
InstrumentationScopeInfo scope =
381+
InstrumentationScopeInfo.builder("scope")
382+
.setVersion("version")
383+
.setSchemaUrl("schemaUrl")
384+
.setAttributes(Attributes.of(stringKey("foo"), "bar"))
385+
.build();
371386
switch (metricDataType) {
372387
case SUMMARY:
373388
return ImmutableMetricData.createDoubleSummary(
374389
resourceToUse,
375-
InstrumentationScopeInfo.create("scope"),
390+
scope,
376391
metricName,
377392
"description",
378393
metricUnit,
@@ -383,7 +398,7 @@ static MetricData createSampleMetricData(
383398
case LONG_SUM:
384399
return ImmutableMetricData.createLongSum(
385400
resourceToUse,
386-
InstrumentationScopeInfo.create("scope"),
401+
scope,
387402
metricName,
388403
"description",
389404
metricUnit,
@@ -395,7 +410,7 @@ static MetricData createSampleMetricData(
395410
case DOUBLE_SUM:
396411
return ImmutableMetricData.createDoubleSum(
397412
resourceToUse,
398-
InstrumentationScopeInfo.create("scope"),
413+
scope,
399414
metricName,
400415
"description",
401416
metricUnit,
@@ -407,7 +422,7 @@ static MetricData createSampleMetricData(
407422
case LONG_GAUGE:
408423
return ImmutableMetricData.createLongGauge(
409424
resourceToUse,
410-
InstrumentationScopeInfo.create("scope"),
425+
scope,
411426
metricName,
412427
"description",
413428
metricUnit,
@@ -417,7 +432,7 @@ static MetricData createSampleMetricData(
417432
case DOUBLE_GAUGE:
418433
return ImmutableMetricData.createDoubleGauge(
419434
resourceToUse,
420-
InstrumentationScopeInfo.create("scope"),
435+
scope,
421436
metricName,
422437
"description",
423438
metricUnit,
@@ -427,7 +442,7 @@ static MetricData createSampleMetricData(
427442
case HISTOGRAM:
428443
return ImmutableMetricData.createDoubleHistogram(
429444
resourceToUse,
430-
InstrumentationScopeInfo.create("scope"),
445+
scope,
431446
metricName,
432447
"description",
433448
metricUnit,
@@ -448,7 +463,7 @@ static MetricData createSampleMetricData(
448463
case EXPONENTIAL_HISTOGRAM:
449464
return ImmutableMetricData.createExponentialHistogram(
450465
resourceToUse,
451-
InstrumentationScopeInfo.create("scope"),
466+
scope,
452467
metricName,
453468
"description",
454469
metricUnit,

0 commit comments

Comments
 (0)