From 14d97e5416ef8c401fd11aafd0b44a26ad21f261 Mon Sep 17 00:00:00 2001 From: Daniel Nelson Date: Wed, 23 May 2018 16:37:14 -0700 Subject: [PATCH] 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 --- plugins/inputs/logparser/README.md | 1 + plugins/inputs/logparser/grok/grok.go | 17 +++++++++++++++++ plugins/inputs/logparser/grok/grok_test.go | 12 ++++++++++++ 3 files changed, 30 insertions(+) diff --git a/plugins/inputs/logparser/README.md b/plugins/inputs/logparser/README.md index cfa9d02b2..7a1df8bc8 100644 --- a/plugins/inputs/logparser/README.md +++ b/plugins/inputs/logparser/README.md @@ -104,6 +104,7 @@ You must capture at least one field per line. - ts-httpd ("02/Jan/2006:15:04:05 -0700") - ts-epoch (seconds since unix epoch, may contain decimal) - ts-epochnano (nanoseconds since unix epoch) + - ts-syslog ("Jan 02 15:04:05", parsed time is set to the current year) - ts-"CUSTOM" CUSTOM time layouts must be within quotes and be the representation of the diff --git a/plugins/inputs/logparser/grok/grok.go b/plugins/inputs/logparser/grok/grok.go index 47d4ecdf5..57d8691cf 100644 --- a/plugins/inputs/logparser/grok/grok.go +++ b/plugins/inputs/logparser/grok/grok.go @@ -32,6 +32,7 @@ var timeLayouts = map[string]string{ // will get handled in the ParseLine function. "ts-epoch": "EPOCH", "ts-epochnano": "EPOCH_NANO", + "ts-syslog": "SYSLOG_TIMESTAMP", "ts": "GENERIC_TIMESTAMP", // try parsing all known timestamp layouts. } @@ -44,6 +45,7 @@ const ( DROP = "drop" EPOCH = "EPOCH" EPOCH_NANO = "EPOCH_NANO" + SYSLOG_TIMESTAMP = "SYSLOG_TIMESTAMP" GENERIC_TIMESTAMP = "GENERIC_TIMESTAMP" ) @@ -112,6 +114,7 @@ type Parser struct { // layouts. foundTsLayouts []string + timeFunc func() time.Time g *grok.Grok tsModder *tsModder } @@ -174,6 +177,10 @@ func (p *Parser) Compile() error { p.loc, _ = time.LoadLocation("UTC") } + if p.timeFunc == nil { + p.timeFunc = time.Now + } + return p.compileCustomPatterns() } @@ -285,6 +292,16 @@ func (p *Parser) ParseLine(line string) (telegraf.Metric, error) { } else { 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: var foundTs bool // first try timestamp layouts that we've already found diff --git a/plugins/inputs/logparser/grok/grok_test.go b/plugins/inputs/logparser/grok/grok_test.go index a585140f6..1008ce941 100644 --- a/plugins/inputs/logparser/grok/grok_test.go +++ b/plugins/inputs/logparser/grok/grok_test.go @@ -970,3 +970,15 @@ func TestNewlineInPatterns(t *testing.T) { require.NoError(t, err) 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()) +}