-
Notifications
You must be signed in to change notification settings - Fork 154
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Multiline messages support #121
base: master
Are you sure you want to change the base?
Changes from all commits
d5c82ba
6e9eab3
317d8f6
000b000
5e73acf
b1c838f
e93e1ee
4a00937
537d32a
22cd07d
169a776
51c2b2d
5021ddf
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -15,16 +15,19 @@ | |
package fswatcher | ||
|
||
import ( | ||
"bytes" | ||
"io" | ||
"regexp" | ||
"strings" | ||
) | ||
|
||
type lineReader struct { | ||
lineDelimiter string | ||
remainingBytesFromLastRead []byte | ||
} | ||
|
||
func NewLineReader() *lineReader { | ||
func NewLineReader(lineDelimiter string) *lineReader { | ||
return &lineReader{ | ||
lineDelimiter: lineDelimiter, | ||
remainingBytesFromLastRead: []byte{}, | ||
} | ||
} | ||
|
@@ -41,19 +44,32 @@ func (r *lineReader) ReadLine(file io.Reader) (string, bool, error) { | |
err error | ||
buf = make([]byte, 512) | ||
n = 0 | ||
reg = regexp.MustCompile(r.lineDelimiter) | ||
) | ||
for { | ||
newlinePos := bytes.IndexByte(r.remainingBytesFromLastRead, '\n') | ||
if newlinePos >= 0 { | ||
newlinesLoc := reg.FindAllIndex(r.remainingBytesFromLastRead, 2) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In almost all cases the line delimiter will be |
||
var newlinePos int | ||
if newlinesLoc != nil { | ||
// if first found match is not the first symbol(s) | ||
newlinePos = newlinesLoc[0][0] | ||
if len(newlinesLoc) == 2 && newlinePos == 0 { | ||
// if first found match is message start symbol(s) | ||
newlinePos = newlinesLoc[1][0] | ||
} | ||
} | ||
if newlinePos != 0 { | ||
l := len(r.remainingBytesFromLastRead) | ||
result := make([]byte, newlinePos) | ||
copy(result, r.remainingBytesFromLastRead[:newlinePos]) | ||
copy(r.remainingBytesFromLastRead, r.remainingBytesFromLastRead[newlinePos+1:]) | ||
r.remainingBytesFromLastRead = r.remainingBytesFromLastRead[:l-(newlinePos+1)] | ||
return string(stripWindowsLineEnding(result)), false, nil | ||
return stripLineEnding(string(result)), false, nil | ||
} else if err != nil { | ||
if err == io.EOF { | ||
return "", true, nil | ||
result := make([]byte, len(r.remainingBytesFromLastRead)) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The application might be in the middle of writing a log line when we hit
so that we wait until the line is complete. |
||
copy(result, r.remainingBytesFromLastRead) | ||
r.remainingBytesFromLastRead = []byte{} | ||
return stripLineEnding(string(result)), true, nil | ||
} else { | ||
return "", false, err | ||
} | ||
|
@@ -67,12 +83,11 @@ func (r *lineReader) ReadLine(file io.Reader) (string, bool, error) { | |
} | ||
} | ||
|
||
func stripWindowsLineEnding(s []byte) []byte { | ||
if len(s) > 0 && s[len(s)-1] == '\r' { | ||
return s[:len(s)-1] | ||
} else { | ||
return s | ||
} | ||
func stripLineEnding(s string) string { | ||
// in standard delimiter case | ||
s = strings.TrimPrefix(s, "\n") | ||
s = strings.TrimSuffix(s, "\r") | ||
return s | ||
} | ||
|
||
func (r *lineReader) Clear() { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the user has an invalid regular expression in
line_delimiter
, grok_exporter should fail on startup with a reasonable error message. Please add a check for this tofunc (c *InputConfig) validate()
inconfigV3.go
.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you compile the regular expression when loading the config, you might as well store the result so that you don't need to compile it again here.