Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 16 additions & 10 deletions format/automatic.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package format
import (
"bufio"
"bytes"
"errors"
"strconv"

"gopkg.in/mcuadros/go-syslog.v2/internal/syslogparser/rfc3164"
Expand Down Expand Up @@ -31,33 +30,40 @@ const (
detectedRFC6587 = iota
)

func detect(data []byte) (detected int, err error) {
/*
* Will always fallback to rfc3164 (see section 4.3.3)
*/
func detect(data []byte) int {
// all formats have a sapce somewhere
if i := bytes.IndexByte(data, ' '); i > 0 {
pLength := data[0:i]
if _, err := strconv.Atoi(string(pLength)); err == nil {
return detectedRFC6587, nil
return detectedRFC6587
}
// are we starting with <
if data[0] != '<' {
return detectedRFC3164
}

// is there a close angle bracket before the ' '? there should be
angle := bytes.IndexByte(data, '>')
if (angle < 0) || (angle >= i) {
return detectedUnknown, errors.New("No close angle bracket before space")
return detectedRFC3164
}

// if a single digit immediately follows the angle bracket, then a space
// it is RFC5424, as RFC3164 must begin with a letter (month name)
if (angle+2 == i) && (data[angle+1] >= '0') && (data[angle+1] <= '9') {
return detectedRFC5424, nil
return detectedRFC5424
} else {
return detectedRFC3164, nil
return detectedRFC3164
}
}
return detectedUnknown, nil
// fallback to rfc 3164 section 4.3.3
return detectedRFC3164
}

func (f *Automatic) GetParser(line []byte) LogParser {
switch format, _ := detect(line); format {
switch format := detect(line); format {
case detectedRFC3164:
return &parserWrapper{rfc3164.NewParser(line)}
case detectedRFC5424:
Expand All @@ -82,7 +88,7 @@ func (f *Automatic) automaticScannerSplit(data []byte, atEOF bool) (advance int,
return 0, nil, nil
}

switch format, err := detect(data); format {
switch format := detect(data); format {
case detectedRFC6587:
return rfc6587ScannerSplit(data, atEOF)
case detectedRFC3164, detectedRFC5424:
Expand Down
14 changes: 12 additions & 2 deletions internal/syslogparser/rfc3164/rfc3164.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,12 +43,22 @@ func (p *Parser) Location(location *time.Location) {
}

func (p *Parser) Parse() error {
tcursor := p.cursor
pri, err := p.parsePriority()
if err != nil {
return err
// RFC3164 sec 4.3.3
p.priority = syslogparser.Priority{13, syslogparser.Facility{Value: 1}, syslogparser.Severity{Value: 5}}
p.cursor = tcursor
content, err := p.parseContent()
p.header.timestamp = time.Now().Round(time.Second)
if err != syslogparser.ErrEOL {
return err
}
p.message = rfc3164message{content: content}
return nil
}

tcursor := p.cursor
tcursor = p.cursor
hdr, err := p.parseHeader()
if err == syslogparser.ErrTimestampUnknownFormat {
// RFC3164 sec 4.3.2.
Expand Down
49 changes: 49 additions & 0 deletions internal/syslogparser/rfc3164/rfc3164_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,10 @@ func (s *Rfc3164TestSuite) TestParser_NoTimestamp(c *C) {
now := time.Now()

obtained := p.Dump()

obtainedTime := obtained["timestamp"].(time.Time)
s.assertTimeIsCloseToNow(c, obtainedTime)

obtained["timestamp"] = now // XXX: Need to mock out time to test this fully
expected := syslogparser.LogParts{
"timestamp": now,
Expand All @@ -121,6 +125,43 @@ func (s *Rfc3164TestSuite) TestParser_NoTimestamp(c *C) {
c.Assert(obtained, DeepEquals, expected)
}

// RFC 3164 section 4.3.3
func (s *Rfc3164TestSuite) TestParser_NoPriority(c *C) {
buff := []byte("Oct 11 22:14:15 Testing no priority")

p := NewParser(buff)
expectedP := &Parser{
buff: buff,
cursor: 0,
l: len(buff),
location: time.UTC,
}

c.Assert(p, DeepEquals, expectedP)

err := p.Parse()
c.Assert(err, IsNil)

now := time.Now()

obtained := p.Dump()
obtainedTime := obtained["timestamp"].(time.Time)
s.assertTimeIsCloseToNow(c, obtainedTime)

obtained["timestamp"] = now // XXX: Need to mock out time to test this fully
expected := syslogparser.LogParts{
"timestamp": now,
"hostname": "",
"tag": "",
"content": "Oct 11 22:14:15 Testing no priority",
"priority": 13,
"facility": 1,
"severity": 5,
}

c.Assert(obtained, DeepEquals, expected)
}

func (s *Rfc3164TestSuite) TestParseHeader_Valid(c *C) {
buff := []byte("Oct 11 22:14:15 mymachine ")
now := time.Now()
Expand Down Expand Up @@ -375,3 +416,11 @@ func (s *Rfc3164TestSuite) assertRfc3164message(c *C, msg rfc3164message, b []by
c.Assert(obtained, Equals, msg)
c.Assert(p.cursor, Equals, expC)
}

func (s *Rfc3164TestSuite) assertTimeIsCloseToNow(c *C, obtainedTime time.Time) {
now := time.Now()
timeStart := now.Add(-(time.Second * 5))
timeEnd := now.Add(time.Second)
c.Assert(obtainedTime.After(timeStart), Equals, true)
c.Assert(obtainedTime.Before(timeEnd), Equals, true)
}
2 changes: 1 addition & 1 deletion server.go
Original file line number Diff line number Diff line change
Expand Up @@ -258,7 +258,7 @@ func (s *Server) parser(line []byte, client string, tlsPeer string) {

logParts := parser.Dump()
logParts["client"] = client
if logParts["hostname"] == "" && s.format == RFC3164 {
if logParts["hostname"] == "" && (s.format == RFC3164 || s.format == Automatic) {
if i := strings.Index(client, ":"); i > 1 {
logParts["hostname"] = client[:i]
} else {
Expand Down
19 changes: 19 additions & 0 deletions server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ type ServerSuite struct {
var _ = Suite(&ServerSuite{})
var exampleSyslog = "<31>Dec 26 05:08:46 hostname tag[296]: content"
var exampleSyslogNoTSTagHost = "<14>INFO leaving (1) step postscripts"
var exampleSyslogNoPriority = "Dec 26 05:08:46 hostname test with no priority - see rfc 3164 section 4.3.3"
var exampleRFC5424Syslog = "<34>1 2003-10-11T22:14:15.003Z mymachine.example.com su - ID47 - 'su root' failed for lonvick on /dev/pts/8"

func (s *ServerSuite) TestTailFile(c *C) {
Expand Down Expand Up @@ -184,6 +185,24 @@ func (s *ServerSuite) TestUDP3164NoTag(c *C) {
c.Check(handler.LastError, IsNil)
}

func (s *ServerSuite) TestUDPAutomatic3164NoPriority(c *C) {
handler := new(HandlerMock)
server := NewServer()
server.SetFormat(Automatic)
server.SetHandler(handler)
server.SetTimeout(10)
server.goParseDatagrams()
server.datagramChannel <- DatagramMessage{[]byte(exampleSyslogNoPriority), "127.0.0.1:45789"}
close(server.datagramChannel)
server.Wait()
c.Check(handler.LastLogParts["hostname"], Equals, "127.0.0.1")
c.Check(handler.LastLogParts["tag"], Equals, "")
c.Check(handler.LastLogParts["priority"], Equals, 13)
c.Check(handler.LastLogParts["content"], Equals, exampleSyslogNoPriority)
c.Check(handler.LastMessageLength, Equals, int64(len(exampleSyslogNoPriority)))
c.Check(handler.LastError, IsNil)
}

func (s *ServerSuite) TestUDP6587(c *C) {
handler := new(HandlerMock)
server := NewServer()
Expand Down