Skip to content

Commit

Permalink
#342 - Implemented Label Value Sanitizer
Browse files Browse the repository at this point in the history
Signed-off-by: Daniel Hoelbling-Inzko <[email protected]>
  • Loading branch information
Tigraine committed Apr 22, 2022
1 parent ca6145f commit 065f82a
Show file tree
Hide file tree
Showing 3 changed files with 85 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package io.prometheus.client;

public interface LabelValueSanitizer {
String[] sanitize(String... labelValue);
}
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ public abstract class SimpleCollector<Child> extends Collector {
protected final String help;
protected final String unit;
protected final List<String> labelNames;
protected final LabelValueSanitizer labelValueSanitizer;

protected final ConcurrentMap<List<String>, Child> children = new ConcurrentHashMap<List<String>, Child>();
protected Child noLabelsChild;
Expand All @@ -64,6 +65,7 @@ public Child labels(String... labelValues) {
if (labelValues.length != labelNames.size()) {
throw new IllegalArgumentException("Incorrect number of labels.");
}
labelValues = labelValueSanitizer.sanitize(labelValues);
for (String label: labelValues) {
if (label == null) {
throw new IllegalArgumentException("Label cannot be null.");
Expand Down Expand Up @@ -174,12 +176,42 @@ protected SimpleCollector(Builder b) {
for (String n: labelNames) {
checkMetricLabelName(n);
}
labelValueSanitizer = b.labelValueSanitizer;

if (!b.dontInitializeNoLabelsChild) {
initializeNoLabelsChild();
}
}

/**
* Default Sanitizer - Will not perform any manipulation on labels
*/
static LabelValueSanitizer NoOpLabelValueSanitizer() {
return new LabelValueSanitizer() {
@Override
public String[] sanitize(String... labelValue) {
return labelValue;
}
};
}

/**
* Transforms null labels to an empty string to guard against IllegalArgument runtime exceptions
*/
static LabelValueSanitizer TransformNullLabelsToEmptyString() {
return new LabelValueSanitizer() {
@Override
public String[] sanitize(String... labelValue) {
for (int i = 0; i < labelValue.length; i++) {
if (labelValue[i] == null) {
labelValue[i] = "";
}
}
return labelValue;
}
};
}

/**
* Builders let you configure and then create collectors.
*/
Expand All @@ -191,6 +223,7 @@ public abstract static class Builder<B extends Builder<B, C>, C extends SimpleCo
String unit = "";
String help = "";
String[] labelNames = new String[]{};
LabelValueSanitizer labelValueSanitizer = NoOpLabelValueSanitizer();
// Some metrics require additional setup before the initialization can be done.
boolean dontInitializeNoLabelsChild;

Expand Down Expand Up @@ -239,6 +272,18 @@ public B labelNames(String... labelNames) {
return (B)this;
}

/**
* Sanitize labels. Optional, defaults to no manipulation of labels.
* Useful to scrub credentials from labels
* or avoid Null values causing runtime exceptions
* @param handler
* @return new array of labels to use
*/
public B labelValueSanitizer(LabelValueSanitizer handler) {
this.labelValueSanitizer = handler;
return (B)this;
}

/**
* Return the constructed collector.
* <p>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package io.prometheus.client;

import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;

import static org.junit.Assert.*;
import static org.junit.rules.ExpectedException.none;


public class SimpleCollectorWithLabelSanitizerTest {

CollectorRegistry registry;
Gauge metric;

@Rule
public final ExpectedException thrown = none();

@Before
public void setUp() {
registry = new CollectorRegistry();
metric = Gauge.build().name("nonulllabels").help("help").labelNames("l").labelValueSanitizer(Gauge.TransformNullLabelsToEmptyString()).register(registry);
}

private Double getValue(String labelValue) {
return registry.getSampleValue("nonulllabels", new String[]{"l"}, new String[]{labelValue});
}

@Test
public void testNullLabelDoesntThrowWithLabelSanitizer() {
metric.labels(new String[]{null}).inc();
assertEquals(1.0, getValue("").doubleValue(), .001);
}
}

0 comments on commit 065f82a

Please sign in to comment.