Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[pkg/ottl] Allow Converter in constant BoolExpr #20911

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions .chloggen/ottl-allow-converters-as-constbool.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: Allow using Converters as constant boolean expressions

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

# (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: This means you don't need to add `== true` after `IsMatch` in OTTL conditions.
40 changes: 20 additions & 20 deletions connector/countconnector/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -126,31 +126,31 @@ func TestLoadConfig(t *testing.T) {
Spans: map[string]MetricInfo{
"my.span.count": {
Description: "My span count.",
Conditions: []string{`IsMatch(resource.attributes["host.name"], "pod-s") == true`},
Conditions: []string{`IsMatch(resource.attributes["host.name"], "pod-s")`},
},
},
SpanEvents: map[string]MetricInfo{
"my.spanevent.count": {
Description: "My span event count.",
Conditions: []string{`IsMatch(resource.attributes["host.name"], "pod-e") == true`},
Conditions: []string{`IsMatch(resource.attributes["host.name"], "pod-e")`},
},
},
Metrics: map[string]MetricInfo{
"my.metric.count": {
Description: "My metric count.",
Conditions: []string{`IsMatch(resource.attributes["host.name"], "pod-m") == true`},
Conditions: []string{`IsMatch(resource.attributes["host.name"], "pod-m")`},
},
},
DataPoints: map[string]MetricInfo{
"my.datapoint.count": {
Description: "My data point count.",
Conditions: []string{`IsMatch(resource.attributes["host.name"], "pod-d") == true`},
Conditions: []string{`IsMatch(resource.attributes["host.name"], "pod-d")`},
},
},
Logs: map[string]MetricInfo{
"my.logrecord.count": {
Description: "My log record count.",
Conditions: []string{`IsMatch(resource.attributes["host.name"], "pod-l") == true`},
Conditions: []string{`IsMatch(resource.attributes["host.name"], "pod-l")`},
},
},
},
Expand All @@ -162,44 +162,44 @@ func TestLoadConfig(t *testing.T) {
"my.span.count": {
Description: "My span count.",
Conditions: []string{
`IsMatch(resource.attributes["host.name"], "pod-s") == true`,
`IsMatch(resource.attributes["foo"], "bar-s") == true`,
`IsMatch(resource.attributes["host.name"], "pod-s")`,
`IsMatch(resource.attributes["foo"], "bar-s")`,
},
},
},
SpanEvents: map[string]MetricInfo{
"my.spanevent.count": {
Description: "My span event count.",
Conditions: []string{
`IsMatch(resource.attributes["host.name"], "pod-e") == true`,
`IsMatch(resource.attributes["foo"], "bar-e") == true`,
`IsMatch(resource.attributes["host.name"], "pod-e")`,
`IsMatch(resource.attributes["foo"], "bar-e")`,
},
},
},
Metrics: map[string]MetricInfo{
"my.metric.count": {
Description: "My metric count.",
Conditions: []string{
`IsMatch(resource.attributes["host.name"], "pod-m") == true`,
`IsMatch(resource.attributes["foo"], "bar-m") == true`,
`IsMatch(resource.attributes["host.name"], "pod-m")`,
`IsMatch(resource.attributes["foo"], "bar-m")`,
},
},
},
DataPoints: map[string]MetricInfo{
"my.datapoint.count": {
Description: "My data point count.",
Conditions: []string{
`IsMatch(resource.attributes["host.name"], "pod-d") == true`,
`IsMatch(resource.attributes["foo"], "bar-d") == true`,
`IsMatch(resource.attributes["host.name"], "pod-d")`,
`IsMatch(resource.attributes["foo"], "bar-d")`,
},
},
},
Logs: map[string]MetricInfo{
"my.logrecord.count": {
Description: "My log record count.",
Conditions: []string{
`IsMatch(resource.attributes["host.name"], "pod-l") == true`,
`IsMatch(resource.attributes["foo"], "bar-l") == true`,
`IsMatch(resource.attributes["host.name"], "pod-l")`,
`IsMatch(resource.attributes["foo"], "bar-l")`,
},
},
},
Expand Down Expand Up @@ -256,7 +256,7 @@ func TestLoadConfig(t *testing.T) {
},
"limited.span.count": {
Description: "Limited span count.",
Conditions: []string{`IsMatch(resource.attributes["host.name"], "pod-s") == true`},
Conditions: []string{`IsMatch(resource.attributes["host.name"], "pod-s")`},
Attributes: []AttributeConfig{
{
Key: "env",
Expand All @@ -274,7 +274,7 @@ func TestLoadConfig(t *testing.T) {
},
"limited.spanevent.count": {
Description: "Limited span event count.",
Conditions: []string{`IsMatch(resource.attributes["host.name"], "pod-e") == true`},
Conditions: []string{`IsMatch(resource.attributes["host.name"], "pod-e")`},
Attributes: []AttributeConfig{
{
Key: "env",
Expand All @@ -291,7 +291,7 @@ func TestLoadConfig(t *testing.T) {
Description: "My metric count."},
"limited.metric.count": {
Description: "Limited metric count.",
Conditions: []string{`IsMatch(resource.attributes["host.name"], "pod-m") == true`},
Conditions: []string{`IsMatch(resource.attributes["host.name"], "pod-m")`},
},
},
DataPoints: map[string]MetricInfo{
Expand All @@ -300,7 +300,7 @@ func TestLoadConfig(t *testing.T) {
},
"limited.datapoint.count": {
Description: "Limited data point count.",
Conditions: []string{`IsMatch(resource.attributes["host.name"], "pod-d") == true`},
Conditions: []string{`IsMatch(resource.attributes["host.name"], "pod-d")`},
Attributes: []AttributeConfig{
{
Key: "env",
Expand All @@ -318,7 +318,7 @@ func TestLoadConfig(t *testing.T) {
},
"limited.logrecord.count": {
Description: "Limited log record count.",
Conditions: []string{`IsMatch(resource.attributes["host.name"], "pod-l") == true`},
Conditions: []string{`IsMatch(resource.attributes["host.name"], "pod-l")`},
Attributes: []AttributeConfig{
{
Key: "env",
Expand Down
40 changes: 20 additions & 20 deletions connector/countconnector/testdata/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -36,58 +36,58 @@
my.span.count:
description: My span count.
conditions:
- IsMatch(resource.attributes["host.name"], "pod-s") == true
- IsMatch(resource.attributes["host.name"], "pod-s")
spanevents:
my.spanevent.count:
description: My span event count.
conditions:
- IsMatch(resource.attributes["host.name"], "pod-e") == true
- IsMatch(resource.attributes["host.name"], "pod-e")
metrics:
my.metric.count:
description: My metric count.
conditions:
- IsMatch(resource.attributes["host.name"], "pod-m") == true
- IsMatch(resource.attributes["host.name"], "pod-m")
datapoints:
my.datapoint.count:
description: My data point count.
conditions:
- IsMatch(resource.attributes["host.name"], "pod-d") == true
- IsMatch(resource.attributes["host.name"], "pod-d")
logs:
my.logrecord.count:
description: My log record count.
conditions:
- IsMatch(resource.attributes["host.name"], "pod-l") == true
- IsMatch(resource.attributes["host.name"], "pod-l")
count/multiple_condition:
spans:
my.span.count:
description: My span count.
conditions:
- IsMatch(resource.attributes["host.name"], "pod-s") == true
- IsMatch(resource.attributes["foo"], "bar-s") == true
- IsMatch(resource.attributes["host.name"], "pod-s")
- IsMatch(resource.attributes["foo"], "bar-s")
spanevents:
my.spanevent.count:
description: My span event count.
conditions:
- IsMatch(resource.attributes["host.name"], "pod-e") == true
- IsMatch(resource.attributes["foo"], "bar-e") == true
- IsMatch(resource.attributes["host.name"], "pod-e")
- IsMatch(resource.attributes["foo"], "bar-e")
metrics:
my.metric.count:
description: My metric count.
conditions:
- IsMatch(resource.attributes["host.name"], "pod-m") == true
- IsMatch(resource.attributes["foo"], "bar-m") == true
- IsMatch(resource.attributes["host.name"], "pod-m")
- IsMatch(resource.attributes["foo"], "bar-m")
datapoints:
my.datapoint.count:
description: My data point count.
conditions:
- IsMatch(resource.attributes["host.name"], "pod-d") == true
- IsMatch(resource.attributes["foo"], "bar-d") == true
- IsMatch(resource.attributes["host.name"], "pod-d")
- IsMatch(resource.attributes["foo"], "bar-d")
logs:
my.logrecord.count:
description: My log record count.
conditions:
- IsMatch(resource.attributes["host.name"], "pod-l") == true
- IsMatch(resource.attributes["foo"], "bar-l") == true
- IsMatch(resource.attributes["host.name"], "pod-l")
- IsMatch(resource.attributes["foo"], "bar-l")
count/attribute:
spans:
my.span.count:
Expand Down Expand Up @@ -120,7 +120,7 @@
limited.span.count:
description: Limited span count.
conditions:
- IsMatch(resource.attributes["host.name"], "pod-s") == true
- IsMatch(resource.attributes["host.name"], "pod-s")
attributes:
- key: env
- key: component
Expand All @@ -131,7 +131,7 @@
limited.spanevent.count:
description: Limited span event count.
conditions:
- IsMatch(resource.attributes["host.name"], "pod-e") == true
- IsMatch(resource.attributes["host.name"], "pod-e")
attributes:
- key: env
- key: component
Expand All @@ -142,14 +142,14 @@
limited.metric.count:
description: Limited metric count.
conditions:
- IsMatch(resource.attributes["host.name"], "pod-m") == true
- IsMatch(resource.attributes["host.name"], "pod-m")
datapoints:
my.datapoint.count:
description: My data point count.
limited.datapoint.count:
description: Limited data point count.
conditions:
- IsMatch(resource.attributes["host.name"], "pod-d") == true
- IsMatch(resource.attributes["host.name"], "pod-d")
attributes:
- key: env
- key: component
Expand All @@ -160,7 +160,7 @@
limited.logrecord.count:
description: Limited log record count.
conditions:
- IsMatch(resource.attributes["host.name"], "pod-l") == true
- IsMatch(resource.attributes["host.name"], "pod-l")
attributes:
- key: env
- key: component
Expand Down
10 changes: 5 additions & 5 deletions internal/filter/filterottl/filter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ func Test_NewBoolExprForSpan(t *testing.T) {
{
name: "With Converter",
conditions: []string{
`IsMatch("test", "pass") == true`,
`IsMatch("test", "pass")`,
},
expectedResult: false,
},
Expand Down Expand Up @@ -95,7 +95,7 @@ func Test_NewBoolExprForSpanEvent(t *testing.T) {
{
name: "With Converter",
conditions: []string{
`IsMatch("test", "pass") == true`,
`IsMatch("test", "pass")`,
},
expectedResult: false,
},
Expand Down Expand Up @@ -137,7 +137,7 @@ func Test_NewBoolExprForMetric(t *testing.T) {
{
name: "With Converter",
conditions: []string{
`IsMatch("test", "pass") == true`,
`IsMatch("test", "pass")`,
},
expectedResult: false,
},
Expand Down Expand Up @@ -179,7 +179,7 @@ func Test_NewBoolExprForDataPoint(t *testing.T) {
{
name: "With Converter",
conditions: []string{
`IsMatch("test", "pass") == true`,
`IsMatch("test", "pass")`,
},
expectedResult: false,
},
Expand Down Expand Up @@ -221,7 +221,7 @@ func Test_NewBoolExprForLog(t *testing.T) {
{
name: "With Converter",
conditions: []string{
`IsMatch("test", "pass") == true`,
`IsMatch("test", "pass")`,
},
expectedResult: false,
},
Expand Down
7 changes: 4 additions & 3 deletions pkg/ottl/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,7 @@ Boolean Expressions can be grouped with parentheses to override evaluation prece

Booleans can be either:
- A literal boolean value (`true` or `false`).
- A Converter that returns a boolean value (`true` or `false`).
- A Comparison, made up of a left Value, an operator, and a right Value. See [Values](#values) for details on what a Value can be.

Operators determine how the two Values are compared.
Expand All @@ -183,8 +184,8 @@ The valid operators are:

Booleans can be negated with the `not` keyword such as
- `not true`
- `not name == "foo"`
- `not (IsMatch(name, "http_.*") == true and kind > 0)`
- `not name == "foo"`
- `not (IsMatch(name, "http_.*") and kind > 0)`

### Comparison Rules

Expand Down Expand Up @@ -212,7 +213,7 @@ Examples:
- `name == "a name"`
- `1 < 2`
- `attributes["custom-attr"] != nil`
- `IsMatch(resource.attributes["host.name"], "pod-*") == true`
- `IsMatch(resource.attributes["host.name"], "pod-*")`

## Accessing signal telemetry

Expand Down
36 changes: 32 additions & 4 deletions pkg/ottl/boolean_value.go
Original file line number Diff line number Diff line change
Expand Up @@ -162,10 +162,20 @@ func (p *Parser[K]) newBooleanValueEvaluator(value *booleanValue) (BoolExpr[K],
return BoolExpr[K]{}, err
}
case value.ConstExpr != nil:
if *value.ConstExpr {
boolExpr = BoolExpr[K]{alwaysTrue[K]}
} else {
boolExpr = BoolExpr[K]{alwaysFalse[K]}
switch {
case value.ConstExpr.Boolean != nil:
if *value.ConstExpr.Boolean {
boolExpr = BoolExpr[K]{alwaysTrue[K]}
} else {
boolExpr = BoolExpr[K]{alwaysFalse[K]}
}
case value.ConstExpr.Converter != nil:
boolExpr, err = p.newConverterEvaluator(*value.ConstExpr.Converter)
if err != nil {
return BoolExpr[K]{}, err
}
default:
return BoolExpr[K]{}, fmt.Errorf("unhandled boolean operation %v", value)
}
case value.SubExpr != nil:
boolExpr, err = p.newBoolExpr(value.SubExpr)
Expand All @@ -181,3 +191,21 @@ func (p *Parser[K]) newBooleanValueEvaluator(value *booleanValue) (BoolExpr[K],
}
return boolExpr, nil
}

func (p *Parser[K]) newConverterEvaluator(c converter) (BoolExpr[K], error) {
getter, err := p.newGetterFromConverter(c)
if err != nil {
return BoolExpr[K]{}, err
}
return BoolExpr[K]{func(ctx context.Context, tCtx K) (bool, error) {
result, err := getter.Get(ctx, tCtx)
if err != nil {
return false, err
}
boolResult, ok := result.(bool)
if !ok {
return false, fmt.Errorf("value returned from Converter in constant expression must be bool but got %T", result)
}
return boolResult, nil
}}, nil
}
Loading