-
-
Notifications
You must be signed in to change notification settings - Fork 0
/
syslog_parser.ex
126 lines (111 loc) · 3.65 KB
/
syslog_parser.ex
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
# SPDX-FileCopyrightText: 2017 Nerves Project Developers
#
# SPDX-License-Identifier: Apache-2.0
defmodule NervesLogging.SyslogParser do
@moduledoc """
Functions for parsing syslog strings
"""
@type severity ::
:alert | :critical | :debug | :emergency | :error | :info | :notice | :warning
@type facility ::
:kernel
| :user_level
| :mail
| :system
| :security_authorization
| :syslogd
| :line_printer
| :network_news
| :UUCP
| :clock
| :security_authorization
| :FTP
| :NTP
| :log_audit
| :log_alert
| :clock
| :local0
| :local1
| :local2
| :local3
| :local4
| :local5
| :local6
| :local7
@doc """
Parse out the syslog facility, severity, and message (including the timestamp
and host) from a syslog-formatted string.
The message is of the form:
```text
<pri>message
```
`pri` is an integer that when broken apart gives you a facility and severity.
`message` is everything else.
"""
@spec parse(String.t()) ::
{:ok, %{facility: facility(), severity: severity(), message: binary()}}
| {:error, :parse_error}
def parse(<<"<", pri, ">", message::binary>>) when pri >= ?0 and pri <= ?9 do
do_parse(pri - ?0, message)
end
def parse(<<"<", pri0, pri1, ">", message::binary>>)
when pri0 >= ?1 and pri0 <= ?9 and pri1 >= ?0 and pri1 <= ?9 do
do_parse((pri0 - ?0) * 10 + (pri1 - ?0), message)
end
def parse(<<"<", ?1, pri0, pri1, ">", message::binary>>)
when pri0 >= ?0 and pri0 <= ?9 and pri1 >= ?0 and pri1 <= ?9 do
do_parse(100 + (pri0 - ?0) * 10 + (pri1 - ?0), message)
end
def parse(_) do
{:error, :parse_error}
end
defp do_parse(pri, message) do
with {:ok, facility, severity} <- decode_priority(pri) do
{:ok, %{facility: facility, severity: severity, message: message}}
end
end
@doc """
Decode a syslog priority to facility and severity
"""
@spec decode_priority(0..191) :: {:ok, facility(), severity()} | {:error, :parse_error}
def decode_priority(priority) when priority >= 0 and priority <= 191 do
facility = div(priority, 8)
severity = Integer.mod(priority, 8)
{:ok, facility_name(facility), severity_name(severity)}
end
def decode_priority(_priority) do
{:error, :parse_error}
end
defp facility_name(0), do: :kernel
defp facility_name(1), do: :user_level
defp facility_name(2), do: :mail
defp facility_name(3), do: :system
defp facility_name(4), do: :security_authorization
defp facility_name(5), do: :syslogd
defp facility_name(6), do: :line_printer
defp facility_name(7), do: :network_news
defp facility_name(8), do: :UUCP
defp facility_name(9), do: :clock
defp facility_name(10), do: :security_authorization
defp facility_name(11), do: :FTP
defp facility_name(12), do: :NTP
defp facility_name(13), do: :log_audit
defp facility_name(14), do: :log_alert
defp facility_name(15), do: :clock
defp facility_name(16), do: :local0
defp facility_name(17), do: :local1
defp facility_name(18), do: :local2
defp facility_name(19), do: :local3
defp facility_name(20), do: :local4
defp facility_name(21), do: :local5
defp facility_name(22), do: :local6
defp facility_name(23), do: :local7
defp severity_name(0), do: :emergency
defp severity_name(1), do: :alert
defp severity_name(2), do: :critical
defp severity_name(3), do: :error
defp severity_name(4), do: :warning
defp severity_name(5), do: :notice
defp severity_name(6), do: :info
defp severity_name(7), do: :debug
end