-
Notifications
You must be signed in to change notification settings - Fork 0
/
syslogjd.nim
133 lines (108 loc) · 3.37 KB
/
syslogjd.nim
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
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
## syslogjd - syslog to Journald collector
# Copyright 2018 Federico Ceratto <[email protected]> <[email protected]>
# Released under GPLv3. See LICENSE file.
import net,
os,
sets
from posix import SIGABRT, SIGINT, SIGTERM, onSignal
from strutils import parseInt, split
from morelogging import sd_journal_send
const month_names = toSet(["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"])
onSignal(SIGABRT):
## Handle SIGABRT from systemd
echo "<2>Received SIGABRT"
quit(1)
var cnt = 0
onSignal(SIGINT, SIGTERM):
echo "syslogjd exiting..."
quit()
proc log_parsing_error(data: string, ipaddr: string) =
let msg = "Unable to parse '" & data & "' from " & ipaddr & " " & getCurrentExceptionMsg()
let rc = sd_journal_send(
"PRIORITY=7",
"SYSLOG_FACILITY=3",
"UNIT=syslogjd.service",
"SYSLOG_IDENTIFIER=syslogjd",
"SYSLOGJD_INTERNAL=error",
"MESSAGE=" & msg,
nil
)
type
Log = ref object
priority*, date*, hostname*, appname*, procid*, msgid*, msg*: string
is_rfc5424*: bool
proc parse_log*(rawlog: string): Log =
## Parse raw log message
#echo "-->" & rawlog & "<--"
result = Log()
if rawlog[0] != '<':
raise newException(Exception, "Unknown format")
let pos = rawlog.find('>')
if pos < 2:
raise newException(Exception, "Unknown format")
result.priority = rawlog[1..pos-1]
let body = rawlog[pos+1..^1]
if body.len < 2:
raise newException(Exception, "Unknown format")
if body[0..1] == "1 ":
# RFC5424
result.is_rfc5424 = true
(result.date, result.hostname, result.appname,
result.procid, result.msgid, result.msg) = body[2..^1].split(' ', maxsplit=5)
else:
# RFC3164 or unsupported
var month, day, hour: string
(month, day, hour, result.hostname, result.msg) = body.split(' ', maxsplit=5)
if not month_names.contains(month):
raise newException(Exception, "Unknown format")
result.date = month & " " & day & " " & hour
# prio = facility (0..23) * 8 + severity (0..7)
proc main() =
echo "starting syslogjd"
let port = 514.Port
var socket = newSocket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)
socket.setSockOpt(OptReusePort, true)
socket.setSockOpt(OptReuseAddr, true)
socket.bind_addr(port)
while true:
var data = ""
var ipaddr = ""
var remote_port: Port
let l = socket.recv_from(data, 65536, ipaddr, remote_port)
assert l == data.len
if l == 0:
continue
if data[data.high] == '\0':
data.setLen(data.len - 1)
try:
let log = parse_log(data)
if log.is_rfc5424:
let rc = sd_journal_send(
"SYSLOG_FACILITY=3",
"UNIT=syslogjd.service",
"SYSLOG_IDENTIFIER=syslogjd",
"PRIORITY=" & log.priority,
"TIMESTAMP=" & log.date,
"IPADDR=" & ipaddr,
"HOSTNAME=" & log.hostname,
"APPNAME=" & log.appname,
"PROCID=" & log.procid,
"MSGID=" & log.msgid,
"MESSAGE=" & log.msg,
nil
)
else:
let rc = sd_journal_send(
"SYSLOG_FACILITY=3",
"UNIT=syslogjd.service",
"SYSLOG_IDENTIFIER=syslogjd",
"PRIORITY=" & log.priority,
"TIMESTAMP=" & log.date,
"IPADDR=" & ipaddr,
"MESSAGE=" & log.msg,
nil
)
except:
log_parsing_error(data, ipaddr)
when isMainModule:
main()