riak / src / riak_eventer.erl

Diff from to

File src/riak_eventer.erl

 %% specific language governing permissions and limitations
 %% under the License.    
 %% @doc
-%% riak_eventer allows you to attach event handlers to a running Riak cluster to
-%% receive event notifications (in the form of Erlang messages) about what is happening
-%% in the application. 
+%% Riak events provide information about what is happening behind-the-scenes
+%% in a Riak cluster. 
-%% Events are generated using notify/1 or notify/3. Each event consists
-%% of a Module, an EventName, the Node on which the event is generated,
-%% and additional detail about the event.
+%% Events are generated using {@link notify/1} or {@link notify/3}. 
+%% Each event consists of a Module, an EventName, the Node on which 
+%% the event is generated, and additional detail about the event. 
-%% This is stored in a tuple of the form {event, {Module, EventName, Node, EventDetail}}.
-%% For example, a 'put' operation will generate an event such as 
-%% {event,{riak_vnode,put, 'node@hostname', ...}}.
+%% A process can register to receive evets using
+%% {@link add_handler/4}. Full ETS MatchSpec style matching is supported, allowing
+%% the process to receive a subset of events, if desired. Filtering occurs at the
+%% server level. 
-%% Event handlers are added via add_handler(Pid, Description, MatchHead, MatchGuard),
-%% and can be removed via remove_handler(Pid, MatchHead, MatchGuard).
-%% Full MatchSpec style matching is allowed (see
-%% to filter events at the server level, and the system fully supports registering 
-%% a single process for multiple events.
+%% An application can register multiple event handlers, and can register multiple
+%% filters for a single pid.
 %% Riak monitors running handlers, and automatically removes 
-%% handlers of dead processors.
+%% handlers of dead processors. Alternatively, an event handler
+%% can be removed using {@link remove_handler/3}.
 	 terminate/2, code_change/3]).
 -export([notify/1, notify/3]).
--export ([add_handler/4]).
--export ([remove_handler/1, remove_handler/3]).
--export ([remove_dead_handlers/0]).
+-export ([add_handler/4, remove_handler/3]).
 -define(REMOVE_INTERVAL, 5 * 1000).
     matchguard  % MatchGuard, defaults to []
+%% @type eventmessage() = {event, Event::event()}
+%% @type event() = {EventModule::atom(), EventName::atom(), Node::atom(), EventData::term()}
+%% @spec notify(Event :: event()) -> ok
+%% @doc Generate an event that will be sent to all
+%% handlers whose MatchSpecs match the event.
+notify(Event) ->
+    gen_server2:cast(riak_local_logger, {event, Event}),
+    gen_server2:cast(?MODULE, {event, Event}).
+%% @spec notify(EventModule :: atom(), EventName :: atom(), EventDetail :: term()) -> ok
+%% @equiv notify({EventModule, EventName, node(), EventDetail})
+notify(EventModule, EventName, EventDetail) ->
+    notify({EventModule, EventName, node(), EventDetail}).
+%% @spec 
+%% add_handler(Pid::pid(), Desc::string(), MatchHead::tuple(), MatchGuard::tuple()) -> ok
+%% EventMessage = eventmessage()
+%% @doc
+%% Register a process that will receive Riak events 
+%% generated by the cluster. Events are Erlang messages in the form 
+%% <code>{event, {EventModule, EventName, Node, EventData}}</code>.
+%% During operation, Riak generates events for reporting
+%% and monitoring purposes. By registering an event handler
+%% an application can choose to receive all or a subset of these events.
+%% Riak allows for an unlimited number of event handlers (bounded only by memory).
+%% When an event handler process dies, Riak automatically removes
+%% that event handler from the list of event handlers. Alternatively,
+%% an event handler can be programatically removed via the 
+%% {@link remove_handler/3} function.
+%% Event handlers are judged to be unique based on the Pid, MatchHead, and MatchGuard.
+%% In other words, multiple event handlers can be wired to the same pid so long as 
+%% either their MatchHead or MatchGuard is different. If add_handler/4 is called twice 
+%% with the same exact same Pid, MatchHead, and MatchGuard, then the old handler
+%% is replaced by the new handler.
+%% In addition, while registering an event handler, a 
+%% developer can choose to filter the events that the 
+%% event handler will receive. This filtering happens on 
+%% the node generating the event. Riak generates a large number
+%% of events, so tight filtering is a good idea in order to minimize
+%% network traffic.
+%% An event filter is specified using the MatchSpec syntax
+%% established by the ETS module. See 
+%% <a href="">ETS MatchSpec</a>
+%% for more information.
+%% Register for all events generated by the node 'riak@':
+%% <pre>
+%% RiakClient:add_event_handler(self(), "Description", {'_', '_', 'riak@', '_'}, [])).
+%% </pre>
+%% Register for all events generated by the riak_vnode module:
+%% <pre>
+%% RiakClient:add_event_handler(self(), "Description", {riak_vnode, '_', '_', '_'}, []))
+%% </pre>
+%% Register for all 'put', 'get', and 'delete' events generated by the riak_vnode module:
+%% <pre>
+%% MatchHead = {'$1', '$2', '_', '_'},
+%% MatchGuard = [
+%%   {'andalso', {'==', '$1', riak_vnode}, {'orelse', {'==', '$2', get}, {'==', '$2', put}, {'==', '$2', delete}}}
+%% ],
+%% RiakClient:add_event_handler(self(), "Description", MatchHead, MatchGuard).
+%% </pre>
+%% Events are sent once per matching filter. If a single process registers under more than
+%% one MatchSpecs, and an event matches both MatchSpecs, then the process will
+%% receive the event multiple times.
+%% The Description parameter is used to supply a human readable
+%% string used by monitoring software to displaying connected event handlers.
+%% Because of the way Riak shares information between clusters, it may be 
+%% a few seconds before events start being sent to the handler from all nodes.
+add_handler(Pid, Description, MatchHead, MatchGuard) ->
+    gen_server:call(?MODULE, {add_handler, Pid, Description, MatchHead, MatchGuard}).
+%% @spec remove_handler(Pid::pid(), MatchHead::tuple(), MatchGuard::list()) -> ok
+%% @doc
+%% Remove the previously registered event handler. The arguments
+%% supplied to remove_handler/3 must be the same arguments supplied to
+%% add_handler/4. remove_handler/3 returns 'ok' regardless of whether
+%% any event handlers are removed.
+%% Because of the way Riak shares information between clusters, it may be 
+%% a few seconds before events stop being sent to the handler.
+remove_handler(Pid, MatchHead, MatchGuard) ->
+    HandlerID = get_handler_id(Pid, MatchHead, MatchGuard),
+    gen_server:call(?MODULE, {remove_handler, HandlerID}).
 %% @private
 start_link() -> gen_server2:start_link({local, ?MODULE}, ?MODULE, [], []).
+%% @private
 start_link(test) -> % when started this way, run a mock server (nop)
     gen_server2:start_link({local, ?MODULE}, ?MODULE, [test], []).
 %% @private
 init([]) -> {ok, stateless_server};
 init([test]) -> {ok, test}.
-notify(Event) ->
-    gen_server2:cast(riak_local_logger, {event, Event}),
-    gen_server2:cast(?MODULE, {event, Event}).
-notify(Module, EventName, EventDetail) ->
-    notify({Module, EventName, node(), EventDetail}).
-add_handler(Pid, Desc, MatchHead, MatchSpec) ->
-    gen_server:call(?MODULE, {add_handler, Pid, Desc, MatchHead, MatchSpec}).
-remove_handler(Pid, MatchHead, MatchSpec) ->
-    HandlerID = get_handler_id(Pid, MatchHead, MatchSpec),
-    remove_handler(HandlerID).
-remove_handler(HandlerID) ->
-    gen_server:call(?MODULE, {remove_handler, HandlerID}).
-remove_dead_handlers() ->
-    gen_server:call(?MODULE, {remove_dead_handlers, false}).
 %% @private (only used for test instances)
 stop() -> gen_server2:cast(?MODULE, stop).
 %% @private
-handle_call({add_handler, Pid, Desc, MatchHead, MatchSpec},_From,State) -> 
+handle_call({add_handler, Pid, Desc, MatchHead, MatchGuard},_From,State) -> 
     % Monitor the pid, we want to know when to remove it...
     erlang:monitor(process, Pid),
     % Add the handler...
     {ok, Ring} = riak_ring_manager:get_my_ring(),
-    Handler = make_handler(Pid, Desc, MatchHead, MatchSpec),
+    Handler = make_handler(Pid, Desc, MatchHead, MatchGuard),
     Ring1 = add_handler_to_ring(Handler, Ring),
     % Set and save the new ring...
 handle_cast(_, State) -> {noreply, State}.
+%% @private
 handle_info({'DOWN', _, process, Pid, _}, State) ->
     % Get a 'DOWN' message, so remove any handlers from this Pid...
     {ok, Ring} = riak_ring_manager:get_my_ring(),