Skip to content

Commit d239b70

Browse files
onurkybsijack-berg
andauthored
Prometheus label conversion refactored to align with spec (#7291)
Co-authored-by: Jack Berg <[email protected]>
1 parent f720735 commit d239b70

File tree

2 files changed

+248
-118
lines changed

2 files changed

+248
-118
lines changed

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

Lines changed: 77 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import static java.util.Objects.requireNonNull;
1111

1212
import io.opentelemetry.api.common.AttributeKey;
13+
import io.opentelemetry.api.common.AttributeType;
1314
import io.opentelemetry.api.common.Attributes;
1415
import io.opentelemetry.api.trace.SpanContext;
1516
import io.opentelemetry.sdk.common.InstrumentationScopeInfo;
@@ -60,6 +61,7 @@
6061
import java.util.Locale;
6162
import java.util.Map;
6263
import java.util.Set;
64+
import java.util.StringJoiner;
6365
import java.util.concurrent.ConcurrentHashMap;
6466
import java.util.concurrent.TimeUnit;
6567
import java.util.function.Predicate;
@@ -472,7 +474,9 @@ private Labels convertAttributes(
472474

473475
Map<String, String> labelNameToValue = new HashMap<>();
474476
attributes.forEach(
475-
(key, value) -> labelNameToValue.put(sanitizeLabelName(key.getKey()), value.toString()));
477+
(key, value) ->
478+
labelNameToValue.put(
479+
sanitizeLabelName(key.getKey()), toLabelValue(key.getType(), value)));
476480

477481
for (int i = 0; i < additionalAttributes.length; i += 2) {
478482
labelNameToValue.putIfAbsent(
@@ -642,4 +646,76 @@ private static String typeString(MetricSnapshot snapshot) {
642646
// Simple helper for a log message.
643647
return snapshot.getClass().getSimpleName().replace("Snapshot", "").toLowerCase(Locale.ENGLISH);
644648
}
649+
650+
private static String toLabelValue(AttributeType type, Object attributeValue) {
651+
switch (type) {
652+
case STRING:
653+
case BOOLEAN:
654+
case LONG:
655+
case DOUBLE:
656+
return attributeValue.toString();
657+
case BOOLEAN_ARRAY:
658+
case LONG_ARRAY:
659+
case DOUBLE_ARRAY:
660+
case STRING_ARRAY:
661+
if (attributeValue instanceof List) {
662+
return toJsonStr((List<?>) attributeValue);
663+
} else {
664+
throw new IllegalStateException(
665+
String.format(
666+
"Unexpected label value of %s for %s",
667+
attributeValue.getClass().getName(), type.name()));
668+
}
669+
}
670+
throw new IllegalStateException("Unrecognized AttributeType: " + type);
671+
}
672+
673+
public static String toJsonStr(List<?> attributeValue) {
674+
StringJoiner joiner = new StringJoiner(",", "[", "]");
675+
for (int i = 0; i < attributeValue.size(); i++) {
676+
Object value = attributeValue.get(i);
677+
joiner.add(value instanceof String ? toJsonValidStr((String) value) : String.valueOf(value));
678+
}
679+
return joiner.toString();
680+
}
681+
682+
public static String toJsonValidStr(String str) {
683+
StringBuilder sb = new StringBuilder();
684+
sb.append('"');
685+
for (int i = 0; i < str.length(); i++) {
686+
char c = str.charAt(i);
687+
688+
switch (c) {
689+
case '"':
690+
sb.append("\\\"");
691+
break;
692+
case '\\':
693+
sb.append("\\\\");
694+
break;
695+
case '\b':
696+
sb.append("\\b");
697+
break;
698+
case '\f':
699+
sb.append("\\f");
700+
break;
701+
case '\n':
702+
sb.append("\\n");
703+
break;
704+
case '\r':
705+
sb.append("\\r");
706+
break;
707+
case '\t':
708+
sb.append("\\t");
709+
break;
710+
default:
711+
if (c <= 0x1F) {
712+
sb.append(String.format(Locale.ROOT, "\\u%04X", (int) c));
713+
} else {
714+
sb.append(c);
715+
}
716+
}
717+
}
718+
sb.append('"');
719+
return sb.toString();
720+
}
645721
}

0 commit comments

Comments
 (0)