gen_event(3)

MODULE
gen_event - A Generic Event Handling Behavior.

DESCRIPTION

gen_event provides a general framework for building application specific event handling routines. Event managers can be built for tasks like:

    *   error logging

    *   alarm handling

    *   call record logging

    *   debugging

    *   equipment management.

All event handlers are written as generic event managers and share a common set of interface functions. The generic parts of the event manager contains functions for debugging, handling the termination of the parent, and error handling.

The idea is that a server, the event manager, implements all server specific parts, while event handlers are added in order to handle specific events. Each event handler should be implemented in a module (called the callback module). Each callback module contains callback functions (e.g. handle_event/2) which are called whenever the event manager receives a corresponding message.

Event handlers can be written which act on all events, on some of the events, or on some particular combination of events. Event handlers can also be manipulated at runtime. In particular, an event handler can be:

    *   installed

    *   removed

    *   replaced by a different handler

We can even install several event handlers in the same event manager.

The relationship between the generic interface functions (and received messages) and the callback functions can be illustrated as follows:
Callback module  gen_event
----------------         ---------
gen_event:add_handler  ----->
Module:init/1            <-----
gen_event:notify        ----->
Module:handle_event/2   <-----
gen_event:call          ----->
Module:handle_call/2    <-----
gen_event:delete_handler ----->
Module:terminate/2       <-----
gen_event:stop          ----->
Module:terminate/2       <-----
gen_event:swap_handler         ----->
Mod1:terminate/2         <-----
Mod2:init/1              <-----
Module:handle_info/2    <-----   other message
                                  received.

The event manager can be debugged using the sys module.

EXPORTS

start() -> ServerRet
start(Name) -> ServerRet
start_link() -> ServerRet
start_link(Name) -> ServerRet

    Types
        Name = {local, atom()} | {global, atom()}
        ServerRet = {ok, Pid} | {error, Reason}
        Pid = pid()
        Reason = {already_started, Pid} | term()

    This function starts an event manager. If the manager is started without Name, it can only be called by using the returned Pid identifier. If started with Name, the name is registered locally or globally.

    An event manager started with start/0 or start/1 does not care about the parent. This means that the parent is not handled explicitly in the generic manager part. If started in this manner, these functions must not be used if the event manager is a worker in a supervision tree.

    A manager started with start_link/0 or start_link/1 is initially linked to the caller - the parent - and it will terminate whenever the parent process terminates, with the same reason as the parent. An event manager always traps exit signals, so the terminate/2 callback function is called for each added event handler in order to clean up before termination. If started in this manner, these functions should be used if the event manager is a worker in a supervision tree.

stop(EventMgr) -> ok

    Types
        EventMgr = Name | {Name, Node} | {global, Name} | Pid
        Name = atom()
        Node = atom()
        Pid = pid()

    Terminates the event manager. The terminate/2 callback function is called for each added event handler in order to clean up. The Arg argument of each terminate/2 will have the value stop.

notify(EventMgr, Event) -> ok
sync_notify(EventMgr, Event) -> ok

    Types
        EventMgr = Name | {Name, Node} | {global, Name} | Pid
        Name = atom()
        Node = atom()
        Pid = pid()
        Event = term()

    Sends an event notification to the EventMgr event manager. The Event sent can be any Erlang term. However, the added event handlers must know about the term, and for this reason an event format must be specified for each event manager.

    The event manager calls each associated handle_event/2 callback function to inform each added event handler about the event.

    The notify/2 function is asynchronous, whereas sync_notify/2 is synchronous in the sense that it returns when all handlers have handled the Event.

add_handler(EventMgr, Handler, Args) -> ok | ErrorRet

    Types
        EventMgr = Name | {Name, Node} | {global, Name} | Pid
        Name = atom()
        Node = atom()
        Pid = pid()
        Handler = Module | {Module, Id}
        Module = atom()
        Id = term()
        Args = term()
        ErrorRet = term()

    This function adds a new event handler to the EventMgr event manager. The callback module of the event handler is Module and the name of the handler is Handler. The Id term is used to identify a specific handler when installing several handlers which all use the same callback module. Args is supplied with the Module:init(Args) call in order to initialize the event handler. ErrorRet is any unexpected return value from the init/1 function.

add_sup_handler(EventMgr, Handler, Args) -> ok | ErrorRet

    Types
        EventMgr = Name | {Name, Node} | {global, Name} | Pid
        Name = atom()
        Node = atom()
        Pid = pid()
        Handler = Module | {Module, Id}
        Module = atom()
        Id = term()
        Args = term()
        ErrorRet = term()

    Adds a new supervised event handler to the EventMgr event manager. The handler is added in the manner previously described for the add_handler/3 function.

    Whenever the process which evaluated this function terminates, the Handler is automatically deleted from the EventMgr. The Module:terminate/2 function is called in order to clean up with Arg equal to {stop, Reason}. Reason is the termination reason of the process.

    Whenever the Handler is deleted from the EventMgr, the process which evaluated this function receives the message {gen_event_EXIT, Handler, Reason}. Reason is one of the following:

        *   normal. The handler has been removed by the delete_handler/3 function, or remove_handler has been returned by a callback function (see below).

        *   shutdown. The EventMgr process terminates, or the parent process of the handler terminates (the parent process could have sent an explicit EXIT signal to the EventMgr process and expects a message in response).

        *   {swapped, NewHandler, NewParent}. The handler has been replaced by NewHandler (see below).

        *   Error. The handler crashed due to Error. Error is any Erlang term (term()).

delete_handler(EventMgr, Handler, Args) -> DelRet

    Types
        EventMgr = Name | {Name, Node} | {global, Name} | Pid
        Name = atom()
        Node = atom()
        Pid = pid()
        Handler = Module | {Module, Id}
        Module = atom()
        Id = term()
        Args = term()
        DelRet = term() | {error, module_not_found}

    Removes the event handler Handler from the EventMgr event manager. Args is supplied with the Module:terminate(Args, ...) call in order to clean up the handler. Normally, it is preferable if Args is the atom stop as described for stop/1.

    DelRet can be any Erlang term as returned from the Module:terminate/2 function. This value can be used later on as a start argument (Args = DelRet) in order to restart (re-add) the same event handler with its old internal state. See also swap_handler/3 below.

swap_handler(EventMgr, OldHandler, NewHandler) -> SwRet

    Types
        EventMgr = Name | {Name, Node} | {global, Name} | Pid
        Name = atom()
        Node = atom()
        Pid = pid()
        OldHandler = {Handler1, Args1}
        NewHandler = {Handler2, Args2}
        Handler1 = Module1 | {Module1, Id1}
        Handler2 = Module2 | {Module2, Id2}
        Module1 = Module2 = atom()
        Id1 = Id2 = term()
        Args1 = Args2 = term()
        SwRet = ok | {error, SwErr}
        SwErr = term()

    Removes the Handler1 event handler and installs the new Handler2 event handler. If appropriate, the new handler can inherit the internal state of the old handler.

    Module1:terminate(Args1, ...) is called to remove the old handler. The return value of the terminate/2 function is passed to the new handler as TermRet below. The new handler is initialized by calling the Module2:init({Args2, TermRet}) function in the new callback module. If an error occurs, the return value of the init/1 function is returned as SwErr. To ignore the internal state of the old handler, the TermRet value should be ignored in the init/1 function of the new handler.

    If Handler1 was added as a supervised handler, with the add_sup_handler/3 function for example, the Handler2 inherits the same parent. Thus, Handler2 will be supervised by the same process as Handler1.

swap_sup_handler(EventMgr, OldHandler, NewHandler) -> SwRet

    Types
        EventMgr = Name | {Name, Node} | {global, Name} | Pid
        Name = atom()
        Node = atom()
        Pid = pid()
        OldHandler = {Handler1, Args1}
        NewHandler = {Handler2, Args2}
        Handler1 = Module1 | {Module1, Id1}
        Handler2 = Module2 | {Module2, Id2}
        Module1 = Module2 = atom()
        Id1 = Id2 = term()
        Args1 = Args2 = term()
        SwRet = ok | {error, SwErr}
        SwErr = term()

    Removes the Handler1 event handler and installs the new Handler2 event handler in the same manner described for the swap_handler/3 function above.

    The Handler2 event handler will be supervised by the process that evaluated this function, in the manner described for the add_sup_handler/3 function above.

call(EventMgr, Handler, Query) -> Ret
call(EventMgr, Handler, Query, Timeout) -> Ret

    Types
        EventMgr = Name | {Name, Node} | {global, Name} | Pid
        Name = atom()
        Node = atom()
        Pid = pid()
        Handler = Module | {Module, Id}
        Module = atom()
        Id = term()
        Query = term()
        Timeout = int() > 0 | infinity
        Ret = Reply | {error, ErrCall}
        Reply = term()
        ErrCall = bad_module | term()

    Sends a request to the specified event handler Handler in the EventMgr event manager. Query can be any Erlang term, but it must be recognized by the event handler. To handle the request, the callback function Module:handle_call/2 is called. bad_module is returned if the Module event handler does not exist. Reply is the returned Reply value of the callback function, while ErrCall is returned as an error descriptor if the callback module fails.

    Timeout should be set to some reasonable value (in milliseconds). The special value infinity can be used if the user has no idea how long the request is supposed to take. If Timeout is not specified, the default value is 5000.

    If Timeout has an integer value and no response has been delivered within Timeout milliseconds, then the client will terminate with reason {timeout, {gen_event, call, [EventMgr, Handler, Query, Timeout]}}.

which_handlers(EventMgr) -> [Handler]

    Types
        EventMgr = Name | {Name, Node} | {global, Name} | Pid
        Name = atom()
        Node = atom()
        Pid = pid()
        Handler = Module | {Module, Id}
        Module = atom()
        Id = term()

    Asks the EventMgr event manager about active event handlers. This function returns a list of each added event handler.

Callback Functions

The following functions should be exported from a gen_event callback module.

EXPORTS

Module:init(Args) -> InitRes

    Types
        Args = term()
        InitRes = {ok, State} | Other
        State = term()
        Other = term()

    Whenever a new event handler is added to an event manager, the init/1 function in the specified callback module is called in order to initialise the handler. If the initialization function succeeds, it is supposed to return the initialized internal State of the handler. The State is passed to all subsequent callback function calls to the handler.

    The Args argument supplied to the init/1 function is the same argument that is supplied to, for example, the add_handler/3 function.

Module:handle_event(Event, State) -> EventRet

    Types
        Event = term()
        EventRet = {ok, State1} | {swap_handler, Args1, State1, Handler2, Args2} | remove_handler | Other
        Args1 = Args2 = term()
        State1 = State = term()
        Handler2 = Module | {Module, Id}
        Module = atom()
        Id = term()
        Other = term()

    For each event handler, this function is called by the event manager whenever the event manager has received an event. Event is the value sent with the gen_event:notify/2 function call. (Any other unmatched messages which are received by the event manager - such as {'EXIT', Pid, Why} - are processed using handle_info/2)

    Normally, the event handler returns a new state with {ok, State1} after the event has been processed. The event handler can also remove itself or swap to another handler. If the handler is removed (returned remove_handler), the terminate/2 callback function is called with remove_handler as the first argument. The swap procedure is the same as described for swap_handler/3.

    If the handle_event/2 function crashes, or returns Other, the Module:terminate/2 function is called in order to clean up (if possible) and the handler is removed from the event manager. The Arg argument of Module:terminate/2 is {error, Reason}, where Reason is {'EXIT', Why} if crashed, or Other.

Module:handle_call(Query, State) -> CallRet

    Types
        Query = term()
        CallRet = {ok, Reply, State1} | {swap_handler, Reply, Args1, State1, Handler2, Args2} | {remove_handler, Reply} | Other
        Reply = term()
        Args1 = Args2 = term()
        State1 = State = term()
        Handler2 = Module | {Module, Id}
        Module = atom()
        Id = term()
        Other = term()

    Handles a request generated by a call/3 function call. The request is dedicated to this handler. Query can be any Erlang term recognized by the event handler. The type of queries which are handled is a design issue. Reply is any Erlang term which represents the reply to the call. Reply is returned by the call/3 function.

    Normally, the event handler returns a new state with {ok, Reply, State1} after the call has been processed. The event handler can also decide to remove itself or to swap to another handler. If the handler should be removed (returned {remove_handler, Reply}), the terminate/2 callback function is called with remove_handler as the first argument. The swap procedure is the same as described for swap_handler/3.

    If the handle_call/2 function crashes, or returns Other, the Module:terminate/2 function is called in order to clean up (if possible) and the handler is removed from the event manager. The Arg argument of Module:terminate/2 is {error, Reason}, where Reason is {'EXIT', Why} if crashed, or Other.

Module:handle_info(Info, State) -> EventRet

    Types
        Info = term()
        EventRet = {ok, State1} | {swap_handler, Args1, State1, Handler2, Args2} | remove_handler | Other
        Args1 = Args2 = term()
        State1 = State = term()
        Handler2 = Module | {Module, Id}
        Module = atom()
        Id = term()
        Other = term()

    This callback function handles events other than notify and call, which are received by the event manager. Typical events, or messages, which are handled include:

        {'EXIT', Pid, Reason}:
            If the process traps exit signals, the corresponding messages are handled here.

        {nodedown, Node}:
            If another Erlang node is monitored, the corresponding nodedown message is handled here.

        Msg:
            All other messages, sent to the event manager using EventMgr ! Msg, are also handled here.

  Note:

Communication with the event manager should always go through the above interface functions.

The EventRet value is the same as for handle_event.

Module:terminate(Arg, State) -> TermRet

    Types
        Arg = stop | remove_handler | {error, term()} | {stop, term()} | term()
        TermRet = term()

    Cleans up the event handler before it is removed from the event manager. If Arg is stop or remove_handler, the event handler is supposed to be removed and no other handler is supposed to take over the internal state. In this case, TermRet is ignored.

    If another handler is taking over the internal state of this handler, this should be marked with Arg as some other Erlang term, swap for example. In this case, the event handler should return the internal state State, or parts of the state, in a way that is recognized by the handler which is supposed to take over.

    Arg is {error, Error} if a callback function has crashed or returned something inappropriate. Error is {'EXIT', Why} if it has crashed.

    Arg is {stop, Reason} if the parent of a supervised event handler has terminated. Reason is the termination reason for the parent process.

Module:code_change(OldVsn, State, Extra) -> {ok, NewState}

    Types
        OldVsn = undefined | term()
        State = term()
        Extra = term()
        NewState = term()

    This function is called when a code change is performed, which implies that the internal data structures of the Module event handler has changed. This function is supposed to convert the old state to the new one. OldVsn is the vsn attribute of the old version of the module. If no such attribute was defined, the atom undefined is sent. Extra is an optional term, which is typically defined in the release upgrade script.

System events

The gen_event behaviour generates the following system events, which are handled by the sys module:

    *   {in, Msg} when a message is received.

See also

sys(3)

AUTHORS
Joe Armstrong - joe@erix.ericsson.se
Magnus Froberg - magnus@erix.ericsson.se
Martin Bjorklund - mbj@erlang.ericsson.se