Erlang Gen_Event Behaviour

2009-03-29
Event Handling Principles
在Erlang OTP里,事件管理器(event manager)係一個用于處理事件的模塊,這些事件可能係錯誤、警報、或其他需要被記錄的信息。

在事件管理器里可能會有0個、1個或多個事件處理器(event handlers),當事件管理器接收到事件時,所有這些事件處理器都會對事件進行處理。比如有一個處理錯誤的事件管理器,它有一個默認的事件處理器將錯誤信息輸出到終端顯示;你可以為其添加另一個事件處理器,在特定情況下將錯誤信息寫入文件;當不再需要將信息寫入文件時,可以將這個事件處理器移除。

事件管理器實質上係一個接收事件的進程,而事件處理器則為一個回調模塊(callback module)。

Example
下例演示如何實現一個將錯誤信息輸出到終端的事件處理器:
-module(terminal_logger).
-behaviour(gen_event).
-export([init/1, handle_event/2, terminate/2]).

init(_Args) ->
{ok, []}.

handle_event(ErrorMsg, State) ->
io:format("***ERROR*** ~p\n", [ErrorMsg]),
{ok, State}.

terminate(_Args, _State) ->
ok.

而將錯誤信息寫入文件的事件處理器可以這樣寫:
-module(file_logger).
-behaviour(gen_event).
-export([init/1, handle_event/2, terminate/2]).

init(File) ->
{ok, Fd} = file:open(File, read),
%原文的打開方式係read,但我覺得應該是write或append吧
{ok, Fd}.

handle_event(ErrorMsg, Fd) ->
io:format(Fd, "***ERROR*** ~p\n", [ErrorMsg]),
{ok, Fd}.

terminate(_Args, Fd) ->
file:close(Fd).

下面會詳細講解上述代碼。

Starting an Event Manager
要啟動事件管理器來處理錯誤,可使用如下函數:
gen_event:start_link({local, error_man}).

這函數會新生并連接一個新進程,即事件管理器進程。參數{local, error_man}指定了該事件管理器的注冊名,此例中其注冊名為error_man,僅在本節點有效。如果不注冊一個名字,則必需通過事件管理器進程的進程標識PID來向其發送信息,注冊名也可以設置為{global, Name}。

如果事件管理器係屬於監督樹的一部分,則必需通過gen_event:start_link來啟動。另外有一個gen_event:start函數來啟動一個獨立的事件管理器~~

Adding an Event Handler
下例在shell里演示如何啟動一個事件處理器并為其添加一個事件處理器:
1> gen_event:start({local, error_man}).
{ok, <0.31.0>}
2> gen_event:add_handler(error_man, terminal_logger, []).
ok

上述函數向名為error_man的事件管理器發送一個事件,告訴它添加一個事件處理器terminal_logger,事件管理器會調用terminal_logger模塊的初始化函數terminal_logger:init([]),其中[]即add_handler函數里的第三個參數。init應該返回{ok, State},State即事件處理器的內部狀態。

Notifying About Events
3> gen_event:notify(error_man, no_reply).
***Error*** no_reply
ok

error_man係事件管理器的名字,no_reply係事件。事件會作為信息發送給事件管理器進程,接收到事件後,事件管理器會按照添加順序調用它每個事件處理器的handle_event(Event, State)函數來處理事件,這些函數都應返回{ok, State1},State1即事件處理器的新內部狀態。

Deleting an Event Handler
4> gen_event:delete_handler(error_man, terminal_logger, []).
ok

上述函數向名為error_man的事件管理器發送一個信息,告知它刪除事件處理器terminal_logger,事件管理器會調用terminal_logger模塊的terminate([], State)函數來終止該處理器。terminate函數應進行一些必要的清理工作等,其返回值會被忽略~~

Stopping
當事件管理器停止時,它會給机會給它的每一個事件處理器進行清理工作。如果該事件處理器係監督樹的一部分,事件管理器在必要的時候會被其監督者關閉;如果是一個獨立的事件管理器,則可調用如下函數去停止它:
>gen_event:stop(error_man).
ok

M-OSCAR | Powered by Blogger | Entries (RSS) | Comments (RSS) | Designed by MB Web Design | XML Coded By Cahayabiru.com