开发者

Ensuring an event is handled while switching gen_event handlers in Erlang/OTP

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 wron开发者_JAVA技巧g 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.


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, []}).
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜