Question

Let's say I have several versions of a gen_event handler and want to change them around while the program is running:

-module(logger_all).
-behaviour(gen_event).
-export([init/1, handle_event/2, terminate/2]).
init(_Args) ->
    {ok, []}.
handle_event({Severity, ErrorMsg}, State) ->
    io:format("***~p*** ~p~n", [Severity, ErrorMsg]),
    {ok, State}.
terminate(_Args, _State) ->
    ok.

-module(logger_errors_only).
-behaviour(gen_event).
-export([init/1, handle_event/2, terminate/2]).
init(_Args) ->
    {ok, []}.
handle_event({error, ErrorMsg}, State) ->
    io:format("***Error*** ~p~n", [ErrorMsg]),
    {ok, State}.
handle_event({_, ErrorMsg}, State) ->
    {ok, State}. %% ignore everything except errors
terminate(_Args, _State) ->
    ok.

Obviously, I can switch them around by removing one handler and adding the other one:

log_errors_only() -> 
    gen_event:delete_handler(error_man, logger_all, []),
    gen_event:add_handler(error_man, logger_errors_only, []).

But this leaves a possibility of a race condition; if error_man receives an event just at the wrong time, it won't be logged. Or if I change the order of actions, it will be logged twice, which is also undesirable. How can I make sure it's handled precisely once?

For this case I can just have one handler and keep logging level as the State, but suppose this isn't acceptable.

Was it helpful?

Solution

The OTP team is good at forseeing needs like this; gen_event has a function to swap event handlers atomically:

log_errors_only() ->
    gen_event:swap_handler(error_man,
                           {logger_all, swapped_out},
                           {logger_errors_only, []}).
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top