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