# eva

### MODULE

eva

### MODULE SUMMARY

Client API for the Event and Alarm handling Functionality in the EVA Application

### DESCRIPTION

This module contains functions for the client API to the Event and Alarm handling application EVA. EVA is a distributed global application, which means that clients can access the EVA functionality from any node. There is a globally registered server called `eva_server` to which all requests are sent. The client functions for sending and clearing events and alarms exist in two variants; one asynchronous and one synchronous. The decision to use one or the other depends on how secure the delivery of events should be. If the asynchronous variant is used, the message may be lost if the node where the `eva_server` crashes after the message is sent, but before it is correctly received. The synchronous variant fails if it does not get an acknowledgment back from the server. In this case, it is up to the client application to decide what to do. It may, for example, wait a few seconds for another node to takeover the EVA application, and then try again.

An event is a notification sent from the NE to a management application. An event is uniquely identified by its name. A special form of an event is an alarm. An alarm represents a fault in the system that needs to be reported to the manager. An example of an alarm could be `equipment_on_fire`. When an alarm is sent, it becomes active and is stored in an active alarm list. When the application from which the alarm was sent notices that the fault that caused the alarm is not valid anymore, it clears the alarm. When an alarm is cleared, the alarm is deleted from the active alarm list, and an `clear_alarm` event is generated by EVA. Each fault may give rise to several alarms, maybe with different severities. There can, however, only be one active alarm for each fault at any one time. For example, associated with disk space usage may be two alarms, `disk_80_percent_filled` and `disk_90_percent_filled`. These two alarms represents the same fault, but only one of them can be active at the same time. An active alarm is identified by its fault_id. In contrast to alarms, ordinary events do not represent a fault, and they are not stored as the alarms in the active alarm list.

The basic EVA server is a global server to which all events and alarms are sent. The server updates its tables, the active alarm list for example, and sends the event or alarm to the `alarm_handler` process that runs on the same node as the global server. `alarm_handler` is a `gen_event` process defined in SASL.

EVA stores the definitions of events and alarms in the Mnesia tables `eventTable` and `alarmTable` respectively. As an alarm is a special form of an event, each alarm is present in both of these tables. The active alarm list is stored in the Mnesia table `alarm`. The records for all these tables are defined in the header file `eva.hrl`, available in the `include` directory in the distribution.

The EVA application provides functionality to send and to log events and alarms. The logs can be examined by a manager at a later time.

Before a client can send any events or alarms, the name of the event must be registered in EVA. To register an event, a client calls `register_event/2`. The parameters of this function are the name of the event and notification of whether the event should be logged by default or not. A manager can decide to change this value later. To register an alarm, a client calls `register_alarm/4`. The parameters of this function are the name and logging parameters as for events, and the class and default severity of the alarm.

### Adaptations and Subscriptions

The EVA services are management protocol independent. However, to provide EVA services to a manager, a management protocol is however needed. EVA uses adaptations for mapping of EVA services to specific protocols. Adaptations need access to the Mnesia tables used in EVA.

The event definitions are stored in the Mnesia table `eventTable`, and the alarm definitions in `alarmTable`. They are replicated to disk and RAM on each node that may run the EVA application. The tables are defined as follows:

    -record(eventTable, {name, log, generated}).
    -record(alarmTable, {name, class, severity}).

Each alarm is defined in both the event and alarm table, since an alarm is a special kind of event. `log` is a boolean which defines whether the event should be logged or not, `generated` is a counter that is incremented each time this event is sent, `class` and `severity` are as defined in `register_alarm/4` below.

The active alarm list is stored in the Mnesia table `alarm`. The `alarm` record is defined as:

    -record(alarm, {index, fault_id, name, sender,
                    cause, severity, time, extra}).

These records are defined in the file `include/eva.hrl`. To include this file in your code, use `-include_lib("eva/include/eva.hrl").`.

All these tables are part of the API, which means that they may be accessed and modified by any application, for example by an EVA adaptation. They must be accessed and modified within a transaction.

When an event or alarm is generated by an application, it is sent to the global eva server, which updates the Mnesia tables, and constructs a record that it sends to the local `alarm_handler` process in the SASL application. `alarm_handler` is a `gen_event` manager process, which means that eva server uses `gen_event:notify` to send the event or alarm record. An application which needs to subscribe to certain events, should write a `gen_event` handler module and install it in the `alarm_handler`. EVA adaptations should do this as well. The eva server sends the following gen_event notifications to `alarm_handler`:

`{register_alarm, Name}`
  Sent when an alarm has been registered.
`{register_event, Name}`
  Sent when an event has been registered.
`{send_alarm, #alarm}`
  Sent when an alarm is to be sent. The eva server sends this notification after the Mnesia tables have been updated. An adaptation should translate the `#alarm` into a format suitable for the protocol that the adaptation implements.
`{send_event, #event}`
  Sent when an event is to be sent. The eva server sends this notification after the Mnesia tables have been updated. An adaptation should translate the `#event` into a format suitable for the protocol the adaptation implements.
`{unregister_alarm, Name}`
  Sent when an alarm has been unregistered.
`{unregister_event, Name}`
  Sent when an event has been unregistered.

When an alarm is cleared, EVA generates an event called `clear_alarm`, where `#event.sender` is the index in the table `alarm`. For example, if an application calls `eva:clear_alarm(Fault)` and the fault was stored with index 6 in the active alarm list, the following `#event` is generated: `#event{name = clear_alarm, sender = 6}`.

The `clear_alarm` event is generated using `gen_event:sync_notify`, which means that all adaptations and subscribers are given a chance to take care of this event, before the alarm is deleted from the active alarm list.

### EXPORTS

`aclear_alarm(FaultId)`
`clear_alarm(FaultId)`
`clear_alarm(FaultId, Time) -> ok`

Types:

`FaultId = fault_id()`
`Time = integer() > 0 | infinity`

These functions are used to clear an active alarm. The `FaultId` is a term the uniquely identifies the fault. For example, the function `get_fault_id/0` can be used to generate a unique id.

`aclear_alarm/1` is an asynchronous function which just sends the clear alarm request to the global eva server. `clear_alarm/1,2` are synchronous functions that wait `Time` ms for an answer. If `Time` is not given, it defaults to 10000 ms.

If the server does not respond within the specified time, the function exits with reason `{timeout, _}`.

`get_alarm_status() -> [{Severity, boolean()}]`

Types:

`Severity = severity()`

For each alarm severity, it returns information on whether there is any active alarm for that severity or not.

`get_alarms(Item) -> [#alarm]`

Types:

`Item = {name, Name} | {sender, Sender}`
`Name = atom()`
`Sender = term()`

Returns all active alarms which match `Item`. This function can be used by a client to check if it has any active alarms defined when it starts. For each such alarm, it must be prepared to clear it. A client may, for example, at start-up perform a "self-test" to see which alarms should be active, and compare then this with what this function returns, and clear or send missing alarms.

`get_fault_id() -> fault_id()`

This function can be called before a client sends an alarm to obtain a globally unique fault identity that can be used in subsequent calls to `send_alarm` and `clear_alarm`.

This function does not communicate with the `eva_server`, it just constructs a unique reference and is therefore fast.

`get_no_alarms() -> integer()`

Returns the number of active alarms in the system.

`register_alarm(Name, Log, Class, Severity) -> boolean()`

Types:

`Name = atom()`
`Log = boolean()`
`Class = class()`
`Severity = severity()`
`class() = unknown | communications | qos | processing | equipment | environmental`
`severity() = indeterminate | critical | major | minor| warning`

Registers an alarm within EVA. An alarm must be registered before it is sent the first time. The registration information is stored persistently, so this function can be called just once. However, if EVA detects that the alarm is already registered, it discards the registration and returns `false`. Otherwise, it returns `true`.

The `Log` parameter defines if the alarm should be logged by default or not.

The `Class` and `Severity` parameters are originally defined in X.733, ITU Alarm Reporting Function.

`register_event(Name, Log) -> boolean()`

Types:

`Name = atom()`
`Log = boolean()`

Registers an event within EVA. An event must be registered before it is sent the first time. The registration information is stored persistently, so this function can be called just once. However, if EVA detects that the event is already registered, it discards the registration and returns `false`. Otherwise, it returns `true`.

The `Log` parameter defines if the event should be logged by default or not.

`asend_alarm(Name, FaultId, Sender, Cause, Extra)`
`send_alarm(Name, FaultId, Sender, Cause, Extra)`
`send_alarm(Name, FaultId, Sender, Cause, Extra, Time) -> ok | {error, Reason}`

Types:

`Name = atom()`
`FaultId = fault_id()`
`Sender = term()`
`Cause = term()`
`Extra = term()`
`Time = integer() > 0 | infinity`
`Reason = {no_such_alarm, Name} | {aborted, Name, R}`

These functions are used to send an alarm and make it active (stored in the active alarm list).

`Name` is the name of the alarm. The alarm must be registered before this function is called.

`FaultId` is a term the uniquely identifies the fault. For example, the function `get_fault_id/0` can be used to generate a unique id.

`Sender` is the object that generated the alarm. It could, for example, be a tuple `{board, 7}` or a registered name. This object should be fairly constant - not a Pid - so that it is possible to trace the sending object at a later time.

`Cause` is the cause of the alarm. It is recommended not to use strings as cause, to make it easier to match upon for other programs. For example a management application may want to translate the cause into another language.

`Extra` is any extra information which describes the alarm.

`asend_alarm/5` is an asynchronous function which just sends the alarm request to the global eva server. `send_alarm/5,6` are synchronous functions that wait `Time` ms for an answer. If `Time` is not given, it defaults to 10000 ms.

If the server does not respond within the specified time, the function exits with reason `{timeout, _}`.

`asend_event(Name, Sender, Extra)`
`send_event(Name, Sender, Extra)`
`send_event(Name, Sender, Extra, Time) -> ok | {error, Reason}`

Types:

`Name = atom()`
`Sender = term()`
`Extra = term()`
`Time = integer() > 0 | infinity`
`Reason = {no_such_event, Name} | {aborted, Name, R}`

These functions are used to send an event to the eva server.

`Name` is the name of the event. The event must be registered before this function is called.

`Sender` is the object that generated the event. It could, for example, be a tuple `{board, 7}` or a registered name. This object should be fairly constant - not a Pid - so that it is possible to trace the sending object at a later time.

`Extra` is any extra information which describes the event.

`asend_event/3` is an asynchronous function, that just sends the event request to the global eva server. `send_event/3,4` are synchronous functions that waits `Time` ms for an answer. If `Time` is not given, it defaults to 10000 ms.

If the server does not respond within the specified time, the function exits with reason `{timeout, _}`.

`unregister_alarm(Name) -> void()`

Types:

`Name = atom()`

Unregisters an alarm within EVA. This function should only be used when an alarm definition should be removed, due to a new release of the system, for example.

`unregister_event(Name) -> void()`

Types:

`Name = atom()`

Unregisters an event within EVA. This function should only be used when an event definition should be removed, due to a new release of the system, for example.

### Access Functions for the Active Alarm List

The active alarm list is stored in the Mnesia table `alarm`. This table is indexed by an integer `alarmIndex`. This integer is used to get the table ordered, with the latest sent alarm after the previous. Currently ordered Mnesia tables cannot be traversed in a convenient way and for this reason this module provides two functions to handle the traversal. These functions will be removed if ordered tables are implemented in Mnesia.

### EXPORTS

`alarm_first() -> {ok, Index} | '$end_of_table'`

Types:

`Index = integer()`

Returns the index of the first element in the alarm table. This is a temporary function which will be removed if ordered tables are implemented in Mnesia.

`alarm_next(Index) -> {ok, NextIndex} | '$end_of_table'`

Types:

`Index = NextIndex = integer()`

Returns the next index after `Index` in the alarm table. This is a temporary function which will be removed if ordered tables are implemented in Mnesia.

### See Also

alarm_handler(3), gen_event(3), mnesia(3)

### AUTHORS

Martin Björklund - support@erlang.ericsson.se

eva 2.0.2.1
Copyright © 1991-2002 Ericsson Utvecklings AB