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.
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}
{register_event, Name}
{send_alarm, #alarm}
#alarm
into a
format suitable for the protocol that the adaptation implements.
{send_event, #event}
#event
into a
format suitable for the protocol the adaptation implements.
{unregister_alarm, Name}
{unregister_event, Name}
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.
aclear_alarm(FaultId)
clear_alarm(FaultId)
clear_alarm(FaultId, Time) -> ok
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()}]
Severity = severity()
For each alarm severity, it returns information on whether there is any active alarm for that severity or not.
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.
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.
Returns the number of active alarms in the system.
register_alarm(Name, Log, Class, Severity) -> boolean()
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()
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}
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}
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()
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()
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.
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.
alarm_first() -> {ok, Index} | '$end_of_table'
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'
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.
alarm_handler(3), gen_event(3), mnesia(3)