diff --git a/pkg/formatters/event_to_tag/event_to_tag.go b/pkg/formatters/event_to_tag/event_to_tag.go index aa9558fb..d633c5ff 100644 --- a/pkg/formatters/event_to_tag/event_to_tag.go +++ b/pkg/formatters/event_to_tag/event_to_tag.go @@ -10,6 +10,7 @@ package event_to_tag import ( "encoding/json" + "fmt" "io" "log" "os" @@ -87,13 +88,18 @@ func (t *toTag) Apply(es ...*formatters.EventMsg) []*formatters.EventMsg { if e == nil { continue } + if e.Tags == nil { + e.Tags = make(map[string]string) + } for k, v := range e.Values { for _, re := range t.valueNames { if re.MatchString(k) { - if e.Tags == nil { - e.Tags = make(map[string]string) + switch v := v.(type) { + case string: + e.Tags[k] = v + default: + e.Tags[k] = fmt.Sprint(v) } - e.Tags[k] = v.(string) if !t.Keep { delete(e.Values, k) } @@ -102,9 +108,38 @@ func (t *toTag) Apply(es ...*formatters.EventMsg) []*formatters.EventMsg { for _, re := range t.values { if vs, ok := v.(string); ok { if re.MatchString(vs) { - if e.Tags == nil { - e.Tags = make(map[string]string) + e.Tags[k] = vs + if !t.Keep { + delete(e.Values, k) } + } + } + } + } + } + return es +} + +func (t *toTag) Apply2(es ...*formatters.EventMsg) []*formatters.EventMsg { + for _, e := range es { + if e == nil { + continue + } + if e.Tags == nil { + e.Tags = make(map[string]string) + } + for k, v := range e.Values { + for _, re := range t.valueNames { + if re.MatchString(k) { + e.Tags[k] = fmt.Sprint(v) // always cast v results on extra allocations: Apply > Apply2 + if !t.Keep { + delete(e.Values, k) + } + } + } + for _, re := range t.values { + if vs, ok := v.(string); ok { + if re.MatchString(vs) { e.Tags[k] = vs if !t.Keep { delete(e.Values, k) diff --git a/pkg/formatters/event_to_tag/event_to_tag_test.go b/pkg/formatters/event_to_tag/event_to_tag_test.go index 61057e32..4b7458fd 100644 --- a/pkg/formatters/event_to_tag/event_to_tag_test.go +++ b/pkg/formatters/event_to_tag/event_to_tag_test.go @@ -9,7 +9,9 @@ package event_to_tag import ( + "fmt" "reflect" + "regexp" "testing" "github.com/openconfig/gnmic/pkg/formatters" @@ -42,6 +44,7 @@ var testset = map[string]struct { }, output: []*formatters.EventMsg{ { + Tags: map[string]string{}, Values: map[string]interface{}{}}, }, }, @@ -76,6 +79,7 @@ var testset = map[string]struct { }, output: []*formatters.EventMsg{ { + Tags: map[string]string{}, Values: map[string]interface{}{}}, }, }, @@ -109,6 +113,7 @@ var testset = map[string]struct { }, output: []*formatters.EventMsg{ { + Tags: map[string]string{}, Values: map[string]interface{}{}}, }, }, @@ -148,6 +153,7 @@ var testset = map[string]struct { }, output: []*formatters.EventMsg{ { + Tags: map[string]string{}, Values: map[string]interface{}{}}, }, }, @@ -171,6 +177,51 @@ var testset = map[string]struct { }, }, }, + "match_integer_value": { + processorType: processorType, + processor: map[string]interface{}{ + "value-names": []string{".*peer-as$"}, + "keep": true, + }, + tests: []item{ + { + input: nil, + output: nil, + }, + { + input: []*formatters.EventMsg{ + { + Values: map[string]interface{}{}}, + }, + output: []*formatters.EventMsg{ + { + Tags: map[string]string{}, + Values: map[string]interface{}{}}, + }, + }, + { + input: []*formatters.EventMsg{ + { + Values: map[string]interface{}{ + "name": "dummy", + "peer-as": 65000, + }, + }, + }, + output: []*formatters.EventMsg{ + { + Tags: map[string]string{ + "peer-as": "65000", + }, + Values: map[string]interface{}{ + "name": "dummy", + "peer-as": 65000, + }, + }, + }, + }, + }, + }, } func TestEventToTag(t *testing.T) { @@ -185,7 +236,7 @@ func TestEventToTag(t *testing.T) { } t.Logf("processor: %+v", p) for i, item := range ts.tests { - t.Run("uint_convert", func(t *testing.T) { + t.Run(name, func(t *testing.T) { t.Logf("running test item %d", i) outs := p.Apply(item.input...) for j := range outs { @@ -203,3 +254,63 @@ func TestEventToTag(t *testing.T) { } } } + +// Helper function to generate test messages +func generateTestMessages(count int) []*formatters.EventMsg { + messages := make([]*formatters.EventMsg, count) + for i := 0; i < count; i++ { + messages[i] = &formatters.EventMsg{ + Name: fmt.Sprintf("event%d", i), + Timestamp: int64(i), + Values: map[string]interface{}{ + fmt.Sprintf("key%d", i): fmt.Sprintf("value%d", i), + "staticKey": "staticValue", + fmt.Sprintf("tagw%d", i): fmt.Sprintf("value%d", i), + }, + } + } + return messages +} + +// Benchmark test for the Apply function +func BenchmarkApply(b *testing.B) { + // Create a toTag instance with sample regex patterns + toTagInstance := &toTag{ + valueNames: []*regexp.Regexp{ + regexp.MustCompile(`^key\d+$`), // Matches keys like "key1", "key2", etc. + }, + values: []*regexp.Regexp{ + regexp.MustCompile(`^value\d+$`), // Matches values like "value1", "value2", etc. + }, + Keep: false, + } + + // Generate a sample EventMsg array + eventMessages := generateTestMessages(10000) + // Benchmark the Apply function + b.ResetTimer() + for i := 0; i < b.N; i++ { + toTagInstance.Apply(eventMessages...) + } +} + +func BenchmarkApply2(b *testing.B) { + // Create a toTag instance with sample regex patterns + toTagInstance := &toTag{ + valueNames: []*regexp.Regexp{ + regexp.MustCompile(`^key\d+$`), // Matches keys like "key1", "key2", etc. + }, + values: []*regexp.Regexp{ + regexp.MustCompile(`^value\d+$`), // Matches values like "value1", "value2", etc. + }, + Keep: false, + } + + // Generate a sample EventMsg array + eventMessages := generateTestMessages(10000) + // Benchmark the Apply function + b.ResetTimer() + for i := 0; i < b.N; i++ { + toTagInstance.Apply2(eventMessages...) + } +}