Skip to content

Commit

Permalink
[pkg/ottl] Update Statements to implement filter.BoolExpr (#18915)
Browse files Browse the repository at this point in the history
* Update Statements to implement filter.BoolExpr

* add changelog

* Don't execute function
  • Loading branch information
TylerHelmuth authored Feb 28, 2023
1 parent bf5f1d0 commit f92be2c
Show file tree
Hide file tree
Showing 4 changed files with 168 additions and 23 deletions.
16 changes: 16 additions & 0 deletions .chloggen/ottl-add-eval-to-statements.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# 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 Eval function to Statements

# One or more tracking issues related to the change
issues: [18915]

# (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:
22 changes: 22 additions & 0 deletions pkg/ottl/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -211,3 +211,25 @@ func (s *Statements[K]) Execute(ctx context.Context, tCtx K) error {
}
return nil
}

// Eval returns true if any statement's condition is true and returns false otherwise.
// Does not execute the statement's function.
// When errorMode is `propagate`, errors cause the evaluation to be false and an error is returned.
// When errorMode is `ignore`, errors cause evaluation to continue to the next statement.
func (s *Statements[K]) Eval(ctx context.Context, tCtx K) (bool, error) {
for _, statement := range s.statements {
match, err := statement.condition.Eval(ctx, tCtx)
if err != nil {
if s.errorMode == PropagateError {
err = fmt.Errorf("failed to eval statement: %v, %w", statement.origText, err)
return false, err
}
s.telemetrySettings.Logger.Warn("failed to eval statement", zap.Error(err), zap.String("statement", statement.origText))
continue
}
if match {
return true, nil
}
}
return false, nil
}
121 changes: 120 additions & 1 deletion pkg/ottl/parser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1312,7 +1312,7 @@ func Test_Execute(t *testing.T) {
}
}

func Test_Execute_Error(t *testing.T) {
func Test_Statements_Execute_Error(t *testing.T) {
tests := []struct {
name string
condition boolExpressionEvaluator[interface{}]
Expand Down Expand Up @@ -1382,3 +1382,122 @@ func Test_Execute_Error(t *testing.T) {
})
}
}

func Test_Statements_Eval(t *testing.T) {
tests := []struct {
name string
conditions []boolExpressionEvaluator[interface{}]
function ExprFunc[interface{}]
errorMode ErrorMode
expectedResult bool
}{
{
name: "True",
conditions: []boolExpressionEvaluator[interface{}]{
alwaysTrue[interface{}],
},
errorMode: IgnoreError,
expectedResult: true,
},
{
name: "At least one True",
conditions: []boolExpressionEvaluator[interface{}]{
alwaysFalse[interface{}],
alwaysFalse[interface{}],
alwaysTrue[interface{}],
},
errorMode: IgnoreError,
expectedResult: true,
},
{
name: "False",
conditions: []boolExpressionEvaluator[interface{}]{
alwaysFalse[interface{}],
alwaysFalse[interface{}],
},
errorMode: IgnoreError,
expectedResult: false,
},
{
name: "Error is false when using Ignore",
conditions: []boolExpressionEvaluator[interface{}]{
alwaysFalse[interface{}],
func(context.Context, interface{}) (bool, error) {
return true, fmt.Errorf("test")
},
alwaysTrue[interface{}],
},
errorMode: IgnoreError,
expectedResult: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
var rawStatements []*Statement[interface{}]
for _, condition := range tt.conditions {
rawStatements = append(rawStatements, &Statement[interface{}]{
condition: BoolExpr[any]{condition},
function: Expr[any]{
exprFunc: func(ctx context.Context, tCtx interface{}) (interface{}, error) {
return nil, fmt.Errorf("function should not be called")
},
},
})
}

statements := Statements[interface{}]{
statements: rawStatements,
telemetrySettings: componenttest.NewNopTelemetrySettings(),
errorMode: tt.errorMode,
}

result, err := statements.Eval(context.Background(), nil)
assert.NoError(t, err)
assert.Equal(t, tt.expectedResult, result)
})
}
}

func Test_Statements_Eval_Error(t *testing.T) {
tests := []struct {
name string
conditions []boolExpressionEvaluator[interface{}]
function ExprFunc[interface{}]
errorMode ErrorMode
}{
{
name: "Propagate Error from function",
conditions: []boolExpressionEvaluator[interface{}]{
func(context.Context, interface{}) (bool, error) {
return true, fmt.Errorf("test")
},
},
errorMode: PropagateError,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
var rawStatements []*Statement[interface{}]
for _, condition := range tt.conditions {
rawStatements = append(rawStatements, &Statement[interface{}]{
condition: BoolExpr[any]{condition},
function: Expr[any]{
exprFunc: func(ctx context.Context, tCtx interface{}) (interface{}, error) {
return nil, fmt.Errorf("function should not be called")
},
},
})
}

statements := Statements[interface{}]{
statements: rawStatements,
telemetrySettings: componenttest.NewNopTelemetrySettings(),
errorMode: tt.errorMode,
}

result, err := statements.Eval(context.Background(), nil)
assert.Error(t, err)
assert.False(t, result)
})
}
}
32 changes: 10 additions & 22 deletions processor/filterprocessor/internal/common/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@ func ParseSpan(conditions []string, set component.TelemetrySettings) (expr.BoolE
if err != nil {
return nil, err
}
return statementsToExpr(statements), nil
s := ottlspan.NewStatements(statements, set, ottlspan.WithErrorMode(ottl.PropagateError))
return &s, nil
}

func ParseSpanEvent(conditions []string, set component.TelemetrySettings) (expr.BoolExpr[ottlspanevent.TransformContext], error) {
Expand All @@ -54,7 +55,8 @@ func ParseSpanEvent(conditions []string, set component.TelemetrySettings) (expr.
if err != nil {
return nil, err
}
return statementsToExpr(statements), nil
s := ottlspanevent.NewStatements(statements, set, ottlspanevent.WithErrorMode(ottl.PropagateError))
return &s, nil
}

func ParseLog(conditions []string, set component.TelemetrySettings) (expr.BoolExpr[ottllog.TransformContext], error) {
Expand All @@ -67,7 +69,8 @@ func ParseLog(conditions []string, set component.TelemetrySettings) (expr.BoolEx
if err != nil {
return nil, err
}
return statementsToExpr(statements), nil
s := ottllog.NewStatements(statements, set, ottllog.WithErrorMode(ottl.PropagateError))
return &s, nil
}

func ParseMetric(conditions []string, set component.TelemetrySettings) (expr.BoolExpr[ottlmetric.TransformContext], error) {
Expand All @@ -80,7 +83,8 @@ func ParseMetric(conditions []string, set component.TelemetrySettings) (expr.Boo
if err != nil {
return nil, err
}
return statementsToExpr(statements), nil
s := ottlmetric.NewStatements(statements, set, ottlmetric.WithErrorMode(ottl.PropagateError))
return &s, nil
}

func ParseDataPoint(conditions []string, set component.TelemetrySettings) (expr.BoolExpr[ottldatapoint.TransformContext], error) {
Expand All @@ -93,7 +97,8 @@ func ParseDataPoint(conditions []string, set component.TelemetrySettings) (expr.
if err != nil {
return nil, err
}
return statementsToExpr(statements), nil
s := ottldatapoint.NewStatements(statements, set, ottldatapoint.WithErrorMode(ottl.PropagateError))
return &s, nil
}

func conditionsToStatements(conditions []string) []string {
Expand All @@ -104,23 +109,6 @@ func conditionsToStatements(conditions []string) []string {
return statements
}

type statementExpr[K any] struct {
statement *ottl.Statement[K]
}

func (se statementExpr[K]) Eval(ctx context.Context, tCtx K) (bool, error) {
_, ret, err := se.statement.Execute(ctx, tCtx)
return ret, err
}

func statementsToExpr[K any](statements []*ottl.Statement[K]) expr.BoolExpr[K] {
var rets []expr.BoolExpr[K]
for _, statement := range statements {
rets = append(rets, statementExpr[K]{statement: statement})
}
return expr.Or(rets...)
}

func functions[K any]() map[string]interface{} {
return map[string]interface{}{
"TraceID": ottlfuncs.TraceID[K],
Expand Down

0 comments on commit f92be2c

Please sign in to comment.