Add special syslog timestamp parser that uses current year (#4190)

Previously it was impossible to parse syslog timestamps without the date
being reported as year 0, due to the year not being specified
This commit is contained in:
Daniel Nelson 2018-05-23 16:37:14 -07:00 committed by GitHub
parent 44e3b9bee3
commit 14d97e5416
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 30 additions and 0 deletions

View File

@ -104,6 +104,7 @@ You must capture at least one field per line.
- ts-httpd ("02/Jan/2006:15:04:05 -0700") - ts-httpd ("02/Jan/2006:15:04:05 -0700")
- ts-epoch (seconds since unix epoch, may contain decimal) - ts-epoch (seconds since unix epoch, may contain decimal)
- ts-epochnano (nanoseconds since unix epoch) - ts-epochnano (nanoseconds since unix epoch)
- ts-syslog ("Jan 02 15:04:05", parsed time is set to the current year)
- ts-"CUSTOM" - ts-"CUSTOM"
CUSTOM time layouts must be within quotes and be the representation of the CUSTOM time layouts must be within quotes and be the representation of the

View File

@ -32,6 +32,7 @@ var timeLayouts = map[string]string{
// will get handled in the ParseLine function. // will get handled in the ParseLine function.
"ts-epoch": "EPOCH", "ts-epoch": "EPOCH",
"ts-epochnano": "EPOCH_NANO", "ts-epochnano": "EPOCH_NANO",
"ts-syslog": "SYSLOG_TIMESTAMP",
"ts": "GENERIC_TIMESTAMP", // try parsing all known timestamp layouts. "ts": "GENERIC_TIMESTAMP", // try parsing all known timestamp layouts.
} }
@ -44,6 +45,7 @@ const (
DROP = "drop" DROP = "drop"
EPOCH = "EPOCH" EPOCH = "EPOCH"
EPOCH_NANO = "EPOCH_NANO" EPOCH_NANO = "EPOCH_NANO"
SYSLOG_TIMESTAMP = "SYSLOG_TIMESTAMP"
GENERIC_TIMESTAMP = "GENERIC_TIMESTAMP" GENERIC_TIMESTAMP = "GENERIC_TIMESTAMP"
) )
@ -112,6 +114,7 @@ type Parser struct {
// layouts. // layouts.
foundTsLayouts []string foundTsLayouts []string
timeFunc func() time.Time
g *grok.Grok g *grok.Grok
tsModder *tsModder tsModder *tsModder
} }
@ -174,6 +177,10 @@ func (p *Parser) Compile() error {
p.loc, _ = time.LoadLocation("UTC") p.loc, _ = time.LoadLocation("UTC")
} }
if p.timeFunc == nil {
p.timeFunc = time.Now
}
return p.compileCustomPatterns() return p.compileCustomPatterns()
} }
@ -285,6 +292,16 @@ func (p *Parser) ParseLine(line string) (telegraf.Metric, error) {
} else { } else {
timestamp = time.Unix(0, iv) timestamp = time.Unix(0, iv)
} }
case SYSLOG_TIMESTAMP:
ts, err := time.ParseInLocation("Jan 02 15:04:05", v, p.loc)
if err == nil {
if ts.Year() == 0 {
ts = ts.AddDate(timestamp.Year(), 0, 0)
}
timestamp = ts
} else {
log.Printf("E! Error parsing %s to time layout [%s]: %s", v, t, err)
}
case GENERIC_TIMESTAMP: case GENERIC_TIMESTAMP:
var foundTs bool var foundTs bool
// first try timestamp layouts that we've already found // first try timestamp layouts that we've already found

View File

@ -970,3 +970,15 @@ func TestNewlineInPatterns(t *testing.T) {
require.NoError(t, err) require.NoError(t, err)
require.NotNil(t, m) require.NotNil(t, m)
} }
func TestSyslogTimestampParser(t *testing.T) {
p := &Parser{
Patterns: []string{`%{SYSLOGTIMESTAMP:timestamp:ts-syslog} value=%{NUMBER:value:int}`},
timeFunc: func() time.Time { return time.Date(2018, time.April, 1, 0, 0, 0, 0, nil) },
}
require.NoError(t, p.Compile())
m, err := p.ParseLine("Sep 25 09:01:55 value=42")
require.NoError(t, err)
require.NotNil(t, m)
require.Equal(t, 2018, m.Time().Year())
}