%%%------------------------------------------------------------------- %% @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"). -ifdef('OTP_RELEASE'). -include_lib("kernel/include/logger.hrl"). -else. -define(LOG_ERROR(Msg, Args), error_logger:error_msg(Msg, Args)). -endif. -ifdef('OTP_RELEASE'). -include_lib("kernel/include/logger.hrl"). -else. -define(LOG_WARNING(Msg, Args), error_logger:warning_msg(Msg, Args)). -endif. -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()). %% TODO: change to := when OTP-18 support can be dropped -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. -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}). -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: %%