= Event Translator
:description: Overview and examples of event translator in {page-component-title}, which transforms and enhances data from events that other daemons generate.

The Event Translator can transform and enhance the data from {page-component-title} events that other daemons generate.
This feature enables better integration with external systems, based on data from sources internal and external to {page-component-title}.

When an event is published on the event bus for which the event translator has configuration, the translator clones the event and changes the new event's attributes (fields and parameters) as defined in the translator configuration.
These transformations can come as a result of SQL queries, regular expression matches, and string literals that are then assigned to attributes of the new event.

If you would like to generate multiple events from a single source event, you can add multiple `<mapping>` elements within the `<mappings>` for a UEI.

The `$\{OPENNMS_HOME}/etc/translator-configuration.xml` file contains elements and attributes that create and/or change the fields or parameters of one event and publish a new event with these changes.

TIP: If the configured UEI in the event-translation-spec ends with a `/`, it acts as a prefix wildcard. Any event whose UEI starts with that prefix will match. IE, configuring `uei.opennms.org/nodes/` would match `uei.opennms.org/nodes/nodeDown`, `uei.opennms.org/nodes/nodeUp`, etc.

== Examples

=== Example 1: Associate traps with a node other than the SNMP manager

The following example associates an event with a different node.
The typical case for this would be an SNMP manager that proxies informational messages from non-SNMP entities to {page-component-title} via an SNMP trap.
This lets you associate the traps with a node other than the SNMP manager (typically a passive node), making correlation much easier.

.`$\{OPENNMS_HOME}/etc/translator-configuration.xml`
[source, xml]
----
<?xml version="1.0" encoding="UTF-8"?>
<event-translator-configuration
xmlns="http://xmlns.opennms.org/xsd/translator-configuration"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" >
  <translation>
    <event-translation-spec uei="uei.opennms.org/mib2opennms/tspEventPCRRepetitionError">
      <!-- Each event can have 1 or more mappings. -->
      <mappings>
        <mapping>
          <!-- This mapping uses the SQL value type to query the DB and change the nodeid of the new event -->
          <assignment type="field" name="nodeid">
            <value type="sql" result="select node.nodeid from node, ipInterface where node.nodeLabel=? and ipinterface.ipaddr=? and node.nodeId=ipinterface.nodeid and ipInterface.isManaged != 'D' and node.nodeType != 'D'" >
              <!-- These are sub value types that are used as parameters to the above sql as in JDBC speak -->
              <value type="parameter" name=".1.3.6.1.4.1.6768.6.2.2.5.0" matches="^([A-z]+) ([0-9]+).*" result="${1}-${2}" />
              <value type="constant" result="169.254.1.1" />
            </value>
          </assignment>
        </mapping>
      </mappings>
    </event-translation-spec>
  </translation>
</event-translator-configuration>
----

In this example, the `nodeid` will be replaced with the resulting `nodeid` from the SQL query when an event with the UEI `uei.opennms.org/mib2opennms/tspEventPCRRepetitionError` is received.
The `?` in the SQL query are populated with the values obtained from the nested value elements.
The first of the nested value elements creates a result string from a regular expression match of the event parameter named `.1.3.6.1.4.1.6768.6.2.2.5.0`.
This example uses the string `DEMO 10 example server` to represent the value of the parameter.
The resulting match would produce `DEMO-10`.
The second nested value is a constant and simply returns the value `169.254.1.1`.
These are assembled into the SQL query.

[source, sql]
----
SELECT node.nodeid
FROM node, ipInterface
WHERE node.nodeLabel='DEMO-10'
    AND ipinterface.ipaddr='169.254.1.1'
    AND node.nodeId=ipinterface.nodeid
    AND ipInterface.isManaged != 'D'
    AND node.nodeType != 'D'
----

The value returned is then substituted for the existing nodeid into a new event cloned from the original event.

[[ga-event-translator-psk]]
=== Example 2: Create a PassiveStatusKeeper update event

The xref:reference:service-assurance/monitors/PassiveStatusMonitor.adoc#ref-passivestatuskeeper[PassiveStatusKeeper] feature provides a way to track service outages for synthetic nodes that are not directly pollable.
This example uses a trap from an Adtran TA 4303 to create a new passive status event.

To provide details for this device, we created SQL tables `etlookup` and `ta4303` within the {page-component-title} database to use as lookups.

.`$\{OPENNMS_HOME}/etc/translator-configuration.xml`
[source,xml]
----
<event-translation-spec uei="uei.opennms.org/vendor/adtran/traps/adta4303">
  <mappings>
    <mapping>
      <assignment type="field" name="uei">
        <value type="constant" result="uei.opennms.org/services/passiveServiceStatus" /><1>
      </assignment>
      <assignment type="field" name="passiveNodeLabel">
        <value type="constant" result="Switch - TA4303" /><2>
      </assignment>
      <assignment type="field" name="nodeid">
        <value type="constant" result="307" /><3>
      </assignment>
      <assignment type="parameter" name="passiveIpAddr">
        <value type="sql" result="select ta4303.ip from ta4303 where ta4303.slot=? and ta4303.port=? " ><4>
          <value type="parameter" name=".1.3.6.1.4.1.664.5.13.2.3.1.1" matches="^([0-9]+)" result="${1}" />
          <value type="parameter" name=".1.3.6.1.4.1.664.5.13.2.3.1.1" matches="^([0-9]+)" result="${2}" />
        </value>
      </assignment>
      <assignment type="parameter" name="portdesc"><5>
        <value type="sql" result="select ta4303.description from ta4303 where ta4303.slot=? and ta4303.port=? " >
          <value type="parameter" name=".1.3.6.1.4.1.664.5.13.2.3.1.1" matches="^([0-9]+)" result="${1}" />
          <value type="parameter" name=".1.3.6.1.4.1.664.5.13.2.3.1.1" matches="^([0-9]+)" result="${2}" />
        </value>
      </assignment>
      <assignment type="parameter" name="passiveServiceName">
        <value type="sql" result="select etlookup.output from etlookup where etlookup.variable='ta4303service' and etlookup.input=? " ><6>
          <value type="parameter" name="specific" matches="^([0-9]+)" result="${1}" />
        </value>
      </assignment>
      <assignment type="parameter" name="passiveStatus" >
        <value type="sql" result="select etlookup.output from etlookup where etlookup.variable='ta4303status' and etlookup.input=? " ><7>
          <value type="parameter" name="specific" matches="^([0-9]+)" result="${1}" />
        </value>
      </assignment>
    </mapping>
  </mappings>
</event-translation-spec>
----
<1> The PassiveStatusKeeper looks for this specific UEI.
<2> The `passiveNodeLabel` must match the label of the node.
This example hard codes the label, but this can also be a lookup from the original event's parameters.
<3> In practice, you would not want to hard code the node ID on the event.
<4> Since this is a passive node without a real IP address, this lookup uses the slot and port fields from the original event to query the database for a "dummy" IP assigned to the node.
<5> Look up the port description from our SQL table.
You can use this new parameter in the event and notifications as `%parm[portdesc]%`.
<6> The name of the xref:reference:service-assurance/monitors/PassiveStatusMonitor.adoc[PassiveStatusMonitor] service assigned to the node.
If more than one passive service is assigned to the same interface, this field is used to trigger outages on a specific service.
<7> Must be either "Up" or "Down" and is case sensitive.

=== Example 3: Include multiple category names in an event

If an SQL statement you want to read data with returns multiple rows, the event translator will give you only one result row for a new parameter.
A workaround is to create an aggregate function in PostgreSQL that accumulates the output to one single row.
A use case would be to include multiple categories' names into a nodeCategoryMembershipChanged event.

.Create SQL aggregate
[source, sql]
----
CREATE AGGREGATE array_accum (anyelement)
(
    sfunc = array_append,
    stype = anyarray,
    initcond = '{}'
);
----

.`$\{OPENNMS_HOME}/etc/translator-configuration.xml`
[source, xml]
----
<event-translation-spec uei="uei.opennms.org/nodes/nodeCategoryMembershipChanged">
  <mappings>
    <mapping>
      <assignment name="uei" type="field" >
        <value type="constant" result="uei.opennms.org/test/nodeCategoryMembershipChanged" />
      </assignment>
      <assignment name="categories" type="parameter">
        <value type="sql" result="select array_accum(categoryname) from categories,category_node,node where node.nodeid=?::integer and node.nodeid=category_node.nodeid and category_node.categoryid=categories.categoryid;" >
          <value type="field" name="nodeid" matches=".*" result="${0}" />
        </value>
      </assignment>
    </mapping>
  </mappings>
</event-translation-spec>
----
