2010-09-22 45 views
3

比方說,我有一個gen_event處理程序的多個版本,並希望改變周圍它們的程序運行時的處理:確保事件而在二郎山/ OTP開關gen_event處理

-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. 

很顯然,我可以切換他們通過刪除一個處理程序並添加另一個處理程序:

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

但是這留下了競爭條件的可能性;如果error_man只是在錯誤的時間收到一個事件,它不會被記錄。或者如果我改變了動作的順序,它會被記錄兩次,這也是不可取的。我如何確保一次處理它?

對於這種情況,我只需要一個處理程序並將日誌記錄級別保存爲State,但假設這不可接受。

回答

3

OTP團隊擅長這樣的需求; gen_event具有原子地swap event handlers的功能:

log_errors_only() -> 
    gen_event:swap_handler(error_man, 
          {logger_all, swapped_out}, 
          {logger_errors_only, []}).