From fe6a321187768a75d075ec9f0e56aa30cf0c5348 Mon Sep 17 00:00:00 2001 From: Sylvain Juge <763082+SylvainJuge@users.noreply.github.com> Date: Wed, 11 Mar 2026 14:55:41 +0100 Subject: [PATCH 1/4] fix include by default --- .../internal/IncludeExcludePredicate.java | 30 ++++++++++--------- .../internal/IncludeExcludePredicateTest.java | 3 +- 2 files changed, 18 insertions(+), 15 deletions(-) diff --git a/sdk/common/src/main/java/io/opentelemetry/sdk/common/internal/IncludeExcludePredicate.java b/sdk/common/src/main/java/io/opentelemetry/sdk/common/internal/IncludeExcludePredicate.java index dd6ba4e63b4..e482ddf7c7b 100644 --- a/sdk/common/src/main/java/io/opentelemetry/sdk/common/internal/IncludeExcludePredicate.java +++ b/sdk/common/src/main/java/io/opentelemetry/sdk/common/internal/IncludeExcludePredicate.java @@ -9,6 +9,7 @@ import static java.util.stream.Collectors.joining; import java.util.Collection; +import java.util.Collections; import java.util.LinkedHashSet; import java.util.Set; import java.util.StringJoiner; @@ -29,8 +30,8 @@ public final class IncludeExcludePredicate implements Predicate { private final boolean globMatchingEnabled; - @Nullable private final Set included; - @Nullable private final Set excluded; + private final Set included; + private final Set excluded; private final Predicate predicate; private IncludeExcludePredicate( @@ -38,19 +39,20 @@ private IncludeExcludePredicate( @Nullable Collection excluded, boolean globMatchingEnabled) { this.globMatchingEnabled = globMatchingEnabled; - this.included = included == null ? null : new LinkedHashSet<>(included); - this.excluded = excluded == null ? null : new LinkedHashSet<>(excluded); - if (this.included != null && this.excluded != null) { - this.predicate = - includedPredicate(this.included, globMatchingEnabled) - .and(excludedPredicate(this.excluded, globMatchingEnabled)); - } else if (this.included == null && this.excluded != null) { + this.included = included == null ? Collections.emptySet() : new LinkedHashSet<>(included); + this.excluded = excluded == null ? Collections.emptySet() : new LinkedHashSet<>(excluded); + if (this.included.isEmpty() && this.excluded.isEmpty()) { + throw new IllegalArgumentException( + "At least one of include or exclude patterns must not be null or empty"); + } + if (this.included.isEmpty()) { this.predicate = excludedPredicate(this.excluded, globMatchingEnabled); - } else if (this.excluded == null && this.included != null) { + } else if (this.excluded.isEmpty()) { this.predicate = includedPredicate(this.included, globMatchingEnabled); } else { - throw new IllegalArgumentException( - "At least one of includedPatterns or excludedPatterns must not be null"); + this.predicate = + includedPredicate(this.included, globMatchingEnabled) + .and(excludedPredicate(this.excluded, globMatchingEnabled)); } } @@ -85,10 +87,10 @@ public boolean test(String s) { public String toString() { StringJoiner joiner = new StringJoiner(", ", "IncludeExcludePredicate{", "}"); joiner.add("globMatchingEnabled=" + globMatchingEnabled); - if (included != null) { + if (!included.isEmpty()) { joiner.add("included=" + included.stream().collect(joining(", ", "[", "]"))); } - if (excluded != null) { + if (!excluded.isEmpty()) { joiner.add("excluded=" + excluded.stream().collect(joining(", ", "[", "]"))); } return joiner.toString(); diff --git a/sdk/common/src/test/java/io/opentelemetry/sdk/common/internal/IncludeExcludePredicateTest.java b/sdk/common/src/test/java/io/opentelemetry/sdk/common/internal/IncludeExcludePredicateTest.java index 2340d1009b0..5c30c279961 100644 --- a/sdk/common/src/test/java/io/opentelemetry/sdk/common/internal/IncludeExcludePredicateTest.java +++ b/sdk/common/src/test/java/io/opentelemetry/sdk/common/internal/IncludeExcludePredicateTest.java @@ -9,6 +9,7 @@ import static java.util.Collections.singletonList; import static org.assertj.core.api.Assertions.assertThat; +import java.util.Collections; import java.util.function.Predicate; import java.util.stream.Stream; import org.junit.jupiter.params.ParameterizedTest; @@ -20,7 +21,7 @@ class IncludeExcludePredicateTest { private static final Predicate EXACT_INCLUDE = IncludeExcludePredicate.createExactMatching(singletonList("foo"), null); private static final Predicate EXACT_EXCLUDE = - IncludeExcludePredicate.createExactMatching(null, singletonList("bar")); + IncludeExcludePredicate.createExactMatching(Collections.emptyList(), singletonList("bar")); private static final Predicate EXACT_INCLUDE_AND_EXCLUDE = IncludeExcludePredicate.createExactMatching(singletonList("foo"), singletonList("bar")); private static final Predicate EXACT_MULTI = From 3e46fe5b58a9993ef860e9b623659b2bb1a20e2f Mon Sep 17 00:00:00 2001 From: Sylvain Juge <763082+SylvainJuge@users.noreply.github.com> Date: Wed, 11 Mar 2026 16:29:40 +0100 Subject: [PATCH 2/4] revert + alternative approach --- .../ComposableRuleBasedSamplerFactory.java | 7 ++++- .../incubator/fileconfig/ResourceFactory.java | 5 ++++ .../fileconfig/ResourceFactoryTest.java | 7 ++++- .../internal/IncludeExcludePredicate.java | 30 +++++++++---------- .../internal/IncludeExcludePredicateTest.java | 12 ++++++-- 5 files changed, 41 insertions(+), 20 deletions(-) diff --git a/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ComposableRuleBasedSamplerFactory.java b/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ComposableRuleBasedSamplerFactory.java index aea589ede38..bcef6a8faf4 100644 --- a/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ComposableRuleBasedSamplerFactory.java +++ b/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ComposableRuleBasedSamplerFactory.java @@ -98,10 +98,15 @@ private static AttributeMatcher attributePatternsMatcher( if (attributePatternsModel == null) { return null; } + List included = attributePatternsModel.getIncluded(); + if (included != null && included.isEmpty()) { + // empty included should be treated as include everything by default. + included = null; + } return new AttributeMatcher( requireNonNull(attributePatternsModel.getKey(), "attribute_patterns key"), IncludeExcludePredicate.createPatternMatching( - attributePatternsModel.getIncluded(), attributePatternsModel.getExcluded())); + included, attributePatternsModel.getExcluded())); } // Visible for testing diff --git a/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ResourceFactory.java b/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ResourceFactory.java index e43de54a34c..3f849c836af 100644 --- a/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ResourceFactory.java +++ b/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ResourceFactory.java @@ -93,6 +93,11 @@ private static Predicate detectorAttributeFilter( if (included == null && excluded == null) { return ResourceFactory::matchAll; } + // when "included" is omitted in configuration, we get an empty list + // in this context it should be interpreted as "include everything" + if (included != null && included.isEmpty()) { + included = null; + } return IncludeExcludePredicate.createPatternMatching(included, excluded); } } diff --git a/sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ResourceFactoryTest.java b/sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ResourceFactoryTest.java index a426e8bb9d0..904f79e3032 100644 --- a/sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ResourceFactoryTest.java +++ b/sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ResourceFactoryTest.java @@ -141,7 +141,12 @@ private static Stream createWithDetectorsArgs() { Arguments.of( Collections.singletonList("*o*"), Collections.singletonList("order"), - Resource.getDefault().toBuilder().put("color", "red").build())); + Resource.getDefault().toBuilder().put("color", "red").build()), + // empty include should be treated as include all + Arguments.of( + Collections.emptyList(), + Collections.singletonList("order"), + Resource.getDefault().toBuilder().put("color", "red").put("shape", "square").build())); } @ParameterizedTest diff --git a/sdk/common/src/main/java/io/opentelemetry/sdk/common/internal/IncludeExcludePredicate.java b/sdk/common/src/main/java/io/opentelemetry/sdk/common/internal/IncludeExcludePredicate.java index e482ddf7c7b..dd6ba4e63b4 100644 --- a/sdk/common/src/main/java/io/opentelemetry/sdk/common/internal/IncludeExcludePredicate.java +++ b/sdk/common/src/main/java/io/opentelemetry/sdk/common/internal/IncludeExcludePredicate.java @@ -9,7 +9,6 @@ import static java.util.stream.Collectors.joining; import java.util.Collection; -import java.util.Collections; import java.util.LinkedHashSet; import java.util.Set; import java.util.StringJoiner; @@ -30,8 +29,8 @@ public final class IncludeExcludePredicate implements Predicate { private final boolean globMatchingEnabled; - private final Set included; - private final Set excluded; + @Nullable private final Set included; + @Nullable private final Set excluded; private final Predicate predicate; private IncludeExcludePredicate( @@ -39,20 +38,19 @@ private IncludeExcludePredicate( @Nullable Collection excluded, boolean globMatchingEnabled) { this.globMatchingEnabled = globMatchingEnabled; - this.included = included == null ? Collections.emptySet() : new LinkedHashSet<>(included); - this.excluded = excluded == null ? Collections.emptySet() : new LinkedHashSet<>(excluded); - if (this.included.isEmpty() && this.excluded.isEmpty()) { - throw new IllegalArgumentException( - "At least one of include or exclude patterns must not be null or empty"); - } - if (this.included.isEmpty()) { - this.predicate = excludedPredicate(this.excluded, globMatchingEnabled); - } else if (this.excluded.isEmpty()) { - this.predicate = includedPredicate(this.included, globMatchingEnabled); - } else { + this.included = included == null ? null : new LinkedHashSet<>(included); + this.excluded = excluded == null ? null : new LinkedHashSet<>(excluded); + if (this.included != null && this.excluded != null) { this.predicate = includedPredicate(this.included, globMatchingEnabled) .and(excludedPredicate(this.excluded, globMatchingEnabled)); + } else if (this.included == null && this.excluded != null) { + this.predicate = excludedPredicate(this.excluded, globMatchingEnabled); + } else if (this.excluded == null && this.included != null) { + this.predicate = includedPredicate(this.included, globMatchingEnabled); + } else { + throw new IllegalArgumentException( + "At least one of includedPatterns or excludedPatterns must not be null"); } } @@ -87,10 +85,10 @@ public boolean test(String s) { public String toString() { StringJoiner joiner = new StringJoiner(", ", "IncludeExcludePredicate{", "}"); joiner.add("globMatchingEnabled=" + globMatchingEnabled); - if (!included.isEmpty()) { + if (included != null) { joiner.add("included=" + included.stream().collect(joining(", ", "[", "]"))); } - if (!excluded.isEmpty()) { + if (excluded != null) { joiner.add("excluded=" + excluded.stream().collect(joining(", ", "[", "]"))); } return joiner.toString(); diff --git a/sdk/common/src/test/java/io/opentelemetry/sdk/common/internal/IncludeExcludePredicateTest.java b/sdk/common/src/test/java/io/opentelemetry/sdk/common/internal/IncludeExcludePredicateTest.java index 5c30c279961..55b2c02472f 100644 --- a/sdk/common/src/test/java/io/opentelemetry/sdk/common/internal/IncludeExcludePredicateTest.java +++ b/sdk/common/src/test/java/io/opentelemetry/sdk/common/internal/IncludeExcludePredicateTest.java @@ -21,11 +21,13 @@ class IncludeExcludePredicateTest { private static final Predicate EXACT_INCLUDE = IncludeExcludePredicate.createExactMatching(singletonList("foo"), null); private static final Predicate EXACT_EXCLUDE = - IncludeExcludePredicate.createExactMatching(Collections.emptyList(), singletonList("bar")); + IncludeExcludePredicate.createExactMatching(null, singletonList("bar")); private static final Predicate EXACT_INCLUDE_AND_EXCLUDE = IncludeExcludePredicate.createExactMatching(singletonList("foo"), singletonList("bar")); private static final Predicate EXACT_MULTI = IncludeExcludePredicate.createExactMatching(asList("foo", "fooo"), asList("bar", "barr")); + public static final Predicate EXACT_INCLUDE_NONE = + IncludeExcludePredicate.createExactMatching(Collections.emptyList(), null); private static final Predicate PATTERN_INCLUDE = IncludeExcludePredicate.createPatternMatching(singletonList("f?o"), null); @@ -35,6 +37,8 @@ class IncludeExcludePredicateTest { IncludeExcludePredicate.createPatternMatching(singletonList("f?o"), singletonList("b?r")); private static final Predicate PATTERN_MULTI = IncludeExcludePredicate.createPatternMatching(asList("f?o", "f?oo"), asList("b?r", "b?rr")); + public static final Predicate PATTERN_INCLUDE_NONE = + IncludeExcludePredicate.createPatternMatching(Collections.emptyList(), null); @ParameterizedTest @MethodSource("testArgs") @@ -71,6 +75,8 @@ private static Stream testArgs() { Arguments.of(EXACT_MULTI, "bar", false), Arguments.of(EXACT_MULTI, "barr", false), Arguments.of(EXACT_MULTI, "baz", false), + // include none + Arguments.of(EXACT_INCLUDE_NONE, "foo", false), // pattern matching // include only Arguments.of(PATTERN_INCLUDE, "foo", true), @@ -100,7 +106,9 @@ private static Stream testArgs() { Arguments.of(PATTERN_MULTI, "bAr", false), Arguments.of(PATTERN_MULTI, "barr", false), Arguments.of(PATTERN_MULTI, "bArr", false), - Arguments.of(PATTERN_MULTI, "baz", false)); + Arguments.of(PATTERN_MULTI, "baz", false), + // include none + Arguments.of(PATTERN_INCLUDE_NONE, "foo", false)); } @ParameterizedTest From acbfb46fdae87a246765d95db6242500e77ddea6 Mon Sep 17 00:00:00 2001 From: Sylvain Juge <763082+SylvainJuge@users.noreply.github.com> Date: Wed, 11 Mar 2026 16:47:22 +0100 Subject: [PATCH 3/4] try to get a bit more coverage --- .../extension/incubator/fileconfig/ResourceFactoryTest.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ResourceFactoryTest.java b/sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ResourceFactoryTest.java index 904f79e3032..942b5cbf006 100644 --- a/sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ResourceFactoryTest.java +++ b/sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ResourceFactoryTest.java @@ -142,10 +142,14 @@ private static Stream createWithDetectorsArgs() { Collections.singletonList("*o*"), Collections.singletonList("order"), Resource.getDefault().toBuilder().put("color", "red").build()), - // empty include should be treated as include all + // empty or missing include should be treated as include all Arguments.of( Collections.emptyList(), Collections.singletonList("order"), + Resource.getDefault().toBuilder().put("color", "red").put("shape", "square").build()), + Arguments.of( + null, + Collections.singletonList("order"), Resource.getDefault().toBuilder().put("color", "red").put("shape", "square").build())); } From 4972a83d462a81cbc360da2ef1cc4108c8ac76fd Mon Sep 17 00:00:00 2001 From: Sylvain Juge <763082+SylvainJuge@users.noreply.github.com> Date: Wed, 11 Mar 2026 16:48:25 +0100 Subject: [PATCH 4/4] remove useless change --- .../fileconfig/ComposableRuleBasedSamplerFactory.java | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ComposableRuleBasedSamplerFactory.java b/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ComposableRuleBasedSamplerFactory.java index bcef6a8faf4..aea589ede38 100644 --- a/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ComposableRuleBasedSamplerFactory.java +++ b/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ComposableRuleBasedSamplerFactory.java @@ -98,15 +98,10 @@ private static AttributeMatcher attributePatternsMatcher( if (attributePatternsModel == null) { return null; } - List included = attributePatternsModel.getIncluded(); - if (included != null && included.isEmpty()) { - // empty included should be treated as include everything by default. - included = null; - } return new AttributeMatcher( requireNonNull(attributePatternsModel.getKey(), "attribute_patterns key"), IncludeExcludePredicate.createPatternMatching( - included, attributePatternsModel.getExcluded())); + attributePatternsModel.getIncluded(), attributePatternsModel.getExcluded())); } // Visible for testing