-
Notifications
You must be signed in to change notification settings - Fork 1
/
syslogparse.go
52 lines (44 loc) · 1.7 KB
/
syslogparse.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
package io
import (
"bufio"
"fmt"
"net"
"os"
"regexp"
)
// We support syslog messages as specified in https://www.rfc-editor.org/rfc/rfc3164
// Format of syslog event is "<PRI> MM DD TIMESTAMP HOSTNAME MSG"
// <PRI> can be handled by rsyslog (or other processes) already, thus I make this field optional
var syslogParser *regexp.Regexp = regexp.MustCompile(`(<\d{3,5}>)?(\w{3}) (\s\d|\d{2}) (\d\d:\d\d:\d\d) ([^\s]+) (.+)`)
// Format of syslog message *often* is "SERVICE: [DATA] MSG"; we only handle
// messages prefixed by "emblem_server_event:".
var msgGroup int = 6
var syslogMsgParser *regexp.Regexp = regexp.MustCompile(`([^:]+: )?(\[.+\] )?emblem_server_event: (.*)`)
// The data part of the mesasge should contain a SRC=... field that maps to an
// IPv4 or IPv6 field.
var dataGroup int = 3
var ipGroup = 1
var msgDataParser *regexp.Regexp = regexp.MustCompile(`SRC=([\d\.]+|[\d\w:\[\]]+)`)
func parseLine(line string, emblemPort int) *net.UDPAddr {
if syslogMatch := syslogParser.FindStringSubmatch(line); syslogMatch == nil {
return nil
} else if msgMatch := syslogMsgParser.FindStringSubmatch(syslogMatch[msgGroup]); msgMatch == nil {
return nil
} else if dataMatch := msgDataParser.FindStringSubmatch(msgMatch[dataGroup]); dataMatch == nil {
return nil
} else if addr, err := net.ResolveUDPAddr("udp", fmt.Sprintf("%s:%d", dataMatch[ipGroup], emblemPort)); err != nil || addr.IP.IsLoopback() {
return nil
} else {
return addr
}
}
func WatchSyslog(file *os.File, emblemPort int, c chan *net.UDPAddr) {
reader := bufio.NewReader(file)
for {
if line, err := reader.ReadString('\n'); err != nil {
return
} else if request := parseLine(line, emblemPort); request != nil {
c <- request
}
}
}