From 726d6fb1d5983828e85a36288cec314e7ea54861 Mon Sep 17 00:00:00 2001 From: Nelson Vides Date: Mon, 9 Mar 2026 14:21:32 +0100 Subject: [PATCH 1/2] Capture function object just like handlers also prefer them In `telemetry:attach_many/4`, we check if the function given to the config is an external function and log noisy errors if it is not, because the Erlang efficiency guide says these are more efficient. Enforce the same for the `telemetry_handler_table` module at least for the very hot path that looks up the handlers for an event. Also remove a case-of from the execution path for another picosecond shave off. --- src/telemetry_handler_table.erl | 47 ++++++++++++++------------------- 1 file changed, 20 insertions(+), 27 deletions(-) diff --git a/src/telemetry_handler_table.erl b/src/telemetry_handler_table.erl index b01f97d..a1a7fb9 100644 --- a/src/telemetry_handler_table.erl +++ b/src/telemetry_handler_table.erl @@ -46,60 +46,49 @@ delete(HandlerId) -> gen_server:call(?MODULE, {delete, HandlerId}). persist() -> - {Mod, State} = impl_get(), + {Mod, _, State} = impl_get(), case Mod:persist(State) of {ok, NewState} -> - persistent_term:put(telemetry, {telemetry_pt, NewState}), - ok; + ListForEventFun = fun telemetry_pt:list_for_event/2, + persistent_term:put(telemetry, {telemetry_pt, ListForEventFun, NewState}); _ -> ok end. -impl_get() -> persistent_term:get(telemetry, undefined). +impl_get() -> + persistent_term:get(telemetry, default_impl()). -spec list_for_event(telemetry:event_name()) -> [#handler{}]. list_for_event(EventName) -> - case impl_get() of - {Mod, State} -> - Mod:list_for_event(State, EventName); - undefined -> - ?LOG_WARNING("Failed to lookup telemetry handlers. " - "Ensure the telemetry application has been started. ", []), - [] - end. + {_Mod, ListForEventFun, State} = impl_get(), + ListForEventFun(State, EventName). -spec list_by_prefix(telemetry:event_prefix()) -> [#handler{}]. list_by_prefix(EventPrefix) -> - case impl_get() of - {Mod, State} -> - Mod:list_by_prefix(State, EventPrefix); - undefined -> - ?LOG_WARNING("Failed to lookup telemetry handlers. " - "Ensure the telemetry application has been started. ", []), - [] - end. + {Mod, _ListForEventFun, State} = impl_get(), + Mod:list_by_prefix(State, EventPrefix). init([]) -> + process_flag(trap_exit, true), TID = create_table(), - - persistent_term:put(telemetry, {telemetry_ets, TID}), - + ListForEventFun = fun telemetry_ets:list_for_event/2, + persistent_term:put(telemetry, {telemetry_ets, ListForEventFun, TID}), {ok, []}. handle_call({insert, HandlerId, EventNames, Function, Config}, _From, State) -> - {Mod, MState} = impl_get(), + {Mod, ListForEventFun, MState} = impl_get(), case Mod:insert(MState, HandlerId, EventNames, Function, Config) of {ok, NewState} -> - persistent_term:put(telemetry, {Mod, NewState}), + persistent_term:put(telemetry, {Mod, ListForEventFun, NewState}), {reply, ok, State}; {error, _} = Error -> {reply, Error, State} end; handle_call({delete, HandlerId}, _From, State) -> - {Mod, MState} = impl_get(), + {Mod, ListForEventFun, MState} = impl_get(), case Mod:delete(MState, HandlerId) of {ok, NewState} -> - persistent_term:put(telemetry, {Mod, NewState}), + persistent_term:put(telemetry, {Mod, ListForEventFun, NewState}), {reply, ok, State}; {error, _} = Error -> {reply, Error, State} @@ -120,6 +109,10 @@ terminate(_Reason, _State) -> %% +default_impl() -> + ListForEventFun = fun(_, _) -> [] end, + {telemetry_ets, ListForEventFun, #{}}. + create_table() -> ets:new(?MODULE, [duplicate_bag, protected, {keypos, #handler.event_name}, {read_concurrency, true}]). From f12fd9dc8f01ee635f16e7ccdb1d4ee381a6a861 Mon Sep 17 00:00:00 2001 From: Nelson Vides Date: Mon, 9 Mar 2026 14:23:39 +0100 Subject: [PATCH 2/2] Create the handler record only when is needed --- src/telemetry_pt.erl | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/telemetry_pt.erl b/src/telemetry_pt.erl index ad74bbc..99831db 100644 --- a/src/telemetry_pt.erl +++ b/src/telemetry_pt.erl @@ -29,14 +29,15 @@ starts_with(_Haystack, _Needle) -> false. insert(Map, _HandlerId, [], _Function, _Config) -> {ok, Map}; insert(Map, HandlerId, [EventName | Rest], Function, Config) -> - Handler = #handler{id=HandlerId, - event_name=EventName, - function=Function, - config=Config}, OldHandlers = maps:get(EventName, Map, []), case OldHandlers of - #{HandlerId := _} -> {error, already_exists}; + #{HandlerId := _} -> + {error, already_exists}; _ -> + Handler = #handler{id=HandlerId, + event_name=EventName, + function=Function, + config=Config}, case put_new(Handler, OldHandlers) of {ok, NewHandlers} -> NewMap = Map#{EventName => NewHandlers},