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