Event Transforms and Examples

From Zenoss Wiki
This is the approved revision of this page, as well as being the most recent.
Jump to: navigation, search

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.

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.

  1. Create the dedup id; This is what zenoss normally does to the event to ascertain if
  2. it is a duplicate (another occurance) of an existing event. We are doing it in this
  3. transform to be able to reference the count variable, which does not come with an
  4. 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))
  1. 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