go-parsesyslog
fully implements the RFC3164 format including
timestamp parsing and optional tags.
Please note: the RFC is not providing any message length definition and explicity states that there
is "no ending delimiter to this part"
for this reason we are using the newline (\n
(ASCII: 10)) as delimiter. This will therefore truncate messages that
have a newline in it. Additionally the RFC does specify a timestamp format that has not provide any information about
the year. For this reason, we will interpret the year for the message as the current year.
Available fields in the LogMsg
:
AppName
: this represents theTAG
part ofTAG[pid]:
format (if given in the message) that is often used for the name off the application or process loggingProcID
: this represents thepid
part ofTAG[pid]:
format (if given in the message) that is often used for the process IDHostName
: this represents the hostname part of the RFC3164 messagePriority
: ThePriority
part of the messageFacility
: The facility calculated from thePriority
part of the messageSeverity
: The severity calculated from thePriority
part of the messageTimestamp
: The parsed timestamp of the RFC3164 message astime.Time
representationMessage
: The message part of the log message asbytes.Buffer
MsgLength
: The length of theMessage
(not including any header part)Type
: This will be always set toRFC3164
go-parsesyslog
is also fully (RFC5424) compliant. All available
fields are parsed and represented accordingly in the LogMsg
fields. Although the RFC5424 mandates a maximum length of
2048 bytes for a log message, go-parsesyslog
does only obey the message length given in the header of the message.
Available fields in the LogMsg
:
Priority
: this represents the PRI field of the headerProtoVersion
: this represents the VERSION field of the headerTimestamp
: this represents the TIMESTAMP field of the headerHostname
: this represents the HOSTNAME field of the headerAppName
: this represents the APP-NAME field of the headerProcID
: this represents the PROCID field of the headerMsgID
: this represents the MSGID field of the headerStructuredData
this represents fully parsed structured data as described in the STRUCTURED-DATA section of the RFCHasBOM
: is set totrue
if the log message starts with a BOMFacility
: The facility calculated from thePriority
part of the messageSeverity
: The severity calculated from thePriority
part of the messageMessage
: The message part of the log message asbytes.Buffer
MsgLength
: The length of theMessage
(not including any header part)Type
: This will be always set toRFC5424
go-parsesyslog
implements an interface
for various syslog formats, which makes it easy to extend your own log
parser. As long as the Parser
interface is satisfied, go-parsesyslog
will be able to work.
The interface looks as following:
type Parser interface {
ParseReader(io.Reader) (LogMsg, error)
ParseString(string) (LogMsg, error)
}
As you can see, the ParseReader()
method expects an io.Reader
interface as argument. This allows you to
easily parse your logs from any kind of source (STDIN, a file, a network socket...). ParseString() instead takes
a string and parses it accordingly.
This example code show how to parse a RFC3164 conformant message:
package main
import (
"fmt"
"github.com/wneessen/go-parsesyslog"
"github.com/wneessen/go-parsesyslog/rfc3164"
"os"
)
func main() {
msg := "<34>Oct 11 22:14:15 mymachine su: 'su root' failed for lonvick on /dev/pts/8\n"
p, err := parsesyslog.New(rfc3164.Type)
if err != nil {
fmt.Printf("failed to create RFC3164 parser: %s", err)
os.Exit(1)
}
lm, err := p.ParseString(msg)
if err != nil {
panic(err)
}
fmt.Printf("Log message: %+v", lm)
}
This example code show how to parse a RFC5424 conformant message:
package main
import (
"fmt"
"github.com/wneessen/go-parsesyslog"
"github.com/wneessen/go-parsesyslog/rfc5424"
"os"
)
func main() {
msg := `197 <165>1 2003-10-11T22:14:15.003Z mymachine.example.com evntslog - ID47 [exampleSDID@32473 iut="3" eventSource="Application" eventID="1011"][foo@1234 foo="bar" blubb="bluh"] \xEF\xBB\xBFAn application event log entry..."`
p, err := parsesyslog.New(rfc5424.Type)
if err != nil {
fmt.Printf("failed to create RFC3164 parser: %s", err)
os.Exit(1)
}
lm, err := p.ParseString(msg)
if err != nil {
panic(err)
}
fmt.Printf("Log message: %+v", lm)
}
An example implementation can be found in cmd/stdin-parser
$ $ echo -ne '197 <165>1 2003-10-11T22:14:15.003Z mymachine.example.com evntslog - ID47 [exampleSDID@32473 iut="3" eventSource="Application" eventID="1011"][foo@1234 foo="bar" blubb="bluh"] \xEF\xBB\xBFAn application event log entry...' | go run github.com/wneessen/go-parsesyslog/cmd/stdin-parser
This command will output:
Log message details:
+ Log format: RFC5424
+ Header:
- Priority: 165 (Facility: LOCAL4 / Severity: NOTICE)
- Protocol Version: 1
- Hostname: mymachine.example.com
- AppName: evntslog
- ProcID:
- MsgID: ID47
- Timestamp (UTC): 2003-10-11 22:14:15.003 +0000 UTC
+ Structured Data:
- ID: exampleSDID@32473
+ Param 0:
- Name: iut
- Value: 3
+ Param 1:
- Name: eventSource
- Value: Application
+ Param 2:
- Name: eventID
- Value: 1011
- ID: foo@1234
+ Param 0:
- Name: foo
- Value: bar
+ Param 1:
- Name: blubb
- Value: bluh
+ Message has BOM: true
+ Message Length: 25
+ Message: An application event l
Log parsed in 18.745µs
As the main intention of this library was for me to use it in a network service that parses incoming syslog messages,
quite some work has been invested to make go-parsesyslog
fast and memory efficient. We are trying to allocate as less
as possible and make use of buffered I/O where possible.
$ go test -run=X -bench=.\*ParseReader -benchtime=5s ./...
goos: linux
goarch: amd64
pkg: github.com/wneessen/go-parsesyslog
cpu: AMD Ryzen 9 3950X 16-Core Processor
BenchmarkRFC3164Msg_ParseReader-2 7971660 748.9 ns/op 96 B/op 4 allocs/op
BenchmarkRFC5424Msg_ParseReader-2 3458671 1734 ns/op 1144 B/op 16 allocs/op
PASS