aboutsummaryrefslogtreecommitdiffstats
path: root/lib/et/src/et_selector.erl
diff options
context:
space:
mode:
Diffstat (limited to 'lib/et/src/et_selector.erl')
-rw-r--r--lib/et/src/et_selector.erl529
1 files changed, 529 insertions, 0 deletions
diff --git a/lib/et/src/et_selector.erl b/lib/et/src/et_selector.erl
new file mode 100644
index 0000000000..845359622d
--- /dev/null
+++ b/lib/et/src/et_selector.erl
@@ -0,0 +1,529 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2001-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+%%----------------------------------------------------------------------
+%% Purpose: Define event transforms and trace patterns
+%%----------------------------------------------------------------------
+
+-module(et_selector).
+
+-export([
+ make_pattern/1,
+ change_pattern/1,
+ parse_event/2
+ ]).
+
+-include("../include/et.hrl").
+
+%%----------------------------------------------------------------------
+%% make_pattern(RawPattern) -> TracePattern
+%%
+%% Makes a trace pattern suitable to feed change_pattern/1
+%% See also erlang:trace_pattern/2 for more info about its match_spec()
+%%
+%% RawPattern = detail_level()
+%% TracePattern = erlang_trace_pattern_match_spec()
+%%
+%% detail_level() = min | max | integer(X) when X =< 0, X >= 100
+%%
+%% min - minimum level of tracing (ignore calls to report_event/4,5)
+%% max - maximum level of tracing (all calls to report_event/4,5)
+%% integer() - explicit detail level of tracing
+%%----------------------------------------------------------------------
+
+make_pattern(undefined) ->
+ {undefined, undefined};
+make_pattern({Mod, Pattern}) when atom(Mod) ->
+ case Pattern of
+ min ->
+ {Mod, []};
+ max ->
+ Head = ['$1', '_', '_', '_', '_'],
+ Body = [],
+ Cond = [],
+ {Mod, [{Head, Cond, Body}]};
+ DetailLevel when integer(DetailLevel) ->
+ Head = ['$1', '_', '_', '_', '_'],
+ Body = [],
+ Cond = [{ '<', '$1', DetailLevel}],
+ {Mod, [{Head, Cond, Body}]};
+ undefined ->
+ {Mod, undefined};
+ _ ->
+ exit({bad_pattern, Pattern})
+ end.
+
+%%----------------------------------------------------------------------
+%% change_pattern(Pattern) -> ok
+%%
+%% Activates/deactivates tracing by changing the current trace pattern
+%%
+%% Pattern = detail_level() |
+%% empty_match_spec() |
+%% erlang_trace_pattern_match_spec()
+%%
+%% detail_level() = min | max | integer(X) when X =<0, X >= 100
+%% empty_match_spec() = []
+%%
+%% Min detail level deactivates tracing of calls to report_event/4,5
+%%
+%% Max detail level activates tracing of all calls to report_event/4,5
+%%
+%% integer(X) detail level activates tracing of all calls to
+%% report_event/4,5 whose detail level argument is lesser than X.
+%%
+%% An empty match spec deactivates tracing of calls to report_event/4,5
+%%
+%% Other match specs activates tracing of calls to report_event/4,5
+%% accordlingly with erlang:trace_pattern/2.
+%%----------------------------------------------------------------------
+
+change_pattern({Mod, Pattern}) when atom(Mod) ->
+ MFA = {Mod, report_event, 5},
+ case Pattern of
+ undefined ->
+ ignore;
+ [] ->
+ error_to_exit(dbg:ctp(MFA)),
+ error_to_exit(dbg:p(all, clear));
+ List when list(List) ->
+ error_to_exit(dbg:ctp(MFA)),
+ error_to_exit(dbg:tp(MFA, Pattern)),
+ error_to_exit(dbg:p(all, [call, timestamp]));
+ Other ->
+ change_pattern(make_pattern({Mod, Other}))
+ end,
+ ok.
+
+error_to_exit({error, Reason}) ->
+ exit(Reason);
+error_to_exit({ok, Res}) ->
+ Res.
+
+%%----------------------------------------------------------------------
+%% parse_event(Mod, ValidTraceData) -> false | true | {true, Event}
+%%
+%% Transforms trace data and makes an event record out of it
+%%
+%% ValidTraceData = erlang_trace_data() | record(event)
+%% Mod = module_name() | undefined
+%% module_name() = atom()
+%%
+%% erlang_trace_data() =
+%%
+%% {trace, Pid, Label, Info} |
+%% {trace, Pid, Label, Info, Extra} |
+%% {trace_ts, Pid, Label, Info, ReportedTS} |
+%% {trace_ts, Pid, Label, Info, Extra, ReportedTS} |
+%% {seq_trace, Label, Info} |
+%% {seq_trace, Label, Info, ReportedTS} |
+%% {drop, NumberOfDroppedItems}
+%%
+%% See erlang:trace/3 for more info about the semantics of
+%% the trace data.
+%%
+%% An event record consists of the following fields:
+%%
+%% detail_level - Noise has a high level as opposed to essentials.
+%% trace_ts - Time when the trace was generated.
+%% Same as event_ts if omitted in trace data.
+%% event_ts - Time when the event record was created.
+%% from - From actor, such as sender of a message.
+%% to - To actor, such as receiver of message.
+%% label - Label intended to provide a brief event summary.
+%% contents - All nitty gritty details of the event.
+%%
+%% See et:report_event/4 and et:report_event/5 for details.
+%%
+%% Returns:
+%%
+%% {true, Event} - where Event is an #event{} record representing the
+%% trace data
+%% true - means that the trace data already is an event
+%% record and that it is valid as it is.
+%% No transformation is needed.
+%% false - means that the trace data is uninteresting and
+%% should be dropped
+%%----------------------------------------------------------------------
+
+parse_event(_Mod, E) when record(E, event) ->
+ true;
+parse_event(Mod, Trace) ->
+ ParsedTS = erlang:now(),
+ case Trace of
+ {trace, Pid, Label, Info} ->
+ parse_event(Mod, Trace, ParsedTS, ParsedTS, Pid, Label, [Info]);
+ {trace, Pid, Label, Info, Extra} ->
+ parse_event(Mod, Trace, ParsedTS, ParsedTS, Pid, Label, [Info, Extra]);
+ {trace_ts, Pid, Label, Info, ReportedTS} ->
+ parse_event(Mod, Trace, ParsedTS, ReportedTS, Pid, Label, [Info]);
+ {trace_ts, Pid, Label, Info, Extra, ReportedTS} ->
+ parse_event(Mod, Trace, ParsedTS, ReportedTS, Pid, Label, [Info, Extra]);
+ {seq_trace, Label, Info} ->
+ parse_seq_event(Trace, ParsedTS, ParsedTS, Label, Info);
+ {seq_trace, Label, Info, ReportedTS} ->
+ parse_seq_event(Trace, ParsedTS, ReportedTS, Label, Info);
+ {drop, NumberOfDroppedItems} ->
+ DetailLevel = 20,
+ {true, #event{detail_level = DetailLevel,
+ trace_ts = ParsedTS,
+ event_ts = ParsedTS,
+ from = undefined,
+ to = undefined,
+ label = drop,
+ contents = [{label, drop},
+ {detail_level, DetailLevel},
+ {from, undefined},
+ {to, undefined},
+ {drop, NumberOfDroppedItems}]}};
+ _ ->
+ error_logger:format("~p(~p): Ignoring unknown trace type -> ~p~n~n",
+ [?MODULE, ?LINE, Trace]),
+ false
+ end.
+
+parse_seq_event(Trace, ParsedTS, ReportedTS, Label, Info) ->
+ case Info of
+ {send, Serial, From, To, Msg} ->
+ DetailLevel = 15,
+ {true, #event{detail_level = DetailLevel,
+ trace_ts = ReportedTS,
+ event_ts = ParsedTS,
+ from = From,
+ to = To,
+ label = {seq_send, Label},
+ contents = [{label, {seq_send, Label}},
+ {detail_level, DetailLevel},
+ {from, From},
+ {to, To},
+ {serial, Serial},
+ {msg, Msg}]}};
+ {'receive', Serial, From, To, Msg} ->
+ DetailLevel = 10,
+ {true, #event{detail_level = DetailLevel,
+ trace_ts = ReportedTS,
+ event_ts = ParsedTS,
+ from = From,
+ to = To,
+ label = {seq_receive, Label},
+ contents = [{label, {seq_receive, Label}},
+ {detail_level, DetailLevel},
+ {from, From},
+ {to, To},
+ {serial, Serial},
+ {msg, Msg}]}};
+ {print, Serial, From, _, UserInfo} ->
+ DetailLevel = 5,
+ {true, #event{detail_level = DetailLevel,
+ trace_ts = ReportedTS,
+ event_ts = ParsedTS,
+ from = From,
+ to = From,
+ label = {seq_print, Label},
+ contents = [{label, {seq_print, Label}},
+ {detail_level, DetailLevel},
+ {from, From},
+ {to, From},
+ {serial, Serial},
+ {user_info, UserInfo}]}};
+ _ ->
+ error_logger:format("~p(~p): Ignoring unknown trace type -> ~p~n~n",
+ [?MODULE, ?LINE, Trace]),
+ false
+ end.
+
+parse_event(Mod, Trace, ParsedTS, ReportedTS, From, Label, Contents) ->
+ case Label of
+ 'receive' ->
+ DetailLevel = 35,
+ [Msg] = Contents,
+ {true, #event{detail_level = DetailLevel,
+ trace_ts = ReportedTS,
+ event_ts = ParsedTS,
+ from = From,
+ to = From,
+ label = Label,
+ contents = [{label, Label},
+ {detail_level, DetailLevel},
+ {from, From},
+ {to, From},
+ {msg, Msg}]}};
+ send ->
+ DetailLevel = 40,
+ [Msg, To] = Contents,
+ {true, #event{detail_level = DetailLevel,
+ trace_ts = ReportedTS,
+ event_ts = ParsedTS,
+ from = From,
+ to = To,
+ label = Label,
+ contents = [{label, Label},
+ {detail_level, DetailLevel},
+ {from, From},
+ {to, To},
+ {msg, Msg}]}};
+ send_to_non_existing_process ->
+ DetailLevel = 40,
+ [Msg, To] = Contents,
+ {true, #event{detail_level = DetailLevel,
+ trace_ts = ReportedTS,
+ event_ts = ParsedTS,
+ from = From,
+ to = To,
+ label = Label,
+ contents = [{label, Label},
+ {detail_level, DetailLevel},
+ {from, From},
+ {to, To},
+ {msg, Msg}]}};
+ call ->
+ case Contents of
+ [{M, report_event, [UserDetailLevel, UserFrom, UserTo, UserLabel, UserContents]}] when M == Mod, Mod /= undefined ->
+ {true, #event{detail_level = UserDetailLevel,
+ trace_ts = ReportedTS,
+ event_ts = ParsedTS,
+ from = UserFrom,
+ to = UserTo,
+ label = UserLabel,
+ contents = UserContents}}; % Term
+ [MFA] ->
+ DetailLevel = 45,
+ {true, #event{detail_level = DetailLevel,
+ trace_ts = ReportedTS,
+ event_ts = ParsedTS,
+ from = From,
+ to = From,
+ label = Label,
+ contents = [{label, Label},
+ {detail_level, DetailLevel},
+ {from, From},
+ {to, From},
+ {mfa, MFA}]}};
+ [MFA, PamResult] ->
+ DetailLevel = 45,
+ {true, #event{detail_level = DetailLevel,
+ trace_ts = ReportedTS,
+ event_ts = ParsedTS,
+ from = From,
+ to = From,
+ label = Label,
+ contents = [{label, Label},
+ {detail_level, DetailLevel},
+ {from, From},
+ {to, From},
+ {mfa, MFA},
+ {pam_result, PamResult}]}}
+ end;
+ return_to ->
+ DetailLevel = 50,
+ [MFA] = Contents,
+ {true, #event{detail_level = DetailLevel,
+ trace_ts = ReportedTS,
+ event_ts = ParsedTS,
+ from = From,
+ to = From,
+ label = Label,
+ contents = [{label, Label},
+ {detail_level, DetailLevel},
+ {from, From},
+ {to, From},
+ {mfa, MFA}]}};
+ return_from ->
+ DetailLevel = 52,
+ [MFA, ReturnValue] = Contents,
+ {true, #event{detail_level = DetailLevel,
+ trace_ts = ReportedTS,
+ event_ts = ParsedTS,
+ from = From,
+ to = From,
+ label = Label,
+ contents = [{label, Label},
+ {detail_level, DetailLevel},
+ {from, From},
+ {to, From},
+ {mfa, MFA},
+ {return, ReturnValue}]}};
+ spawn ->
+ DetailLevel = 25,
+ [NewPid, MFA] = Contents,
+ {true, #event{detail_level = DetailLevel,
+ trace_ts = ReportedTS,
+ event_ts = ParsedTS,
+ from = From,
+ to = NewPid,
+ label = Label,
+ contents = [{label, Label},
+ {detail_level, DetailLevel},
+ {from, From},
+ {to, NewPid},
+ {mfa, MFA}]}}; % MFA | Term
+ exit ->
+ DetailLevel = 30,
+ [Reason] = Contents,
+ {true, #event{detail_level = DetailLevel,
+ trace_ts = ReportedTS,
+ event_ts = ParsedTS,
+ from = From,
+ to = From,
+ label = Label,
+ contents = [{label, Label},
+ {detail_level, DetailLevel},
+ {from, From},
+ {to, From},
+ {reason, Reason}]}};
+ link ->
+ DetailLevel = 55,
+ [LinkTo] = Contents,
+ {true, #event{detail_level = DetailLevel,
+ trace_ts = ReportedTS,
+ event_ts = ParsedTS,
+ from = From,
+ to = LinkTo,
+ label = Label,
+ contents = [{label, Label},
+ {detail_level, DetailLevel},
+ {from, From},
+ {to, LinkTo}]}};
+ unlink ->
+ DetailLevel = 60,
+ [UnlinkFrom] = Contents,
+ {true, #event{detail_level = DetailLevel,
+ trace_ts = ReportedTS,
+ event_ts = ParsedTS,
+ from = From,
+ to = UnlinkFrom,
+ label = Label,
+ contents = [{label, Label},
+ {detail_level, DetailLevel},
+ {from, From},
+ {to, UnlinkFrom}]}};
+ getting_linked ->
+ DetailLevel = 65,
+ [LinkTo] = Contents,
+ {true, #event{detail_level = DetailLevel,
+ trace_ts = ReportedTS,
+ event_ts = ParsedTS,
+ from = From,
+ to = LinkTo,
+ label = Label,
+ contents = [{label, Label},
+ {detail_level, DetailLevel},
+ {from, From},
+ {to, LinkTo}]}};
+ getting_unlinked ->
+ DetailLevel = 67,
+ [UnlinkFrom] = Contents,
+ {true, #event{detail_level = DetailLevel,
+ trace_ts = ReportedTS,
+ event_ts = ParsedTS,
+ from = From,
+ to = UnlinkFrom,
+ label = Label,
+ contents = [{label, Label},
+ {detail_level, DetailLevel},
+ {from, From},
+ {to, UnlinkFrom}]}};
+ register ->
+ DetailLevel = 70,
+ [Name] = Contents,
+ {true, #event{detail_level = DetailLevel,
+ trace_ts = ReportedTS,
+ event_ts = ParsedTS,
+ from = From,
+ to = From,
+ label = Label,
+ contents = [{label, Label},
+ {detail_level, DetailLevel},
+ {from, From},
+ {to, From},
+ {name, Name}]}};
+ unregister ->
+ DetailLevel = 75,
+ [Name] = Contents,
+ {true, #event{detail_level = DetailLevel,
+ trace_ts = ReportedTS,
+ event_ts = ParsedTS,
+ from = From,
+ to = From,
+ label = Label,
+ contents = [{label, Label},
+ {detail_level, DetailLevel},
+ {from, From},
+ {to, From},
+ {name, Name}]}};
+ in ->
+ DetailLevel = 90,
+ [MFA] = Contents,
+ {true, #event{detail_level = DetailLevel,
+ trace_ts = ReportedTS,
+ event_ts = ParsedTS,
+ from = From,
+ to = From,
+ label = Label,
+ contents = [{label, Label},
+ {detail_level, DetailLevel},
+ {from, From},
+ {to, From},
+ {mfa, MFA}]}}; % MFA | 0
+ out ->
+ DetailLevel = 95,
+ [MFA] = Contents,
+ {true, #event{detail_level = DetailLevel,
+ trace_ts = ReportedTS,
+ event_ts = ParsedTS,
+ from = From,
+ to = From,
+ label = Label,
+ contents = [{label, Label},
+ {detail_level, DetailLevel},
+ {from, From},
+ {to, From},
+ {mfa, MFA}]}}; % MFA | 0
+ gc_start ->
+ DetailLevel = 80,
+ [GcKeyValueList] = Contents,
+ {true, #event{detail_level = DetailLevel,
+ trace_ts = ReportedTS,
+ event_ts = ParsedTS,
+ from = From,
+ to = From,
+ label = Label,
+ contents = [{label, Label},
+ {detail_level, DetailLevel},
+ {from, From},
+ {to, From},
+ {gc_items, GcKeyValueList}]}};
+ gc_end ->
+ DetailLevel = 85,
+ [GcKeyValueList] = Contents,
+ {true, #event{detail_level = DetailLevel,
+ trace_ts = ReportedTS,
+ event_ts = ParsedTS,
+ from = From,
+ to = From,
+ label = Label,
+ contents = [{label, Label},
+ {detail_level, DetailLevel},
+ {from, From},
+ {to, From},
+ {gc_items, GcKeyValueList}]}};
+ _ ->
+ error_logger:format("~p(~p): Ignoring unknown trace type -> ~p~n~n",
+ [?MODULE, ?LINE, Trace]),
+ false
+ end.