Package ZenEvents :: Module SyslogProcessing
[hide private]
[frames] | no frames]

Source Code for Module ZenEvents.SyslogProcessing

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