Warning: strpos() [function.strpos]: Empty needle in /home/dealer/kasat/pkg/cahir/web/html/lib/plugins/translation2/action.php on line 53

Warning: Cannot modify header information - headers already sent by (output started at /home/dealer/kasat/pkg/cahir/web/html/lib/plugins/translation2/action.php:53) in /home/dealer/kasat/pkg/cahir/web/html/inc/actions.php on line 163
erlang:otp-event [Krystian Bacławski Wiki]
 

Szablon agenta obsługi zdarzeń

Opis działania

Agent zarządzający zdarzeniami może być przydatny przy konstrukcji uniwersalnego systemu logowania lub zbierania statystyk.

gen_event to w pewnym sensie demultiplekser zdarzeń:

  • trzyma listę modułów obsługujących zdarzenia,
  • umożliwia dynamiczne dodawanie, usuwanie i przeładowywanie modułów,
  • otrzymuje zdarzenia i przekazuje do wszystkich modułów,
  • oczekuje na odpowiedzi z modułów.

Ze względu na to, że wszystkie moduły wykonują się na koszt procesu gen_event, to agent musi być bardziej tolerancyjny na awarie w modułach obsługi zdarzeń. Jeśli obsługa zdarzenia w pewnym module się nie powiedzie i zostanie rzucony wyjątek do zostanie on przechwycony i przekazany do odpowiedniej procedury terminate/2.

Uwaga! gen_event przechwytuje domyślnie sygnały z procesów pochodnych!

Aby umożliwić pracę kilku modułów obsługi zdarzeń z tym samym modułem zawierającym funkcje zwrotne, wprowadzono możliwość powiązania z identyfikatora. Zatem moduł obsługi zdarzeń można specyfikować dwojako:

Handler = Module | {Module,Id}

Przykłady

System logowania

  1. niech każdy komunikat ma:
    • priorytet,
    • nazwę usługi, która go wygenerowała (autoryzacja, dekodowanie protokołu, baza danych, etc.);
  2. normalnie chcielibyśmy logować wszystko na dysk - tworzymy specyficzny moduł zapisu wszystkich zdarzeń do pliku;
  3. od czasu do czasu chcielibyśmy (np. w środowisku testowym) drukować specyficzne komunikaty na ekran, być może filtrować pod względem:
    • priorytetu,
    • nazwy usługi,
    • zawartości - dopasowywać wyrażeniem regularnym;
  4. w środowisku produkcyjnym komunikaty związane z niektórymi usługami chcemy ze względów bezpieczeństwa wysyłać przez sieć na centralny serwer logów;

Wszystkie logi będą wysyłane do gen_event nazywającego się our_logger. Tworzymy trzy moduły:

  • disk_logger - ten będzie dodany zawsze przy starcie our_logger,
  • devel_logger - ten będziemy dodawać na żądanie, jeśli zechcemy śledzić działający system w poszukiwaniu konkretnego błędu,
  • prod_logger - ten będzie dodane przy starcie our_logger na systemie produkcyjnym.

Zauważmy, że możemy chcieć w trakcie działania systemu:

  • zmieniać priorytet i zakres logowanych usług,
  • zmienić sposób logowania w systemie produkcyjnym (np. z syslog na bazę danych) - co wiąże się z wymianą modułu.

System zbierania statystyk

  1. niech każda statystka ma:
    • nazwę,
    • nazwę usługi, która ją wygenerowała,
  2. niech część statystyk odpowiada:
    • pojedynczemu zdarzeniu (np. nawiązano połączenie, zapisano plik, etc.),
    • wartości zebranej w ciągu jakiegoś czasu (np. przesłano n bajtów w ciągu sekundy, odczytano m plików, etc.),
  3. chcielibyśmy kumulować statystyki z poszczególnych usług
  4. jeśli któreś statystyki przekroczą dopuszczalne wartości - podjąć pewne działania (np. wszcząć alarm, zalogować, odpalić jakąś procedurę).

Część uniwersalna

Startowanie i zatrzymywanie

gen_event:start() -> Result
gen_event:start(EventMgrName) -> Result
gen_event:start_link() -> Result
gen_event:start_link(EventMgrName) -> Result
gen_event:stop(EventMgrRef) -> ok

EventMgrName podobnie jak w reszcie procesów OTP jest uchwytem po nazwie.

W wyniku startu możemy otrzymać:

{ok,Pid}
{error,{already_started,Pid}}

Zarządzanie modułami obsługi zdarzeń

Dodawanie

gen_event:add_handler(EventMgrRef, Handler, Args) -> Result
gen_event:add_sup_handler(EventMgrRef, Handler, Args) -> Result

Usuwanie

gen_event:delete_handler(EventMgrRef, Handler, Args) -> Result

Wymiana

gen_event:swap_handler(EventMgrRef, {Handler1,Args1}, {Handler2,Args2}) -> Result
gen_event:swap_sup_handler(EventMgrRef, {Handler1,Args1}, {Handler2,Args2}) -> Result

Listowanie

gen_event:which_handlers(EventMgrRef) -> [Handler]

Powiadamianie o zdarzeniach

gen_event:notify(EventMgrRef, Event) -> ok
gen_event:sync_notify(EventMgrRef, Event) -> ok

Żądania synchroniczne

gen_event:call(EventMgrRef, Handler, Request) -> Result
gen_event:call(EventMgrRef, Handler, Request, Timeout) -> Result

Moduły obsługi zdarzeń

Zwracane wartości

Wywołania asynchroniczne

{ok,NewState}
{ok,NewState,hibernate}
{swap_handler,Args1,NewState,Handler2,Args2}
remove_handler

Wywołania synchroniczne

{ok,Reply,NewState}
{ok,Reply,NewState,hibernate}
{swap_handler,Reply,Args1,NewState,Handler2,Args2}
{remove_handler, Reply}

Błędy

{stop,Reason}
stop
{error,{'EXIT',Reason}}
{error,Term}

Startowanie i kończenie

Module:init(InitArgs) -> {ok,State} | {ok,State,hibernate}
Module:terminate(Arg, State) -> term()

Wołane przez gen_event:add_handler/3 i gen_event:add_sup_handler/3.

Obsługa zdarzeń

Module:handle_event(Event, State) -> Result

Wołane przez gen_event:notify/2 i gen_event:sync_notify/2.

Obsługa wywołań synchronicznych

Module:handle_call(Request, State) -> Result

Wołane przez gen_event:call/3 i gen_event:call/4.

Obsługa komunikatów

Module:handle_info(Info, State) -> Result

Wymiana oprogramowania

Module:code_change(OldVsn, State, Extra) -> {ok, NewState}

Przykład

Moduł logujący na standardowe wyjście

 1: -module(terminal_logger).
 2: -behaviour(gen_event).
 3: -export([init/1, handle_event/2, terminate/2]).
 4:
 5: init(_Args) ->
 6:     {ok, []}.
 7:
 8: handle_event(ErrorMsg, State) ->
 9:     io:format("***Error*** ~p~n", [ErrorMsg]),
10:     {ok, State}.
11:
12: terminate(_Args, _State) ->
13:     ok.

Moduł logujący do pliku

 1: -module(file_logger).
 2: -behaviour(gen_event).
 3: -export([init/1, handle_event/2, terminate/2]).
 4:
 5: init(File) ->
 6:     {ok, Fd} = file:open(File, read),
 7:     {ok, Fd}.
 8:
 9: handle_event(ErrorMsg, Fd) ->
10:     io:format(Fd, "***Error*** ~p~n", [ErrorMsg]),
11:     {ok, Fd}.
12:
13: terminate(_Args, Fd) ->
14:     file:close(Fd).

Przykładowa sesja

> gen_event:start({local, error_man}).
{ok,<0.31.0>}
> gen_event:add_handler(error_man, terminal_logger, []).
ok
> gen_event:notify(error_man, no_reply).
***Error*** no_reply
ok
> gen_event:delete_handler(error_man, terminal_logger, []).
ok
> gen_event:stop(error_man).
ok

Źródła

 
erlang/otp-event.txt · Last modified: 2010/05/24 00:30 by Krystian Baclawski
 
Except where otherwise noted, content on this wiki is licensed under the following license:CC Attribution-Noncommercial-No Derivative Works 3.0 Unported
Recent changes RSS feed Donate Powered by PHP Valid XHTML 1.0 Valid CSS Driven by DokuWiki