Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@ final class Otel2PrometheusConverter {
private static final ThrottlingLogger THROTTLING_LOGGER = new ThrottlingLogger(LOGGER);
private static final String OTEL_SCOPE_NAME = "otel_scope_name";
private static final String OTEL_SCOPE_VERSION = "otel_scope_version";
private static final String OTEL_SCOPE_SCHEMA_URL = "otel_scope_schema_url";
private static final String OTEL_SCOPE_ATTRIBUTE_PREFIX = "otel_scope_";
private static final long NANOS_PER_MILLISECOND = TimeUnit.MILLISECONDS.toNanos(1);
static final int MAX_CACHE_SIZE = 10;

Expand Down Expand Up @@ -488,6 +490,16 @@ private Labels convertAttributes(
if (scope.getVersion() != null) {
labelNameToValue.putIfAbsent(OTEL_SCOPE_VERSION, scope.getVersion());
}
String schemaUrl = scope.getSchemaUrl();
if (schemaUrl != null) {
labelNameToValue.putIfAbsent(OTEL_SCOPE_SCHEMA_URL, schemaUrl);
}
scope
.getAttributes()
.forEach(
(key, value) ->
labelNameToValue.putIfAbsent(
OTEL_SCOPE_ATTRIBUTE_PREFIX + key.getKey(), value.toString()));
}

if (resource != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,9 @@
import io.opentelemetry.sdk.metrics.internal.data.ImmutableSummaryPointData;
import io.opentelemetry.sdk.resources.Resource;
import io.prometheus.metrics.expositionformats.ExpositionFormats;
import io.prometheus.metrics.model.snapshots.CounterSnapshot;
import io.prometheus.metrics.model.snapshots.Labels;
import io.prometheus.metrics.model.snapshots.MetricSnapshot;
import io.prometheus.metrics.model.snapshots.MetricSnapshots;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
Expand All @@ -47,9 +49,9 @@
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Predicate;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.Stream;
Expand All @@ -63,7 +65,9 @@ class Otel2PrometheusConverterTest {

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

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

// Uncomment to debug exposition format output
// System.out.println(expositionFormat);

Matcher matcher = PATTERN.matcher(expositionFormat);
assertThat(matcher.matches()).isTrue();
assertThat(matcher.group("help")).isEqualTo(expectedHelp);
assertThat(matcher.group("type")).isEqualTo(expectedType);
// Note: Summaries and histograms produce output which matches METRIC_NAME_PATTERN multiple
// times. The pattern ends up matching against the first.
assertThat(matcher.group("metricName")).isEqualTo(expectedMetricName);
assertThat(expositionFormat)
.matchesSatisfying(
PATTERN,
matcher -> {
assertThat(matcher.group("help")).isEqualTo(expectedHelp);
assertThat(matcher.group("type")).isEqualTo(expectedType);
// Note: Summaries and histograms produce output which matches METRIC_NAME_PATTERN
// multiple
// times. The pattern ends up matching against the first.
assertThat(matcher.group("metricName")).isEqualTo(expectedMetricName);
});
}

private static Stream<Arguments> metricMetadataArgs() {
Expand Down Expand Up @@ -239,7 +244,7 @@ private static Stream<Arguments> resourceAttributesAdditionArgs() {
: "my_metric_units",

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

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

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

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

return arguments.stream();
}
Expand Down Expand Up @@ -314,7 +319,11 @@ void labelValueSerialization(Attributes attributes) {

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

Labels labels = snapshots.get(0).getDataPoints().get(0).getLabels();
Optional<MetricSnapshot> metricSnapshot =
snapshots.stream().filter(snapshot -> snapshot instanceof CounterSnapshot).findFirst();
assertThat(metricSnapshot).isPresent();

Labels labels = metricSnapshot.get().getDataPoints().get(0).getLabels();
attributes.forEach(
(key, value) -> {
String labelValue = labels.get(key.getKey());
Expand Down Expand Up @@ -368,11 +377,17 @@ static MetricData createSampleMetricData(
Attributes attributesToUse = attributes == null ? Attributes.empty() : attributes;
Resource resourceToUse = resource == null ? Resource.getDefault() : resource;

InstrumentationScopeInfo scope =
InstrumentationScopeInfo.builder("scope")
.setVersion("version")
.setSchemaUrl("schemaUrl")
.setAttributes(Attributes.of(stringKey("foo"), "bar"))
.build();
switch (metricDataType) {
case SUMMARY:
return ImmutableMetricData.createDoubleSummary(
resourceToUse,
InstrumentationScopeInfo.create("scope"),
scope,
metricName,
"description",
metricUnit,
Expand All @@ -383,7 +398,7 @@ static MetricData createSampleMetricData(
case LONG_SUM:
return ImmutableMetricData.createLongSum(
resourceToUse,
InstrumentationScopeInfo.create("scope"),
scope,
metricName,
"description",
metricUnit,
Expand All @@ -395,7 +410,7 @@ static MetricData createSampleMetricData(
case DOUBLE_SUM:
return ImmutableMetricData.createDoubleSum(
resourceToUse,
InstrumentationScopeInfo.create("scope"),
scope,
metricName,
"description",
metricUnit,
Expand All @@ -407,7 +422,7 @@ static MetricData createSampleMetricData(
case LONG_GAUGE:
return ImmutableMetricData.createLongGauge(
resourceToUse,
InstrumentationScopeInfo.create("scope"),
scope,
metricName,
"description",
metricUnit,
Expand All @@ -417,7 +432,7 @@ static MetricData createSampleMetricData(
case DOUBLE_GAUGE:
return ImmutableMetricData.createDoubleGauge(
resourceToUse,
InstrumentationScopeInfo.create("scope"),
scope,
metricName,
"description",
metricUnit,
Expand All @@ -427,7 +442,7 @@ static MetricData createSampleMetricData(
case HISTOGRAM:
return ImmutableMetricData.createDoubleHistogram(
resourceToUse,
InstrumentationScopeInfo.create("scope"),
scope,
metricName,
"description",
metricUnit,
Expand All @@ -448,7 +463,7 @@ static MetricData createSampleMetricData(
case EXPONENTIAL_HISTOGRAM:
return ImmutableMetricData.createExponentialHistogram(
resourceToUse,
InstrumentationScopeInfo.create("scope"),
scope,
metricName,
"description",
metricUnit,
Expand Down
Loading