telemetry_handler_table.erl (3498B)
1 %%%------------------------------------------------------------------- 2 %% @private ETS table for handlers. 3 %% 4 %% Each handler is stored in the table. A key is an event name the 5 %% handler is attached to. All writes to a table go through a single 6 %% Agent process to make sure that we don't get duplicate handler IDs. 7 %% 8 %% Reads (`list_handlers_...') are executed by the calling process. 9 %% @end 10 %%%------------------------------------------------------------------- 11 -module(telemetry_handler_table). 12 13 -behaviour(gen_server). 14 15 -export([start_link/0, 16 insert/4, 17 delete/1, 18 list_for_event/1, 19 list_by_prefix/1]). 20 21 -export([init/1, 22 handle_call/3, 23 handle_cast/2, 24 handle_info/2, 25 code_change/3, 26 terminate/2]). 27 28 -include("telemetry.hrl"). 29 30 start_link() -> 31 gen_server:start_link({local, ?MODULE}, ?MODULE, [], []). 32 33 -spec insert(HandlerId, EventNames, Function, Config) -> ok | {error, already_exists} when 34 HandlerId :: telemetry:handler_id(), 35 EventNames :: [telemetry:event_name()], 36 Function :: telemetry:handler_function(), 37 Config :: telemetry:handler_config(). 38 insert(HandlerId, EventNames, Function, Config) -> 39 gen_server:call(?MODULE, {insert, HandlerId, EventNames, Function, Config}). 40 41 -spec delete(telemetry:handler_id()) -> ok | {error, not_found}. 42 delete(HandlerId) -> 43 gen_server:call(?MODULE, {delete, HandlerId}). 44 45 -spec list_for_event(telemetry:event_name()) -> [#handler{}]. 46 list_for_event(EventName) -> 47 try 48 ets:lookup(?MODULE, EventName) 49 catch 50 error:badarg -> 51 ?LOG_WARNING("Failed to lookup telemetry handlers. " 52 "Ensure the telemetry application has been started. ", []), 53 [] 54 end. 55 56 -spec list_by_prefix(telemetry:event_prefix()) -> [#handler{}]. 57 list_by_prefix(EventPrefix) -> 58 Pattern = match_pattern_for_prefix(EventPrefix), 59 ets:match_object(?MODULE, Pattern). 60 61 init([]) -> 62 _ = create_table(), 63 {ok, []}. 64 65 handle_call({insert, HandlerId, EventNames, Function, Config}, _From, State) -> 66 case ets:match(?MODULE, #handler{id=HandlerId, 67 _='_'}) of 68 [] -> 69 Objects = [#handler{id=HandlerId, 70 event_name=EventName, 71 function=Function, 72 config=Config} || EventName <- EventNames], 73 ets:insert(?MODULE, Objects), 74 {reply, ok, State}; 75 _ -> 76 {reply, {error, already_exists}, State} 77 end; 78 handle_call({delete, HandlerId}, _From, State) -> 79 case ets:select_delete(?MODULE, [{#handler{id=HandlerId, 80 _='_'}, [], [true]}]) of 81 0 -> 82 {reply, {error, not_found}, State}; 83 _ -> 84 {reply, ok, State} 85 end. 86 87 handle_cast(_Msg, State) -> 88 {noreply, State}. 89 90 handle_info(_Msg, State) -> 91 {noreply, State}. 92 93 code_change(_, State, _) -> 94 {ok, State}. 95 96 terminate(_Reason, _State) -> 97 ok. 98 99 %% 100 101 create_table() -> 102 ets:new(?MODULE, [duplicate_bag, protected, named_table, 103 {keypos, 3}, {read_concurrency, true}]). 104 105 match_pattern_for_prefix(EventPrefix) -> 106 #handler{event_name=match_for_prefix(EventPrefix), 107 _='_'}. 108 109 -dialyzer({nowarn_function, match_for_prefix/1}). 110 match_for_prefix([]) -> 111 '_'; 112 match_for_prefix([Segment | Rest]) -> 113 [Segment | match_for_prefix(Rest)].