File 0001-Inform-user-about-usage-of-local-functions-as-handle.patch of Package telemetry
From a2e98a6474212a518fd1406d457e39839ae51e0b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=C5=81ukasz=20Jan=20Niemier?= <lukasz@niemier.pl>
Date: Wed, 30 Jun 2021 19:14:23 +0200
Subject: [PATCH] Inform user about usage of local functions as handlers (#84)
This provides immediate feedback for the Telemetry user about improper
handler function definition.
---
src/telemetry.erl | 24 ++++++++++++++++++++++++
test/telemetry_SUITE.erl | 34 +++++++++++++++++++++++++++++++++-
2 files changed, 57 insertions(+), 1 deletion(-)
diff --git a/src/telemetry.erl b/src/telemetry.erl
index 782f3c6..19452d0 100644
--- a/src/telemetry.erl
+++ b/src/telemetry.erl
@@ -16,6 +16,8 @@
execute/3,
span/3]).
+-export([report_cb/1]).
+
-include("telemetry.hrl").
-type handler_id() :: term().
@@ -45,6 +47,8 @@
span_result/0,
span_function/0]).
+-import_lib("kernel/import/logger.hrl").
+
%% @doc Attaches the handler to the event.
%%
%% `handler_id' must be unique, if another handler with the same ID already exists the
@@ -91,6 +95,17 @@ attach(HandlerId, EventName, Function, Config) ->
Config :: handler_config().
attach_many(HandlerId, EventNames, Function, Config) when is_function(Function, 4) ->
assert_event_names(EventNames),
+ case erlang:fun_info(Function, type) of
+ {type, external} ->
+ ok;
+ {type, local} ->
+ ?LOG_INFO(#{handler_id => HandlerId,
+ event_names => EventNames,
+ function => Function,
+ config => Config,
+ type => local},
+ #{report_cb => fun ?MODULE:report_cb/1})
+ end,
telemetry_handler_table:insert(HandlerId, EventNames, Function, Config).
%% @doc Removes the existing handler.
@@ -345,3 +360,12 @@ assert_event_name(Term) ->
-spec merge_ctx(event_metadata(), any()) -> event_metadata().
merge_ctx(#{telemetry_span_context := _} = Metadata, _Ctx) -> Metadata;
merge_ctx(Metadata, Ctx) -> Metadata#{telemetry_span_context => Ctx}.
+
+%% @hidden
+report_cb(#{handler_id := Id}) ->
+ {"Function passed as a handler with ID ~w is local function.\n"
+ "This mean that it is either anonymous function or capture of function "
+ "without module specified. That may cause performance penalty when calling "
+ "such handler. For more details see note in `telemetry:attach/4` "
+ "documentation.\n\n"
+ "https://hexdocs.pm/telemetry/telemetry.html#attach-4", [Id]}.
diff --git a/test/telemetry_SUITE.erl b/test/telemetry_SUITE.erl
index 9a9007e..58df646 100644
--- a/test/telemetry_SUITE.erl
+++ b/test/telemetry_SUITE.erl
@@ -14,7 +14,7 @@ all() ->
handler_on_multiple_events, remove_all_handler_on_failure,
list_handler_on_many, detach_from_all, old_execute, default_metadata,
off_execute, invoke_successful_span_handlers, invoke_exception_span_handlers,
- spans_generate_unique_default_contexts].
+ spans_generate_unique_default_contexts, logs_on_local_function].
init_per_suite(Config) ->
application:ensure_all_started(telemetry),
@@ -403,6 +403,34 @@ spans_generate_unique_default_contexts(Config) ->
1000 -> ct:fail(timeout_receive_echo)
end.
+logs_on_local_function(Config) ->
+ HandlerId = ?config(id, Config),
+ Event = [some, action],
+
+ OldConfig = logger:get_primary_config(),
+ logger:add_primary_filter(logs_on_local_function, {fun ?MODULE:send_logs/2,
+ self()}),
+ logger:update_primary_config(#{level => info}),
+
+ try
+ telemetry:attach(HandlerId, Event, fun raise_on_event/4, []),
+ receive
+ {log, #{msg := {report, #{handler_id := HandlerId}}}} -> ok
+ after
+ 1000 -> ct:fail(timeout_receive_log)
+ end,
+
+ Fun = fun(_Event, _Measurements, _Meta, _Config) -> ok end,
+ telemetry:attach(HandlerId, Event, Fun, []),
+ receive
+ {log, #{msg := {report, #{handler_id := HandlerId}}}} -> ok
+ after
+ 1000 -> ct:fail(timeout_receive_log)
+ end
+ after
+ logger:set_primary_config(OldConfig)
+ end.
+
% Ensure calling execute is safe when the telemetry application is off
off_execute(_Config) ->
application:stop(telemetry),
@@ -414,3 +442,7 @@ echo_event(Event, Measurements, Metadata, #{send_to := Pid} = Config) ->
raise_on_event(_, _, _, _) ->
throw(got_event).
+
+send_logs(Event, Pid) ->
+ Pid ! {log, Event},
+ ignore.
--
2.35.3