이전 포스팅에 이어서 RFC5424 파싱을 추가 해 보았습니다.
RFC5424 generator는 아래 있는 걸 사용하였습니다.
정규식 검색해서 있는 거 편하게 가려고 했는데 지금 사용한 generator가 표준대로인지 아닌지 지금 확인하기가 어렵네요.
결국 직접 작성 해 보았습니다. 급조하게 작성해서 맹점이 있을지 모르니 선수님들의 고급스러운 정규식을 쓰시기를 바랍니다.
마무리가 급히 정리되어 죄송한 따름입니다.
그럼, 결과 확인을 해보실까요.
스크린숏을 보시면 2개의 generator에서 UDP 514를 송신하여 두 가지 포맷의 패킷을 수신할 수 있게 되었습니다.
package main
import (
"errors"
"fmt"
"net"
"regexp"
"strconv"
"time"
)
// mix RFC3164 and RFC5424
type syslog struct {
Version int // 0: RFC3164, 1: RFC5424, 2: RFC5424 // RFC5424 Version 2는 생략
Facility int
Datetime time.Time //hostname or IP address
Hostname string
Msg string
// RFC5424 only
Priority int
Application string
PID int
MessageID string
StructuredData string
}
// RFC3164 https://www.rfc-editor.org/rfc/rfc3164.html
// * regex -> https://regex101.com/library/97phrb
// RFC5424 https://www.rfc-editor.org/rfc/rfc5424
var regRFC3164 *regexp.Regexp
var regRFC5424 *regexp.Regexp // is next time
var facilityMap = map[int]string{
0: "kernel messages",
1: "user-level messages",
2: "mail system",
3: "system daemons",
4: "security/authorization messages",
5: "messages generated internally by syslogd",
6: "line printer subsystem",
7: "network news subsystem",
8: "UUCP subsystem",
9: "clock daemon",
10: "security/authorization messages",
11: "FTP daemon",
12: "NTP subsystem",
13: "log audit",
14: "log alert",
15: "clock daemon (note 2)",
16: "local use 0 (local0)",
17: "local use 1 (local1)",
18: "local use 2 (local2)",
19: "local use 3 (local3)",
20: "local use 4 (local4)",
21: "local use 5 (local5)",
22: "local use 6 (local6)",
23: "local use 7 (local7)",
}
func syslogParser(r []byte) (syslog, error) {
var log syslog
var err error
var rs [][]byte
// try RFC3164
rs = regRFC3164.FindSubmatch(r)
if len(rs) > 1 {
log.Version = 0
log.Facility, err = strconv.Atoi(string(rs[1]))
if err != nil {
return log, err
}
t, err := time.Parse("Jan _2 15:04:05", string(rs[2]))
if err != nil {
return log, err
}
t = t.AddDate(time.Now().Year(), 0, 0) // 년 보정
log.Datetime = t
log.Hostname = string(rs[3])
log.Msg = string(rs[4])
return log, err
}
rs = regRFC5424.FindSubmatch(r)
if len(rs) > 1 {
log.Priority, err = strconv.Atoi(string(rs[1]))
if err != nil {
return log, err
}
log.Datetime, err = time.Parse("2006-01-02T15:04:05.999999-07:00", string(rs[3]))
if err != nil {
return log, err
}
log.Version, err = strconv.Atoi(string(rs[2]))
log.Hostname = string(rs[4])
log.Application = string(rs[5])
log.PID, err = strconv.Atoi(string(rs[6]))
log.MessageID = string(rs[7])
log.StructuredData = string(rs[8])
log.Msg = string(rs[9])
return log, err
}
return log, errors.New("Not match")
}
func init() {
var err error
regRFC3164, err = regexp.Compile("<([0-9]{1,3})\\>([A-Za-z]{3} [0-9]{1,2} \\d{2}:\\d{2}:\\d{2}) ([\\S]+) ([\\S\\s]+)")
if err != nil {
fmt.Println(err.Error())
panic(err)
}
// 대충 짜서 현업에선 결점 주의, 검증 없이 대충 짜서 누락 되는건 보충 해주세요. 죄송합니다. 포스팅 fin하려다 보니...
regRFC5424, err = regexp.Compile("<([0-9]{1,3})\\>([0-9]) (([12]\\d{3}-0\\d|[1][012])-([012]\\d|3[01])T([01]\\d|2[0-4]):([0-5]\\d):([0-5]\\d|60)(?:\\.(\\d{1,6}))?(Z|[+-]\\d{2}:\\d{2})) [\\S]{1,255} [\\S]{1,255} [\\S]{1,255} [\\S]{1,255} [\\S]{1,255} ([\\S\\s]+)")
if err != nil {
fmt.Println(err.Error())
panic(err)
}
}
func main() {
var ServerAddr *net.UDPAddr
var err error
ServerAddr, err = net.ResolveUDPAddr("udp", "0.0.0.0:514")
if err != nil {
fmt.Println(err.Error())
panic(err)
}
ServerConn, err := net.ListenUDP("udp", ServerAddr)
if err != nil {
fmt.Println(err.Error())
panic(err)
}
defer ServerConn.Close()
serverConn := ServerConn
buf := make([]byte, 65535)
for {
n, addr, _ := serverConn.ReadFromUDP(buf)
if n != 0 {
address := addr.IP.String()
log, err := syslogParser(buf[:n])
if err != nil {
fmt.Println(err.Error())
continue
}
if log.Version == 0 {
fmt.Print(fmt.Sprintf(
`Version : RFC3164
IP Address : %s
Facility : %s
Datetime : %s
Hostname : %s
Message : %s
`,
address,
facilityMap[log.Facility],
log.Datetime.String(),
log.Hostname,
log.Msg,
))
} else {
fmt.Print(fmt.Sprintf(
`Version : RFC5424-%d
IP Address : %s
Priority : %d
Datetime : %s
Hostname : %s
Application : %s
PID : %d
MessageID : %s
StructureData : %s
Message : %s
`,
log.Version,
address,
log.Priority,
log.Datetime.String(),
log.Hostname,
log.Application,
log.PID,
log.MessageID,
log.StructuredData,
log.Msg,
))
}
fmt.Println("-----------------------------")
}
}
}
'Go언어 golang' 카테고리의 다른 글
golang REST API / go언어 REST API 서버 #5 METHOD GET item (0) | 2023.03.21 |
---|---|
golang REST API / go언어 REST API 서버. #2 docker mariadb 설치 및 접속 확인 (0) | 2023.03.16 |
golang Syslog server / Go언어 Syslog collector #2 파싱 (0) | 2023.03.11 |
golang Syslog server / Go언어 Syslog collector #1 (0) | 2023.03.10 |
golang pretty progress bar (0) | 2023.03.09 |