确保在 Erlang/OTP 中切换 gen_event 处理程序时处理事件

发布于 2024-09-24 03:17:29 字数 1126 浏览 5 评论 0原文

假设我有多个版本的 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

她说她爱他 2024-10-01 03:17:29

OTP团队很擅长预见这样的需求; gen_event 有一个原子地交换事件处理程序的函数:

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

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, []}).
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文