Skip to content

Commit 5445c1d

Browse files
committed
Add UTF-8 support in metric and label names
Signed-off-by: Federico Torres <[email protected]>
1 parent efd138d commit 5445c1d

File tree

28 files changed

+1278
-123
lines changed

28 files changed

+1278
-123
lines changed

integration-tests/it-common/src/test/java/io/prometheus/client/it/common/ExporterTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
import org.testcontainers.containers.BindMode;
2424
import org.testcontainers.containers.GenericContainer;
2525

26-
public abstract class ExporterTest {
26+
public abstract class ExporterTest {
2727
private final GenericContainer<?> sampleAppContainer;
2828
private final Volume sampleAppVolume;
2929
protected final String sampleApp;
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
package io.prometheus.metrics.config;
2+
3+
import java.util.Map;
4+
5+
public class NamingProperties {
6+
7+
private static final String VALIDATION_SCHEME = "validationScheme";
8+
private final String validationScheme;
9+
10+
private NamingProperties(String validation) {
11+
this.validationScheme = validation;
12+
}
13+
14+
public String getValidationScheme() {
15+
return validationScheme;
16+
}
17+
18+
static NamingProperties load(String prefix, Map<Object, Object> properties) throws PrometheusPropertiesException {
19+
String validationScheme = Util.loadString(prefix + "." + VALIDATION_SCHEME, properties);
20+
return new NamingProperties(validationScheme);
21+
}
22+
23+
public static Builder builder() {
24+
return new Builder();
25+
}
26+
27+
public static class Builder {
28+
29+
private String validationScheme;
30+
31+
private Builder() {}
32+
33+
public Builder validation(String validationScheme) {
34+
this.validationScheme = validationScheme;
35+
return this;
36+
}
37+
38+
public NamingProperties build() {
39+
return new NamingProperties(validationScheme);
40+
}
41+
}
42+
43+
}

prometheus-metrics-config/src/main/java/io/prometheus/metrics/config/PrometheusProperties.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ public class PrometheusProperties {
2020
private final ExporterHttpServerProperties exporterHttpServerProperties;
2121
private final ExporterOpenTelemetryProperties exporterOpenTelemetryProperties;
2222
private final ExporterPushgatewayProperties exporterPushgatewayProperties;
23+
private final NamingProperties namingProperties;
2324

2425
/**
2526
* Get the properties instance. When called for the first time, {@code get()} loads the properties
@@ -44,7 +45,8 @@ public PrometheusProperties(
4445
ExporterFilterProperties exporterFilterProperties,
4546
ExporterHttpServerProperties httpServerConfig,
4647
ExporterPushgatewayProperties pushgatewayProperties,
47-
ExporterOpenTelemetryProperties otelConfig) {
48+
ExporterOpenTelemetryProperties otelConfig,
49+
NamingProperties namingProperties) {
4850
this.defaultMetricsProperties = defaultMetricsProperties;
4951
this.metricProperties.putAll(metricProperties);
5052
this.exemplarProperties = exemplarProperties;
@@ -53,6 +55,7 @@ public PrometheusProperties(
5355
this.exporterHttpServerProperties = httpServerConfig;
5456
this.exporterPushgatewayProperties = pushgatewayProperties;
5557
this.exporterOpenTelemetryProperties = otelConfig;
58+
this.namingProperties = namingProperties;
5659
}
5760

5861
/**
@@ -95,4 +98,8 @@ public ExporterPushgatewayProperties getExporterPushgatewayProperties() {
9598
public ExporterOpenTelemetryProperties getExporterOpenTelemetryProperties() {
9699
return exporterOpenTelemetryProperties;
97100
}
101+
102+
public NamingProperties getNamingProperties() {
103+
return namingProperties;
104+
}
98105
}

prometheus-metrics-config/src/main/java/io/prometheus/metrics/config/PrometheusPropertiesLoader.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import java.io.InputStream;
55
import java.nio.file.Files;
66
import java.nio.file.Paths;
7+
import java.rmi.Naming;
78
import java.util.HashMap;
89
import java.util.HashSet;
910
import java.util.Map;
@@ -42,6 +43,7 @@ public static PrometheusProperties load(Map<Object, Object> externalProperties)
4243
ExporterPushgatewayProperties.load(properties);
4344
ExporterOpenTelemetryProperties exporterOpenTelemetryProperties =
4445
ExporterOpenTelemetryProperties.load(properties);
46+
NamingProperties namingProperties = NamingProperties.load("io.prometheus.naming", properties);
4547
validateAllPropertiesProcessed(properties);
4648
return new PrometheusProperties(
4749
defaultMetricsProperties,
@@ -51,7 +53,8 @@ public static PrometheusProperties load(Map<Object, Object> externalProperties)
5153
exporterFilterProperties,
5254
exporterHttpServerProperties,
5355
exporterPushgatewayProperties,
54-
exporterOpenTelemetryProperties);
56+
exporterOpenTelemetryProperties,
57+
namingProperties);
5558
}
5659

5760
// This will remove entries from properties when they are processed.

prometheus-metrics-core/src/test/java/io/prometheus/metrics/core/metrics/HistogramTest.java

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package io.prometheus.metrics.core.metrics;
22

33
import static io.prometheus.metrics.core.metrics.TestUtil.assertExemplarEquals;
4+
import static io.prometheus.metrics.model.snapshots.PrometheusNaming.nameEscapingScheme;
45
import static org.assertj.core.api.Assertions.assertThat;
56
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
67
import static org.assertj.core.data.Offset.offset;
@@ -11,12 +12,7 @@
1112
import io.prometheus.metrics.expositionformats.generated.com_google_protobuf_4_29_1.Metrics;
1213
import io.prometheus.metrics.expositionformats.internal.PrometheusProtobufWriterImpl;
1314
import io.prometheus.metrics.expositionformats.internal.ProtobufUtil;
14-
import io.prometheus.metrics.model.snapshots.ClassicHistogramBucket;
15-
import io.prometheus.metrics.model.snapshots.Exemplar;
16-
import io.prometheus.metrics.model.snapshots.Exemplars;
17-
import io.prometheus.metrics.model.snapshots.HistogramSnapshot;
18-
import io.prometheus.metrics.model.snapshots.Labels;
19-
import io.prometheus.metrics.model.snapshots.MetricSnapshots;
15+
import io.prometheus.metrics.model.snapshots.*;
2016
import io.prometheus.metrics.tracer.common.SpanContext;
2117
import io.prometheus.metrics.tracer.initializer.SpanContextSupplier;
2218
import java.io.ByteArrayOutputStream;
@@ -946,6 +942,7 @@ public void testDefaults() throws IOException {
946942
// text
947943
ByteArrayOutputStream out = new ByteArrayOutputStream();
948944
OpenMetricsTextFormatWriter writer = new OpenMetricsTextFormatWriter(false, true);
945+
nameEscapingScheme = EscapingScheme.NO_ESCAPING;
949946
writer.write(out, MetricSnapshots.of(snapshot));
950947
assertThat(out).hasToString(expectedTextFormat);
951948
}

prometheus-metrics-core/src/test/java/io/prometheus/metrics/core/metrics/InfoTest.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
package io.prometheus.metrics.core.metrics;
22

3+
import static io.prometheus.metrics.model.snapshots.PrometheusNaming.nameEscapingScheme;
34
import static org.assertj.core.api.Assertions.assertThat;
45
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
56

67
import io.prometheus.metrics.expositionformats.OpenMetricsTextFormatWriter;
78
import io.prometheus.metrics.expositionformats.generated.com_google_protobuf_4_29_1.Metrics;
89
import io.prometheus.metrics.expositionformats.internal.PrometheusProtobufWriterImpl;
910
import io.prometheus.metrics.expositionformats.internal.ProtobufUtil;
11+
import io.prometheus.metrics.model.snapshots.EscapingScheme;
1012
import io.prometheus.metrics.model.snapshots.Labels;
1113
import io.prometheus.metrics.model.snapshots.MetricSnapshots;
1214
import io.prometheus.metrics.model.snapshots.Unit;
@@ -121,6 +123,7 @@ public void testConstLabelsDuplicate2() {
121123
private void assertTextFormat(String expected, Info info) throws IOException {
122124
OpenMetricsTextFormatWriter writer = new OpenMetricsTextFormatWriter(true, true);
123125
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
126+
nameEscapingScheme = EscapingScheme.NO_ESCAPING;
124127
writer.write(outputStream, MetricSnapshots.of(info.collect()));
125128
String result = outputStream.toString(StandardCharsets.UTF_8.name());
126129
if (!result.contains(expected)) {

prometheus-metrics-exporter-common/src/main/java/io/prometheus/metrics/exporter/common/PrometheusScrapeHandler.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import io.prometheus.metrics.expositionformats.ExpositionFormats;
77
import io.prometheus.metrics.model.registry.MetricNameFilter;
88
import io.prometheus.metrics.model.registry.PrometheusRegistry;
9+
import io.prometheus.metrics.model.snapshots.EscapingScheme;
910
import io.prometheus.metrics.model.snapshots.MetricSnapshots;
1011
import java.io.ByteArrayOutputStream;
1112
import java.io.IOException;
@@ -19,6 +20,8 @@
1920
import java.util.function.Predicate;
2021
import java.util.zip.GZIPOutputStream;
2122

23+
import static io.prometheus.metrics.model.snapshots.PrometheusNaming.nameEscapingScheme;
24+
2225
/** Prometheus scrape endpoint. */
2326
public class PrometheusScrapeHandler {
2427

@@ -54,12 +57,13 @@ public void handleRequest(PrometheusHttpExchange exchange) throws IOException {
5457
try {
5558
PrometheusHttpRequest request = exchange.getRequest();
5659
MetricSnapshots snapshots = scrape(request);
60+
String acceptHeader = request.getHeader("Accept");
61+
nameEscapingScheme = EscapingScheme.fromAcceptHeader(acceptHeader);
5762
if (writeDebugResponse(snapshots, exchange)) {
5863
return;
5964
}
6065
ByteArrayOutputStream responseBuffer =
6166
new ByteArrayOutputStream(lastResponseSize.get() + 1024);
62-
String acceptHeader = request.getHeader("Accept");
6367
ExpositionFormatWriter writer = expositionFormats.findWriter(acceptHeader);
6468
writer.write(responseBuffer, snapshots);
6569
lastResponseSize.set(responseBuffer.size());

prometheus-metrics-exporter-pushgateway/src/main/java/io/prometheus/metrics/exporter/pushgateway/PushGateway.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package io.prometheus.metrics.exporter.pushgateway;
22

33
import static io.prometheus.metrics.exporter.pushgateway.Scheme.HTTP;
4+
import static io.prometheus.metrics.model.snapshots.PrometheusNaming.nameEscapingScheme;
45

56
import io.prometheus.metrics.config.ExporterPushgatewayProperties;
67
import io.prometheus.metrics.config.PrometheusProperties;
@@ -11,6 +12,8 @@
1112
import io.prometheus.metrics.model.registry.Collector;
1213
import io.prometheus.metrics.model.registry.MultiCollector;
1314
import io.prometheus.metrics.model.registry.PrometheusRegistry;
15+
import io.prometheus.metrics.model.snapshots.EscapingScheme;
16+
1417
import java.io.ByteArrayOutputStream;
1518
import java.io.IOException;
1619
import java.io.InputStream;
@@ -200,6 +203,7 @@ private void doRequest(PrometheusRegistry registry, String method) throws IOExce
200203
try {
201204
if (!method.equals("DELETE")) {
202205
OutputStream outputStream = connection.getOutputStream();
206+
nameEscapingScheme = EscapingScheme.NO_ESCAPING;
203207
writer.write(outputStream, registry.scrape());
204208
outputStream.flush();
205209
outputStream.close();

0 commit comments

Comments
 (0)