Fix template pattern partial wildcard matching (#6135)
This commit is contained in:
parent
5c9923a20a
commit
77b1a43539
|
@ -3,6 +3,7 @@ package templating
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -20,3 +21,57 @@ func TestEngineAlternateSeparator(t *testing.T) {
|
||||||
}, tags)
|
}, tags)
|
||||||
require.Equal(t, "", field)
|
require.Equal(t, "", field)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestEngineWithWildcardTemplate(t *testing.T) {
|
||||||
|
var (
|
||||||
|
defaultTmpl, err = NewDefaultTemplateWithPattern("measurement*")
|
||||||
|
templates = []string{
|
||||||
|
"taskmanagerTask.alarm-detector.Assign.alarmDefinitionId metricsType.process.nodeId.x.alarmDefinitionId.measurement.field rule=1",
|
||||||
|
"taskmanagerTask.*.*.*.* metricsType.process.nodeId.measurement rule=2",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
engine, err := NewEngine(".", defaultTmpl, templates)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
for _, testCase := range []struct {
|
||||||
|
line string
|
||||||
|
measurement string
|
||||||
|
field string
|
||||||
|
tags map[string]string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
line: "taskmanagerTask.alarm-detector.Assign.alarmDefinitionId.timeout_errors.duration.p75",
|
||||||
|
measurement: "duration",
|
||||||
|
field: "p75",
|
||||||
|
tags: map[string]string{
|
||||||
|
"metricsType": "taskmanagerTask",
|
||||||
|
"process": "alarm-detector",
|
||||||
|
"nodeId": "Assign",
|
||||||
|
"x": "alarmDefinitionId",
|
||||||
|
"alarmDefinitionId": "timeout_errors",
|
||||||
|
"rule": "1",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
line: "taskmanagerTask.alarm-detector.Assign.numRecordsInPerSecond.m5_rate",
|
||||||
|
measurement: "numRecordsInPerSecond",
|
||||||
|
tags: map[string]string{
|
||||||
|
"metricsType": "taskmanagerTask",
|
||||||
|
"process": "alarm-detector",
|
||||||
|
"nodeId": "Assign",
|
||||||
|
"rule": "2",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
} {
|
||||||
|
t.Run(testCase.line, func(t *testing.T) {
|
||||||
|
measurement, tags, field, err := engine.Apply(testCase.line)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
assert.Equal(t, testCase.measurement, measurement)
|
||||||
|
assert.Equal(t, testCase.field, field)
|
||||||
|
assert.Equal(t, testCase.tags, tags)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -55,32 +55,44 @@ func (n *node) search(line string) *Template {
|
||||||
|
|
||||||
// recursiveSearch performs the actual recursive search
|
// recursiveSearch performs the actual recursive search
|
||||||
func (n *node) recursiveSearch(lineParts []string) *Template {
|
func (n *node) recursiveSearch(lineParts []string) *Template {
|
||||||
// Nothing to search
|
// nothing to search
|
||||||
if len(lineParts) == 0 || len(n.children) == 0 {
|
if len(lineParts) == 0 || len(n.children) == 0 {
|
||||||
return n.template
|
return n.template
|
||||||
}
|
}
|
||||||
|
|
||||||
// If last element is a wildcard, don't include it in this search since it's sorted
|
var (
|
||||||
// to the end but lexicographically it would not always be and sort.Search assumes
|
hasWildcard bool
|
||||||
// the slice is sorted.
|
length = len(n.children)
|
||||||
length := len(n.children)
|
)
|
||||||
if n.children[length-1].value == "*" {
|
|
||||||
|
// exclude last child from search if it is a wildcard. sort.Search expects
|
||||||
|
// a lexicographically sorted set of children and we have artificially sorted
|
||||||
|
// wildcards to the end of the child set
|
||||||
|
// wildcards will be searched seperately if no exact match is found
|
||||||
|
if hasWildcard = n.children[length-1].value == "*"; hasWildcard {
|
||||||
length--
|
length--
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find the index of child with an exact match
|
|
||||||
i := sort.Search(length, func(i int) bool {
|
i := sort.Search(length, func(i int) bool {
|
||||||
return n.children[i].value >= lineParts[0]
|
return n.children[i].value >= lineParts[0]
|
||||||
})
|
})
|
||||||
|
|
||||||
// Found an exact match, so search that child sub-tree
|
// given an exact match is found within children set
|
||||||
if i < len(n.children) && n.children[i].value == lineParts[0] {
|
if i < length && n.children[i].value == lineParts[0] {
|
||||||
return n.children[i].recursiveSearch(lineParts[1:])
|
// decend into the matching node
|
||||||
|
if tmpl := n.children[i].recursiveSearch(lineParts[1:]); tmpl != nil {
|
||||||
|
// given a template is found return it
|
||||||
|
return tmpl
|
||||||
}
|
}
|
||||||
// Not an exact match, see if we have a wildcard child to search
|
|
||||||
if n.children[len(n.children)-1].value == "*" {
|
|
||||||
return n.children[len(n.children)-1].recursiveSearch(lineParts[1:])
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// given no template is found and the last child is a wildcard
|
||||||
|
if hasWildcard {
|
||||||
|
// also search the wildcard child node
|
||||||
|
return n.children[length].recursiveSearch(lineParts[1:])
|
||||||
|
}
|
||||||
|
|
||||||
|
// fallback to returning template at this node
|
||||||
return n.template
|
return n.template
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue