Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Filter metrics by suffix #787

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
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 @@ -22,13 +22,17 @@ public class SampleNameFilter implements Predicate<String> {
private final Collection<String> nameIsNotEqualTo;
private final Collection<String> nameStartsWith;
private final Collection<String> nameDoesNotStartWith;
private final Collection<String> nameEndsWith;
private final Collection<String> nameDoesNotEndWith;

@Override
public boolean test(String sampleName) {
return matchesNameEqualTo(sampleName)
&& !matchesNameNotEqualTo(sampleName)
&& matchesNameNotEqualTo(sampleName)
&& matchesNameStartsWith(sampleName)
&& !matchesNameDoesNotStartWith(sampleName);
&& matchesNameDoesNotStartWith(sampleName)
&& matchesNameEndsWith(sampleName)
&& matchesNameDoesNotEndWith(sampleName);
}

/**
Expand All @@ -55,9 +59,9 @@ private boolean matchesNameEqualTo(String metricName) {

private boolean matchesNameNotEqualTo(String metricName) {
if (nameIsNotEqualTo.isEmpty()) {
return false;
return true;
}
return nameIsNotEqualTo.contains(metricName);
return !nameIsNotEqualTo.contains(metricName);
}

private boolean matchesNameStartsWith(String metricName) {
Expand All @@ -74,22 +78,48 @@ private boolean matchesNameStartsWith(String metricName) {

private boolean matchesNameDoesNotStartWith(String metricName) {
if (nameDoesNotStartWith.isEmpty()) {
return false;
return true;
}
for (String prefix : nameDoesNotStartWith) {
if (metricName.startsWith(prefix)) {
return false;
}
}
return true;
}

private boolean matchesNameEndsWith(String metricName) {
if (nameEndsWith.isEmpty()) {
return true;
}
for (String suffix : nameEndsWith) {
if (metricName.endsWith(suffix)) {
return true;
}
}
return false;
}

private boolean matchesNameDoesNotEndWith(String metricName) {
if (nameDoesNotEndWith.isEmpty()) {
return true;
}
for (String suffix : nameDoesNotEndWith) {
if (metricName.endsWith(suffix)) {
return false;
}
}
return true;
}

public static class Builder {

private final Collection<String> nameEqualTo = new ArrayList<String>();
private final Collection<String> nameNotEqualTo = new ArrayList<String>();
private final Collection<String> nameStartsWith = new ArrayList<String>();
private final Collection<String> nameDoesNotStartWith = new ArrayList<String>();
private final Collection<String> nameEndsWith = new ArrayList<String>();
private final Collection<String> nameDoesNotEndWith = new ArrayList<String>();

/**
* @see #nameMustBeEqualTo(Collection)
Expand Down Expand Up @@ -167,16 +197,54 @@ public Builder nameMustNotStartWith(Collection<String> prefixes) {
return this;
}

/**
* @see #nameMustEndWith(Collection)
*/
public Builder nameMustEndWith(String... prefixes) {
return nameMustEndWith(Arrays.asList(prefixes));
}

/**
* Only samples whose name ends with one of the {@code prefixes} will be included.
* @param prefixes empty means no restriction.
*/
public Builder nameMustEndWith(Collection<String> prefixes) {
nameEndsWith.addAll(prefixes);
return this;
}

/**
* @see #nameMustNotEndWith(Collection)
*/
public Builder nameMustNotEndWith(String... prefixes) {
return nameMustNotEndWith(Arrays.asList(prefixes));
}

/**
* Samples with names ending with one of the {@code prefixes} will be excluded.
* For example, this can be used to exclude {@code _created} metrics.
* @param prefixes empty means no time series will be excluded.
*/
public Builder nameMustNotEndWith(Collection<String> prefixes) {
nameDoesNotEndWith.addAll(prefixes);
return this;
}

public SampleNameFilter build() {
return new SampleNameFilter(nameEqualTo, nameNotEqualTo, nameStartsWith, nameDoesNotStartWith);
return new SampleNameFilter(nameEqualTo, nameNotEqualTo, nameStartsWith, nameDoesNotStartWith,
nameEndsWith, nameDoesNotEndWith);
}
}

private SampleNameFilter(Collection<String> nameIsEqualTo, Collection<String> nameIsNotEqualTo, Collection<String> nameStartsWith, Collection<String> nameDoesNotStartWith) {
private SampleNameFilter(Collection<String> nameIsEqualTo, Collection<String> nameIsNotEqualTo,
Collection<String> nameStartsWith, Collection<String> nameDoesNotStartWith,
Collection<String> nameEndsWith, Collection<String> nameDoesNotEndWith) {
this.nameIsEqualTo = unmodifiableCollection(nameIsEqualTo);
this.nameIsNotEqualTo = unmodifiableCollection(nameIsNotEqualTo);
this.nameStartsWith = unmodifiableCollection(nameStartsWith);
this.nameDoesNotStartWith = unmodifiableCollection(nameDoesNotStartWith);
this.nameEndsWith = unmodifiableCollection(nameEndsWith);
this.nameDoesNotEndWith = unmodifiableCollection(nameDoesNotEndWith);
}

private static class AllowAll implements Predicate<String> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import com.sun.net.httpserver.HttpsConfigurator;
import com.sun.net.httpserver.HttpsParameters;
import io.prometheus.client.CollectorRegistry;
import io.prometheus.client.Counter;
import io.prometheus.client.Gauge;
import io.prometheus.client.SampleNameFilter;
import org.junit.Assert;
Expand Down Expand Up @@ -191,6 +192,45 @@ public void testSampleNameFilter() throws IOException {
}
}

@Test
public void testCreatedMetricPresent() throws IOException {
Counter counter = Counter.build("my_counter", "my counter help").register(registry);
HTTPServer httpServer = new HTTPServer.Builder()
.withRegistry(registry)
.build();
try {
String body = createHttpRequestBuilder(httpServer, "/metrics")
.withHeader("Accept", "application/openmetrics-text; version=0.0.1,text/plain;version=0.0.4;q=0.5,*/*;q=0.1")
.build().execute().getBody();
assertThat(body).contains("my_counter_total 0.0");
assertThat(body).contains("my_counter_created ");
} finally {
registry.unregister(counter);
httpServer.close();
}
}

@Test
public void testCreatedMetricRemoved() throws IOException {
Counter counter = Counter.build("my_counter", "my counter help").register(registry);
HTTPServer httpServer = new HTTPServer.Builder()
.withRegistry(registry)
.withSampleNameFilter(new SampleNameFilter.Builder()
.nameMustNotEndWith("_created")
.build())
.build();
try {
String body = createHttpRequestBuilder(httpServer, "/metrics")
.withHeader("Accept", "application/openmetrics-text; version=0.0.1,text/plain;version=0.0.4;q=0.5,*/*;q=0.1")
.build().execute().getBody();
assertThat(body).contains("my_counter_total 0.0");
assertThat(body).doesNotContain("my_counter_created ");
} finally {
registry.unregister(counter);
httpServer.close();
}
}

@Test
public void testSampleNameFilterEmptyBody() throws IOException {
HTTPServer httpServer = new HTTPServer.Builder()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ public class Exporter {
public static final String NAME_MUST_NOT_BE_EQUAL_TO = "name-must-not-be-equal-to";
public static final String NAME_MUST_START_WITH = "name-must-start-with";
public static final String NAME_MUST_NOT_START_WITH = "name-must-not-start-with";
public static final String NAME_MUST_END_WITH = "name-must-end-with";
public static final String NAME_MUST_NOT_END_WITH = "name-must-not-end-with";

private CollectorRegistry registry;
private Predicate<String> sampleNameFilter;
Expand All @@ -48,12 +50,16 @@ public void init(ServletConfigAdapter servletConfig) throws ServletConfiguration
List<String> excludedNames = SampleNameFilter.stringToList(servletConfig.getInitParameter(NAME_MUST_NOT_BE_EQUAL_TO));
List<String> allowedPrefixes = SampleNameFilter.stringToList(servletConfig.getInitParameter(NAME_MUST_START_WITH));
List<String> excludedPrefixes = SampleNameFilter.stringToList(servletConfig.getInitParameter(NAME_MUST_NOT_START_WITH));
List<String> allowedSuffixes = SampleNameFilter.stringToList(servletConfig.getInitParameter(NAME_MUST_END_WITH));
List<String> excludedSuffixes = SampleNameFilter.stringToList(servletConfig.getInitParameter(NAME_MUST_NOT_END_WITH));
if (!allowedPrefixes.isEmpty() || !excludedPrefixes.isEmpty() || !allowedNames.isEmpty() || !excludedNames.isEmpty()) {
SampleNameFilter filter = new SampleNameFilter.Builder()
.nameMustBeEqualTo(allowedNames)
.nameMustNotBeEqualTo(excludedNames)
.nameMustStartWith(allowedPrefixes)
.nameMustNotStartWith(excludedPrefixes)
.nameMustEndWith(allowedSuffixes)
.nameMustNotEndWith(excludedSuffixes)
.build();
if (this.sampleNameFilter != null) {
this.sampleNameFilter = filter.and(this.sampleNameFilter);
Expand Down