SysLog Client
Recently I was consuming a binary log format and was wanting to send messages through to a syslog server from a Windows machine. I was looking up the RFC specification (RFC3164) for sending a message - below is a summary if anyone was interested in doing something similar.
Structure
A syslog message is made from 3 components, PRI (priority), HEADER and the MESSAGE. Example from the specification with some annotation
PRI HEADER MESSAGE
| <-----------------------> <-------------------------------------------->
| TIMESTAMP HOST TAG CONTENT
<---><-------------> <-------> <-> <---------------------------------------->
<134>Oct 11 22:14:15 mymachine su: 'su root' failed for lonvick on /dev/pts/8
PRI (Priority)
The priority of a syslog message is made up to two components; the facility and the severity.
- Encoded as a seven-bit ASCII in an eight-bit field
- The priority is encapsulated between angled brackets <0>
- It is calculated using the following formula
Priority = Facility x 8 + Severity
Facilities
Numerical Code | Facility |
---|---|
0 | kernel messages |
1 | user-level messages |
2 | mail system |
3 | system daemons |
4 | security/authorization messages (note 1) |
5 | messages generated internally by syslogd |
6 | line printer subsystem |
7 | network news subsystem |
8 | UUCP subsystem |
9 | clock daemon (note 2) |
10 | security/authorization messages (note 1) |
11 | FTP daemon |
12 | NTP subsystem |
13 | log audit (note 1) |
14 | log alert (note 1) |
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) |
Severity
Numerical Code | Severity |
---|---|
0 | Emergency: system is unusable |
1 | Alert: action must be taken immediately |
2 | Critical: critical conditions |
3 | Error: error conditions |
4 | Warning: warning conditions |
5 | Notice: normal but significant condition |
6 | Informational: informational messages |
7 | Debug: debug-level messages |
Header
- Header is made up of two components - the timestamp and the host which generated the message.
- Encoded as a seven-bit ASCII in an eight-bit field
Timestamp
- The time must directly follow the close of the angled brackets.
- Must be formatted as below
- Months formatted as Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec
- If the day of the month is less than 10 then use a space to pad not a leading zero
- Single space following the timestamp
Mmm dd hh:mm:ss
Jun 30 18:10:55
Jun 1 09:10:55
# Ruby example
Time.now.strftime("%b %e %k:%M:%S")
Hostname / IP Address
- Encoded as a seven-bit ASCII in an eight-bit field
- Either the hostname or an IP address can be used but not both.
- A space represents the end of the hostname field so the hostname should not contain one.
Message
- Generally encoded as a seven-bit ASCII - however encoding set is not enforced.
- Contains two parts, the TAG and the CONTENT
Tag
- Normally the name of the program or process which generated the message
- Alphanumeric
- Most not exceed 32 characters
- End delimiter is one of the following
- Left square bracket ‘[’
- Colon ‘:’
- Space
Content
- No ending delimiter
Basic Ruby Client
class Client
def initialize(host, port)
@host = host
@port = port
@sock = UDPSocket.new
end
def calculate_priority(severity, facility)
return facility * 8 + severity
end
def send(severity, facility, epoch, host, application, content)
priority = calculate_priority(severity, facility)
timestamp = Time.at(epoch).strftime("%b %e %k:%M:%S")
host = host.encode("ASCII-8BIT", :invalid => :replace, :undef => :replace, :replace => "?")
app = application.encode("ASCII-8BIT", :invalid => :replace, :undef => :replace, :replace => "?")
con = content.encode("ASCII-8BIT", :invalid => :replace, :undef => :replace, :replace => "?")
# structure packet
packet = [
"<#{priority}>", # PRI
"#{timestamp} #{host}", # HEADER
" #{application}: #{content}" # CONTENT
].join("").encode(Encoding::ASCII_8BIT)
@sock.send(packet, 0, @host, @port)
end
end