Skip to content

Commit

Permalink
[pkg/ottl] Add new silent ErrorMode (#29710)
Browse files Browse the repository at this point in the history
**Description:**
Adds a new ErrorMode, `silent`, that `StatementSequence` and
`ConditionSequence` can use to disable logging when ignoring errors.

**Link to tracking Issue:** 

Closes
#22743

**Testing:**
Updated unit tests

**Documentation:** 
Updated READMEs and godoc comments.
  • Loading branch information
TylerHelmuth authored Dec 8, 2023
1 parent 536635f commit fb2718d
Show file tree
Hide file tree
Showing 8 changed files with 94 additions and 16 deletions.
27 changes: 27 additions & 0 deletions .chloggen/ottl-silent-error-mode.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Use this changelog template to create an entry for release notes.

# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix'
change_type: enhancement

# The name of the component, or a single word describing the area of concern, (e.g. filelogreceiver)
component: pkg/ottl

# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`).
note: Add `silent` ErrorMode to allow disabling logging of errors that are ignored.

# Mandatory: One or more tracking issues related to the change. You can use the PR number here if no issue exists.
issues: [29710]

# (Optional) One or more lines of additional information to render under the primary note.
# These lines will be padded with 2 spaces and then inserted directly into the document.
# Use pipe (|) for multiline entries.
subtext:

# If your change doesn't affect end users or the exported elements of any package,
# you should instead start your pull request title with [chore] or use the "Skip Changelog" label.
# Optional: The change log or logs in which this entry should be included.
# e.g. '[user]' or '[user, api]'
# Include 'user' if the change is relevant to end users.
# Include 'api' if there is a change to a library API.
# Default: '[user]'
change_logs: []
2 changes: 1 addition & 1 deletion connector/routingconnector/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ The following settings are available:
- `table.statement (required)`: the routing condition provided as the [OTTL] statement.
- `table.pipelines (required)`: the list of pipelines to use when the routing condition is met.
- `default_pipelines (optional)`: contains the list of pipelines to use when a record does not meet any of specified conditions.
- `error_mode (optional)`: determines how errors returned from OTTL statements are handled. Valid values are `ignore` and `propagate`. If `ignored` is used and a statement's condition has an error then the payload will be routed to the default pipelines. If not supplied, `propagate` is used.
- `error_mode (optional)`: determines how errors returned from OTTL statements are handled. Valid values are `propagate`, `ignore` and `silent`. If `ignored` or `silent` is used and a statement's condition has an error then the payload will be routed to the default pipelines. When `silent` is used the error is not logged. If not supplied, `propagate` is used.

Example:

Expand Down
3 changes: 2 additions & 1 deletion pkg/ottl/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,13 @@ type ErrorMode string
const (
IgnoreError ErrorMode = "ignore"
PropagateError ErrorMode = "propagate"
SilentError ErrorMode = "silent"
)

func (e *ErrorMode) UnmarshalText(text []byte) error {
str := ErrorMode(strings.ToLower(string(text)))
switch str {
case IgnoreError, PropagateError:
case IgnoreError, PropagateError, SilentError:
*e = str
return nil
default:
Expand Down
12 changes: 9 additions & 3 deletions pkg/ottl/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,7 @@ func NewStatementSequence[K any](statements []*Statement[K], telemetrySettings c
// Execute is a function that will execute all the statements in the StatementSequence list.
// When the ErrorMode of the StatementSequence is `propagate`, errors cause the execution to halt and the error is returned.
// When the ErrorMode of the StatementSequence is `ignore`, errors are logged and execution continues to the next statement.
// When the ErrorMode of the StatementSequence is `silent`, errors are not logged and execution continues to the next statement.
func (s *StatementSequence[K]) Execute(ctx context.Context, tCtx K) error {
for _, statement := range s.statements {
_, _, err := statement.Execute(ctx, tCtx)
Expand All @@ -268,7 +269,9 @@ func (s *StatementSequence[K]) Execute(ctx context.Context, tCtx K) error {
err = fmt.Errorf("failed to execute statement: %v, %w", statement.origText, err)
return err
}
s.telemetrySettings.Logger.Warn("failed to execute statement", zap.Error(err), zap.String("statement", statement.origText))
if s.errorMode == IgnoreError {
s.telemetrySettings.Logger.Warn("failed to execute statement", zap.Error(err), zap.String("statement", statement.origText))
}
}
}
return nil
Expand Down Expand Up @@ -323,7 +326,8 @@ func NewConditionSequence[K any](conditions []*Condition[K], telemetrySettings c
// If using the default OR LogicOperation, if any Condition evaluates to true, then true is returned and if all Conditions evaluate to false, then false is returned.
// If using the AND LogicOperation, if any Condition evaluates to false, then false is returned and if all Conditions evaluate to true, then true is returned.
// When the ErrorMode of the ConditionSequence is `propagate`, errors cause the evaluation to be false and an error is returned.
// When the ErrorMode of the ConditionSequence is `ignore`, errors cause the evaluation to continue to the next condition.
// When the ErrorMode of the ConditionSequence is `ignore`, errors are logged and cause the evaluation to continue to the next condition.
// When the ErrorMode of the ConditionSequence is `silent`, errors are not logged and cause the evaluation to continue to the next condition.
// When using the AND LogicOperation with the `ignore` ErrorMode the sequence will evaluate to false if all conditions error.
func (c *ConditionSequence[K]) Eval(ctx context.Context, tCtx K) (bool, error) {
var atLeastOneMatch bool
Expand All @@ -334,7 +338,9 @@ func (c *ConditionSequence[K]) Eval(ctx context.Context, tCtx K) (bool, error) {
err = fmt.Errorf("failed to eval condition: %v, %w", condition.origText, err)
return false, err
}
c.telemetrySettings.Logger.Warn("failed to eval condition", zap.Error(err), zap.String("condition", condition.origText))
if c.errorMode == IgnoreError {
c.telemetrySettings.Logger.Warn("failed to eval condition", zap.Error(err), zap.String("condition", condition.origText))
}
continue
}
if match {
Expand Down
46 changes: 44 additions & 2 deletions pkg/ottl/parser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2091,6 +2091,26 @@ func Test_Statements_Execute_Error(t *testing.T) {
},
errorMode: PropagateError,
},
{
name: "SilentError error from condition",
condition: func(context.Context, any) (bool, error) {
return true, fmt.Errorf("test")
},
function: func(ctx context.Context, tCtx any) (any, error) {
return 1, nil
},
errorMode: SilentError,
},
{
name: "SilentError error from function",
condition: func(context.Context, any) (bool, error) {
return true, nil
},
function: func(ctx context.Context, tCtx any) (any, error) {
return 1, fmt.Errorf("test")
},
errorMode: SilentError,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
Expand Down Expand Up @@ -2262,14 +2282,32 @@ func Test_ConditionSequence_Eval_Error(t *testing.T) {
errorMode ErrorMode
}{
{
name: "Propagate Error from function",
name: "Propagate Error from condition",
conditions: []boolExpressionEvaluator[any]{
func(context.Context, any) (bool, error) {
return true, fmt.Errorf("test")
},
},
errorMode: PropagateError,
},
{
name: "Ignore Error from function with IgnoreError",
conditions: []boolExpressionEvaluator[any]{
func(context.Context, any) (bool, error) {
return true, fmt.Errorf("test")
},
},
errorMode: IgnoreError,
},
{
name: "Ignore Error from function with SilentError",
conditions: []boolExpressionEvaluator[any]{
func(context.Context, any) (bool, error) {
return true, fmt.Errorf("test")
},
},
errorMode: SilentError,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
Expand All @@ -2287,8 +2325,12 @@ func Test_ConditionSequence_Eval_Error(t *testing.T) {
}

result, err := conditions.Eval(context.Background(), nil)
assert.Error(t, err)
assert.False(t, result)
if tt.errorMode == PropagateError {
assert.Error(t, err)
} else {
assert.NoError(t, err)
}
})
}
}
9 changes: 5 additions & 4 deletions processor/filterprocessor/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,11 @@ If all datapoints for a metric are dropped, the metric will also be dropped.

The filter processor also allows configuring an optional field, `error_mode`, which will determine how the processor reacts to errors that occur while processing an OTTL condition.

| error_mode | description |
|-----------------------|----------------------------------------------------------------------------------------------------------------------------|
| ignore | The processor ignores errors returned by conditions and continues on to the next condition. This is the recommended mode. |
| propagate | The processor returns the error up the pipeline. This will result in the payload being dropped from the collector. |
| error_mode | description |
|------------|----------------------------------------------------------------------------------------------------------------------------------------|
| ignore | The processor ignores errors returned by conditions, logs them, and continues on to the next condition. This is the recommended mode. |
| silent | The processor ignores errors returned by conditions, does not log them, and continues on to the next condition. |
| propagate | The processor returns the error up the pipeline. This will result in the payload being dropped from the collector. |

If not specified, `propagate` will be used.

Expand Down
2 changes: 1 addition & 1 deletion processor/routingprocessor/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ To configure the routing processor with [OTTL] routing conditions use the follow
- `table.statement (required)`: the routing condition provided as the [OTTL] statement.
- `table.exporters (required)`: the list of exporters to use when the routing condition is met.
- `default_exporters (optional)`: contains the list of exporters to use when a record does not meet any of specified conditions.
- `error_mode (optional)`: determines how errors returned from OTTL statements are handled. Valid values are `ignore` and `propagate`. If `ignored` is used and a statement's condition has an error then the payload will be routed to the default exporter. If not supplied, `propagate` is used.
- `error_mode (optional)`: determines how errors returned from OTTL statements are handled. Valid values are `ignore` and `propagate`. If `ignored` or `silent` is used and a statement's condition has an error then the payload will be routed to the default exporter. When `silent` is used the error is not logged. If not supplied, `propagate` is used.


```yaml
Expand Down
9 changes: 5 additions & 4 deletions processor/transformprocessor/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,11 @@ Each context will be processed in the order specified and each statement for a c

The transform processor also allows configuring an optional field, `error_mode`, which will determine how the processor reacts to errors that occur while processing a statement.

| error_mode | description |
|-----------------------|----------------------------------------------------------------------------------------------------------------------------|
| ignore | The processor ignores errors returned by statements and continues on to the next statement. This is the recommended mode. |
| propagate | The processor returns the error up the pipeline. This will result in the payload being dropped from the collector. |
| error_mode | description |
|------------|---------------------------------------------------------------------------------------------------------------------------------------------|
| ignore | The processor ignores errors returned by statements, logs the error, and continues on to the next statement. This is the recommended mode. |
| silent | The processor ignores errors returned by statements, does not log the error, and continues on to the next statement. |
| propagate | The processor returns the error up the pipeline. This will result in the payload being dropped from the collector. |

If not specified, `propagate` will be used.

Expand Down

0 comments on commit fb2718d

Please sign in to comment.