예전 포스팅에서 regRFC5424 을 간략하게 했었습니다.
마침 Grok 보고 있다가 RFC5424를 리팩토링 해보겠습니다.
여기가 주요 포인트 입니다.
g.Parse("<%{NUMBER:facility:int}>%{NUMBER:version:int} %{TIMESTAMP_ISO8601:datetime} %{USERNAME:hostname} %{DATA:application} %{DATA:structure_data} %{DATA:message_id} %{GREEDYDATA:msg}", string(r))
hostname, application, structure_data, message_id 는 명확하게 패턴을 몰라 USERNAME, DATA로 정의하였습니다.
미스매치 나는 로그가 있다면 상황에 따라 다른 패턴으로 정의 필요합니다.
다음과 같은 슛터에서 받은 로그만 제한적으로 테스트하였습니다.
슛터는 이전 포스팅에 있습니다.
샘플로그
<38>1 2023-03-28T20:51:31.014207+09:00 - ps 3499 ID665 [exampleSDID@55989 khh="Vtw"]
<60>1 2023-03-28T20:51:28.974364+09:00 190.174.201.31 find 3850 - [exampleSDID@79574 jcf="eM0N"] xLgFmB1gC5
<59>1 2023-03-28T20:51:27.968301+09:00 17.39.202.226 echo 8163 ID100 -
package main
import (
"fmt"
"net"
"regexp"
"strconv"
"time"
"github.com/vjeantet/grok"
)
// 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
//}
// RFC5424 Grok 적용해보기
//"<([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]+)"
// <159>1 2023-03-28T20:00:47.595639+09:00 woodmicrosystems.net make - ID662 [exampleSDID@17867 dlmzvy="ytcgegPske" uxjssi="us" xyjdpve="LRu"]
g, _ := grok.New()
values, err := g.Parse("<%{NUMBER:facility:int}>%{NUMBER:version:int} %{TIMESTAMP_ISO8601:datetime} %{USERNAME:hostname} %{DATA:application} %{DATA:structure_data} %{DATA:message_id} %{GREEDYDATA:msg}", string(r))
if err != nil {
return log, err
}
// err 처리 안하면 위험, 예제이니 생략함.
log.Facility, _ = strconv.Atoi(values["facility"])
log.Version, _ = strconv.Atoi(values["version"])
log.Hostname = values["hostname"]
log.Application = values["application"]
log.StructuredData = values["structure_data"]
log.MessageID = values["message_id"]
log.Msg = values["msg"]
t, err := time.Parse("2006-01-02T15:04:05.999999-07:00", values["datetime"])
if err != nil {
return log, err
}
log.Datetime = t
return log, nil
}
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하려다 보니...
// 지금 포스팅에서는 Grok으로 변경
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 elasticsearch / go언어 elasticsearch 사용하여 REST API 만들기 - #1 개발 환경 셋팅 (0) | 2023.04.11 |
---|---|
golang grok / go언어 grok 패턴 (0) | 2023.03.27 |
2023-03-24 json decoder 주석 허용 하는 기능 구현 (0) | 2023.03.24 |
golang JSON 설정 파일 로더 / JSON 주석 처리 (0) | 2023.03.23 |
golang REST API / go언어 REST API 서버 #6 PUT & DELETE (0) | 2023.03.22 |