Module: check_mk
Branch: master
Commit: b12c796a58efa9ddea2d0e6ca90882aeac138037
URL:
http://git.mathias-kettner.de/git/?p=check_mk.git;a=commit;h=b12c796a58efa9…
Author: Lars Michelsen <lm(a)mathias-kettner.de>
Date: Fri Dec 6 10:09:07 2013 +0100
Handling messages of special syslog format correctly
The syslog RFCs allow different formats of syslog messages. The
message parsing code in the event console does support several
formats and should be able to deal with all formats allowed by
the specifications. However, one format was not supported in
past versions. Those messages were simply dropped and only seen
in the logs of the event console, when rule execution debugging
is enabled.
These log entries look as follows:
<tt><5>SYSTEM_INFO: [WLAN-1] Performing Background Scan : channel 12, active,
28 TU</tt>
The specific part here is the missing date/time and missing hostname
information, which is sent by most syslog clients. The parser has been
changed to be able to parse this format. The event console adds the
current date/time to the event and the IP address of the sending
client as host information.
---
.werks/301 | 24 +++++++++++++++++++
ChangeLog | 3 +++
mkeventd/bin/mkeventd | 62 ++++++++++++++++++++++++++++++++++---------------
3 files changed, 70 insertions(+), 19 deletions(-)
diff --git a/.werks/301 b/.werks/301
new file mode 100644
index 0000000..1b19f1e
--- /dev/null
+++ b/.werks/301
@@ -0,0 +1,24 @@
+Title: Handling messages of special syslog format correctly
+Level: 1
+Component: ec
+Version: 1.2.3i8
+Date: 1386320542
+Class: feature
+
+The syslog RFCs allow different formats of syslog messages. The
+message parsing code in the event console does support several
+formats and should be able to deal with all formats allowed by
+the specifications. However, one format was not supported in
+past versions. Those messages were simply dropped and only seen
+in the logs of the event console, when rule execution debugging
+is enabled.
+
+These log entries look as follows:
+
+<tt><5>SYSTEM_INFO: [WLAN-1] Performing Background Scan : channel 12, active,
28 TU</tt>
+
+The specific part here is the missing date/time and missing hostname
+information, which is sent by most syslog clients. The parser has been
+changed to be able to parse this format. The event console adds the
+current date/time to the event and the IP address of the sending
+client as host information.
diff --git a/ChangeLog b/ChangeLog
index 7ba75cf..fb37ec6 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -7,6 +7,9 @@
Reporting & Availability:
* 0018 New option for displaying a legend for the colors used in the timeline...
+ Event Console:
+ * 0301 Handling messages of special syslog format correctly...
+
1.2.3i7:
Core & Setup:
diff --git a/mkeventd/bin/mkeventd b/mkeventd/bin/mkeventd
index 6e90fe2..df5aac8 100755
--- a/mkeventd/bin/mkeventd
+++ b/mkeventd/bin/mkeventd
@@ -991,22 +991,23 @@ class EventServer:
# Accept new connection on event unix socket
if self._eventsocket in readable:
- client_socket, addr_info = self._eventsocket.accept()
- client_sockets[client_socket.fileno()] = (client_socket, "")
+ client_socket, address = self._eventsocket.accept()
+ client_sockets[client_socket.fileno()] = (self._eventsocket.accept(),
address, "")
# Same for the TCP syslog socket
if self._syslog_tcp and self._syslog_tcp in readable:
- client_socket, addr_info = self._syslog_tcp.accept()
- client_sockets[client_socket.fileno()] = (client_socket, "")
+ client_socket, address = self._syslog_tcp.accept()
+ client_sockets[client_socket.fileno()] = (client_socket, address,
"")
# Read data from existing event unix socket connections
- for fd, (cs, previous_data) in client_sockets.items():
+ for fd, (cs, address, previous_data) in client_sockets.items():
if fd in readable:
# Receive next part of data
try:
new_data = cs.recv(4096)
except:
new_data = ""
+ address = None
# Put together with incomplete messages from last time
data = previous_data + new_data
@@ -1018,19 +1019,19 @@ class EventServer:
# Do we have any complete messages?
if '\n' in data:
complete, rest = data.rsplit("\n", 1)
- self.process_raw_lines(complete + "\n")
+ self.process_raw_lines(complete + "\n", address)
else:
rest = data # keep for next time
# Only complete messages
else:
if data:
- self.process_raw_lines(data)
+ self.process_raw_lines(data, address)
rest = ""
# Connection still open?
if new_data:
- client_sockets[fd] = (cs, rest)
+ client_sockets[fd] = (cs, address, rest)
else:
cs.close()
del client_sockets[fd]
@@ -1068,7 +1069,7 @@ class EventServer:
# Read events from builtin syslog server
if self._syslog != None and self._syslog.fileno() in readable:
- self.process_raw_lines(self._syslog.recv(4096))
+ self.process_raw_lines(*self._syslog.recvfrom(4096))
# Read events from builtin snmptrap server
if self._snmptrap != None and self._snmptrap.fileno() in readable:
@@ -1108,7 +1109,7 @@ class EventServer:
g_perfcounters.count_time("processing", elapsed)
# Takes several lines of messages, handles encoding and processes them separated
- def process_raw_lines(self, data):
+ def process_raw_lines(self, data, address = None):
lines = data.splitlines()
for line in lines:
line = line.rstrip()
@@ -1119,7 +1120,7 @@ class EventServer:
line = line.decode("latin-1")
if line:
- self.process_raw_data(self.process_line, line)
+ self.process_raw_data(self.process_line, (line, address))
def do_housekeeping(self):
with lock_eventstatus:
@@ -1450,11 +1451,14 @@ class EventServer:
syslog_facilities[facility], syslog_priorities[priority], count,
(100.0 * count / float(total_count))))
- def process_line(self, line):
+ def process_line(self, (line, address)):
line = line.rstrip()
if g_config["debug_rules"]:
- log(u"Processing message '%s'" % line)
- self.process_event(self.parse_event(line))
+ if address:
+ log(u"Processing message from %r: '%s'" % (address,
line))
+ else:
+ log(u"Processing message '%s'" % line)
+ self.process_event(self.parse_event(line, address))
def process_event(self, event):
# Rule optimizer
@@ -1748,7 +1752,7 @@ class EventServer:
return backedhost
- def parse_event(self, line):
+ def parse_event(self, line, address):
event = {}
try:
# Variant 1: plain syslog message without priority/facility:
@@ -1770,7 +1774,15 @@ class EventServer:
# - Leap seconds MUST NOT be used.
# <166>2013-04-05T13:49:31.685Z esx Vpxa: message....
- # Variant 2,3,4,5
+ # Variant 6: syslog message without date / host:
+ # <5>SYSTEM_INFO: [WLAN-1] Triggering Background Scan
+
+ # FIXME: Would be better to parse the syslog messages in another way:
+ # Split the message by the first ":", then split the syslog header
part
+ # and detect which information are present. Take a look at the syslog RFCs
+ # for details.
+
+ # Variant 2,3,4,5,6
if line.startswith('<'):
i = line.find('>')
prio = int(line[1:i])
@@ -1796,6 +1808,15 @@ class EventServer:
event['time'] = time.mktime(time.strptime(rfc3339_part[:19],
'%Y-%m-%dT%H:%M:%S'))
event.update(self.parse_syslog_info(line))
+ # Variant 6
+ elif len(line.split(': ', 1)[0].split(' ')) == 1:
+ event.update(self.parse_syslog_info(line))
+ # There is no datetime information in the message, use current time
+ event['time'] = time.time()
+ # There is no host information, use the provided address
+ if address and type(address) == tuple:
+ event["host"] = address[0]
+
# Variant 1,2,4
else:
month_name, day, timeofday, host, rest = line.split(None, 4)
@@ -1825,8 +1846,6 @@ class EventServer:
# A further problem here: we do not now wether the message is in DST
or not
event["time"] = time.mktime((year, month, day, hours,
minutes, seconds, 0, 0, lt.tm_isdst))
-
-
except Exception, e:
if g_config["debug_rules"]:
log('Got non-syslog message "%s" (%s)' % (line, e) )
@@ -1840,7 +1859,12 @@ class EventServer:
"time" : time.time(),
}
- event["host"] = self.translate_hostname(event["host"])
+ try:
+ event["host"] = self.translate_hostname(event["host"])
+ except Exception, e:
+ if g_config["debug_rules"]:
+ log('Unable to parse host "%s" (%s)' %
(event.get("host"), e))
+ event["host"] = ""
if g_config["debug_rules"]:
log('Parsed message:\n' +