eva(3)

MODULE
eva - 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)

AUTHOR
Martin Bjorklund - support@erlang.ericsson.se