Skip to content

Commit 9e2e518

Browse files
portertechdragonlord93
authored andcommitted
[processor/tailsampling] Deprecate invert sample decisions (open-telemetry#39833)
#### Description Users can now use the newly added [Drop policy type](open-telemetry#39668) to explicitly drop (not sample) specific traces regardless of other policy decisions. This pull-request deprecates the invert sample decisions. This pull-request introduces a feature gate/flag, `processor.tailsamplingprocessor.disableinvertdecisions`, to disable the invert sampling decisions. The gate/flag influences the underlying policy evaluation for simplicity. With the gate/flag enabled, the string, numeric, and boolean filter policies still support `invert_match`, which continues to flip the decision for the individual policy (only `Sampled` and `NotSampled`). Letting `invert_match` be simple. #### Related Issues - open-telemetry#36673 - open-telemetry#33656 - open-telemetry#36795 - open-telemetry#34296 - open-telemetry#34085 - open-telemetry#29637 - open-telemetry#27049 - Probably more 😅 --------- Signed-off-by: Sean Porter <[email protected]>
1 parent 4c372a4 commit 9e2e518

File tree

7 files changed

+149
-35
lines changed

7 files changed

+149
-35
lines changed
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# Use this changelog template to create an entry for release notes.
2+
3+
# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix'
4+
change_type: deprecation
5+
6+
# The name of the component, or a single word describing the area of concern, (e.g. filelogreceiver)
7+
component: processor/tailsampling
8+
9+
# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`).
10+
note: The invert decisions (InvertSampled and InvertNotSampled) have been deprecated, please make use of drop policy to explicitly not sample select traces.
11+
12+
# Mandatory: One or more tracking issues related to the change. You can use the PR number here if no issue exists.
13+
issues: [39833]
14+
15+
# (Optional) One or more lines of additional information to render under the primary note.
16+
# These lines will be padded with 2 spaces and then inserted directly into the document.
17+
# Use pipe (|) for multiline entries.
18+
subtext:
19+
20+
# If your change doesn't affect end users or the exported elements of any package,
21+
# you should instead start your pull request title with [chore] or use the "Skip Changelog" label.
22+
# Optional: The change log or logs in which this entry should be included.
23+
# e.g. '[user]' or '[user, api]'
24+
# Include 'user' if the change is relevant to end users.
25+
# Include 'api' if there is a change to a library API.
26+
# Default: '[user]'
27+
change_logs: []

processor/tailsamplingprocessor/README.md

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -65,12 +65,12 @@ The following configuration options can also be modified:
6565
Each policy will result in a decision, and the processor will evaluate them to make a final decision:
6666

6767
- When there's a "drop" decision, the trace is not sampled;
68-
- When there's an "inverted not sample" decision, the trace is not sampled;
68+
- When there's an "inverted not sample" decision, the trace is not sampled; ***Deprecated***
6969
- When there's a "sample" decision, the trace is sampled;
70-
- When there's a "inverted sample" decision and no "not sample" decisions, the trace is sampled;
70+
- When there's a "inverted sample" decision and no "not sample" decisions, the trace is sampled; ***Deprecated***
7171
- In all other cases, the trace is NOT sampled
7272

73-
An "inverted" decision is the one made based on the "invert_match" attribute, such as the one from the string, numeric or boolean tag policy.
73+
An "inverted" decision is the one made based on the "invert_match" attribute, such as the one from the string, numeric or boolean tag policy. There is an exception to this if the policy is within an and or composite policy, the resulting decision will be either sampled or not sampled. The "inverted" decisions have been deprecated, please make use of drop policy to explicitly not sample select traces.
7474

7575
Examples:
7676

@@ -560,6 +560,12 @@ When this feature gate is set, this will add additional attributes on each sampl
560560
| `tailsampling.policy` | Records the configured name of the policy that sampled a trace | Always |
561561
| `tailsampling.composite_policy` | Records the configured name of a composite subpolicy that sampled a trace | When composite policy used |
562562

563+
### Disable invert decisions
564+
565+
The invert sampling decisions (`InvertSampled` and `InvertNotSampled`) have been deprecated, however, they are still available. To disable them before their complete removal, you can use the `processor.tailsamplingprocessor.disableinvertdecisions` feature gate. When this feature gate is set, sampling policy `invert_match` will result in a `Sampled` or `NotSampled` decision instead of `InvertSampled` or `InvertNotSampled`. This applies to the string, numeric, and boolean tag policy.
566+
567+
If you disable invert decisions, you can make use of drop policy to explicitly not sample select traces.
568+
563569
### Policy Evaluation Errors
564570

565571
```

processor/tailsamplingprocessor/internal/sampling/boolean_tag_filter_test.go

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
"github.com/google/uuid"
1111
"github.com/stretchr/testify/assert"
1212
"go.opentelemetry.io/collector/component/componenttest"
13+
"go.opentelemetry.io/collector/featuregate"
1314
"go.opentelemetry.io/collector/pdata/pcommon"
1415
"go.opentelemetry.io/collector/pdata/ptrace"
1516
)
@@ -61,9 +62,10 @@ func TestBooleanTagFilterInverted(t *testing.T) {
6162
resAttr["example"] = 8
6263

6364
cases := []struct {
64-
Desc string
65-
Trace *TraceData
66-
Decision Decision
65+
Desc string
66+
Trace *TraceData
67+
Decision Decision
68+
DisableInvertDecision bool
6769
}{
6870
{
6971
Desc: "non-matching span attribute",
@@ -80,10 +82,30 @@ func TestBooleanTagFilterInverted(t *testing.T) {
8082
Trace: newTraceBoolAttrs(empty, "example", true),
8183
Decision: InvertNotSampled,
8284
},
85+
{
86+
Desc: "span attribute with non matching boolean value with DisableInvertDecision",
87+
Trace: newTraceBoolAttrs(empty, "example", false),
88+
Decision: Sampled,
89+
DisableInvertDecision: true,
90+
},
91+
{
92+
Desc: "span attribute with matching boolean value with DisableInvertDecision",
93+
Trace: newTraceBoolAttrs(empty, "example", true),
94+
Decision: NotSampled,
95+
DisableInvertDecision: true,
96+
},
8397
}
8498

8599
for _, c := range cases {
86100
t.Run(c.Desc, func(t *testing.T) {
101+
if c.DisableInvertDecision {
102+
err := featuregate.GlobalRegistry().Set("processor.tailsamplingprocessor.disableinvertdecisions", true)
103+
assert.NoError(t, err)
104+
defer func() {
105+
err := featuregate.GlobalRegistry().Set("processor.tailsamplingprocessor.disableinvertdecisions", false)
106+
assert.NoError(t, err)
107+
}()
108+
}
87109
u, _ := uuid.NewRandom()
88110
decision, err := filter.Evaluate(context.Background(), pcommon.TraceID(u), c.Trace)
89111
assert.NoError(t, err)
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// Copyright The OpenTelemetry Authors
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
package sampling // import "github.com/open-telemetry/opentelemetry-collector-contrib/processor/tailsamplingprocessor/internal/sampling"
5+
6+
import "go.opentelemetry.io/collector/featuregate"
7+
8+
var disableInvertDecisions = featuregate.GlobalRegistry().MustRegister(
9+
"processor.tailsamplingprocessor.disableinvertdecisions",
10+
featuregate.StageAlpha,
11+
featuregate.WithRegisterDescription("When enabled, sampling policy 'invert_match' will result in a SAMPLED or NOT SAMPLED decision instead of INVERT SAMPLED or INVERT NOT SAMPLED."),
12+
)
13+
14+
func IsInvertDecisionsDisabled() bool {
15+
return disableInvertDecisions.IsEnabled()
16+
}

processor/tailsamplingprocessor/internal/sampling/numeric_tag_filter_test.go

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import (
1212
"github.com/stretchr/testify/assert"
1313
"github.com/stretchr/testify/require"
1414
"go.opentelemetry.io/collector/component/componenttest"
15+
"go.opentelemetry.io/collector/featuregate"
1516
"go.opentelemetry.io/collector/pdata/pcommon"
1617
"go.opentelemetry.io/collector/pdata/ptrace"
1718
)
@@ -97,9 +98,10 @@ func TestNumericTagFilterInverted(t *testing.T) {
9798
resAttr["example"] = 8
9899

99100
cases := []struct {
100-
Desc string
101-
Trace *TraceData
102-
Decision Decision
101+
Desc string
102+
Trace *TraceData
103+
Decision Decision
104+
DisableInvertDecision bool
103105
}{
104106
{
105107
Desc: "nonmatching span attribute",
@@ -146,10 +148,30 @@ func TestNumericTagFilterInverted(t *testing.T) {
146148
Trace: newTraceIntAttrs(map[string]any{"example": math.MaxInt32 + 1}, "non_matching", math.MaxInt32+1),
147149
Decision: InvertSampled,
148150
},
151+
{
152+
Desc: "nonmatching span attribute with DisableInvertDecision",
153+
Trace: newTraceIntAttrs(empty, "non_matching", math.MinInt32),
154+
Decision: Sampled,
155+
DisableInvertDecision: true,
156+
},
157+
{
158+
Desc: "span attribute at the lower limit with DisableInvertDecision",
159+
Trace: newTraceIntAttrs(empty, "example", math.MinInt32),
160+
Decision: NotSampled,
161+
DisableInvertDecision: true,
162+
},
149163
}
150164

151165
for _, c := range cases {
152166
t.Run(c.Desc, func(t *testing.T) {
167+
if c.DisableInvertDecision {
168+
err := featuregate.GlobalRegistry().Set("processor.tailsamplingprocessor.disableinvertdecisions", true)
169+
assert.NoError(t, err)
170+
defer func() {
171+
err := featuregate.GlobalRegistry().Set("processor.tailsamplingprocessor.disableinvertdecisions", false)
172+
assert.NoError(t, err)
173+
}()
174+
}
153175
u, _ := uuid.NewRandom()
154176
decision, err := filter.Evaluate(context.Background(), pcommon.TraceID(u), c.Trace)
155177
assert.NoError(t, err)

processor/tailsamplingprocessor/internal/sampling/string_tag_filter_test.go

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99

1010
"github.com/stretchr/testify/assert"
1111
"go.opentelemetry.io/collector/component/componenttest"
12+
"go.opentelemetry.io/collector/featuregate"
1213
"go.opentelemetry.io/collector/pdata/pcommon"
1314
"go.opentelemetry.io/collector/pdata/ptrace"
1415
)
@@ -24,10 +25,11 @@ type TestStringAttributeCfg struct {
2425

2526
func TestStringTagFilter(t *testing.T) {
2627
cases := []struct {
27-
Desc string
28-
Trace *TraceData
29-
filterCfg *TestStringAttributeCfg
30-
Decision Decision
28+
Desc string
29+
Trace *TraceData
30+
filterCfg *TestStringAttributeCfg
31+
Decision Decision
32+
DisableInvertDecision bool
3133
}{
3234
{
3335
Desc: "nonmatching node attribute key",
@@ -197,10 +199,32 @@ func TestStringTagFilter(t *testing.T) {
197199
filterCfg: &TestStringAttributeCfg{Key: "example", Values: []string{}, EnabledRegexMatching: true, InvertMatch: true},
198200
Decision: InvertSampled,
199201
},
202+
{
203+
Desc: "invert matching node attribute key with DisableInvertDecision",
204+
Trace: newTraceStringAttrs(map[string]any{"example": "value"}, "", ""),
205+
filterCfg: &TestStringAttributeCfg{Key: "example", Values: []string{"value"}, EnabledRegexMatching: false, CacheMaxSize: defaultCacheSize, InvertMatch: true},
206+
Decision: NotSampled,
207+
DisableInvertDecision: true,
208+
},
209+
{
210+
Desc: "invert nonmatching node attribute key with DisableInvertDecision",
211+
Trace: newTraceStringAttrs(map[string]any{"non_matching": "value"}, "", ""),
212+
filterCfg: &TestStringAttributeCfg{Key: "example", Values: []string{"value"}, EnabledRegexMatching: false, CacheMaxSize: defaultCacheSize, InvertMatch: true},
213+
Decision: Sampled,
214+
DisableInvertDecision: true,
215+
},
200216
}
201217

202218
for _, c := range cases {
203219
t.Run(c.Desc, func(t *testing.T) {
220+
if c.DisableInvertDecision {
221+
err := featuregate.GlobalRegistry().Set("processor.tailsamplingprocessor.disableinvertdecisions", true)
222+
assert.NoError(t, err)
223+
defer func() {
224+
err := featuregate.GlobalRegistry().Set("processor.tailsamplingprocessor.disableinvertdecisions", false)
225+
assert.NoError(t, err)
226+
}()
227+
}
204228
filter := NewStringAttributeFilter(componenttest.NewNopTelemetrySettings(), c.filterCfg.Key, c.filterCfg.Values, c.filterCfg.EnabledRegexMatching, c.filterCfg.CacheMaxSize, c.filterCfg.InvertMatch)
205229
decision, err := filter.Evaluate(context.Background(), pcommon.TraceID([16]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}), c.Trace)
206230
assert.NoError(t, err)

processor/tailsamplingprocessor/internal/sampling/util.go

Lines changed: 19 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ func hasResourceOrSpanWithCondition(
2323
return Sampled
2424
}
2525

26-
if hasInstrumentationLibrarySpanWithCondition(rs.ScopeSpans(), shouldSampleSpan) {
26+
if hasInstrumentationLibrarySpanWithCondition(rs.ScopeSpans(), shouldSampleSpan, false) {
2727
return Sampled
2828
}
2929
}
@@ -37,18 +37,30 @@ func invertHasResourceOrSpanWithCondition(
3737
shouldSampleResource func(resource pcommon.Resource) bool,
3838
shouldSampleSpan func(span ptrace.Span) bool,
3939
) Decision {
40+
isd := IsInvertDecisionsDisabled()
41+
4042
for i := 0; i < td.ResourceSpans().Len(); i++ {
4143
rs := td.ResourceSpans().At(i)
4244

4345
resource := rs.Resource()
4446
if !shouldSampleResource(resource) {
47+
if isd {
48+
return NotSampled
49+
}
4550
return InvertNotSampled
4651
}
4752

48-
if !invertHasInstrumentationLibrarySpanWithCondition(rs.ScopeSpans(), shouldSampleSpan) {
53+
if !hasInstrumentationLibrarySpanWithCondition(rs.ScopeSpans(), shouldSampleSpan, true) {
54+
if isd {
55+
return NotSampled
56+
}
4957
return InvertNotSampled
5058
}
5159
}
60+
61+
if isd {
62+
return Sampled
63+
}
5264
return InvertSampled
5365
}
5466

@@ -57,41 +69,26 @@ func hasSpanWithCondition(td ptrace.Traces, shouldSample func(span ptrace.Span)
5769
for i := 0; i < td.ResourceSpans().Len(); i++ {
5870
rs := td.ResourceSpans().At(i)
5971

60-
if hasInstrumentationLibrarySpanWithCondition(rs.ScopeSpans(), shouldSample) {
72+
if hasInstrumentationLibrarySpanWithCondition(rs.ScopeSpans(), shouldSample, false) {
6173
return Sampled
6274
}
6375
}
6476
return NotSampled
6577
}
6678

67-
func hasInstrumentationLibrarySpanWithCondition(ilss ptrace.ScopeSpansSlice, check func(span ptrace.Span) bool) bool {
68-
for i := 0; i < ilss.Len(); i++ {
69-
ils := ilss.At(i)
70-
71-
for j := 0; j < ils.Spans().Len(); j++ {
72-
span := ils.Spans().At(j)
73-
74-
if check(span) {
75-
return true
76-
}
77-
}
78-
}
79-
return false
80-
}
81-
82-
func invertHasInstrumentationLibrarySpanWithCondition(ilss ptrace.ScopeSpansSlice, check func(span ptrace.Span) bool) bool {
79+
func hasInstrumentationLibrarySpanWithCondition(ilss ptrace.ScopeSpansSlice, check func(span ptrace.Span) bool, invert bool) bool {
8380
for i := 0; i < ilss.Len(); i++ {
8481
ils := ilss.At(i)
8582

8683
for j := 0; j < ils.Spans().Len(); j++ {
8784
span := ils.Spans().At(j)
8885

89-
if !check(span) {
90-
return false
86+
if r := check(span); r != invert {
87+
return r
9188
}
9289
}
9390
}
94-
return true
91+
return invert
9592
}
9693

9794
func SetAttrOnScopeSpans(data *TraceData, attrName string, attrKey string) {

0 commit comments

Comments
 (0)