Event Transforms and Examples
I've added some of the examples from a forum thread on Event Transforms. Feel free to add your own or discuss the examples here.
One thing I've noticed that keeps tripping me up is that transforms need to be in the mapping they apply to. They usually will not work in the event class the mapping is in. So, if you have /App/Log/IN as an event mapping, putting a transform in /App/Log doesn't work - it never takes effect. You have to go into the event mapping, edit and put the transform there. One exception to this seems to be (for me) the /Perf/Filesystem event class, there it works as I would expect.
Contents
- 1 Beginner Examples
- 2 Dropping Events
- 3 BGP Event Enhancement
- 4 Interface High Utilization Event Enhancement
- 5 Assign Eventclasskey and Event Class to SNMP Traps and Syslog Messages
- 6 Modify Event Down to Specify Which Interface is Down
- 7 Automatically Clear event "Process not running" When the Process Is Restarted
- 8 Event Mapping Based on Interface Description
- 9 Event Mapping Based on Interface Description
- 10 Make Linux Load Averages Actual Values Instead of Raw Data
- 11 List All Event Transforms
Beginner Examples
From guyverix: Here is an example for beginners to be able to start manipulating events. The above stuff is great, but when you are starting out and dont know what is being manipulated and need somewhere to start, here you go, with some easier examples:
Basic transform: This assumes that you want the detail oid values as your message summary. This works well for simple transforms, but does not always work as you would think with string data.
evt.summary = getattr(evt, "--OID# from event Details--")
If the OID value has real string data that you want to display in your summary, try this:
evt.summary = str (getattr(evt, "--OID# from event Details--"))
Now to add different OIDs into your transform, as well as your own text:
(This is a load balancer trap)
evt.summary = "IP addr " + str (getattr(evt, "snL4TrapRealServerIP")) + " Name: " + str (getattr(evt, "snL4TrapRealServerName")) + " Port: " + str (getattr(evt, "snL4TrapRealServerPort")) + " real server port down."
Dropping Events
From nyeates: Following is a simple transform to drop all "oid XXXXXX is bad" events. This is as if the event never existed; the event is not stored in history.
if evt.message.find("Error reading value for") >= 0: evt._action = "drop"
From Zenoss:
# Drop certain trap events from specific interfaces on /Network/Switch devices if getattr(evt, 'agent', None) == 'zentrap' and evt.DeviceClass.startswith('/Network/Switch'): import re # Adjust the regex below to match the interface names you want to consider regex = re.compile('^(ge[-_\d\/.\/]+)$') interface_match = regex.match(component.id) if interface_match: evt._action = "drop"
In general this is a good "pattern" to follow for transforms. Pertinent points are:
- Always check the agent string e.g. if you want to only drops traps, say so ;-)
- Generally try to narrow down criteria for matching as quickly as possible, hence the combined "if a and b" on the first line in this example.
- Here we are checking the regex match against the component id ie the interface the event is for. Again, being very specific about what we want to drop is a good thing.
BGP Event Enhancement
From gentux31: We have a lot of customers that have a BGP session with us. When the event normally comes in you just get the message bgpBackwardTransition. So I wrote a event transform like this:
from socket import gethostbyaddr for attr in dir(evt): if attr.startswith('1.3.6.1.2.1.15.3.1.14.'): evt.bgpPeerIp = attr.replace('1.3.6.1.2.1.15.3.1.14.', '') try: evt.bgpPeerName = gethostbyaddr(evt.bgpPeerIp)[0] evt.summary = "bgpBackwardTransNotification from " + evt.bgpPeerIp + " (" + evt.bgpPeerName + ")" except Exception, ex: evt.exceptionString = str(ex) evt.summary = "bgpBackwardTransNotification from " + evt.bgpPeerIp
Interface High Utilization Event Enhancement
See http://wiki.zenoss.org/Transforms_-_Nice_Interface_Events
Assign Eventclasskey and Event Class to SNMP Traps and Syslog Messages
From Webpass: Here's some basic transforms to take syslog messages and SNMP traps from Adtran Netvanta devices and assign them an eventclasskey and an event class.. I just threw this in the /Unknown class transform.
import re match = re.search('OPERATING_SYSTEM:SESSION[^*]', evt.message) if match and device: evt.severity = 1 evt.eventClassKey = "AdtranLogin" evt.eventClass = "/Security/Auth/Login" match = re.search('(?<=IP:DNS CLIENT)(.*)', evt.message) if match and device: evt.severity = 1 evt.eventClassKey = "AdtranDNSTimeout" evt.eventClass = "/Net/NS" evt.summary = "DNS Client "+match.group(0) match = re.search('(?<=ETHERNET_INTERFACE:)([a-z0-9A-Z\-\/ ]*)([0-9*]\/[0-9]*)(.*)', evt.message) if match and device: evt.severity = 2 evt.eventClassKey = "ETHERNET_INTERFACE" evt.eventClass = "/Net/Link" evt.summary = match.group(0) evt.component = match.group(1)+match.group(2) match = re.search('(?<=ETHERNET_STATUS:)([a-z0-9A-Z\-\/ ]*)([0-9*]\/[0-9]*)(.*)', evt.message) if match and device: evt.severity = 2 evt.eventClassKey = "ETHERNET_STATUS" evt.eventClass = "/Net/Link" evt.summary = match.group(0) evt.component = match.group(1)+match.group(2) match = re.search('(?<=INTERFACE_STATUS:)([a-z0-9A-Z\-\/ ]*)([0-9*]\/[0-9]*)(.*)', evt.message) if match and device: evt.severity = 2 evt.eventClassKey = "INTERFACE_STATUS" evt.eventClass = "/Net/Link" evt.summary = match.group(0) evt.component = match.group(1)+match.group(2) match = re.search('Authentication Failure', evt.message) if match and device: evt.severity = 1 evt.eventClass = "/Security/Auth/Login"
Modify Event Down to Specify Which Interface is Down
From cluther: Try using the following (or something like it) in the transform for the linkUp and linkDown event mapping transforms. Zenoss should already know the description of your interfaces. So we'll just look it up.
index = getattr(evt, 'ifIndex', 0) descr = getattr(evt, 'ifDescr', 'Unknown Interface') evt.component = descr if device: description = '' for iface in device.os.interfaces(): if index and iface.ifindex == index: descr = iface.description elif descr and iface.name == descr: descr = iface.description evt.summary = 'Link down on %s' % (descr)
Automatically Clear event "Process not running" When the Process Is Restarted
From Florian Deckert: Here is an event transform that will automatically move to history a process restarted. when a linux process goes down, an event "Process not running" will be displayed. After the process is manually restarted, the alert is not automatically moved to history. This is because the event triggered when a process is starting is "Process up". If the summary is being changed to "Process not running" the dedup operation will link the UP event to the DOWN event, and then you can move the event to history.
import re sum=evt.summary if (sum.find("Process up:") >= 0): sum=re.sub ("Process up:", "Process not running:", sum) evt.summary=sum evt._action="history"
Event Mapping Based on Interface Description
Here's how : Follow the procedure here to set up the active monitoring of interface states : http://www.zenoss.com/Members/cluther/polling-interface-status/ Only the Event Class Transform is different :
if evt.summary.startswith('threshold of operational status'): fs_id = device.prepId(evt.component) for iface in device.os.interfaces(): if iface.id == fs_id: descr = iface.description if descr == '': descr = 'unknown' # evt.severity = 2 # set the event severity to Info # evt.eventState = 2 # suppress the event # evt._action = 'history' # send the event to history evt._action = 'drop' # drop the event if evt.severity > 0: evt.summary = 'Interface %s' % (evt.component) + ' (%s' % (descr) + '), changed state to down' else: evt.summary = 'Interface %s' % (evt.component) + ' (%s' % (descr) + '), changed state to up'
Event Mapping Based on Interface Description
Here's how : Follow the procedure here to set up the active monitoring of interface states : http://www.zenoss.com/Members/cluther/polling-interface-status/ Only the Event Class Transform is different :
if evt.summary.startswith('threshold of operational status'): fs_id = device.prepId(evt.component) for iface in device.os.interfaces(): if iface.id == fs_id: descr = iface.description if descr == '': descr = 'unknown' # evt.severity = 2 # set the event severity to Info # evt.eventState = 2 # suppress the event # evt._action = 'history' # send the event to history evt._action = 'drop' # drop the event if evt.severity > 0: evt.summary = 'Interface %s' % (evt.component) + ' (%s' % (descr) + '), changed state to down' else: evt.summary = 'Interface %s' % (evt.component) + ' (%s' % (descr) + '), changed state to up'
If the incoming event is about an interface without a description the event will be dropped. If you want to take a different action when such an event comes in just uncomment the appropriate line. Although, If there is a discription the interface it will be included in the event summary.
For example if device "rtr-test" with interface "FastEthernet0?/1" and description "switch01" goes down the event will be transformed from this :
device : rtr-test, component : FastEthernet0/1, eventClass : /Net/Link, summary : threshold of operational status exceeded : current value 2 ...to this : device : rtr-test, component : FastEthernet0/1, eventClass : /Net/Link, summary : Interface FastEthernet0/1 (switch01), changed state to down ...For those who need to match only certain descriptions can use this code : import re
if evt.summary.startswith('threshold of operational status'): fs_id = device.prepId(evt.component) for iface in device.os.interfaces(): if iface.id == fs_id: descr = iface.description match = re.search('(^switch|^ups|^tcm|^bc|server)', descr, re.I) if not match: # evt.severity = 2 # set the event severity to Info # evt.eventState = 2 # suppress the event # evt._action = 'history' # send the event to history evt._action = 'drop' # drop the event if evt.severity > 0: evt.summary = 'Interface %s' % (evt.component) + ' (%s' % (descr) + '), changed state to down' else: evt.summary = 'Interface %s' % (evt.component) + ' (%s' % (descr) + '), changed state to upIf the interface description does not meet one of the criteria (^switch|^ups|^tcm|^bc|server) it will be dropped.
The "re.I" flag makes the search case insensitive.
In this example the description needs to start with switch, ups, tcm or bc, or contain the word server.
From StrongD Fri Jun 5 09:49:44 -0500 2009 From: StrongD Date: Fri, 05 Jun 2009 09:49:44 -0500 Subject: 3 Solutions for Transform Message-ID: <20090605094944-0500@www.zenoss.com>
(1) Raw data
- 10.10.1.240
- UDP: [10.10.1.240]:51275
- .1.3.6.1.2.1.1.3.0 120:2:20:30.49
- .1.3.6.1.6.3.1.1.4.1.0 .1.3.6.1.6.3.1.1.5.3
- .1.3.6.1.2.1.2.2.1.1.16 16
- .1.3.6.1.2.1.2.2.1.2.16 FastEthernet0/16
- .1.3.6.1.2.1.2.2.1.3.16 ethernetCsmacd
- .1.3.6.1.4.1.9.2.2.1.1.20.16 "down"
- .1.3.6.1.6.3.18.1.3.0 10.10.1.240
- .1.3.6.1.6.3.18.1.4.0 "2acce55"
- .1.3.6.1.6.3.1.1.4.3.0 .1.3.6.1.4.1.9.1.429
(2) Transform
---------Good--------- index = None for key, value in evt.__dict__.items(): if key.startswith('1.3.6.1.2.1.2.2.1.1') >= 0: index = value break if index is not None: for obj in device.os.interfaces.objectItems(): if obj[1].ifindex == index: evt.component = obj[1].id evt.summary = "Interface " + evt.component + " is down" break --------Good (Recommended) -------------- evt.summary = evt.ifDescr + " is down!" evt.component = evt.ifDescr --------Good--------------- evt.summary = getattr(evt, "ifDescr") + " is down!" evt.component = getattr(evt, "ifDescr")
Notice: once MIB is imported into Zenoss, “ifDescr” should be used intead of “1.3.6.1.2.1.2.2.1.2.*”=== Change Severity Dependant on Count === From nyeates: Following is a simple transform to to increase the severity of an event, as more and more counts (repeats) of the event come in.
- Create the dedup id; This is what zenoss normally does to the event to ascertain if
- it is a duplicate (another occurance) of an existing event. We are doing it in this
- transform to be able to reference the count variable, which does not come with an
- incoming event.
dedupfields = [ evt.device, evt.component, evt.eventClass, evt.eventKey, evt.severity] if not evt.eventKey: dedupfields += [evt.summary] mydedupid = '|'.join(map(str, dedupfields))
- Get the event details (including count) from the existing event that is in the mysql database
em = dmd.Events.getEventManager() em.cleanCache() try: ed = em.getEventDetail(dedupid=mydedupid) mycount = ed.count except: mycount = 0 # Do what you like with the count; # In this example we up the severity to CRITICAL if the count is > 3 if mycount > 3: evt.severity = 5
Make Linux Load Averages Actual Values Instead of Raw Data
if evt.summary.startswith('threshold of high load exceeded'): import re m = re.search("current value ([\d]+)", evt.summary) if m: currentload = float(m.group(1)) / 100 evt.summary = "threshold of high load exceeded: current value %s" % (currentload) evt.message = "threshold of high load exceeded: current value %s" % (currentload)
List All Event Transforms
From cgriebel: Simple script to print out all event transforms
#!/usr/bin/env python import Globals from Products.ZenUtils.ZenScriptBase import ZenScriptBase dmd = ZenScriptBase(connect=True).dmd print "The following event classes have transforms associated with them:" for ec in [ ec for ec in dmd.Events.getSubOrganizers() if ec.transform ]: print ec.getOrganizerName() print ec.transform print 'X'*80
You may also want to look at here: https://zcaportal.org/wiki/bin/view/ZCA/ZCABestPractices#Transforms