1
2
3
4
5
6
7
8
9
10
11
12
13
14 __doc__ = """SyslogProcessing
15 Class for turning syslog events into Zenoss Events
16 """
17
18 import re
19 import logging
20 slog = logging.getLogger("zen.Syslog")
21 import socket
22
23 import Globals
24 from Products.ZenEvents.syslog_h import *
25 from Products.ZenUtils.IpUtil import isip
26
27
28
29
30
31
32 parsers = (
33
34 r"^(?P<summary>-- (?P<eventClassKey>MARK) --)",
35
36
37 r"^(?P<component>.+)\[(?P<ntseverity>\D+)\] (?P<ntevid>\d+) (?P<summary>.*)",
38
39
40 r"%CARD-\S+:(SLOT\d+) %(?P<eventClassKey>\S+): (?P<summary>.*)",
41
42
43 r"%(?P<eventClassKey>(?P<component>\S+)-\d-\S+): (?P<summary>.*)",
44
45
46 r"^(?P<ipAddress>\S+)\s+(?P<summary>(?P<eventClassKey>CisACS_\d\d_\S+)\s+(?P<eventKey>\S+)\s.*)",
47
48
49 r"device_id=\S+\s+\[\S+\](?P<eventClassKey>\S+\d+):\s+(?P<summary>.*)\s+\((?P<originalTime>\d\d\d\d-\d\d-\d\d \d\d:\d\d:\d\d)\)",
50
51
52
53 r"^\[[^:]+: (?P<component>[^:]+)[^\]]+\]: (?P<summary>.*)",
54
55
56 r"(?P<component>\S+)\[(?P<pid>\d+)\]:\s*(?P<summary>.*)",
57
58
59 r"(?P<component>\S+): (?P<summary>.*)",
60
61
62 r"^(?P<deviceModel>[^\[]+)\[(?P<deviceManufacturer>ADTRAN)\]:(?P<component>[^\|]+\|\d+\|\d+)\|(?P<summary>.*)",
63
64 r"^date=.+ (?P<summary>devname=.+ log_id=(?P<eventClassKey>\d+) type=(?P<component>\S+).+)",
65
66
67 r"^(?P<component>\S+)(\.|\s)[A-Z]{3} \d \S+ \d\d:\d\d:\d\d-\d\d:\d\d:\d\d \d{5} \d{2} \d{5} \S+ \d{4} \d{3,5} (- )*(?P<summary>.*) \d{4} \d{4}",
68
69
70 r"^Process (?P<process_id>\d+), Nbr (?P<device>\d+\.\d+\.\d+\.\d+) on (?P<interface>\w+/\d+) from (?P<start_state>\w+) to (?P<end_state>\w+), (?P<summary>.+)",
71
72
73
74 r"^\d+ \d+\/\d+\/\d+ \d+:\d+:\d+\.\d+ SEV=\d+ (?P<eventClassKey>\S+) RPT=\d+ (?P<summary>.*)",
75
76
77
78 r'^\d+:\d+:(?P<component>[^:]+):\d+-\w{3}-\d{4} \d{2}:\d{2}:\d{2}\.\d+:[^:]+:\d+:\w+:(?P<eventClassKey>[^:]+):(?P<summary>.*)',
79
80
81 r'^\d+-\w{3}-\d{4} \d{2}:\d{2}:\d{2}\.\d+:[^:]+:\d+:\w+:(?P<eventClassKey>[^:]+):(?P<summary>.*)',
82 )
83
84
85 compiledParsers = []
86 for regex in parsers:
87 keepEntry = True
88 if isinstance(regex, tuple):
89 regex, keepEntry = regex
90 try:
91 compiled = re.compile(regex)
92 compiledParsers.append((compiled, keepEntry))
93 except:
94 pass
95
96
98 """
99 Class to process syslog messages and convert them into events viewable
100 in the Zenoss event console.
101 """
102
103 - def __init__(self,sendEvent,minpriority,parsehost,monitor,defaultPriority):
104 """
105 Initializer
106
107 @param sendEvent: message from a remote host
108 @type sendEvent: string
109 @param minpriority: ignore anything under this priority
110 @type minpriority: integer
111 @param parsehost: hostname where this parser is running
112 @type parsehost: string
113 @param monitor: name of the distributed collector monitor
114 @type monitor: string
115 @param defaultPriority: priority to use if it can't be understood from the received packet
116 @type defaultPriority: integer
117 """
118 self.minpriority = minpriority
119 self.parsehost = parsehost
120 self.sendEvent = sendEvent
121 self.monitor = monitor
122 self.defaultPriority = defaultPriority
123
124
125 - def process(self, msg, ipaddr, host, rtime):
126 """
127 Process an event from syslog and convert to a Zenoss event
128
129 @param msg: message from a remote host
130 @type msg: string
131 @param ipaddr: IP address of the remote host
132 @type ipaddr: string
133 @param host: remote host's name
134 @type host: string
135 @param rtime: time as reported by the remote host
136 @type rtime: string
137 """
138 evt = dict(device=host,
139 ipAddress=ipaddr,
140 firstTime=rtime,
141 lastTime=rtime,
142 eventGroup='syslog')
143 slog.debug("host=%s, ip=%s", host, ipaddr)
144 slog.debug(msg)
145
146 evt, msg = self.parsePRI(evt, msg)
147 if evt['priority'] > self.minpriority: return
148
149 evt, msg = self.parseHEADER(evt, msg)
150 evt = self.parseTag(evt, msg)
151 if evt:
152
153 evt = self.buildEventClassKey(evt)
154 evt['monitor'] = self.monitor
155 self.sendEvent(evt)
156
157
159 """
160 Parse RFC-3164 PRI part of syslog message to get facility and priority.
161
162 @param evt: dictionary of event properties
163 @type evt: dictionary
164 @param msg: message from host
165 @type msg: string
166 @return: tuple of dictionary of event properties and the message
167 @type: (dictionary, string)
168 """
169 pri = self.defaultPriority
170 fac = None
171 if msg[:1] == '<':
172 pos = msg.find('>')
173 fac, pri = LOG_UNPACK(int(msg[1:pos]))
174 msg = msg[pos+1:]
175 elif msg and msg[0] < ' ':
176 fac, pri = LOG_KERN, ord(msg[0])
177 msg = msg[1:]
178 evt['facility'] = fac_names.get(fac,"unknown")
179 evt['priority'] = pri
180 evt['severity'] = self.defaultSeverityMap(pri)
181 slog.debug("fac=%s pri=%s", fac, pri)
182 slog.debug("facility=%s severity=%s", evt['facility'], evt['severity'])
183 return evt, msg
184
185
187 """
188 Default mapping from syslog priority to severity.
189
190 @param pri: syslog priority from host
191 @type pri: integer
192 @return: numeric severity
193 @type: integer
194 """
195 sev = 1
196 if pri < 3: sev = 5
197 elif pri == 3: sev = 4
198 elif pri == 4: sev = 3
199 elif pri == 5 or pri == 6: sev = 2
200 return sev
201
202
203 timeParse = \
204 re.compile("^(\S{3} [\d ]{2} [\d ]{2}:[\d ]{2}:[\d ]{2}) (.*)").search
205 notHostSearch = re.compile("[\[:]").search
207 """
208 Parse RFC-3164 HEADER part of syslog message. TIMESTAMP format is:
209 MMM HH:MM:SS and host is next token without the characters '[' or ':'.
210
211 @param evt: dictionary of event properties
212 @type evt: dictionary
213 @param msg: message from host
214 @type msg: string
215 @return: tuple of dictionary of event properties and the message
216 @type: (dictionary, string)
217 """
218 slog.debug(msg)
219 m = re.sub("Kiwi_Syslog_Daemon \d+: \d+: "
220 "\S{3} [\d ]{2} [\d ]{2}:[\d ]{2}:[^:]+: ", "", msg)
221 m = self.timeParse(msg)
222 if m:
223 slog.debug("parseHEADER timestamp=%s", m.group(1))
224 evt['originalTime'] = m.group(1)
225 msg = m.group(2).strip()
226 msglist = msg.split()
227 if self.parsehost and not self.notHostSearch(msglist[0]):
228 device = msglist[0]
229 if device.find('@') >= 0:
230 device = device.split('@', 1)[1]
231 slog.debug("parseHEADER hostname=%s", evt['device'])
232 msg = " ".join(msglist[1:])
233 evt['device'] = device
234 if isip(device):
235 evt['ipAddress'] = device
236 else:
237 if 'ipAddress' in evt:
238 del(evt['ipAddress'])
239 return evt, msg
240
241
243 """
244 Parse the RFC-3164 tag of the syslog message using the regex defined
245 at the top of this module.
246
247 @param evt: dictionary of event properties
248 @type evt: dictionary
249 @param msg: message from host
250 @type msg: string
251 @return: dictionary of event properties
252 @type: dictionary
253 """
254 slog.debug(msg)
255 for parser, keepEntry in compiledParsers:
256 slog.debug("tag regex: %s", parser.pattern)
257 m = parser.search(msg)
258 if not m:
259 continue
260 elif not keepEntry:
261 slog.debug("Dropping syslog message due to parser rule.")
262 return None
263 slog.debug("tag match: %s", m.groupdict())
264 evt.update(m.groupdict())
265 break
266 else:
267 slog.info("No matching parser: '%s'", msg)
268 evt['summary'] = msg
269 return evt
270
271
273 """
274 Build the key used to find an events dictionary record. If eventClass
275 is defined it is used. For NT events "Source_Evid" is used. For other
276 syslog events we use the summary of the event to perform a full text
277 or'ed search.
278
279 @param evt: dictionary of event properties
280 @type evt: dictionary
281 @return: dictionary of event properties
282 @type: dictionary
283 """
284 if evt.has_key('eventClassKey') or evt.has_key( 'eventClass'):
285 return evt
286 elif evt.has_key( 'ntevid'):
287 evt['eventClassKey'] = "%s_%s" % (evt['component'],evt['ntevid'])
288 elif evt.has_key( 'component'):
289 evt['eventClassKey'] = evt['component']
290 if evt.has_key( 'eventClassKey'):
291 slog.debug("eventClassKey=%s", evt['eventClassKey'])
292 try:
293 evt['eventClassKey'] = evt['eventClassKey'].decode('latin-1')
294 except:
295 evt['eventClassKey'] = evt['eventClassKey'].decode('utf-8')
296 else:
297 slog.debug("No eventClassKey assigned")
298 return evt
299