Skip to content

Commit 9fcf30b

Browse files
Add MeterFilter.forMeters utility method (#6594)
* Add MeterFilter.forPrefix(..) utility method I have noticed that I often want to configure MeterFilters only for a selection of meters that start with a given prefix. For example, I might want to ignore tags for a selection of metrics, but not for all of them. The "normal" approach would be to write a custom MeterFilter that checks the name before filtering. The new utility method helps with this task. Signed-off-by: Peter Jeschke <[email protected]> * Add MeterFilter.forMeters utility method --------- Signed-off-by: Peter Jeschke <[email protected]> Co-authored-by: Jonatan Ivanov <[email protected]>
1 parent ddd021e commit 9fcf30b

File tree

3 files changed

+81
-0
lines changed

3 files changed

+81
-0
lines changed

docs/modules/ROOT/pages/concepts/meter-filters.adoc

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,3 +148,22 @@ Generally, you should create a new `DistributionStatisticConfig` with only the p
148148
* `minExpected(Duration/long)`: Governs the lower bound of percentile histogram buckets shipped from a timer or summary.
149149

150150
Spring Boot offers property-based filters for configuring SLOs, percentiles, and percentile histograms by name prefix.
151+
152+
== Apply MeterFilters conditionally
153+
154+
It is a common use-case to apply MeterFilters only for a selection of Meters (for example for ones that has a certain name or starts with a given prefix).
155+
In order to do this, Micrometer provides a convenience method `forMeters(Predicate<Meter.Id> predicate, MeterFilter delegate)` that enables the provided (delegate) filter for the Meters selected by the predicate.
156+
157+
See the following example:
158+
159+
====
160+
[source, java]
161+
----
162+
registry.config()
163+
.meterFilter(MeterFilter.forMeters(startsWith("prefix"), MeterFilter.ignoreTags("extra")));
164+
165+
Predicate<Meter.Id> startsWith(String prefix) {
166+
return id -> id.getName().startsWith(prefix);
167+
}
168+
----
169+
====

micrometer-core/src/main/java/io/micrometer/core/instrument/config/MeterFilter.java

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -412,6 +412,35 @@ public DistributionStatisticConfig configure(Meter.Id id, DistributionStatisticC
412412
};
413413
}
414414

415+
/**
416+
* Enables the provided filter for the Meters selected by the predicate.
417+
* <code>registry.config().meterFilter(MeterFilter.forMeters(id -> id.getName().startsWith("test"), MeterFilter.ignoreTags("ignored")))</code>
418+
* @param predicate Apply the provided filter only to Meters selected by this
419+
* predicate
420+
* @param delegate A filter to apply if the provided predicate returns true
421+
* @return A filter that delegates calls to the delegate filter conditionally (based
422+
* on the predicate)
423+
* @since 1.16.0
424+
*/
425+
static MeterFilter forMeters(Predicate<Meter.Id> predicate, MeterFilter delegate) {
426+
return new MeterFilter() {
427+
@Override
428+
public MeterFilterReply accept(Meter.Id id) {
429+
return predicate.test(id) ? delegate.accept(id) : MeterFilter.super.accept(id);
430+
}
431+
432+
@Override
433+
public Meter.Id map(Meter.Id id) {
434+
return predicate.test(id) ? delegate.map(id) : MeterFilter.super.map(id);
435+
}
436+
437+
@Override
438+
public @Nullable DistributionStatisticConfig configure(Meter.Id id, DistributionStatisticConfig config) {
439+
return predicate.test(id) ? delegate.configure(id, config) : MeterFilter.super.configure(id, config);
440+
}
441+
};
442+
}
443+
415444
/**
416445
* @param id Id with {@link MeterFilter#map} transformations applied.
417446
* @return After all transformations, should a real meter be registered for this id,

micrometer-core/src/test/java/io/micrometer/core/instrument/MeterFilterTest.java

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626

2727
import java.time.Duration;
2828
import java.util.concurrent.atomic.AtomicInteger;
29+
import java.util.function.Predicate;
2930

3031
import static java.util.stream.StreamSupport.stream;
3132
import static org.assertj.core.api.Assertions.assertThat;
@@ -266,4 +267,36 @@ public Meter.Id map(Meter.Id id) {
266267
assertThat(registry.getMeters()).isNotEmpty();
267268
}
268269

270+
@Test
271+
void forPrefix() {
272+
Meter.Id primary = new Meter.Id("primary.gauge", Tags.of("ignored", "true", "other", "value"), null, null,
273+
Meter.Type.GAUGE);
274+
Meter.Id secondary = new Meter.Id("secondary.gauge", Tags.of("ignored", "false"), null, null, Meter.Type.GAUGE);
275+
276+
MeterFilter denyPrimaryGauges = MeterFilter.forMeters(startsWith("primary."),
277+
MeterFilter.deny(id -> id.getType() == Meter.Type.GAUGE));
278+
assertThat(denyPrimaryGauges.accept(primary)).isEqualTo(MeterFilterReply.DENY);
279+
assertThat(denyPrimaryGauges.accept(secondary)).isEqualTo(MeterFilterReply.NEUTRAL);
280+
281+
MeterFilter ignoreTagsOnPrimaryMeters = MeterFilter.forMeters(startsWith("primary."),
282+
MeterFilter.ignoreTags("ignored"));
283+
assertThat(ignoreTagsOnPrimaryMeters.map(primary).getTags()).containsExactly(Tag.of("other", "value"));
284+
assertThat(ignoreTagsOnPrimaryMeters.map(secondary).getTags()).containsExactly(Tag.of("ignored", "false"));
285+
286+
MeterFilter configurePrimaryMeters = MeterFilter.forMeters(startsWith("primary."), new MeterFilter() {
287+
@Override
288+
public DistributionStatisticConfig configure(Meter.Id id, DistributionStatisticConfig config) {
289+
return DistributionStatisticConfig.DEFAULT;
290+
}
291+
});
292+
293+
DistributionStatisticConfig config = new DistributionStatisticConfig();
294+
assertThat(configurePrimaryMeters.configure(primary, config)).isEqualTo(DistributionStatisticConfig.DEFAULT);
295+
assertThat(configurePrimaryMeters.configure(secondary, config)).isEqualTo(config);
296+
}
297+
298+
private Predicate<Meter.Id> startsWith(String prefix) {
299+
return id -> id.getName().startsWith(prefix);
300+
}
301+
269302
}

0 commit comments

Comments
 (0)