%%%------------------------------------------------------------------- %% @doc `telemetry' allows you to invoke certain functions whenever a %% particular event is emitted. %% %% For more information see the documentation for {@link attach/4}, {@link attach_many/4} %% and {@link execute/2}. %% @end %%%------------------------------------------------------------------- -module(telemetry). -export([attach/4, attach_many/4, detach/1, list_handlers/1, execute/2, execute/3]). -include("telemetry.hrl"). -type handler_id() :: term(). -type event_name() :: [atom(), ...]. -type event_measurements() :: map(). -type event_metadata() :: map(). -type event_value() :: number(). -type event_prefix() :: [atom()]. -type handler_config() :: term(). -type handler_function() :: fun((event_name(), event_measurements(), event_metadata(), handler_config()) -> any()). -type handler() :: #{id := handler_id(), event_name := event_name(), function := handler_function(), config := handler_config()}. -export_type([handler_id/0, event_name/0, event_measurements/0, event_metadata/0, event_value/0, event_prefix/0, handler_config/0, handler_function/0, handler/0]). %% @doc Attaches the handler to the event. %% %% `handler_id' must be unique, if another handler with the same ID already exists the %% `{error, already_exists}' tuple is returned. %% %% See {@link execute/3} to learn how the handlers are invoked. %% %% Note: due to how anonymous functions are implemented in the Erlang VM, it is best to use %% function captures (i.e. `fun mod:fun/4' in Erlang or `&Mod.fun/4' in Elixir) as event handlers %% to achieve maximum performance. In other words, avoid using literal anonymous functions %% (`fun(...) -> ... end' or `fn ... -> ... end') or local function captures (`fun handle_event/4' %% or `&handle_event/4' ) as event handlers. %% %% All the handlers are executed by the process dispatching event. If the function fails (raises, %% exits or throws) then the handler is removed. %% Note that you should not rely on the order in which handlers are invoked. -spec attach(HandlerId, EventName, Function, Config) -> ok | {error, already_exists} when HandlerId :: handler_id(), EventName :: event_name(), Function :: handler_function(), Config :: handler_config(). attach(HandlerId, EventName, Function, Config) -> attach_many(HandlerId, [EventName], Function, Config). %% @doc Attaches the handler to many events. %% %% The handler will be invoked whenever any of the events in the `event_names' list is emitted. Note %% that failure of the handler on any of these invokations will detach it from all the events in %% `event_name' (the same applies to manual detaching using {@link detach/1}). %% %% Note: due to how anonymous functions are implemented in the Erlang VM, it is best to use %% function captures (i.e. `fun mod:fun/4' in Erlang or `&Mod.fun/4' in Elixir) as event handlers %% to achieve maximum performance. In other words, avoid using literal anonymous functions %% (`fun(...) -> ... end' or `fn ... -> ... end') or local function captures (`fun handle_event/4' %% or `&handle_event/4' ) as event handlers. %% %% All the handlers are executed by the process dispatching event. If the function fails (raises, %% exits or throws) then the handler is removed. %% Note that you should not rely on the order in which handlers are invoked. -spec attach_many(HandlerId, [EventName], Function, Config) -> ok | {error, already_exists} when HandlerId :: handler_id(), EventName :: event_name(), Function :: handler_function(), Config :: handler_config(). attach_many(HandlerId, EventNames, Function, Config) when is_function(Function, 4) -> assert_event_names(EventNames), telemetry_handler_table:insert(HandlerId, EventNames, Function, Config). %% @doc Removes the existing handler. %% %% If the handler with given ID doesn't exist, `{error, not_found}' is returned. -spec detach(handler_id()) -> ok | {error, not_found}. detach(HandlerId) -> telemetry_handler_table:delete(HandlerId). %% @doc Emits the event, invoking handlers attached to it. %% %% When the event is emitted, the handler function provided to {@link attach/4} is called with four %% arguments: %%