From 12dc08260f1aecae8b6767f5ba0f9e5b90134cdc Mon Sep 17 00:00:00 2001 From: Edward Muller Date: Mon, 9 Feb 2015 12:55:50 -0800 Subject: [PATCH] Add support for RFC6587 Basically length prefixed RFC5424, using a custom scanner function --- rfc6587_test.go | 67 +++++++++++++++++++++++++++++++++++++++++++++++++ server.go | 37 ++++++++++++++++++++++++--- 2 files changed, 101 insertions(+), 3 deletions(-) create mode 100644 rfc6587_test.go diff --git a/rfc6587_test.go b/rfc6587_test.go new file mode 100644 index 0000000..d79be55 --- /dev/null +++ b/rfc6587_test.go @@ -0,0 +1,67 @@ +package syslog + +import ( + "bufio" + "bytes" + "fmt" + "strings" + "testing" +) + +func TestSingleSplit(t *testing.T) { + find := "I am test." + buf := strings.NewReader("10 " + find) + scanner := bufio.NewScanner(buf) + scanner.Split(rfc6587ScannerSplit) + if r := scanner.Scan(); !r { + t.Error("Expected Scan() to return true, but didn't") + } + if found := scanner.Text(); found != find { + t.Errorf("Expected the right ('%s') token, but got: '%s'\n", find, found) + } +} + +func TestMultiSplit(t *testing.T) { + find := []string{ + "I am test.", + "I am test 2.", + "hahahahah", + } + buf := new(bytes.Buffer) + for _, i := range find { + fmt.Fprintf(buf, "%d %s", len(i), i) + } + scanner := bufio.NewScanner(buf) + scanner.Split(rfc6587ScannerSplit) + + i := 0 + for scanner.Scan() { + i++ + } + + if i != len(find) { + t.Errorf("Expected to find %d items, but found: %d\n", len(find), i) + } +} + +func TestBadSplit(t *testing.T) { + find := "I am test.2 ab" + buf := strings.NewReader("9 " + find) + scanner := bufio.NewScanner(buf) + scanner.Split(rfc6587ScannerSplit) + if r := scanner.Scan(); !r { + t.Error("Expected Scan() to return true, but didn't") + } + if found := scanner.Text(); found != find[0:9] { + t.Errorf("Expected to find %s, but found %s.", find[0:9], found) + } + if r := scanner.Scan(); r { + t.Error("Expected Scan() to return false, but didn't") + } + if err := scanner.Err(); err == nil { + t.Error("Expected an error, but didn't get one") + } else { + t.Log("Error: ", err) + } + +} diff --git a/server.go b/server.go index d631644..b557e9a 100644 --- a/server.go +++ b/server.go @@ -2,14 +2,17 @@ package syslog import ( "bufio" + "bytes" "errors" "net" + "strconv" "sync" + "time" + "github.com/jeromer/syslogparser" "github.com/jeromer/syslogparser/rfc3164" "github.com/jeromer/syslogparser/rfc5424" - "time" ) type Format int @@ -17,6 +20,7 @@ type Format int const ( RFC3164 Format = 1 + iota // RFC3164: http://www.ietf.org/rfc/rfc3164.txt RFC5424 // RFC5424: http://www.ietf.org/rfc/rfc5424.txt + RFC6587 // RFC6587: http://www.ietf.org/rfc/rfc6587.txt ) type Server struct { @@ -37,7 +41,7 @@ func NewServer() *Server { return server } -//Sets the syslog format (RFC3164 or RFC5424) +//Sets the syslog format (RFC3164 or RFC5424 or RFC6587) func (self *Server) SetFormat(format Format) { self.format = format } @@ -154,8 +158,33 @@ type ScanCloser struct { closer TimeoutCloser } +func rfc6587ScannerSplit(data []byte, atEOF bool) (advance int, token []byte, err error) { + if atEOF && len(data) == 0 { + return 0, nil, nil + } + + if i := bytes.IndexByte(data, ' '); i > 0 { + pLength := data[0:i] + length, err := strconv.Atoi(string(pLength)) + if err != nil { + return 0, nil, err + } + if len(data) >= length+i+1 { + //Return the frame with the length removed + return length + i + 1, data[i+1 : length+i+1], nil + } + } + + // Request more data + return 0, nil, nil +} + func (self *Server) goScanConnection(connection net.Conn, needClose bool) { scanner := bufio.NewScanner(connection) + switch self.format { + case RFC6587: + scanner.Split(rfc6587ScannerSplit) + } var scanCloser *ScanCloser if needClose { @@ -170,10 +199,12 @@ func (self *Server) goScanConnection(connection net.Conn, needClose bool) { func (self *Server) scan(scanCloser *ScanCloser) { if scanCloser.closer == nil { + // UDP for scanCloser.Scan() { self.parser([]byte(scanCloser.Text())) } } else { + // TCP loop: for { select { @@ -202,7 +233,7 @@ func (self *Server) parser(line []byte) { switch self.format { case RFC3164: parser = self.getParserRFC3164(line) - case RFC5424: + case RFC5424, RFC6587: parser = self.getParserRFC5424(line) }