From 14cc5b03a6df0997c60d02f4c3d4a099cf8e32d6 Mon Sep 17 00:00:00 2001 From: etki Date: Sat, 26 Apr 2025 10:37:08 +0200 Subject: [PATCH 1/2] Introduced FilterSupport for internal MeterFilter implementations Signed-off-by: etki --- .../config/filter/FilterSupport.java | 31 ++++++++++++++++ .../instrument/config/filter/NoOpFilter.java | 37 +++++++++++++++++++ .../config/filter/package-info.java | 16 ++++++++ .../{ => config}/MeterFilterTest.java | 7 ++-- 4 files changed, 88 insertions(+), 3 deletions(-) create mode 100644 micrometer-core/src/main/java/io/micrometer/core/instrument/config/filter/FilterSupport.java create mode 100644 micrometer-core/src/main/java/io/micrometer/core/instrument/config/filter/NoOpFilter.java create mode 100644 micrometer-core/src/main/java/io/micrometer/core/instrument/config/filter/package-info.java rename micrometer-core/src/test/java/io/micrometer/core/instrument/{ => config}/MeterFilterTest.java (98%) diff --git a/micrometer-core/src/main/java/io/micrometer/core/instrument/config/filter/FilterSupport.java b/micrometer-core/src/main/java/io/micrometer/core/instrument/config/filter/FilterSupport.java new file mode 100644 index 0000000000..43b5dd7ac4 --- /dev/null +++ b/micrometer-core/src/main/java/io/micrometer/core/instrument/config/filter/FilterSupport.java @@ -0,0 +1,31 @@ +/* + * Copyright 2025 VMware, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.micrometer.core.instrument.config.filter; + +class FilterSupport { + + /** + * At the moment of writing, it was impossible to estimate tags count from the outside + * of class, but quite often a temporary storage (ArrayList) had to be allocated + * during processing. To avoid excessive resizes, this constant is introduced to + * preallocate space for such a list. + */ + public static final int DEFAULT_TAG_COUNT_EXPECTATION = 32; + + private FilterSupport() { + } + +} diff --git a/micrometer-core/src/main/java/io/micrometer/core/instrument/config/filter/NoOpFilter.java b/micrometer-core/src/main/java/io/micrometer/core/instrument/config/filter/NoOpFilter.java new file mode 100644 index 0000000000..8fb045f602 --- /dev/null +++ b/micrometer-core/src/main/java/io/micrometer/core/instrument/config/filter/NoOpFilter.java @@ -0,0 +1,37 @@ +/* + * Copyright 2025 VMware, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.micrometer.core.instrument.config.filter; + +import io.micrometer.core.instrument.config.MeterFilter; + +/** + * A fallback for all factory methods that have received an input functionally equivalent + * to "abstain from processing". + * + * @since 1.15 + */ +public class NoOpFilter implements MeterFilter { + + private static final MeterFilter INSTANCE = new NoOpFilter(); + + private NoOpFilter() { + } + + public static MeterFilter create() { + return INSTANCE; + } + +} diff --git a/micrometer-core/src/main/java/io/micrometer/core/instrument/config/filter/package-info.java b/micrometer-core/src/main/java/io/micrometer/core/instrument/config/filter/package-info.java new file mode 100644 index 0000000000..c71f075c3e --- /dev/null +++ b/micrometer-core/src/main/java/io/micrometer/core/instrument/config/filter/package-info.java @@ -0,0 +1,16 @@ +/* + * Copyright 2025 VMware, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.micrometer.core.instrument.config.filter; diff --git a/micrometer-core/src/test/java/io/micrometer/core/instrument/MeterFilterTest.java b/micrometer-core/src/test/java/io/micrometer/core/instrument/config/MeterFilterTest.java similarity index 98% rename from micrometer-core/src/test/java/io/micrometer/core/instrument/MeterFilterTest.java rename to micrometer-core/src/test/java/io/micrometer/core/instrument/config/MeterFilterTest.java index a3041e0c04..eed870e736 100644 --- a/micrometer-core/src/test/java/io/micrometer/core/instrument/MeterFilterTest.java +++ b/micrometer-core/src/test/java/io/micrometer/core/instrument/config/MeterFilterTest.java @@ -13,12 +13,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package io.micrometer.core.instrument; +package io.micrometer.core.instrument.config; import io.micrometer.common.lang.Nullable; import io.micrometer.core.Issue; -import io.micrometer.core.instrument.config.MeterFilter; -import io.micrometer.core.instrument.config.MeterFilterReply; +import io.micrometer.core.instrument.Meter; +import io.micrometer.core.instrument.MeterRegistry; +import io.micrometer.core.instrument.Tags; import io.micrometer.core.instrument.distribution.DistributionStatisticConfig; import io.micrometer.core.instrument.simple.SimpleMeterRegistry; import org.assertj.core.api.Condition; From faa66e5e350c329bd160a7530d499c6aa0d01d32 Mon Sep 17 00:00:00 2001 From: etki Date: Sun, 27 Apr 2025 06:52:58 +0200 Subject: [PATCH 2/2] Add Meter dropping filters for MeterFilter#ignoreTags Signed-off-by: etki --- .../core/instrument/config/MeterFilter.java | 40 +++--- .../filter/OneTwoTagsDroppingFilter.java | 120 ++++++++++++++++++ .../filter/SetBackedTagDroppingFilter.java | 108 ++++++++++++++++ .../filter/DroppingFilterTestSupport.java | 59 +++++++++ .../filter/OneTwoTagsDroppingFilterTest.java | 61 +++++++++ .../SetBackedTagDroppingFilterTest.java | 45 +++++++ 6 files changed, 416 insertions(+), 17 deletions(-) create mode 100644 micrometer-core/src/main/java/io/micrometer/core/instrument/config/filter/OneTwoTagsDroppingFilter.java create mode 100644 micrometer-core/src/main/java/io/micrometer/core/instrument/config/filter/SetBackedTagDroppingFilter.java create mode 100644 micrometer-core/src/test/java/io/micrometer/core/instrument/config/filter/DroppingFilterTestSupport.java create mode 100644 micrometer-core/src/test/java/io/micrometer/core/instrument/config/filter/OneTwoTagsDroppingFilterTest.java create mode 100644 micrometer-core/src/test/java/io/micrometer/core/instrument/config/filter/SetBackedTagDroppingFilterTest.java diff --git a/micrometer-core/src/main/java/io/micrometer/core/instrument/config/MeterFilter.java b/micrometer-core/src/main/java/io/micrometer/core/instrument/config/MeterFilter.java index adc0251f7d..c60ba350d0 100644 --- a/micrometer-core/src/main/java/io/micrometer/core/instrument/config/MeterFilter.java +++ b/micrometer-core/src/main/java/io/micrometer/core/instrument/config/MeterFilter.java @@ -17,12 +17,14 @@ import io.micrometer.common.lang.Nullable; import io.micrometer.core.instrument.*; +import io.micrometer.core.instrument.Timer; +import io.micrometer.core.instrument.config.filter.NoOpFilter; +import io.micrometer.core.instrument.config.filter.OneTwoTagsDroppingFilter; +import io.micrometer.core.instrument.config.filter.SetBackedTagDroppingFilter; import io.micrometer.core.instrument.distribution.DistributionStatisticConfig; import java.time.Duration; -import java.util.ArrayList; -import java.util.List; -import java.util.Set; +import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.util.function.Function; import java.util.function.Predicate; @@ -93,21 +95,25 @@ public Meter.Id map(Meter.Id id) { * @param tagKeys Keys of tags that should be suppressed. * @return A tag-suppressing filter. */ - static MeterFilter ignoreTags(String... tagKeys) { - return new MeterFilter() { - @Override - public Meter.Id map(Meter.Id id) { - List tags = stream(id.getTagsAsIterable().spliterator(), false).filter(t -> { - for (String tagKey : tagKeys) { - if (t.getKey().equals(tagKey)) - return false; - } - return true; - }).collect(toList()); + static MeterFilter ignoreTags(Collection tagKeys) { + switch (tagKeys.size()) { + case 0: + return NoOpFilter.create(); + case 1: + case 2: + return OneTwoTagsDroppingFilter.of(tagKeys); + default: + return SetBackedTagDroppingFilter.of(tagKeys); + } + } - return id.replaceTags(tags); - } - }; + /** + * Suppress tags with given tag keys. + * @param tagKeys Keys of tags that should be suppressed. + * @return A tag-suppressing filter. + */ + static MeterFilter ignoreTags(String... tagKeys) { + return ignoreTags(Arrays.asList(tagKeys)); } /** diff --git a/micrometer-core/src/main/java/io/micrometer/core/instrument/config/filter/OneTwoTagsDroppingFilter.java b/micrometer-core/src/main/java/io/micrometer/core/instrument/config/filter/OneTwoTagsDroppingFilter.java new file mode 100644 index 0000000000..9acdc48255 --- /dev/null +++ b/micrometer-core/src/main/java/io/micrometer/core/instrument/config/filter/OneTwoTagsDroppingFilter.java @@ -0,0 +1,120 @@ +/* + * Copyright 2025 VMware, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.micrometer.core.instrument.config.filter; + +import io.micrometer.common.lang.NonNull; +import io.micrometer.common.lang.Nullable; +import io.micrometer.core.instrument.Meter; +import io.micrometer.core.instrument.Tag; +import io.micrometer.core.instrument.config.MeterFilter; + +import java.util.*; + +/** + * Processes identifiers by dropping the tags with the matching keys. Separated from + * {@link SetBackedTagDroppingFilter} for performance reasons: in a frequent case end user + * needs to drop only one or two tags, it's much cheaper to abstain from more expensive + * lookups. + * + * @see SetBackedTagDroppingFilter for input with larger cardinality. + * @see NoOpFilter for input with the lowest cardinality. + * @since 1.15 + */ +public class OneTwoTagsDroppingFilter implements MeterFilter { + + @NonNull + private final String first; + + @Nullable + private final String second; + + private final int expectedSize; + + OneTwoTagsDroppingFilter(@NonNull String first, @Nullable String second, int expectedSize) { + this.first = first; + this.second = second; + this.expectedSize = expectedSize; + } + + @NonNull + @Override + public Meter.Id map(Meter.Id id) { + Iterator iterator = id.getTagsAsIterable().iterator(); + + if (!iterator.hasNext()) { + // fast path avoiding list allocation completely + return id; + } + + List replacement = new ArrayList<>(expectedSize); + int removals = 0; + + while (iterator.hasNext()) { + Tag tag = iterator.next(); + String key = tag.getKey(); + + if (removals != 2 && (key.equals(first) || key.equals(second))) { + removals++; + continue; + } + + replacement.add(tag); + } + + return removals == 0 ? id : id.replaceTags(replacement); + } + + public static MeterFilter of(@NonNull String first, @Nullable String second, int expectedSize) { + return new OneTwoTagsDroppingFilter(first, second, expectedSize); + } + + public static MeterFilter of(@NonNull String first, @Nullable String second) { + return of(first, second, FilterSupport.DEFAULT_TAG_COUNT_EXPECTATION); + } + + public static MeterFilter of(@NonNull String first, int expectedSize) { + return of(first, null, expectedSize); + } + + public static MeterFilter of(@NonNull String first) { + return of(first, null); + } + + public static MeterFilter of(@NonNull Collection keys, int expectedSize) { + if (keys.size() != 1 && keys.size() != 2) { + throw new IllegalArgumentException("Expected collection with exactly one or two elements, got " + keys); + } + + Iterator iterator = keys.iterator(); + String first = iterator.next(); + String second = iterator.hasNext() ? iterator.next() : null; + + return of(first, second, expectedSize); + } + + public static MeterFilter of(@NonNull Collection keys) { + return of(keys, FilterSupport.DEFAULT_TAG_COUNT_EXPECTATION); + } + + public static MeterFilter of(@NonNull String[] keys, int expectedSize) { + return of(Arrays.asList(keys), expectedSize); + } + + public static MeterFilter of(@NonNull String... keys) { + return of(keys, FilterSupport.DEFAULT_TAG_COUNT_EXPECTATION); + } + +} diff --git a/micrometer-core/src/main/java/io/micrometer/core/instrument/config/filter/SetBackedTagDroppingFilter.java b/micrometer-core/src/main/java/io/micrometer/core/instrument/config/filter/SetBackedTagDroppingFilter.java new file mode 100644 index 0000000000..97aaebb6ba --- /dev/null +++ b/micrometer-core/src/main/java/io/micrometer/core/instrument/config/filter/SetBackedTagDroppingFilter.java @@ -0,0 +1,108 @@ +/* + * Copyright 2025 VMware, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.micrometer.core.instrument.config.filter; + +import io.micrometer.common.lang.NonNull; +import io.micrometer.core.instrument.Meter; +import io.micrometer.core.instrument.Tag; +import io.micrometer.core.instrument.Tags; +import io.micrometer.core.instrument.config.MeterFilter; + +import java.util.*; + +/** + * Processes identifiers by dropping the tags with the matching keys. + * + * @see OneTwoTagsDroppingFilter for input with lower cardinality. + * @see NoOpFilter for input with the lowest cardinality. + * @since 1.15 + */ +public class SetBackedTagDroppingFilter implements MeterFilter { + + private final Set keys; + + private final int expectedSize; + + SetBackedTagDroppingFilter(@NonNull Set keys, int expectedSize) { + this.keys = keys; + this.expectedSize = expectedSize; + } + + @Override + public Meter.Id map(Meter.Id id) { + Iterator iterator = id.getTagsAsIterable().iterator(); + + if (!iterator.hasNext()) { + // fast path avoiding list allocation completely + return id; + } + + List replacement = new ArrayList<>(expectedSize); + boolean intercepted = false; + + while (iterator.hasNext()) { + Tag tag = iterator.next(); + + if (keys.contains(tag.getKey())) { + intercepted = true; + continue; + } + + replacement.add(tag); + } + + if (!intercepted) { + // Nothing has changed? Return as is and let GC do the easy + // job of marking zero references array list as trash. + return id; + } + + if (replacement.isEmpty()) { + // At the moment of writing replaceTags(List) would invoke + // a bit heavier path, so it's better to provide empty tags + // directly + return id.replaceTags(Tags.empty()); + } + + return id.replaceTags(replacement); + } + + public static MeterFilter of(@NonNull Set keys, int expectedSize) { + return new SetBackedTagDroppingFilter(keys, expectedSize); + } + + public static MeterFilter of(@NonNull Set keys) { + return of(keys, FilterSupport.DEFAULT_TAG_COUNT_EXPECTATION); + } + + public static MeterFilter of(@NonNull Collection keys, int expectedSize) { + Set converted = keys instanceof Set ? (Set) keys : new HashSet<>(keys); + return of(converted, expectedSize); + } + + public static MeterFilter of(@NonNull Collection keys) { + return of(keys, FilterSupport.DEFAULT_TAG_COUNT_EXPECTATION); + } + + public static MeterFilter of(@NonNull String[] keys, int expectedSize) { + return of(Arrays.asList(keys), expectedSize); + } + + public static MeterFilter of(@NonNull String... keys) { + return of(keys, FilterSupport.DEFAULT_TAG_COUNT_EXPECTATION); + } + +} diff --git a/micrometer-core/src/test/java/io/micrometer/core/instrument/config/filter/DroppingFilterTestSupport.java b/micrometer-core/src/test/java/io/micrometer/core/instrument/config/filter/DroppingFilterTestSupport.java new file mode 100644 index 0000000000..752acaef6e --- /dev/null +++ b/micrometer-core/src/test/java/io/micrometer/core/instrument/config/filter/DroppingFilterTestSupport.java @@ -0,0 +1,59 @@ +/* + * Copyright 2025 VMware, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.micrometer.core.instrument.config.filter; + +import io.micrometer.core.instrument.Tag; +import org.junit.jupiter.params.provider.Arguments; + +import java.util.stream.Stream; + +public class DroppingFilterTestSupport { + + public static Stream variations() { + return Stream.of( + // Identifier tags : forbidden keys : expected result + // Using 0..3 samples to be sure that all implementations are invoked + // Boring no-op + Arguments.of(new Tag[] {}, new String[] {}, new Tag[] {}), + Arguments.of(new Tag[] {}, new String[] { "k1" }, new Tag[] {}), + Arguments.of(new Tag[] {}, new String[] { "k1", "k2" }, new Tag[] {}), + Arguments.of(new Tag[] {}, new String[] { "k1", "k2", "k3" }, new Tag[] {}), + Arguments.of(new Tag[] { Tag.of("k4", "v4") }, new String[] { "k1", "k2", "k3" }, + new Tag[] { Tag.of("k4", "v4") }), + Arguments.of(new Tag[] { Tag.of("k4", "v4") }, new String[] {}, new Tag[] { Tag.of("k4", "v4") }), + Arguments.of(new Tag[] { Tag.of("k4", "v4"), Tag.of("k5", "v5") }, new String[] { "k1", "k2", "k3" }, + new Tag[] { Tag.of("k4", "v4"), Tag.of("k5", "v5") }), + Arguments.of(new Tag[] { Tag.of("k4", "v4"), Tag.of("k5", "v5"), Tag.of("k6", "v6") }, + new String[] { "k1", "k2", "k3" }, + new Tag[] { Tag.of("k4", "v4"), Tag.of("k5", "v5"), Tag.of("k6", "v6") }), + // Finally, let's start actually dropping stuff + Arguments.of(new Tag[] { Tag.of("k4", "v4"), Tag.of("k5", "v5"), Tag.of("k6", "v6") }, + new String[] { "k5" }, new Tag[] { Tag.of("k4", "v4"), Tag.of("k6", "v6") }), + Arguments.of(new Tag[] { Tag.of("k4", "v4"), Tag.of("k5", "v5"), Tag.of("k6", "v6") }, + new String[] { "k1", "k5" }, new Tag[] { Tag.of("k4", "v4"), Tag.of("k6", "v6") }), + Arguments.of(new Tag[] { Tag.of("k4", "v4"), Tag.of("k5", "v5"), Tag.of("k6", "v6") }, + new String[] { "k1", "k5", "k3" }, new Tag[] { Tag.of("k4", "v4"), Tag.of("k6", "v6") }), + Arguments.of(new Tag[] { Tag.of("k4", "v4"), Tag.of("k5", "v5"), Tag.of("k6", "v6") }, + new String[] { "k4", "k5" }, new Tag[] { Tag.of("k6", "v6") }), + Arguments.of(new Tag[] { Tag.of("k4", "v4"), Tag.of("k5", "v5"), Tag.of("k6", "v6") }, + new String[] { "k4", "k5", "k6" }, new Tag[] {}), + Arguments.of(new Tag[] { Tag.of("k4", "v4"), Tag.of("k5", "v5") }, new String[] { "k4", "k5" }, + new Tag[] {}), + Arguments.of(new Tag[] { Tag.of("k4", "v4"), Tag.of("k5", "v5") }, new String[] { "k4" }, + new Tag[] { Tag.of("k5", "v5") })); + } + +} diff --git a/micrometer-core/src/test/java/io/micrometer/core/instrument/config/filter/OneTwoTagsDroppingFilterTest.java b/micrometer-core/src/test/java/io/micrometer/core/instrument/config/filter/OneTwoTagsDroppingFilterTest.java new file mode 100644 index 0000000000..612deeabe5 --- /dev/null +++ b/micrometer-core/src/test/java/io/micrometer/core/instrument/config/filter/OneTwoTagsDroppingFilterTest.java @@ -0,0 +1,61 @@ +/* + * Copyright 2025 VMware, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.micrometer.core.instrument.config.filter; + +import io.micrometer.core.instrument.Meter; +import io.micrometer.core.instrument.Tag; +import io.micrometer.core.instrument.Tags; +import io.micrometer.core.instrument.config.MeterFilter; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +import java.util.Arrays; +import java.util.stream.Stream; + +import static org.assertj.core.api.Assertions.assertThat; + +class OneTwoTagsDroppingFilterTest { + + static Stream variations() { + return DroppingFilterTestSupport.variations().filter(candidate -> { + int keys = ((String[]) candidate.get()[1]).length; + return keys == 1 || keys == 2; + }); + } + + private static MeterFilter create(String... keys) { + switch (keys.length) { + case 1: + return OneTwoTagsDroppingFilter.of(keys[0]); + case 2: + return OneTwoTagsDroppingFilter.of(keys[0], keys[1]); + default: + throw new IllegalArgumentException( + "Invalid amount of keys specified (1 or 2 expected): " + Arrays.toString(keys)); + } + } + + @ParameterizedTest + @MethodSource("variations") + void variation(Tag[] existing, String[] keys, Tag[] expectation) { + Meter.Id identifier = new Meter.Id("any", Tags.of(existing), null, null, Meter.Type.COUNTER); + MeterFilter sut = create(keys); + + assertThat(sut.map(identifier).getTags()).containsExactly(expectation); + } + +} diff --git a/micrometer-core/src/test/java/io/micrometer/core/instrument/config/filter/SetBackedTagDroppingFilterTest.java b/micrometer-core/src/test/java/io/micrometer/core/instrument/config/filter/SetBackedTagDroppingFilterTest.java new file mode 100644 index 0000000000..4ac8f99aa2 --- /dev/null +++ b/micrometer-core/src/test/java/io/micrometer/core/instrument/config/filter/SetBackedTagDroppingFilterTest.java @@ -0,0 +1,45 @@ +/* + * Copyright 2025 VMware, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.micrometer.core.instrument.config.filter; + +import io.micrometer.core.instrument.Meter; +import io.micrometer.core.instrument.Tag; +import io.micrometer.core.instrument.Tags; +import io.micrometer.core.instrument.config.MeterFilter; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +import java.util.stream.Stream; + +import static org.assertj.core.api.Assertions.assertThat; + +class SetBackedTagDroppingFilterTest { + + static Stream variations() { + return DroppingFilterTestSupport.variations(); + } + + @ParameterizedTest + @MethodSource("variations") + void variation(Tag[] existing, String[] keys, Tag[] expectation) { + Meter.Id identifier = new Meter.Id("any", Tags.of(existing), null, null, Meter.Type.COUNTER); + MeterFilter sut = SetBackedTagDroppingFilter.of(keys); + + assertThat(sut.map(identifier).getTags()).containsExactly(expectation); + } + +}