Skip to content

Commit ec002c3

Browse files
make include/exclude easier to use with empty but not null arguments (#8185)
Co-authored-by: Jack Berg <34418638+jack-berg@users.noreply.github.com>
1 parent 7839170 commit ec002c3

6 files changed

Lines changed: 61 additions & 34 deletions

File tree

sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ResourceFactory.java

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -90,16 +90,7 @@ private static Predicate<String> detectorAttributeFilter(
9090
if (includedExcludeModel == null) {
9191
return ResourceFactory::matchAll;
9292
}
93-
List<String> included = includedExcludeModel.getIncluded();
94-
List<String> excluded = includedExcludeModel.getExcluded();
95-
if (included == null && excluded == null) {
96-
return ResourceFactory::matchAll;
97-
}
98-
// when "included" is omitted in configuration, we get an empty list
99-
// in this context it should be interpreted as "include everything"
100-
if (included != null && included.isEmpty()) {
101-
included = null;
102-
}
103-
return IncludeExcludePredicate.createPatternMatching(included, excluded);
93+
return IncludeExcludePredicate.createPatternMatching(
94+
includedExcludeModel.getIncluded(), includedExcludeModel.getExcluded());
10495
}
10596
}

sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ViewFactory.java

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,7 @@ public View create(ViewStreamModel model, DeclarativeConfigContext context) {
3535
if (attributeKeys != null) {
3636
List<String> included = attributeKeys.getIncluded();
3737
List<String> excluded = attributeKeys.getExcluded();
38-
if (included != null || excluded != null) {
39-
builder.setAttributeFilter(IncludeExcludePredicate.createExactMatching(included, excluded));
40-
}
38+
builder.setAttributeFilter(IncludeExcludePredicate.createExactMatching(included, excluded));
4139
}
4240
if (model.getAggregation() != null) {
4341
builder.setAggregation(

sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ComposableRuleBasedSamplerFactoryTest.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ private static Stream<Arguments> createTestCases() {
162162
private static final AttributeKey<String> HTTP_PATH = AttributeKey.stringKey("http.path");
163163

164164
@ParameterizedTest
165-
@MethodSource("declarativeCOnfigSamplingPredicateArgs")
165+
@MethodSource("declarativeConfigSamplingPredicateArgs")
166166
void declarativeConfigSamplingPredicate(
167167
DeclarativeConfigSamplingPredicate predicate,
168168
Context context,
@@ -174,7 +174,7 @@ void declarativeConfigSamplingPredicate(
174174
}
175175

176176
@SuppressWarnings("unused")
177-
private static Stream<Arguments> declarativeCOnfigSamplingPredicateArgs() {
177+
private static Stream<Arguments> declarativeConfigSamplingPredicateArgs() {
178178
DeclarativeConfigSamplingPredicate matchAll =
179179
new DeclarativeConfigSamplingPredicate(null, null, null, null);
180180
DeclarativeConfigSamplingPredicate valuesMatcher =

sdk/common/src/main/java/io/opentelemetry/sdk/common/internal/IncludeExcludePredicate.java

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -38,26 +38,28 @@ private IncludeExcludePredicate(
3838
@Nullable Collection<String> excluded,
3939
boolean globMatchingEnabled) {
4040
this.globMatchingEnabled = globMatchingEnabled;
41-
this.included = included == null ? null : new LinkedHashSet<>(included);
42-
this.excluded = excluded == null ? null : new LinkedHashSet<>(excluded);
41+
this.included = copyIfNotEmpty(included);
42+
this.excluded = copyIfNotEmpty(excluded);
4343
if (this.included != null && this.excluded != null) {
4444
this.predicate =
4545
includedPredicate(this.included, globMatchingEnabled)
4646
.and(excludedPredicate(this.excluded, globMatchingEnabled));
47-
} else if (this.included == null && this.excluded != null) {
47+
} else if (this.excluded != null) {
4848
this.predicate = excludedPredicate(this.excluded, globMatchingEnabled);
49-
} else if (this.excluded == null && this.included != null) {
49+
} else if (this.included != null) {
5050
this.predicate = includedPredicate(this.included, globMatchingEnabled);
5151
} else {
52-
throw new IllegalArgumentException(
53-
"At least one of includedPatterns or excludedPatterns must not be null");
52+
// include everything by default if both included and excluded are null or empt
53+
this.predicate = s -> true;
5454
}
5555
}
5656

5757
/**
5858
* Create a (case-sensitive) exact matching include exclude predicate.
5959
*
60-
* @throws IllegalArgumentException if {@code included} AND {@code excluded} are null.
60+
* <p>When {@code included} is empty or {@literal null}, all values are included.
61+
*
62+
* <p>When {@code excluded} is empty or {@literal null}, no value are excluded.
6163
*/
6264
public static Predicate<String> createExactMatching(
6365
@Nullable Collection<String> included, @Nullable Collection<String> excluded) {
@@ -67,9 +69,11 @@ public static Predicate<String> createExactMatching(
6769
/**
6870
* Create a pattern matching include exclude predicate.
6971
*
70-
* <p>See {@link GlobUtil} for pattern matching details.
72+
* <p>When {@code included} is empty or {@literal null}, all values are included by default.
73+
*
74+
* <p>When {@code excluded} is empty or {@literal null}, no value is excluded by default.
7175
*
72-
* @throws IllegalArgumentException if {@code included} AND {@code excluded} are null.
76+
* <p>See {@link GlobUtil} for pattern matching details.
7377
*/
7478
public static Predicate<String> createPatternMatching(
7579
@Nullable Collection<String> included, @Nullable Collection<String> excluded) {
@@ -119,4 +123,9 @@ private static Predicate<String> excludedPredicate(
119123
}
120124
return result;
121125
}
126+
127+
@Nullable
128+
private static Set<String> copyIfNotEmpty(@Nullable Collection<String> collection) {
129+
return collection == null || collection.isEmpty() ? null : new LinkedHashSet<>(collection);
130+
}
122131
}

sdk/common/src/test/java/io/opentelemetry/sdk/common/internal/IncludeExcludePredicateTest.java

Lines changed: 31 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,13 @@
99
import static java.util.Collections.singletonList;
1010
import static org.assertj.core.api.Assertions.assertThat;
1111

12+
import java.util.Arrays;
13+
import java.util.Collection;
1214
import java.util.Collections;
1315
import java.util.function.Predicate;
1416
import java.util.stream.Stream;
17+
import javax.annotation.Nullable;
18+
import org.junit.jupiter.api.Test;
1519
import org.junit.jupiter.params.ParameterizedTest;
1620
import org.junit.jupiter.params.provider.Arguments;
1721
import org.junit.jupiter.params.provider.MethodSource;
@@ -26,8 +30,6 @@ class IncludeExcludePredicateTest {
2630
IncludeExcludePredicate.createExactMatching(singletonList("foo"), singletonList("bar"));
2731
private static final Predicate<String> EXACT_MULTI =
2832
IncludeExcludePredicate.createExactMatching(asList("foo", "fooo"), asList("bar", "barr"));
29-
public static final Predicate<String> EXACT_INCLUDE_NONE =
30-
IncludeExcludePredicate.createExactMatching(Collections.emptyList(), null);
3133

3234
private static final Predicate<String> PATTERN_INCLUDE =
3335
IncludeExcludePredicate.createPatternMatching(singletonList("f?o"), null);
@@ -37,8 +39,6 @@ class IncludeExcludePredicateTest {
3739
IncludeExcludePredicate.createPatternMatching(singletonList("f?o"), singletonList("b?r"));
3840
private static final Predicate<String> PATTERN_MULTI =
3941
IncludeExcludePredicate.createPatternMatching(asList("f?o", "f?oo"), asList("b?r", "b?rr"));
40-
public static final Predicate<String> PATTERN_INCLUDE_NONE =
41-
IncludeExcludePredicate.createPatternMatching(Collections.emptyList(), null);
4242

4343
@ParameterizedTest
4444
@MethodSource("testArgs")
@@ -75,8 +75,6 @@ private static Stream<Arguments> testArgs() {
7575
Arguments.of(EXACT_MULTI, "bar", false),
7676
Arguments.of(EXACT_MULTI, "barr", false),
7777
Arguments.of(EXACT_MULTI, "baz", false),
78-
// include none
79-
Arguments.of(EXACT_INCLUDE_NONE, "foo", false),
8078
// pattern matching
8179
// include only
8280
Arguments.of(PATTERN_INCLUDE, "foo", true),
@@ -106,9 +104,7 @@ private static Stream<Arguments> testArgs() {
106104
Arguments.of(PATTERN_MULTI, "bAr", false),
107105
Arguments.of(PATTERN_MULTI, "barr", false),
108106
Arguments.of(PATTERN_MULTI, "bArr", false),
109-
Arguments.of(PATTERN_MULTI, "baz", false),
110-
// include none
111-
Arguments.of(PATTERN_INCLUDE_NONE, "foo", false));
107+
Arguments.of(PATTERN_MULTI, "baz", false));
112108
}
113109

114110
@ParameterizedTest
@@ -140,4 +136,30 @@ private static Stream<Arguments> stringRepresentationArgs() {
140136
PATTERN_MULTI,
141137
"IncludeExcludePredicate{globMatchingEnabled=true, included=[f?o, f?oo], excluded=[b?r, b?rr]}"));
142138
}
139+
140+
@Test
141+
void emptyOrNullShouldIncludeAll() {
142+
shouldIncludeAll(null, null);
143+
shouldIncludeAll(Collections.emptyList(), null);
144+
shouldIncludeAll(null, Collections.emptyList());
145+
shouldIncludeAll(Collections.emptyList(), Collections.emptyList());
146+
}
147+
148+
private static void shouldIncludeAll(
149+
@Nullable Collection<String> included, @Nullable Collection<String> excluded) {
150+
Arrays.asList("foo", "fooo", "fOo", "FOO", "bar", "bAr", "barr", "bArr", "baz")
151+
.forEach(
152+
s -> {
153+
Predicate<String> exactMatching =
154+
IncludeExcludePredicate.createExactMatching(included, excluded);
155+
assertThat(exactMatching.test(s)).isTrue();
156+
assertThat(exactMatching.toString())
157+
.isEqualTo("IncludeExcludePredicate{globMatchingEnabled=false}");
158+
Predicate<String> patternMatching =
159+
IncludeExcludePredicate.createPatternMatching(included, excluded);
160+
assertThat(patternMatching.test(s)).isTrue();
161+
assertThat(patternMatching.toString())
162+
.isEqualTo("IncludeExcludePredicate{globMatchingEnabled=true}");
163+
});
164+
}
143165
}

sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/ViewBuilder.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import io.opentelemetry.sdk.metrics.internal.aggregator.AggregatorFactory;
1212
import io.opentelemetry.sdk.metrics.internal.state.MetricStorage;
1313
import io.opentelemetry.sdk.metrics.internal.view.AttributesProcessor;
14+
import java.util.Collections;
1415
import java.util.Objects;
1516
import java.util.Set;
1617
import java.util.function.Predicate;
@@ -74,6 +75,12 @@ public ViewBuilder setAggregation(Aggregation aggregation) {
7475
*/
7576
public ViewBuilder setAttributeFilter(Set<String> keysToRetain) {
7677
Objects.requireNonNull(keysToRetain, "keysToRetain");
78+
if (keysToRetain.isEmpty()) {
79+
// include/exclude predicate requires to include or exclude at least one
80+
// thus an empty list of keys is effectively equivalent to ignore all of them
81+
return setAttributeFilter(
82+
IncludeExcludePredicate.createPatternMatching(null, Collections.singletonList("*")));
83+
}
7784
return setAttributeFilter(IncludeExcludePredicate.createExactMatching(keysToRetain, null));
7885
}
7986

0 commit comments

Comments
 (0)