114 lines
3.4 KiB
Erlang
114 lines
3.4 KiB
Erlang
%%%-------------------------------------------------------------------
|
|
%% @private ETS table for handlers.
|
|
%%
|
|
%% Each handler is stored in the table. A key is an event name the
|
|
%% handler is attached to. All writes to a table go through a single
|
|
%% Agent process to make sure that we don't get duplicate handler IDs.
|
|
%%
|
|
%% Reads (`list_handlers_...') are executed by the calling process.
|
|
%% @end
|
|
%%%-------------------------------------------------------------------
|
|
-module(telemetry_handler_table).
|
|
|
|
-behaviour(gen_server).
|
|
|
|
-export([start_link/0,
|
|
insert/4,
|
|
delete/1,
|
|
list_for_event/1,
|
|
list_by_prefix/1]).
|
|
|
|
-export([init/1,
|
|
handle_call/3,
|
|
handle_cast/2,
|
|
handle_info/2,
|
|
code_change/3,
|
|
terminate/2]).
|
|
|
|
-include("telemetry.hrl").
|
|
|
|
start_link() ->
|
|
gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).
|
|
|
|
-spec insert(HandlerId, EventNames, Function, Config) -> ok | {error, already_exists} when
|
|
HandlerId :: telemetry:handler_id(),
|
|
EventNames :: [telemetry:event_name()],
|
|
Function :: telemetry:handler_function(),
|
|
Config :: telemetry:handler_config().
|
|
insert(HandlerId, EventNames, Function, Config) ->
|
|
gen_server:call(?MODULE, {insert, HandlerId, EventNames, Function, Config}).
|
|
|
|
-spec delete(telemetry:handler_id()) -> ok | {error, not_found}.
|
|
delete(HandlerId) ->
|
|
gen_server:call(?MODULE, {delete, HandlerId}).
|
|
|
|
-spec list_for_event(telemetry:event_name()) -> [#handler{}].
|
|
list_for_event(EventName) ->
|
|
try
|
|
ets:lookup(?MODULE, EventName)
|
|
catch
|
|
error:badarg ->
|
|
?LOG_WARNING("Failed to lookup telemetry handlers. "
|
|
"Ensure the telemetry application has been started. ", []),
|
|
[]
|
|
end.
|
|
|
|
-spec list_by_prefix(telemetry:event_prefix()) -> [#handler{}].
|
|
list_by_prefix(EventPrefix) ->
|
|
Pattern = match_pattern_for_prefix(EventPrefix),
|
|
ets:match_object(?MODULE, Pattern).
|
|
|
|
init([]) ->
|
|
_ = create_table(),
|
|
{ok, []}.
|
|
|
|
handle_call({insert, HandlerId, EventNames, Function, Config}, _From, State) ->
|
|
case ets:match(?MODULE, #handler{id=HandlerId,
|
|
_='_'}) of
|
|
[] ->
|
|
Objects = [#handler{id=HandlerId,
|
|
event_name=EventName,
|
|
function=Function,
|
|
config=Config} || EventName <- EventNames],
|
|
ets:insert(?MODULE, Objects),
|
|
{reply, ok, State};
|
|
_ ->
|
|
{reply, {error, already_exists}, State}
|
|
end;
|
|
handle_call({delete, HandlerId}, _From, State) ->
|
|
case ets:select_delete(?MODULE, [{#handler{id=HandlerId,
|
|
_='_'}, [], [true]}]) of
|
|
0 ->
|
|
{reply, {error, not_found}, State};
|
|
_ ->
|
|
{reply, ok, State}
|
|
end.
|
|
|
|
handle_cast(_Msg, State) ->
|
|
{noreply, State}.
|
|
|
|
handle_info(_Msg, State) ->
|
|
{noreply, State}.
|
|
|
|
code_change(_, State, _) ->
|
|
{ok, State}.
|
|
|
|
terminate(_Reason, _State) ->
|
|
ok.
|
|
|
|
%%
|
|
|
|
create_table() ->
|
|
ets:new(?MODULE, [duplicate_bag, protected, named_table,
|
|
{keypos, 3}, {read_concurrency, true}]).
|
|
|
|
match_pattern_for_prefix(EventPrefix) ->
|
|
#handler{event_name=match_for_prefix(EventPrefix),
|
|
_='_'}.
|
|
|
|
-dialyzer({nowarn_function, match_for_prefix/1}).
|
|
match_for_prefix([]) ->
|
|
'_';
|
|
match_for_prefix([Segment | Rest]) ->
|
|
[Segment | match_for_prefix(Rest)].
|