Skip to content

Commit 2abf07c

Browse files
authored
Metrics filters: allow OR on same key (#1127)
Fix issue where several metrics filters targetting the same key would not be ORed, which should be an expected behaviour. This is necessary for filters such as "SubnetLabel is absent OR starts with EXT-", which is a pattern that should become pretty common.
1 parent 35bc7dd commit 2abf07c

File tree

3 files changed

+47
-8
lines changed

3 files changed

+47
-8
lines changed

pkg/pipeline/encode/metrics/filtering.go

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,32 @@ import "github.com/netobserv/flowlogs-pipeline/pkg/config"
44

55
func (p *Preprocessed) ApplyFilters(flow config.GenericMap, flatParts []config.GenericMap) (bool, []config.GenericMap) {
66
filteredParts := flatParts
7-
for _, filter := range p.filters {
8-
if filter.useFlat {
9-
filteredParts = filter.filterFlatParts(filteredParts)
10-
if len(filteredParts) == 0 {
11-
return false, nil
7+
// For a given key, all related filters are OR'ed
8+
for _, filtersPerKey := range p.filters {
9+
allFailed := true
10+
for _, filter := range filtersPerKey {
11+
passed, nfp := applySingleFilter(flow, &filter, filteredParts)
12+
if passed {
13+
allFailed = false
14+
filteredParts = nfp
15+
break
1216
}
13-
} else if !filter.predicate(flow) {
17+
}
18+
if allFailed {
19+
return false, nil
20+
}
21+
}
22+
return true, filteredParts
23+
}
24+
25+
func applySingleFilter(flow config.GenericMap, filter *preprocessedFilter, filteredParts []config.GenericMap) (bool, []config.GenericMap) {
26+
if filter.useFlat {
27+
filteredParts = filter.filterFlatParts(filteredParts)
28+
if len(filteredParts) == 0 {
1429
return false, nil
1530
}
31+
} else if !filter.predicate(flow) {
32+
return false, nil
1633
}
1734
return true, filteredParts
1835
}

pkg/pipeline/encode/metrics/preprocess.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import (
1010

1111
type Preprocessed struct {
1212
*api.MetricsItem
13-
filters []preprocessedFilter
13+
filters map[string][]preprocessedFilter
1414
MappedLabels []MappedLabel
1515
FlattenedLabels []MappedLabel
1616
}
@@ -60,6 +60,7 @@ func filterToPredicate(filter api.MetricsFilter) filters.Predicate {
6060
func Preprocess(def *api.MetricsItem) *Preprocessed {
6161
mi := Preprocessed{
6262
MetricsItem: def,
63+
filters: make(map[string][]preprocessedFilter),
6364
}
6465
for _, l := range def.Labels {
6566
ml := MappedLabel{Source: l, Target: l}
@@ -73,7 +74,7 @@ func Preprocess(def *api.MetricsItem) *Preprocessed {
7374
}
7475
}
7576
for _, f := range def.Filters {
76-
mi.filters = append(mi.filters, preprocessedFilter{
77+
mi.filters[f.Key] = append(mi.filters[f.Key], preprocessedFilter{
7778
predicate: filterToPredicate(f),
7879
useFlat: mi.isFlattened(f.Key),
7980
})

pkg/pipeline/encode/metrics/preprocess_test.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,3 +42,24 @@ func Test_Flatten(t *testing.T) {
4242
},
4343
}, fl)
4444
}
45+
46+
func Test_ORedFilters(t *testing.T) {
47+
// Several filters on the same key are ORed
48+
pp := Preprocess(&api.MetricsItem{Filters: []api.MetricsFilter{
49+
{
50+
Key: "label",
51+
Type: api.MetricFilterAbsence,
52+
},
53+
{
54+
Key: "label",
55+
Type: api.MetricFilterRegex,
56+
Value: "^EXT-.*",
57+
},
58+
}})
59+
keep, _ := pp.ApplyFilters(config.GenericMap{"namespace": "A", "bytes": 7, "label": "Something"}, nil)
60+
assert.False(t, keep)
61+
keep, _ = pp.ApplyFilters(config.GenericMap{"namespace": "A", "bytes": 7, "label": "EXT-Something"}, nil)
62+
assert.True(t, keep)
63+
keep, _ = pp.ApplyFilters(config.GenericMap{"namespace": "A", "bytes": 7}, nil)
64+
assert.True(t, keep)
65+
}

0 commit comments

Comments
 (0)