diff --git a/lib/et/src/et.erl b/lib/et/src/et.erl index b951439ef388..220a2c884b58 100644 --- a/lib/et/src/et.erl +++ b/lib/et/src/et.erl @@ -89,6 +89,10 @@ trace_me/5, phone_home/5, report_event/5 ]). + +-type actor() :: term(). +-type level() :: 0..100. + %%---------------------------------------------------------------------- %% Reports an event, such as a message %% @@ -126,26 +130,59 @@ %% Other events (termed actions) may be undirected and only have one actor. %%---------------------------------------------------------------------- +-spec trace_me(DetailLevel, FromTo, Label, Contents) -> hopefully_traced when + DetailLevel :: level(), + FromTo :: actor(), + Label :: atom() | string() | term(), + Contents :: [{Key::term(), Value::term()}] | term(). trace_me(DetailLevel, FromTo, Label, Contents) when is_integer(DetailLevel) -> ?MODULE:trace_me(DetailLevel, FromTo, FromTo, Label, Contents). +-spec trace_me(DetailLevel, From, To, Label, Contents) -> hopefully_traced when + DetailLevel :: level(), + From :: actor(), + To :: actor(), + Label :: atom() | string() | term(), + Contents :: [{Key::term(), Value::term()}] | term(). trace_me(DetailLevel, _From, _To, _Label, _Contents) when is_integer(DetailLevel) -> hopefully_traced. +-spec phone_home(DetailLevel, FromTo, Label, Contents) -> hopefully_traced when + DetailLevel :: level(), + FromTo :: actor(), + Label :: atom() | string() | term(), + Contents :: [{Key::term(), Value::term()}] | term(). phone_home(DetailLevel, FromTo, Label, Contents) -> %% N.B External call ?MODULE:trace_me(DetailLevel, FromTo, FromTo, Label, Contents). +-spec phone_home(DetailLevel, From, To, Label, Contents) -> hopefully_traced when + DetailLevel :: level(), + From :: actor(), + To :: actor(), + Label :: atom() | string() | term(), + Contents :: [{Key::term(), Value::term()}] | term(). phone_home(DetailLevel, From, To, Label, Contents) -> %% N.B External call ?MODULE:trace_me(DetailLevel, From, To, Label, Contents). +-spec report_event(DetailLevel, FromTo, Label, Contents) -> hopefully_traced when + DetailLevel :: level(), + FromTo :: actor(), + Label :: atom() | string() | term(), + Contents :: [{Key::term(), Value::term()}] | term(). report_event(DetailLevel, FromTo, Label, Contents) -> %% N.B External call ?MODULE:trace_me(DetailLevel, FromTo, FromTo, Label, Contents). +-spec report_event(DetailLevel, From, To, Label, Contents) -> hopefully_traced when + DetailLevel :: level(), + From :: actor(), + To :: actor(), + Label :: atom() | string() | term(), + Contents :: [{Key::term(), Value::term()}] | term(). report_event(DetailLevel, From, To, Label, Contents) when is_integer(DetailLevel) -> %% N.B External call diff --git a/lib/et/src/et_collector.erl b/lib/et/src/et_collector.erl index 835bb380b8da..058e7f473f7f 100644 --- a/lib/et/src/et_collector.erl +++ b/lib/et/src/et_collector.erl @@ -87,6 +87,44 @@ -record(trace_ts, {trace_ts, event_ts}). -record(event_ts, {event_ts, trace_ts}). +-type event() :: #event{}. +-type table_handle() :: #table_handle{}. +-type event_ts() :: #event_ts{}. +-type trace_ts() :: #trace_ts{}. + +-type collector_fun() :: trace_filter_fun() | event_filter_fun(). + +-type trace_filter_fun() :: fun((TraceData::tuple()) -> boolean() | {true, event()}). +-type event_filter_fun() :: fun((Event::event()) -> boolean() | {true, event()}). + +-type dbg_match_spec() :: [tuple()]. %% See dbg match specs +-type dbg_trace_type() :: ip | file | follow_file. %% See dbg:trace_client +-type dbg_trace_parameters() :: file:filename() | integer() | {string(), integer()}. %% See dbg:trace_client + +-type ets_match_object_pattern() :: term(). %% See ets:match_object() + +-type level() :: 0..100. + +-type option():: + {parent_pid, pid() | undefined} | + {event_order, trace_ts | event_ts} | + {dict_insert, {filter, all}, collector_fun()} | + {dict_insert, {filter, EventFilterName::atom()}, event_filter_fun()} | + {dict_insert, {subscriber, pid()}, Val::term()} | + {dict_insert, Key::term(), Val::term()} | + {dict_delete, Key::term()} | + {trace_client, {event_file, file:filename()} | + {dbg_trace_type(), dbg_trace_parameters()}} | + {trace_global, boolean()} | + {trace_pattern, {module() | undefined, Level::level() | dbg_match_spec()} | + undefined} | + {trace_port, integer()} | + {trace_max_queue, integer()}. + +-type actor() :: term(). + +-export_type([option/0]). + %%%---------------------------------------------------------------------- %%% Client side %%%---------------------------------------------------------------------- @@ -163,7 +201,8 @@ %% CollectorPid = pid() %% Reason = term() %%---------------------------------------------------------------------- - +-spec start_link(Options) -> {ok, Pid::pid()} | {error, term()} when + Options :: [option()]. start_link(Options) -> case parse_opt(Options, default_state(), [], []) of {ok, S, Dict2, Clients} -> @@ -266,7 +305,7 @@ start_clients(CollectorPid, []) -> %% %% CollectorPid = pid() %%---------------------------------------------------------------------- - +-spec stop(CollectorPid::pid()) -> ok. stop(CollectorPid) -> call(CollectorPid, stop). @@ -295,7 +334,10 @@ stop(CollectorPid) -> %% %% The options defaults to existing, write and keep. %%---------------------------------------------------------------------- - +-spec save_event_file(CollectorPid, FileName, [Option]) -> ok | {error, term()} when + CollectorPid :: pid(), + FileName :: file:filename(), + Option :: existing | write | append | keep | clear. save_event_file(CollectorPid, FileName, Options) -> call(CollectorPid, {save_event_file, FileName, Options}). @@ -309,7 +351,10 @@ save_event_file(CollectorPid, FileName, Options) -> %% BadBytes = integer(X) where X >= 0 %% Reason = term() %%---------------------------------------------------------------------- - +-spec load_event_file(CollectorPid, FileName) ->{ok, BadBytes} when + CollectorPid :: pid(), + FileName :: file:filename(), + BadBytes :: pos_integer(). load_event_file(CollectorPid, FileName) -> Fd = make_ref(), Args = [{file, FileName}, {name, Fd}, {repair, true}, {mode, read_only}], @@ -359,6 +404,11 @@ do_load_event_file(Fun, Fd, Cont, Acc, FileName, BadBytes) -> %% Returns: {ok, Continuation} | exit(Reason) %%---------------------------------------------------------------------- +-spec report(Handle, TraceOrEvent) -> {ok, Continuation} when + Handle :: table_handle() | CollectorPid::pid(), + TraceOrEvent :: event() | TraceData | end_of_trace, + TraceData :: tuple(), + Continuation :: table_handle(). report(CollectorPid, TraceOrEvent) when is_pid(CollectorPid) -> case get_table_handle(CollectorPid) of {ok, TH} when is_record(TH, table_handle) -> @@ -411,9 +461,24 @@ report(TH, TraceOrEvent) when is_record(TH, table_handle) -> report(_, Bad) -> exit({bad_event, Bad}). +-spec report_event(CollectorPid, DetailLevel, FromTo, Label, Contents) -> {ok, Continuation} when + CollectorPid :: pid(), + DetailLevel :: level(), + FromTo :: actor(), + Label :: term(), + Contents :: [{Key::term(), Value::term()}] | term(), + Continuation :: table_handle(). report_event(CollectorPid, DetailLevel, FromTo, Label, Contents) -> report_event(CollectorPid, DetailLevel, FromTo, FromTo, Label, Contents). +-spec report_event(CollectorPid, DetailLevel, From, To, Label, Contents) -> {ok, Continuation} when + CollectorPid :: pid(), + DetailLevel :: level(), + From :: actor(), + To :: actor(), + Label :: term(), + Contents :: [{Key::term(), Value::term()}] | term(), + Continuation :: table_handle(). report_event(CollectorPid, DetailLevel, From, To, Label, Contents) when is_integer(DetailLevel), DetailLevel >= ?detail_level_min, @@ -438,6 +503,10 @@ report_event(CollectorPid, DetailLevel, From, To, Label, Contents) %% Key = record(event_ts) | record(trace_ts) %%---------------------------------------------------------------------- +-spec make_key(Handle, Stuff) -> Key when + Handle :: table_handle() | trace_ts | event_ts, + Stuff :: event() | Key, + Key :: event_ts() | trace_ts(). make_key(TH, Stuff) when is_record(TH, table_handle) -> make_key(TH#table_handle.event_order, Stuff); make_key(trace_ts, Stuff) -> @@ -490,7 +559,7 @@ get_table_handle(CollectorPid) when is_pid(CollectorPid) -> %% CollectorPid = pid() %% Reason = term() %%---------------------------------------------------------------------- - +-spec get_global_pid() -> CollectorPid :: pid(). get_global_pid() -> case global:whereis_name(?MODULE) of CollectorPid when is_pid(CollectorPid) -> @@ -512,7 +581,10 @@ get_global_pid() -> %% detail_level() = min | max | integer(X) when X =< 0, X >= 100 %% TracePattern = {report_module(), dbg_match_spec_match_spec()} %%---------------------------------------------------------------------- - +-spec change_pattern(CollectorPid, RawPattern) -> {old_pattern, TracePattern} when + CollectorPid :: pid(), + RawPattern :: {module(), min | max | level()}, + TracePattern :: [{[term()] | '_' | atom(), [term()], [term()]}]. change_pattern(CollectorPid, RawPattern) -> Pattern = et_selector:make_pattern(RawPattern), call(CollectorPid, {change_pattern, Pattern}). @@ -542,7 +614,11 @@ change_pattern(CollectorPid, RawPattern) -> %% Key = term() %% Val = term() %%---------------------------------------------------------------------- - +-spec dict_insert(CollectorPid, What, Value) -> ok when + CollectorPid :: pid(), + What :: {filter, atom()} | {subscriber, pid()} | Key, + Key :: term(), + Value :: collector_fun() | term(). dict_insert(CollectorPid, Key = {filter, Name}, Fun) -> if is_atom(Name), is_function(Fun) -> @@ -569,14 +645,14 @@ dict_insert(CollectorPid, Key, Val) -> %% Key = term() %% Val = term() %%---------------------------------------------------------------------- - +-spec dict_lookup(CollectorPid::pid(), Key::term()) -> [Val::term()]. dict_lookup(CollectorPid, Key) -> call(CollectorPid, {dict_lookup, Key}). %%---------------------------------------------------------------------- -%% Ddict_delete(CollectorPid, Key) -> ok +%% dict_delete(CollectorPid, Key) -> ok %% -%% elete a dictionary entry +%% Delete a dictionary entry %% and send a {et, {dict_delete, Key}} tuple %% to all registered subscribers. %% @@ -591,7 +667,7 @@ dict_lookup(CollectorPid, Key) -> %% SubscriberPid = pid() %% Key = term() %%---------------------------------------------------------------------- - +-spec dict_delete(CollectorPid::pid(), Key::term()) -> ok. dict_delete(CollectorPid, Key) -> call(CollectorPid, {dict_delete, Key}). @@ -608,7 +684,10 @@ dict_delete(CollectorPid, Key) -> %% key() = term() %% val() = term() %%---------------------------------------------------------------------- - +-spec dict_match(CollectorPid::pid(), {KeyPattern, ValPattern}) -> [Match] when + KeyPattern :: ets_match_object_pattern(), + ValPattern :: ets_match_object_pattern(), + Match :: {Key::term(), Val::term()}. dict_match(CollectorPid, Pattern) -> call(CollectorPid, {dict_match, Pattern}). @@ -620,7 +699,7 @@ dict_match(CollectorPid, Pattern) -> %% CollectorPid = pid() %% Msg = term() %%---------------------------------------------------------------------- - +-spec multicast(CollectorPid :: pid(), Msg::term()) -> ok. multicast(_CollectorPid, Msg = {dict_insert, _Key, _Val}) -> exit({badarg, Msg}); multicast(_CollectorPid, Msg = {dict_delete, _Key}) -> @@ -638,7 +717,10 @@ multicast(CollectorPid, Msg) -> %% Parameters = dbg_trace_client_parameters() %% Pid = dbg_trace_client_pid() %%---------------------------------------------------------------------- - +-spec start_trace_client(CollectorPid, Type, Parameter) -> file_loaded | {trace_client_pid, pid()} when + CollectorPid :: pid(), + Type :: event_file | dbg_trace_type(), + Parameter :: dbg_trace_parameters(). start_trace_client(CollectorPid, Type, FileName) when Type =:= event_file -> load_event_file(CollectorPid, FileName); start_trace_client(CollectorPid, Type, FileName) when Type =:= file -> @@ -697,7 +779,15 @@ monitor_trace_port(CollectorPid, Parameters) -> %% %% Short for iterate/5. %%---------------------------------------------------------------------- - +-spec iterate(Handle, Prev, Limit) -> NewAcc when + Handle :: CollectorPid | table_handle(), + CollectorPid :: pid(), + Prev :: first | last | term(), + Limit :: Done | Forward | Backward, + Done :: 0, + Forward :: pos_integer(), + Backward :: neg_integer(), + NewAcc :: term(). iterate(Handle, Prev, Limit) -> iterate(Handle, Prev, Limit, undefined, Prev). @@ -720,7 +810,17 @@ iterate(Handle, Prev, Limit) -> %% Fun = fun(Event, Acc) -> NewAcc %% Acc = NewAcc = term() %%---------------------------------------------------------------------- - +-spec iterate(Handle, Prev, Limit, Fun, Acc) -> NewAcc when + Handle :: CollectorPid | table_handle(), + CollectorPid :: pid(), + Prev :: first | last | term(), + Limit :: Done | Forward | Backward, + Done :: 0, + Forward :: pos_integer() | 'infinity', + Backward :: neg_integer() | '-infinity', + Fun :: fun((event(), Acc) -> NewAcc) | undefined, + Acc :: term(), + NewAcc :: term(). iterate(_, _, Limit, _, Acc) when Limit =:= 0 -> Acc; iterate(CollectorPid, Prev, Limit, Fun, Acc) when is_pid(CollectorPid) -> @@ -858,7 +958,9 @@ incr(Val, Incr) -> %% collector_pid() = pid() %% table_handle() = record(table_handle) %%---------------------------------------------------------------------- - +-spec clear_table(Handle) -> ok when + Handle :: CollectorPid | table_handle(), + CollectorPid :: pid(). clear_table(CollectorPid) when is_pid(CollectorPid) -> call(CollectorPid, clear_table); clear_table(TH) when is_record(TH, table_handle) -> diff --git a/lib/et/src/et_selector.erl b/lib/et/src/et_selector.erl index 18a7e66b1df1..e83088d823fb 100644 --- a/lib/et/src/et_selector.erl +++ b/lib/et/src/et_selector.erl @@ -31,6 +31,10 @@ -include("../include/et.hrl"). +-type event() :: #event{}. + +-type level() :: 0..100. + %%---------------------------------------------------------------------- %% make_pattern(RawPattern) -> TracePattern %% @@ -46,7 +50,9 @@ %% max - maximum level of tracing (all calls to trace_me/4,5) %% integer() - explicit detail level of tracing %%---------------------------------------------------------------------- - +-spec make_pattern({Mod::module(), RawPattern}) -> {Mod::module(), TracePattern} when + RawPattern :: level(), + TracePattern :: [{[term()] | '_' | atom(), [term()], [term()]}]. make_pattern(undefined) -> {undefined, undefined}; make_pattern({Mod, Pattern}) when is_atom(Mod) -> @@ -93,7 +99,11 @@ make_pattern({Mod, Pattern}) when is_atom(Mod) -> %% Other match specs activates tracing of calls to trace_me/4,5 %% accordingly with erlang:trace_pattern/2. %%---------------------------------------------------------------------- - +-spec change_pattern({Mod::module(), Pattern}) -> ok when + Pattern :: DetailLevel | TracePattern | EmptyTracePattern, + DetailLevel :: level(), + TracePattern :: [{[term()] | '_' | atom(), [term()], [term()]}], + EmptyTracePattern :: []. change_pattern({Mod, Pattern}) when is_atom(Mod) -> MFA = {Mod, trace_me, 5}, case Pattern of @@ -176,7 +186,17 @@ error_to_exit({ok, _Res}) -> %% false - means that the trace data is uninteresting and %% should be dropped %%---------------------------------------------------------------------- - +-spec parse_event(Mod, ValidTraceData) -> boolean | {true, event()} when + Mod :: module(), + ValidTraceData :: ErlangTraceData | event(), + ErlangTraceData :: + {trace, pid(), atom(), term()} | + {trace, pid(), atom(), term(), term()} | + {trace_ts, pid(), atom(), term(), TS::{integer(), integer(), integer()}} | + {trace_ts, pid(), atom(), term(), term(), TS::{integer(), integer(), integer()}} | + {seq_trace, atom(), term()} | + {seq_trace, atom(), term(), TS::{integer(), integer(), integer()}} | + {drop, integer()}. parse_event(_Mod, E) when is_record(E, event) -> true; parse_event(Mod, Trace) -> diff --git a/lib/et/src/et_viewer.erl b/lib/et/src/et_viewer.erl index 3928764c7fb3..d3e2c2f4099d 100644 --- a/lib/et/src/et_viewer.erl +++ b/lib/et/src/et_viewer.erl @@ -40,6 +40,24 @@ -define(unknown, "UNKNOWN"). +-type actors() :: [term()]. +-type first_key() :: term(). +-type option() :: + {title, string()} | + {detail_level, 0..100} | + {is_suspended, boolean()} | + {scale, integer()} | + {width, integer()} | + {height, integer()}| + {collector_pid, pid() | undefined} | + {active_filter, atom()} | + {max_events, integer() | undefined} | + {max_actors, integer() | undefined} | + {actors, actors()} | + {first_event, first_key()} | + {hide_unknown, boolean()} | + {hide_actions, boolean()} | + {display_mode, all | {search_actors, forward | reverse, first_key(), actors()}}. %%%---------------------------------------------------------------------- %%% Client side @@ -55,7 +73,7 @@ %% ViewerPid = pid() %% Reason = term() %%---------------------------------------------------------------------- - +-spec file(FileName::file:filename()) -> {ok, pid()} | {error, term()}. file(FileName) -> start_link([{trace_client, {file, FileName}}], default). @@ -70,18 +88,25 @@ file(FileName) -> %% processes are unlinked from the calling process. %%---------------------------------------------------------------------- +-spec start() -> {ok, pid()} | {error, term()}. start() -> start([{trace_global, true}], default). %%---------------------------------------------------------------------- %% start(Options) -> {ok, ViewerPid} | {error, Reason} %%---------------------------------------------------------------------- - +-spec start(GUIorOptions) -> {ok, Viewer::pid()} | {error, term()} when + GUIorOptions :: wx | default | Options, + Options :: [option() | et_collector:option()]. start(GUI) when GUI =:= wx; GUI =:= default -> start_link([{trace_global, true}], GUI); start(Options) -> start_link([{parent_pid, undefined} | Options], default). +-spec start(Options, GUI) -> {ok, Viewer::pid()} | {error, term()} when + GUI :: wx | default, + Options :: [option() | et_collector:option()]. + start(Options, GUI) -> start_link([{parent_pid, undefined} | Options], GUI). @@ -139,12 +164,17 @@ start(Options, GUI) -> %% A filter_fun() takes an event record as sole argument %% and returns false | true | {true, NewEvent}. %%---------------------------------------------------------------------- - +-spec start_link(GUIorOptions) -> {ok, Viewer::pid()} | {error, term()} when + GUIorOptions :: wx | default | Options, + Options :: [option() | et_collector:option()]. start_link(GUI) when GUI =:= wx; GUI =:= default -> start_link([{trace_global, true}], GUI); start_link(Options) -> start_link(Options, default). +-spec start_link(Options, GUI) -> {ok, Viewer::pid()} | {error, term()} when + GUI :: wx | default, + Options :: [option() | et_collector:option()]. start_link(Options, GUI) -> case GUI of wx -> @@ -155,6 +185,7 @@ start_link(Options, GUI) -> which_gui() -> wx. +-spec get_collector_pid(ViewerPid::pid()) -> pid(). get_collector_pid(ViewerPid) -> call(ViewerPid, get_collector_pid). @@ -165,7 +196,7 @@ get_collector_pid(ViewerPid) -> %% %% ViewerPid = pid() %%---------------------------------------------------------------------- - +-spec stop(ViewerPid::pid()) -> ok. stop(ViewerPid) -> call(ViewerPid, stop).