确保在 Erlang/OTP 中切换 gen_event 处理程序时处理事件
假设我有多个版本的 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
,但假设这是不可接受的。
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.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
OTP团队很擅长预见这样的需求; gen_event 有一个原子地交换事件处理程序的函数:
The OTP team is good at forseeing needs like this; gen_event has a function to swap event handlers atomically: