forked from influxdata/telegraf
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmultiline.go
135 lines (115 loc) · 2.81 KB
/
multiline.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
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
package tail
import (
"bytes"
"fmt"
"regexp"
"strings"
"time"
"github.com/influxdata/telegraf/internal"
)
// Indicates relation to the multiline event: previous or next
type MultilineMatchWhichLine int
type Multiline struct {
config *MultilineConfig
enabled bool
patternRegexp *regexp.Regexp
}
type MultilineConfig struct {
Pattern string
MatchWhichLine MultilineMatchWhichLine `toml:"match_which_line"`
InvertMatch bool
Timeout *internal.Duration
}
const (
// Previous => Append current line to previous line
Previous MultilineMatchWhichLine = iota
// Next => Next line will be appended to current line
Next
)
func (m *MultilineConfig) NewMultiline() (*Multiline, error) {
enabled := false
var r *regexp.Regexp
var err error
if m.Pattern != "" {
enabled = true
if r, err = regexp.Compile(m.Pattern); err != nil {
return nil, err
}
if m.Timeout == nil || m.Timeout.Duration.Nanoseconds() == int64(0) {
m.Timeout = &internal.Duration{Duration: 5 * time.Second}
}
}
return &Multiline{
config: m,
enabled: enabled,
patternRegexp: r}, nil
}
func (m *Multiline) IsEnabled() bool {
return m.enabled
}
func (m *Multiline) ProcessLine(text string, buffer *bytes.Buffer) string {
if m.matchString(text) {
buffer.WriteString(text)
return ""
}
if m.config.MatchWhichLine == Previous {
previousText := buffer.String()
buffer.Reset()
buffer.WriteString(text)
text = previousText
} else {
// Next
if buffer.Len() > 0 {
buffer.WriteString(text)
text = buffer.String()
buffer.Reset()
}
}
return text
}
func (m *Multiline) Flush(buffer *bytes.Buffer) string {
if buffer.Len() == 0 {
return ""
}
text := buffer.String()
buffer.Reset()
return text
}
func (m *Multiline) matchString(text string) bool {
return m.patternRegexp.MatchString(text) != m.config.InvertMatch
}
func (w MultilineMatchWhichLine) String() string {
switch w {
case Previous:
return "previous"
case Next:
return "next"
}
return ""
}
// UnmarshalTOML implements ability to unmarshal MultilineMatchWhichLine from TOML files.
func (w *MultilineMatchWhichLine) UnmarshalTOML(data []byte) (err error) {
return w.UnmarshalText(data)
}
// UnmarshalText implements encoding.TextUnmarshaler
func (w *MultilineMatchWhichLine) UnmarshalText(data []byte) (err error) {
s := string(data)
switch strings.ToUpper(s) {
case `PREVIOUS`, `"PREVIOUS"`, `'PREVIOUS'`:
*w = Previous
return
case `NEXT`, `"NEXT"`, `'NEXT'`:
*w = Next
return
}
*w = -1
return fmt.Errorf("E! [inputs.tail] unknown multiline MatchWhichLine")
}
// MarshalText implements encoding.TextMarshaler
func (w MultilineMatchWhichLine) MarshalText() ([]byte, error) {
s := w.String()
if s != "" {
return []byte(s), nil
}
return nil, fmt.Errorf("E! [inputs.tail] unknown multiline MatchWhichLine")
}