forked from ozonru/filebeat-throttle-plugin
-
Notifications
You must be signed in to change notification settings - Fork 0
/
rule.go
98 lines (80 loc) · 1.76 KB
/
rule.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
package throttleplugin
import (
"bytes"
"sort"
"strconv"
"sync"
"unsafe"
"github.com/elastic/beats/libbeat/beat"
)
var sbPool sync.Pool
func init() {
sbPool = sync.Pool{
New: func() interface{} {
return &bytes.Buffer{}
},
}
}
type Rule struct {
keys []string // sorted list of used keys is used for combining limiter key.
values []string // values to check against. order is the same as for keys.
limit int64
// baseKey contains strings representation of limit to increase Match performance.
// strconv.Itoa makes 2 allocations with 32 bytes for each call.
baseKey string
}
// NewRule returns new Rule instance.
func NewRule(fields map[string]string, limit int64) Rule {
var (
keys = make([]string, 0, len(fields))
values = make([]string, len(fields))
)
for k := range fields {
keys = append(keys, k)
}
sort.Strings(keys)
for i, k := range keys {
values[i] = fields[k]
}
return Rule{
keys: keys,
values: values,
limit: limit,
baseKey: strconv.FormatInt(limit, 10),
}
}
// Limit returns current limit.
func (r Rule) Limit() int64 {
return r.limit
}
// Match checks if event has the same field values as expected.
func (r Rule) Match(e *beat.Event) (ok bool, key string) {
b := sbPool.Get()
sb := b.(*bytes.Buffer)
sb.Reset()
defer func() {
sbPool.Put(b)
}()
sb.WriteString(r.baseKey)
sb.WriteByte(':')
for i, k := range r.keys {
v, err := e.GetValue(k)
if err != nil {
return false, ""
}
sv, ok := v.(string)
if !ok {
// only strings values are supported
return false, ""
}
if sv != r.values[i] {
return false, ""
}
sb.WriteString(sv)
sb.WriteByte(':')
}
buf := sb.Bytes()
// zero-allocation convertion from []bytes to string.
s := *(*string)(unsafe.Pointer(&buf))
return true, s
}