aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDan Gudmundsson <[email protected]>2011-11-18 16:14:34 +0100
committerDan Gudmundsson <[email protected]>2011-11-18 16:14:34 +0100
commit39730743916b300eb3e229c4e6e8a2987487d797 (patch)
tree33f2cd67d97ddc3d0fb56091d3e847491808f311
parent45fb452f5f067c5658a3dfe16495032728bf8a9d (diff)
downloadotp-39730743916b300eb3e229c4e6e8a2987487d797.tar.gz
otp-39730743916b300eb3e229c4e6e8a2987487d797.tar.bz2
otp-39730743916b300eb3e229c4e6e8a2987487d797.zip
[observer] Implemented basic tracing functionality
Use ttb which does most of the work already.
-rw-r--r--lib/observer/src/observer_procinfo.erl2
-rw-r--r--lib/observer/src/observer_trace_wx.erl274
-rw-r--r--lib/observer/src/observer_traceoptions_wx.erl658
-rw-r--r--lib/observer/src/ttb.erl44
4 files changed, 195 insertions, 783 deletions
diff --git a/lib/observer/src/observer_procinfo.erl b/lib/observer/src/observer_procinfo.erl
index 2600109161..127599a39e 100644
--- a/lib/observer/src/observer_procinfo.erl
+++ b/lib/observer/src/observer_procinfo.erl
@@ -137,7 +137,7 @@ init_process_page(Panel, Pid) ->
init_text_page(Parent) ->
Style = ?wxTE_MULTILINE bor ?wxTE_RICH2 bor ?wxTE_READONLY,
Text = wxTextCtrl:new(Parent, ?wxID_ANY, [{style, Style}]),
- Font = observer_wx:get_attrib({font, modern}),
+ Font = observer_wx:get_attrib({font, fixed}),
Attr = wxTextAttr:new(?wxBLACK, [{font, Font}]),
true = wxTextCtrl:setDefaultStyle(Text, Attr),
wxTextAttr:destroy(Attr),
diff --git a/lib/observer/src/observer_trace_wx.erl b/lib/observer/src/observer_trace_wx.erl
index 23b9b1fe6b..0ab7db121b 100644
--- a/lib/observer/src/observer_trace_wx.erl
+++ b/lib/observer/src/observer_trace_wx.erl
@@ -39,6 +39,7 @@
-define(PROCESSES, 350).
-define(MODULES, 351).
-define(FUNCTIONS, 352).
+-define(TRACERWIN, 353).
-record(state,
{parent,
@@ -91,6 +92,7 @@ create_window(Notebook, ParentPid) ->
wxWindow:setSizer(Panel, Sizer),
{Panel, #state{parent=ParentPid, panel=Panel,
p_view=ProcessView, m_view=ModView, f_view=FuncView,
+ toggle_button = ToggleButton,
match_specs=default_matchspecs()}}.
default_matchspecs() ->
@@ -204,6 +206,46 @@ handle_event(#wx{id=?MODULES, event=#wxList{type=command_list_item_selected, ite
update_functions_view(dict:fetch(Module, TPs), Fview),
{noreply, State};
+
+handle_event(#wx{event = #wxCommand{type = command_togglebutton_clicked, commandInt = 1}},
+ #state{panel = Panel,
+ nodes = Nodes,
+ tpids = TProcs,
+ tpatterns = TPs,
+ toggle_button = ToggleBtn} = State) ->
+ LogWin = wxFrame:new(Panel, ?TRACERWIN, "Trace Log", [{size, {750, 800}}]),
+ Text = wxTextCtrl:new(LogWin, ?wxID_ANY,
+ [{style, ?wxTE_MULTILINE bor ?wxTE_RICH2 bor
+ ?wxTE_DONTWRAP bor ?wxTE_READONLY}]),
+ Font = observer_wx:get_attrib({font, fixed}),
+ Attr = wxTextAttr:new(?wxBLACK, [{font, Font}]),
+ true = wxTextCtrl:setDefaultStyle(Text, Attr),
+ Env = wx:get_env(),
+ Write = fun(Trace) ->
+ wx:set_env(Env),
+ wxTextCtrl:appendText(Text, textformat(Trace))
+ end,
+ {ok, _} = ttb:tracer(Nodes, [{file, {local,"/tmp/foo"}}, {shell, {only, Write}}]),
+ setup_ttb(dict:to_list(TPs), TProcs),
+ wxFrame:connect(LogWin, close_window, [{skip, true}]),
+ wxFrame:show(LogWin),
+ wxToggleButton:setLabel(ToggleBtn, "Stop Trace"),
+ {noreply, State};
+
+handle_event(#wx{event = #wxCommand{type = command_togglebutton_clicked, commandInt = 0}},
+ #state{toggle_button = ToggleBtn} = State) ->
+ %%Stop tracing
+ ttb:stop(nofetch),
+ wxToggleButton:setLabel(ToggleBtn, "Start Trace"),
+ {noreply, State};
+
+handle_event(#wx{id=?TRACERWIN, event=#wxClose{}},
+ #state{toggle_button = ToggleBtn} = State) ->
+ %%Stop tracing
+ ttb:stop(nofetch),
+ wxToggleButton:setLabel(ToggleBtn, "Start Trace"),
+ {noreply, State};
+
%% handle_event(#wx{id = ?CLEAR, event = #wxCommand{type = command_menu_selected}},
%% #state{text_ctrl = TxtCtrl} = State) ->
%% wxTextCtrl:clear(TxtCtrl),
@@ -261,28 +303,6 @@ handle_event(#wx{id = ?LOAD_TRACEOPTS,
wxDialog:destroy(Dialog),
{noreply, State2};
-
-%% handle_event(#wx{event = #wxCommand{type = command_togglebutton_clicked, commandInt = 1}},
-%% #state{node = Node,
-%% traced_procs = TracedProcs,
-%% traced_funcs = TracedDict,
-%% trace_options = TraceOpts,
-%% text_ctrl = TextCtrl,
-%% toggle_button = ToggleBtn} = State) ->
-
-%% start_trace(Node, TracedProcs, TracedDict, TraceOpts),
-%% wxTextCtrl:appendText(TextCtrl, "Start Trace:\n"),
-%% wxToggleButton:setLabel(ToggleBtn, "Stop Trace"),
-%% {noreply, State};
-
-%% handle_event(#wx{event = #wxCommand{type = command_togglebutton_clicked, commandInt = 0}}, %%Stop tracing
-%% #state{text_ctrl = TxtCtrl,
-%% toggle_button = ToggleBtn} = State) ->
-%% dbg:stop_clear(),
-%% wxTextCtrl:appendText(TxtCtrl, "Stop Trace.\n"),
-%% wxToggleButton:setLabel(ToggleBtn, "Start Trace"),
-%% {noreply, State};
-
handle_event(#wx{id=ID, event = What}, State) ->
io:format("~p:~p: Unhandled event: ~p, ~p ~n", [?MODULE, self(), ID, What]),
{noreply, State}.
@@ -321,7 +341,7 @@ handle_info(Any, State) ->
io:format("~p~p: received unexpected message: ~p\n", [?MODULE, self(), Any]),
{noreply, State}.
-terminate(Reason, #state{nodes=Nodes}) ->
+terminate(_Reason, #state{nodes=_Nodes}) ->
%% case observer_wx:try_rpc(Node, erlang, whereis, [dbg]) of
%% undefined -> fine;
%% Pid -> exit(Pid, kill)
@@ -337,7 +357,7 @@ do_add_processes(POpts, S0=#state{p_view=LCtrl, tpids=OldPids, nodes=Ns0}) ->
case merge_pids(POpts, OldPids) of
{OldPids, [], []} ->
S0;
- {Pids, New, Changed} ->
+ {Pids, New, _Changed} ->
update_process_view(Pids, LCtrl),
Ns1 = lists:usort([node(Pid) || #tpid{pid=Pid} <- New, is_pid(Pid)]),
Nodes = case ordsets:subtract(Ns1, Ns0) of
@@ -369,7 +389,7 @@ do_add_patterns({Module, NewPs}, State=#state{tpatterns=TPs0, m_view=Mview, f_vi
case merge_patterns(NewPs, Old) of
{Old, [], []} ->
State;
- {MPatterns, New, Changed} ->
+ {MPatterns, _New, _Changed} ->
TPs = dict:store(Module, MPatterns, TPs0),
update_modules_view(lists:sort(dict:fetch_keys(TPs)), Module, Mview),
update_functions_view(dict:fetch(Module, TPs), Fview),
@@ -437,111 +457,115 @@ merge(Ns, [], _El, New, Ch, All) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-start_trace(Node, TracedProcs, TracedDict,
- #trace_options{send = Send, treceive = Receive, functions = Functions,
- events = Events, on_1st_spawn = On1Spawn,
- on_all_spawn = AllSpawn, on_1st_link = On1Link,
- on_all_link = AllLink}) ->
- dbg:stop_clear(),
- MyPid = self(),
- HandlerFun = fun(NewMsg, _) ->
- MyPid ! NewMsg
- end,
- dbg:tracer(process, {HandlerFun, []}),
-
- case Node =:= node() of
- true ->
- ok;
- false ->
- dbg:n(Node)
- end,
-
- Recs = [{Send, send},
- {Receive, 'receive'},
- {Functions, call},
- {Events, procs},
- {On1Spawn, set_on_first_spawn},
- {AllSpawn, set_on_spawn},
- {On1Link, set_on_first_link},
- {AllLink, set_on_link}],
- Flags = [Assoc || {true, Assoc} <- Recs],
-
- case TracedProcs of
- all ->
- dbg:p(all, Flags);
- new ->
- dbg:p(new, Flags);
- _Pids ->
- lists:foreach(fun(Pid) -> dbg:p(Pid, Flags) end, TracedProcs)
- end,
+setup_ttb(TPs, TPids) ->
+ _R1 = [setup_tps(FTP, []) || {_, FTP} <- TPs],
+ _R2 = [ttb:p(Pid, dbg_flags(Flags)) || #tpid{pid=Pid, opts=Flags} <- TPids],
+ [#tpid{pid=_Pid, opts=_Flags}|_] = TPids,
+ %% io:format("ttb:p(pid(\"~w\", ~w).", [Pid, Flags]),
+ %% io:format("TTB ~w ~w~n",[R2, R1]),
+ ok.
- case Functions of
- true ->
- trace_functions(TracedDict);
- false ->
- ok
+%% Sigh order is important
+setup_tps([First=#tpattern{fa={_,'_'}}|Rest], Prev) ->
+ setup_tp(First),
+ [setup_tp(TP) || TP <- lists:reverse(Prev)],
+ setup_tps(Rest, []);
+setup_tps([First=#tpattern{fa={F,_}}|Rest], Prev = [#tpattern{fa={F,_}}|_]) ->
+ setup_tps(Rest, [First|Prev]);
+setup_tps([First|Rest], Prev) ->
+ [setup_tp(TP) || TP <- lists:reverse(Prev)],
+ setup_tps(Rest, [First]);
+setup_tps([], Prev) ->
+ [setup_tp(TP) || TP <- lists:reverse(Prev)].
+
+setup_tp(#tpattern{m=M,fa={F,A}, ms=#match_spec{term=Ms}}) ->
+ ttb:tpl(M,F,A,Ms).
+
+dbg_flags(Flags) ->
+ [dbg_flag(Flag) || Flag <- Flags].
+
+dbg_flag(send) -> s;
+dbg_flag('receive') -> r;
+dbg_flag(functions) -> c;
+dbg_flag(on_spawn) -> sos;
+dbg_flag(on_link) -> sol;
+dbg_flag(on_first_spawn) -> sofs;
+dbg_flag(on_first_link) -> sofl;
+dbg_flag(events) -> p.
+
+textformat(Trace) when element(1, Trace) == trace_ts, tuple_size(Trace) >= 4 ->
+ format_trace(Trace, tuple_size(Trace)-1, element(tuple_size(Trace),Trace));
+textformat(Trace) when element(1, Trace) == drop, tuple_size(Trace) =:= 2 ->
+ io_lib:format("*** Dropped ~p messages.~n", [element(2,Trace)]);
+textformat(Trace) when element(1, Trace) == seq_trace, tuple_size(Trace) >= 3 ->
+ io_lib:format("*** Seq trace not implmented.~n", []);
+textformat(_) ->
+ "".
+
+format_trace(Trace, Size, TS0={_,_,MS}) ->
+ {_,{H,M,S}} = calendar:now_to_local_time(TS0),
+ TS = io_lib:format("~.2.0w:~.2.0w:~.2.0w:~.6.0w", [H,M,S,MS]),
+ From = element(2, Trace),
+ case element(3, Trace) of
+ 'receive' ->
+ case element(4, Trace) of
+ {dbg,ok} -> "";
+ Message ->
+ io_lib:format("~s (~100p) << ~100p ~n", [TS,From,Message])
+ end;
+ 'send' ->
+ Message = element(4, Trace),
+ To = element(5, Trace),
+ io_lib:format("~s (~100p) ~100p ! ~100p ~n", [TS,From,To,Message]);
+ call ->
+ case element(4, Trace) of
+ MFA when Size == 5 ->
+ Message = element(5, Trace),
+ io_lib:format("~s (~100p) call ~s (~100p) ~n", [TS,From,ffunc(MFA),Message]);
+ MFA ->
+ io_lib:format("~s (~100p) call ~s ~n", [TS,From,ffunc(MFA)])
+ end;
+ return_from ->
+ MFA = element(4, Trace),
+ Ret = element(5, Trace),
+ io_lib:format("~s (~100p) returned from ~s -> ~100p ~n", [TS,From,ffunc(MFA),Ret]);
+ return_to ->
+ MFA = element(4, Trace),
+ io_lib:format("~s (~100p) returning to ~s ~n", [TS,From,ffunc(MFA)]);
+ spawn when Size == 5 ->
+ Pid = element(4, Trace),
+ MFA = element(5, Trace),
+ io_lib:format("~s (~100p) spawn ~100p as ~s ~n", [TS,From,Pid,ffunc(MFA)]);
+ Op ->
+ io_lib:format("~s (~100p) ~100p ~s ~n", [TS,From,Op,ftup(Trace,4,Size)])
end.
-textformat({died, Pid}) ->
- io_lib:format("~w Process died.~n",[Pid]);
-textformat({shell_died, Old, New}) ->
- io_lib:format("~w Shell Process died. Restarted as ~w~n~n",[Old,New]);
-textformat({trace, From, 'receive', Msg}) ->
- io_lib:format("~w: rec ~s~n", [From,
- tuple_space(Msg)]);
-textformat({trace, From, send, Msg, To}) ->
- io_lib:format("~w: ! To: ~w Msg: ~s~n", [From,
- To,
- tuple_space(Msg)]);
-textformat({trace, From, call, Func}) ->
- io_lib:format("~w: call ~s~n",[From, ffunc(Func)]);
-textformat({trace, From, spawn, Data}) ->
- io_lib:format("~w: spawn ~p~n", [From, Data]);
-textformat({trace, From, link, Data}) ->
- io_lib:format("~w: link ~p~n", [From, Data]);
-textformat({trace, From, unlink, Data}) ->
- io_lib:format("~w: U-lnk ~p~n", [From, Data]);
-
-textformat({trace, From, Op, Data}) ->
- io_lib:format("~w: ~w ~p~n", [From, Op, Data]);
-
-textformat({print, Format, Args}) ->
- io_lib:format(Format, Args);
-textformat(Other) ->
- io_lib:format("~p~n",[Other]).
-
-
-tuple_space(X) when is_tuple(X) -> print(tuple_size(X), X, "}");
-tuple_space(X) -> io_lib:format("~p",[X]).
-
-
-ffunc({M,F, Argl}) ->
- io_lib:format("~w:~w(~s)", [M, F, fargs(Argl)]);
-ffunc(X) -> tuple_space(X).
+%%% These f* functions returns non-flat strings
+
+%% {M,F,[A1, A2, ..., AN]} -> "M:F(A1, A2, ..., AN)"
+%% {M,F,A} -> "M:F/A"
+ffunc({M,F,Argl}) when is_list(Argl) ->
+ io_lib:format("~100p:~100p(~s)", [M, F, fargs(Argl)]);
+ffunc({M,F,Arity}) ->
+ io_lib:format("~100p:~100p/~100p", [M,F,Arity]);
+ffunc(X) -> io_lib:format("~100p", [X]).
+%% Integer -> "Integer"
+%% [A1, A2, ..., AN] -> "A1, A2, ..., AN"
+fargs(Arity) when is_integer(Arity) -> integer_to_list(Arity);
fargs([]) -> [];
-fargs([A]) -> tuple_space(A); %% last arg
-fargs([A|Args]) -> [tuple_space(A),", "|fargs(Args)].
-
-print(0 , _X, Buff) -> ["{"|Buff];
-print(1 , X, Buff) ->
- Str = tuple_space(element(1, X)),
- ["{",Str|Buff];
-print(Num, X, Buff) ->
- Str = tuple_space(element(Num, X)),
- print(Num-1, X, [", ",Str|Buff]).
-
-trace_functions(TracedDict) ->
- Trace = fun(KeyAtom, RecordList, acc_in) ->
- lists:foreach(fun(#traced_func{func_name = Function,
- arity = Arity,
- match_spec = #match_spec{term = MS}}) ->
- dbg:tpl({KeyAtom, Function, Arity}, MS)
- end,
- RecordList),
- acc_in
- end,
- dict:fold(Trace, acc_in, TracedDict).
+fargs([A]) -> io_lib:format("~100p", [A]); %% last arg
+fargs([A|Args]) -> [io_lib:format("~100p,", [A]) | fargs(Args)];
+fargs(A) -> io_lib:format("~100p", [A]). % last or only arg
+
+%% {A_1, A_2, ..., A_N} -> "A_Index A_Index+1 ... A_Size"
+ftup(Trace, Index, Index) ->
+ io_lib:format("~100p", [element(Index, Trace)]);
+ftup(Trace, Index, Size) ->
+ [io_lib:format("~100p ", [element(Index, Trace)])
+ | ftup(Trace, Index+1, Size)].
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
write_file(Frame, Filename, TraceOps, MatchSpecs, TPs) ->
FormatMS = fun(#match_spec{name=Id, term=T, func=F}) ->
diff --git a/lib/observer/src/observer_traceoptions_wx.erl b/lib/observer/src/observer_traceoptions_wx.erl
index 043126d85f..bad05ec016 100644
--- a/lib/observer/src/observer_traceoptions_wx.erl
+++ b/lib/observer/src/observer_traceoptions_wx.erl
@@ -145,14 +145,22 @@ module_selector(Parent, Node) ->
wxListBox:connect(ListBox, command_listbox_doubleclicked,
[{callback, fun(_, _) -> wxDialog:endModal(Dialog, ?wxID_OK) end}]),
wxListBox:connect(ListBox, command_listbox_selected,
- [{callback, fun(_, _) -> wxWindow:enable(OkButt) end}]),
+ [{callback, fun(#wx{event=#wxCommand{commandInt=Id}}, _) ->
+ Id >= 0 andalso wxWindow:enable(OkButt)
+ end}]),
case wxDialog:showModal(Dialog) of
?wxID_OK ->
SelId = wxListBox:getSelection(ListBox),
- Module = wxListBox:getClientData(ListBox, SelId),
- wxDialog:destroy(Dialog),
- Module;
+ case SelId >= 0 of
+ true ->
+ Module = wxListBox:getClientData(ListBox, SelId),
+ wxDialog:destroy(Dialog),
+ Module;
+ false ->
+ wxDialog:destroy(Dialog),
+ throw(cancel)
+ end;
?wxID_CANCEL ->
wxDialog:destroy(Dialog),
throw(cancel)
@@ -194,7 +202,7 @@ function_selector(Parent, Node, Module) ->
filter_listbox_data("", ParsedChoices, ListBox, false),
%% Setup Event handling
wxTextCtrl:connect(TxtCtrl, command_text_updated,
- [{callback,
+ [{callback,
fun(#wx{event=#wxCommand{cmdString=Input}}, _) ->
filter_listbox_data(Input, ParsedChoices, ListBox, false)
end}]),
@@ -208,7 +216,7 @@ function_selector(Parent, Node, Module) ->
Data
end,
wxCheckListBox:connect(ListBox, command_checklistbox_toggled,
- [{callback,
+ [{callback,
fun(#wx{event=#wxCommand{commandInt=N}}, _) ->
Self ! {ListBox, wxCheckListBox:isChecked(ListBox, N),
GetClientData(ListBox, N)}
@@ -443,11 +451,11 @@ filter_listbox_data(Input, Data, ListBox, AddClientData) ->
FilteredData = [X || X = {Str, _} <- Data, re:run(Str, Input) =/= nomatch],
wxListBox:clear(ListBox),
wxListBox:appendStrings(ListBox, [Str || {Str,_} <- FilteredData]),
- AddClientData andalso
+ AddClientData andalso
wx:foldl(fun({_, Term}, N) ->
wxListBox:setClientData(ListBox, N, Term),
N+1
- end, 0, FilteredData),
+ end, 0, FilteredData),
FilteredData.
get_modules(Node) ->
@@ -468,7 +476,7 @@ optionpage_top_right(Panel, TopRightSz, Options, Text) ->
create_styled_txtctrl(Parent) ->
- FixedFont = observer_wx:get_attrib({font, modern}),
+ FixedFont = observer_wx:get_attrib({font, fixed}),
Ed = wxStyledTextCtrl:new(Parent),
wxStyledTextCtrl:styleClearAll(Ed),
wxStyledTextCtrl:styleSetFont(Ed, ?wxSTC_STYLE_DEFAULT, FixedFont),
@@ -553,194 +561,6 @@ ms_names(MatchSpecList) ->
end,
[{MsOrAlias(X), X} || X <- MatchSpecList].
-
-%% find_and_format_ms(Selection, [ #match_spec{str_ms = Spec, alias = Alias, fun2ms = Fun} | T ]) ->
-%% case ((Selection =:= Spec) or (Selection =:= Alias)) or (Selection =:= Fun) of
-%% true ->
-%% if Selection =:= Alias ->
-%% Spec;
-%% true ->
-%% Selection
-%% end;
-%% false ->
-%% find_and_format_ms(Selection, T)
-%% end.
-
-%% find_ms(_, []) ->
-%% {nomatch, #match_spec{}};
-%% find_ms(Str, [ #match_spec{str_ms = Spec, alias = Alias, fun2ms = Fun} = MS | T ]) ->
-%% case ((Str =:= Spec) or (Str =:= Alias)) or (Str =:= Fun) of
-%% true ->
-%% {match, MS};
-%% false ->
-%% find_ms(Str, T)
-%% end.
-
-%% apply_matchspec(MatchSpec, TracedDict, root) ->
-%% UpdateMS = fun(_Key, RecordList) ->
-%% [X#traced_func{match_spec = MatchSpec} || X <- RecordList]
-%% end,
-%% {ok, dict:map(UpdateMS, TracedDict)};
-%% apply_matchspec(MatchSpec, TracedDict, {module, Module}) ->
-%% RecordList = dict:fetch(Module, TracedDict),
-%% RecordList2 = [X#traced_func{match_spec = MatchSpec} || X <- RecordList],
-%% {ok, dict:store(Module, RecordList2, TracedDict)};
-%% apply_matchspec(MatchSpec, TracedDict, {function, Module, TracedFuncRec}) ->
-%% RecordList = dict:fetch(Module, TracedDict),
-%% NewFunc = TracedFuncRec#traced_func{match_spec = MatchSpec},
-%% RecordList2 = [NewFunc | [X || X <- RecordList, X =/= TracedFuncRec]],
-%% {NewFunc, dict:store(Module, RecordList2, TracedDict)}.
-
-%% create_matchspec_page(Parent, MatchSpecs, UserData) ->
-%% Panel = wxPanel:new(Parent),
-%% MainSz = wxBoxSizer:new(?wxVERTICAL),
-%% TxtSz = wxStaticBoxSizer:new(?wxVERTICAL, Panel, [{label, "Match specification:"}]),
-%% BtnSz = wxBoxSizer:new(?wxHORIZONTAL),
-%% SavedSz = wxStaticBoxSizer:new(?wxVERTICAL, Panel, [{label, "Saved match specifications:"}]),
-
-%% TxtCtrl = create_styled_txtctrl(Panel),
-%% wxSizer:add(TxtSz, TxtCtrl, [{flag, ?wxEXPAND}, {proportion, 1}]),
-
-%% AddMsBtn = wxButton:new(Panel, ?MATCHPAGE_ADDMS, [{label, "Add"}]),
-%% AddMsAliasBtn = wxButton:new(Panel, ?MATCHPAGE_ADDMS_ALIAS, [{label, "Add with alias"}]),
-%% Fun2MSBtn = wxButton:new(Panel, ?MATCHPAGE_ADDFUN, [{label, "Add fun"}]),
-%% wxSizer:add(BtnSz, AddMsBtn),
-%% wxSizer:add(BtnSz, AddMsAliasBtn),
-%% wxSizer:add(BtnSz, Fun2MSBtn),
-
-%% Choices = show_ms_in_savedlistbox(MatchSpecs),
-%% SavedMSListBox = wxListBox:new(Panel, ?MATCHPAGE_LISTBOX, [{choices, Choices}]),
-%% wxSizer:add(SavedSz, SavedMSListBox, [{flag, ?wxEXPAND}, {proportion, 1}]),
-
-%% wxButton:connect(AddMsBtn, command_button_clicked, [{userData, UserData}]),
-%% wxButton:connect(AddMsAliasBtn, command_button_clicked, [{userData, UserData}] ),
-%% wxButton:connect(Fun2MSBtn, command_button_clicked, [{userData, UserData}] ),
-%% wxListBox:connect(SavedMSListBox, command_listbox_selected, [{userData, UserData}] ),
-%% wxSizer:add(MainSz, TxtSz, [{flag, ?wxEXPAND}, {proportion, 1}]),
-%% wxSizer:add(MainSz, BtnSz),
-%% wxSizer:add(MainSz, SavedSz, [{flag, ?wxEXPAND}, {proportion, 1}]),
-
-%% wxWindow:setSizer(Panel, MainSz),
-%% {Panel, MainSz, TxtCtrl, SavedMSListBox}.
-
-
-
-%% update_tree(Tree, Dict) ->
-%% RootId = wxTreeCtrl:getRootItem(Tree),
-%% wxTreeCtrl:deleteChildren(Tree, RootId),
-
-%% FillTree = fun(KeyAtom, RecordList, acc_in) ->
-%% ParsedList = parse_record_function_names(RecordList),
-%% Module = wxTreeCtrl:appendItem(Tree, RootId, atom_to_list(KeyAtom)),
-%% lists:foldl(fun(TracedFuncRecord, N) ->
-%% FNameStr = lists:nth(N, ParsedList),
-%% wxTreeCtrl:appendItem(Tree, Module, FNameStr,
-%% [{data, TracedFuncRecord}]),
-%% N+1
-%% end,
-%% 1, RecordList),
-%% wxTreeCtrl:sortChildren(Tree, Module),
-%% acc_in
-%% end,
-%% dict:fold(FillTree, acc_in, Dict),
-%% wxTreeCtrl:sortChildren(Tree, RootId),
-%% wxTreeCtrl:expand(Tree, RootId).
-
-
-
-
-%% create_module_popup(Parent, ModuleName, TracedDict) ->
-%% Module = list_to_atom(ModuleName),
-%% Value = dict:find(Module, TracedDict),
-%% TracedModRecs =
-%% case Value of
-%% {ok, V} ->
-%% V;
-%% error ->
-%% []
-%% end,
-%% Functions = Module:module_info(functions),
-%% Choices = lists:sort([{Name, Arity} || {Name, Arity} <- Functions, not(erl_internal:guard_bif(Name, Arity))]),
-%% ParsedChoices = parse_function_names(Choices),
-
-%% Dialog = wxDialog:new(Parent, ?MODULEPOPUP_DIALOG, ModuleName,
-%% [{style, ?wxDEFAULT_FRAME_STYLE}]),
-%% Panel = wxPanel:new(Dialog),
-%% MainSz = wxBoxSizer:new(?wxVERTICAL),
-
-%% SelBtnSz = wxBoxSizer:new(?wxHORIZONTAL),
-%% TxtCtrl = wxTextCtrl:new(Panel, ?MODULEPOPUP_TXTCTRL),
-%% SelBtn = wxButton:new(Panel, ?MODULEPOPUP_SELECT, [{label, "Select"}]),
-%% DeSelBtn = wxButton:new(Panel, ?MODULEPOPUP_SELECT, [{label, "Deselect"}]),
-%% SelAllBtn = wxButton:new(Panel, ?MODULEPOPUP_SELALL, [{label, "Select all"}]),
-%% DeSelAllBtn = wxButton:new(Panel, ?MODULEPOPUP_SELALL, [{label, "Deselect all"}]),
-%% CheckListBox = wxCheckListBox:new(Panel, ?MODULEPOPUP_CHECKLISTBOX, [{choices, ParsedChoices}, {style, ?wxLB_EXTENDED}]),
-%% Indices = find_index(TracedModRecs, Choices),
-%% lists:foreach(fun(X) -> wxCheckListBox:check(CheckListBox, X) end, Indices),
-%% Selections = [wxControlWithItems:getString(CheckListBox, I) || I <- Indices],
-
-%% OKBtn = wxButton:new(Panel, ?wxID_OK, []),
-%% CancelBtn = wxButton:new(Panel, ?wxID_CANCEL, []),
-%% DialogBtnSz = wxStdDialogButtonSizer:new(),
-%% wxStdDialogButtonSizer:addButton(DialogBtnSz, OKBtn),
-%% wxStdDialogButtonSizer:addButton(DialogBtnSz, CancelBtn),
-%% wxStdDialogButtonSizer:realize(DialogBtnSz),
-
-%% wxSizer:add(SelBtnSz, SelBtn),
-%% wxSizer:add(SelBtnSz, DeSelBtn),
-%% wxSizer:add(SelBtnSz, SelAllBtn),
-%% wxSizer:add(SelBtnSz, DeSelAllBtn),
-%% wxSizer:add(MainSz, TxtCtrl, [{flag, ?wxEXPAND}]),
-%% wxSizer:add(MainSz, CheckListBox, [{flag, ?wxEXPAND}, {proportion, 1}]),
-%% wxSizer:add(MainSz, SelBtnSz, [{flag, ?wxEXPAND}]),
-%% wxSizer:add(MainSz, DialogBtnSz),
-%% wxWindow:setSizer(Panel, MainSz),
-
-%% wxButton:connect(SelBtn, command_button_clicked, [{userData, true}]),
-%% wxButton:connect(DeSelBtn, command_button_clicked, [{userData, false}]),
-%% wxButton:connect(SelAllBtn, command_button_clicked, [{userData, true}]),
-%% wxButton:connect(DeSelAllBtn, command_button_clicked, [{userData, false}]),
-%% wxButton:connect(OKBtn, command_button_clicked, [{userData, {module_popup, Module, ParsedChoices, Choices}}]),
-%% wxButton:connect(CancelBtn, command_button_clicked, [{userData, module_popup}]),
-%% wxTextCtrl:connect(TxtCtrl, command_text_updated, [{userData, ParsedChoices}]),
-%% wxCheckListBox:connect(CheckListBox, command_checklistbox_toggled),
-%% wxDialog:connect(Dialog, close_window),
-%% wxDialog:show(Dialog),
-%% {Dialog, CheckListBox, Selections}.
-
-%% get_selections(Selections, FunctionList) ->
-%% get_selections(Selections, FunctionList, []).
-%% get_selections([], _, Acc) ->
-%% Acc;
-%% get_selections([Int|T], FuncList, Acc) ->
-%% get_selections(T, FuncList, [lists:nth(Int, FuncList) | Acc]).
-
-%% find_index(Selections, FunctionList) ->
-%% find_index(Selections, FunctionList, 1, []).
-%% find_index(Selections, FunctionList, N, Acc) when N > length(FunctionList); Selections =:= [] ->
-%% Acc;
-
-%% find_index([#traced_func{func_name = Name, arity = Arity} |STail] = Selections,
-%% FunctionList, N, Acc) ->
-%% {Fname, A} = lists:nth(N, FunctionList),
-%% case (Fname =:= Name) and (A =:= Arity) of
-%% true ->
-%% find_index(STail, FunctionList, 1, [N-1|Acc]);
-%% false ->
-%% find_index(Selections, FunctionList, N+1, Acc)
-%% end;
-
-%% find_index([Sel|STail] = Selections, FunctionList, N, Acc) when is_list(Sel) ->
-%% case lists:nth(N, FunctionList) =:= Sel of
-%% true ->
-%% find_index(STail, FunctionList, 1, [N-1|Acc]);
-%% false ->
-%% find_index(Selections, FunctionList, N+1, Acc)
-%% end.
-
-%% atomlist_to_stringlist(Modules) ->
-%% [atom_to_list(X) || X <- Modules].
-
ensure_last_is_dot([]) ->
".";
ensure_last_is_dot(String) ->
@@ -750,447 +570,3 @@ ensure_last_is_dot(String) ->
false ->
String ++ "."
end.
-
-
-%% dbg_from_string(Str0) ->
-%% Str = unicode:characters_to_list(Str0),
-%% case erl_scan:string(Str) of
-%% {ok, Tokens,_} ->
-%% case erl_parse:parse_exprs(Tokens) of
-%% {ok,[{'fun',_,{clauses, Cl}}]} ->
-%% case ms_transform:
-%% transform_from_shell(dbg,Cl,orddict:new()) of
-%% {error, [{_,[{Line,ms_transform,Info}]}],_} ->
-%% {error,{Line,ms_transform,Info}};
-%% {error, _} = ET1 ->
-%% ET1;
-%% Else ->
-%% {ok, Else, "[" ++ lists:flatten(io_lib:format("~p", Else)) ++ "]"}
-%% end;
-%% {ok,_} ->
-%% {error, {1,ms_transform,1}};
-%% {error,Reason} ->
-%% {error,Reason}
-%% end;
-%% {error,Reason2,_} ->
-%% {error,Reason2}
-%% end.
-
-%% get_correct_matchspec_components(From, State) ->
-%% case From of
-%% matchpage ->
-%% {State#traceopts_state.matchpage_styled_txtctrl,
-%% State#traceopts_state.frame};
-%% matchpopup ->
-%% {State#traceopts_state.matchspec_popup_styled_txtctrl,
-%% State#traceopts_state.matchspec_popup_dialog}
-%% end.
-
-
-
-%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% %Trace option window
-
-%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% All pages
-
-%% handle_event(#wx{id = ?wxID_OK,
-%% event = #wxCommand{type = command_button_clicked},
-%% userData = trace_options},
-%% #traceopts_state{boxes = Boxes,
-%% trace_options = TraceOpts,
-%% match_specs = MatchSpecs,
-%% traced_funcs = TracedFuncs,
-%% parent = Parent} = State) ->
-%% UpdTraceOpts = wx:batch(fun() ->
-%% read_trace_boxes(Boxes, TraceOpts)
-%% end),
-%% Parent ! {updated_traceopts,
-%% UpdTraceOpts,
-%% MatchSpecs,
-%% TracedFuncs},
-%% {stop, shutdown, State};
-
-%% handle_event(#wx{id = ?wxID_CANCEL,
-%% event = #wxCommand{type = command_button_clicked},
-%% userData = trace_options},
-%% #traceopts_state{parent = Parent} = State) ->
-%% Parent ! traceopts_closed,
-%% {stop, shutdown, State};
-
-%% handle_event(#wx{id = ?TRACEOPTS_FRAME,
-%% event = #wxClose{type = close_window}},
-%% #traceopts_state{parent = Parent} = State) ->
-%% Parent ! traceopts_closed,
-%% {stop, shutdown, State};
-
-
-%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Page - Tracing
-
-%% handle_event(#wx{event = #wxCommand{type = command_checkbox_clicked}, userData = Boxgroup},
-%% State) ->
-%% enable(Boxgroup),
-%% {noreply, State};
-
-
-%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Page - Functions
-
-%% handle_event(#wx{id = ?FUNCTIONPAGE_LISTBOX,
-%% event = #wxCommand{type = command_listbox_doubleclicked,
-%% cmdString = ChosenModule}},
-%% #traceopts_state{frame = Frame,
-%% traced_funcs = TracedDict,
-%% popup_open = false} = State) ->
-%% {Dialog, CheckListBox, CheckedFuncs} = create_module_popup(Frame, ChosenModule, TracedDict),
-%% {noreply, State#traceopts_state{popup_open = true,
-%% module_popup_dialog = Dialog,
-%% module_popup_checklistbox = CheckListBox,
-%% checked_funcs = CheckedFuncs}};
-
-%% handle_event(#wx{id = ?FUNCTIONPAGE_TXTCTRL,
-%% event = #wxCommand{type = command_text_updated,
-%% cmdString = Input},
-%% userData = Data},
-%% #traceopts_state{functionpage_listbox = ListBox} = State) ->
-%% filter_listbox_data(Input, Data, ListBox),
-%% {noreply, State};
-
-%% handle_event(#wx{event = #wxTree{type = command_tree_item_activated,
-%% item = Item}},
-%% #traceopts_state{frame = Frame,
-%% match_specs = MatchSpecs,
-%% popup_open = false} = State) ->
-
-%% Dialog = wxDialog:new(Frame, ?MATCH_POPUP_DIALOG, "Match specification",
-%% [{style, ?wxDEFAULT_FRAME_STYLE}]),
-%% {MatchPanel, MatchSz, StyledTxtCtrl, ListBox} = create_matchspec_page(Dialog, MatchSpecs, matchpopup),
-%% ApplyBtn = wxButton:new(MatchPanel, ?wxID_APPLY),
-%% CancelBtn = wxButton:new(MatchPanel, ?wxID_CANCEL, []),
-%% wxButton:connect(ApplyBtn, command_button_clicked, [{userData, Item}]),
-%% wxButton:connect(CancelBtn, command_button_clicked, [{userData, matchspec_popup}]),
-%% DialogBtnSz = wxStdDialogButtonSizer:new(),
-%% wxStdDialogButtonSizer:addButton(DialogBtnSz, ApplyBtn),
-%% wxStdDialogButtonSizer:addButton(DialogBtnSz, CancelBtn),
-%% wxStdDialogButtonSizer:realize(DialogBtnSz),
-%% wxSizer:add(MatchSz, DialogBtnSz),
-
-%% wxDialog:connect(Dialog, close_window),
-%% wxDialog:show(Dialog),
-%% {noreply, State#traceopts_state{matchspec_popup_dialog = Dialog,
-%% matchspec_popup_listbox = ListBox,
-%% matchspec_popup_styled_txtctrl = StyledTxtCtrl,
-%% popup_open = true}};
-
-%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Page - Match specs
-
-%% handle_event(#wx{event = #wxCommand{type = command_listbox_selected,
-%% cmdString = Txt}},
-%% State) when Txt =:= [] ->
-%% {noreply, State};
-
-%% handle_event(#wx{id = ?MATCHPAGE_LISTBOX,
-%% event = #wxCommand{type = command_listbox_selected,
-%% cmdString = SavedTxt},
-%% userData = From},
-%% #traceopts_state{match_specs = MatchSpecs} = State) ->
-%% {StyledTxtCtrl, _} = get_correct_matchspec_components(From, State),
-%% MsOrFun = find_and_format_ms(SavedTxt, MatchSpecs),
-%% wxStyledTextCtrl:setText(StyledTxtCtrl, MsOrFun),
-%% {noreply, State};
-
-%% handle_event(#wx{id = ?MATCHPAGE_ADDFUN,
-%% event = #wxCommand{type = command_button_clicked},
-%% userData = From},
-%% #traceopts_state{match_specs = MatchSpecs,
-%% matchpage_listbox = PageListBox,
-%% matchspec_popup_listbox = PopupListBox} = State) ->
-
-%% {StyledTxtCtrl, Frame} = get_correct_matchspec_components(From, State),
-%% StrFun = ensure_last_is_dot(wxStyledTextCtrl:getText(StyledTxtCtrl)),
-
-%% MatchSpecs2 = case dbg_from_string(StrFun) of
-%% {ok, TermMS, StrMS} ->
-%% FunMS = #match_spec{str_ms = StrMS, term_ms = TermMS, fun2ms = StrFun},
-%% case lists:member(FunMS, MatchSpecs) of
-%% true ->
-%% observer_wx:create_txt_dialog(Frame, StrFun ++ "\nalready exists",
-%% "Error", ?wxICON_ERROR),
-%% MatchSpecs;
-%% false ->
-%% wxStyledTextCtrl:setText(StyledTxtCtrl, StrMS),
-%% update_matchspec_listbox(StrFun, {PopupListBox, PageListBox}, From),
-%% lists:reverse([FunMS | MatchSpecs])
-%% end;
-%% {error, {_, Module, What}} ->
-%% FailMsg = Module:format_error(What),
-%% observer_wx:create_txt_dialog(Frame, FailMsg, "Error", ?wxICON_ERROR),
-%% MatchSpecs
-%% end,
-%% {noreply, State#traceopts_state{match_specs = MatchSpecs2}};
-
-%% handle_event(#wx{id = ?MATCHPAGE_ADDMS,
-%% event = #wxCommand{type = command_button_clicked},
-%% userData = From},
-%% #traceopts_state{match_specs = MatchSpecs,
-%% matchpage_listbox = PageListBox,
-%% matchspec_popup_listbox = PopupListBox} = State) ->
-
-%% {StyledTxtCtrl, Frame} = get_correct_matchspec_components(From, State),
-%% StrMS = ensure_last_is_dot(wxStyledTextCtrl:getText(StyledTxtCtrl)),
-%% MatchSpecs2 = case check_correct_MS(StrMS) of
-%% {true, TermMS} ->
-%% MS = #match_spec{str_ms = StrMS, term_ms = TermMS},
-%% case lists:member(MS, MatchSpecs) of
-%% true ->
-%% observer_wx:create_txt_dialog(Frame, StrMS ++ "\nalready exists",
-%% "Error", ?wxICON_ERROR),
-%% MatchSpecs;
-%% false ->
-%% update_matchspec_listbox(StrMS, {PopupListBox, PageListBox}, From),
-%% lists:reverse([MS | MatchSpecs])
-%% end;
-%% {false, Reason} ->
-%% observer_wx:create_txt_dialog(Frame, Reason, "Error", ?wxICON_ERROR),
-%% MatchSpecs
-%% end,
-%% {noreply, State#traceopts_state{match_specs = MatchSpecs2}};
-
-
-%% handle_event(#wx{id = ?MATCHPAGE_ADDMS_ALIAS,
-%% event = #wxCommand{type = command_button_clicked},
-%% userData = From},
-%% #traceopts_state{match_specs = MatchSpecs,
-%% matchpage_listbox = PageListBox,
-%% matchspec_popup_listbox = PopupListBox} = State) ->
-
-%% {StyledTxtCtrl, Frame} = get_correct_matchspec_components(From, State),
-%% StrMS = ensure_last_is_dot(wxStyledTextCtrl:getText(StyledTxtCtrl)),
-
-%% MatchSpecs2 = case check_correct_MS(StrMS) of
-%% {true, TermMS} ->
-%% Dialog = wxTextEntryDialog:new(Frame, "Enter ms alias: "),
-%% Alias = case wxDialog:showModal(Dialog) of
-%% ?wxID_OK ->
-%% wxTextEntryDialog:getValue(Dialog);
-%% ?wxID_CANCEL ->
-%% ""
-%% end,
-%% wxDialog:destroy(Dialog),
-
-%% case Alias of
-%% "" ->
-%% observer_wx:create_txt_dialog(Frame, "Bad alias", "Syntax error",
-%% ?wxICON_ERROR),
-%% MatchSpecs;
-
-%% _ ->
-%% MS = #match_spec{alias = Alias, str_ms = StrMS,
-%% term_ms = TermMS},
-%% {OccupiedAlias, _} = find_ms(Alias, MatchSpecs),
-
-%% if
-%% OccupiedAlias =:= match ->
-%% observer_wx:create_txt_dialog(Frame, "Alias " ++ Alias ++ " already exists",
-%% "Error", ?wxICON_ERROR),
-%% MatchSpecs;
-%% true ->
-%% update_matchspec_listbox(Alias, {PopupListBox, PageListBox}, From),
-%% lists:reverse([MS | MatchSpecs])
-%% end
-%% end;
-%% {false, Reason} ->
-%% observer_wx:create_txt_dialog(Frame, Reason, "Error", ?wxICON_ERROR),
-%% MatchSpecs
-%% end,
-%% {noreply, State#traceopts_state{match_specs = MatchSpecs2}};
-
-
-%% handle_event(#wx{id = ?wxID_APPLY,
-%% event = #wxCommand{type = command_button_clicked},
-%% userData = Item},
-%% #traceopts_state{matchspec_popup_dialog = Dialog,
-%% matchspec_popup_listbox = ListBox,
-%% tree = Tree,
-%% match_specs = MatchSpecs,
-%% traced_funcs = TracedDict} = State) ->
-%% IntSelection = wxListBox:getSelection(ListBox),
-%% StrSelection =
-%% case IntSelection >= 0 of
-%% true ->
-%% wxControlWithItems:getString(ListBox, IntSelection);
-%% false ->
-%% []
-%% end,
-%% {_, MS} = find_ms(StrSelection, MatchSpecs),
-%% RootId = wxTreeCtrl:getRootItem(Tree),
-%% ItemParent = wxTreeCtrl:getItemParent(Tree, Item),
-
-%% TracedDict2 =
-%% if (Item =:= RootId) ->
-%% {ok, NewDict} = apply_matchspec(MS, TracedDict, root),
-%% NewDict;
-%% (ItemParent =:= RootId) ->
-%% Module = list_to_atom(wxTreeCtrl:getItemText(Tree, Item)),
-%% {ok, NewDict} = apply_matchspec(MS, TracedDict, {module, Module}),
-%% NewDict;
-%% true ->
-%% TracedFuncRec = wxTreeCtrl:getItemData(Tree, Item),
-%% Module = list_to_atom(wxTreeCtrl:getItemText(Tree, ItemParent)),
-%% {NewTracedFuncRecord, NewDict} =
-%% apply_matchspec(MS,
-%% TracedDict,
-%% {function,
-%% Module,
-%% TracedFuncRec}),
-%% wxTreeCtrl:setItemData(Tree, Item, NewTracedFuncRecord),
-%% NewDict
-%% end,
-%% wxDialog:destroy(Dialog),
-%% {noreply, State#traceopts_state{traced_funcs = TracedDict2,
-%% popup_open = false}};
-
-%% handle_event(#wx{id = ?wxID_CANCEL,
-%% event = #wxCommand{type = command_button_clicked},
-%% userData = matchspec_popup},
-%% #traceopts_state{matchspec_popup_dialog = Dialog} = State) ->
-%% wxDialog:destroy(Dialog),
-%% {noreply, State#traceopts_state{popup_open = false}};
-
-%% handle_event(#wx{id = ?MATCH_POPUP_DIALOG,
-%% event = #wxClose{type = close_window}},
-%% #traceopts_state{matchspec_popup_dialog = Dialog} = State) ->
-%% wxDialog:destroy(Dialog),
-%% {noreply, State#traceopts_state{popup_open = false}};
-
-%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% %Module Popup
-
-%% handle_event(#wx{id = ?wxID_OK,
-%% event = #wxCommand{type = command_button_clicked},
-%% userData = {module_popup, Module,
-%% ParsedChoices, Choices}},
-%% #traceopts_state{
-%% module_popup_dialog = Dialog,
-%% traced_funcs = TracedDict,
-%% tree = Tree,
-%% checked_funcs = CheckedFuncs} = State) ->
-
-%% Indices = [I+1 || I <- find_index(CheckedFuncs, ParsedChoices)],
-%% Selections = get_selections(Indices, Choices),
-%% TracedDict2 = case Selections of
-%% [] ->
-%% dict:erase(Module, TracedDict);
-%% _ ->
-%% Traced = [#traced_func{arity = Arity,
-%% func_name = Function}
-%% || {Function, Arity} <- Selections],
-%% dict:store(Module, Traced, TracedDict)
-%% end,
-
-%% update_tree(Tree, TracedDict2),
-%% wxDialog:destroy(Dialog),
-%% {noreply, State#traceopts_state{traced_funcs = TracedDict2,
-%% checked_funcs = [],
-%% popup_open = false}};
-
-%% handle_event(#wx{id = ?wxID_CANCEL,
-%% event = #wxCommand{type = command_button_clicked},
-%% userData = module_popup},
-%% #traceopts_state{module_popup_dialog = Dialog} = State) ->
-%% wxDialog:destroy(Dialog),
-%% {noreply, State#traceopts_state{popup_open = false,
-%% checked_funcs = []}};
-
-%% handle_event(#wx{id = ?MODULEPOPUP_SELECT,
-%% event = #wxCommand{type = command_button_clicked},
-%% userData = Bool},
-%% #traceopts_state{module_popup_checklistbox = CheckListBox,
-%% checked_funcs = CheckedFuncs} = State) ->
-%% {_, Selections} = wxListBox:getSelections(CheckListBox),
-%% lists:foreach(fun(Index) -> wxCheckListBox:check(CheckListBox, Index, [{check, Bool}]) end, Selections),
-%% StrSelections = [wxControlWithItems:getString(CheckListBox, N) || N <- Selections],
-%% CheckedFuncs2 = case Bool of
-%% true ->
-%% [X || X <- StrSelections,
-%% not(lists:member(X, CheckedFuncs))] ++ CheckedFuncs;
-%% false ->
-%% CheckedFuncs -- StrSelections
-%% end,
-%% {noreply, State#traceopts_state{checked_funcs = CheckedFuncs2}};
-
-%% handle_event(#wx{id = ?MODULEPOPUP_SELALL,
-%% event = #wxCommand{type = command_button_clicked},
-%% userData = Bool},
-%% #traceopts_state{module_popup_checklistbox = CheckListBox} = State) ->
-%% lists:foreach(fun(Index) ->
-%% wxCheckListBox:check(CheckListBox, Index, [{check, Bool}])
-%% end,
-%% lists:seq(0, wxControlWithItems:getCount(CheckListBox))),
-%% CheckedFuncs = case Bool of
-%% true ->
-%% [wxControlWithItems:getString(CheckListBox, N)
-%% || N <- lists:seq(0, wxControlWithItems:getCount(CheckListBox))];
-%% false ->
-%% []
-%% end,
-%% {noreply, State#traceopts_state{checked_funcs = CheckedFuncs}};
-
-%% handle_event(#wx{id = ?MODULEPOPUP_CHECKLISTBOX,
-%% obj = CheckListBox,
-%% event = #wxCommand{type = command_checklistbox_toggled,
-%% commandInt = Index}},
-%% #traceopts_state{checked_funcs = CheckedFuncs} = State) ->
-
-%% UpdCheckedFuncs = case
-%% wxCheckListBox:isChecked(CheckListBox, Index) of
-%% true ->
-%% [wxControlWithItems:getString(CheckListBox, Index) | CheckedFuncs];
-%% false ->
-%% lists:delete(wxControlWithItems:getString(CheckListBox, Index), CheckedFuncs)
-%% end,
-%% {noreply, State#traceopts_state{checked_funcs = UpdCheckedFuncs}};
-
-%% handle_event(#wx{id = ?MODULEPOPUP_TXTCTRL,
-%% event = #wxCommand{type = command_text_updated,
-%% cmdString = Input},
-%% userData = Data},
-%% #traceopts_state{module_popup_checklistbox = CListBox,
-%% checked_funcs = CheckedFuncs} = State) ->
-%% FilteredData = filter_listbox_data(Input, Data, CListBox),
-%% lists:foreach(fun(Index) ->
-%% wxCheckListBox:check(CListBox, Index, [{check, true}])
-%% end,
-%% [wxControlWithItems:findString(CListBox, X) || X <- CheckedFuncs, lists:member(X, FilteredData)]),
-%% {noreply, State};
-
-%% handle_event(#wx{id = ?MODULEPOPUP_DIALOG,
-%% event = #wxClose{type = close_window}},
-%% #traceopts_state{module_popup_dialog = Dialog} = State) ->
-%% wxDialog:destroy(Dialog),
-%% {noreply, State#traceopts_state{popup_open = false,
-%% checked_funcs = []}};
-
-%% handle_event(#wx{event = What}, State) ->
-%% io:format("~p~p: Unhandled event: ~p ~n", [?MODULE, self(), What]),
-%% {noreply, State}.
-
-
-
-%% terminate(Reason, #traceopts_state{frame = Frame}) ->
-%% io:format("~p terminating traceopts. Reason: ~p~n", [?MODULE, Reason]),
-%% wxFrame:destroy(Frame),
-%% ok.
-
-%% code_change(_, _, State) ->
-%% {stop, not_yet_implemented, State}.
-
-%% handle_info(Any, State) ->
-%% io:format("~p~p: received unexpected message: ~p\n", [?MODULE, self(), Any]),
-%% {noreply, State}.
-
-%% handle_call(Msg, _From, State) ->
-%% io:format("~p~p: Got Call ~p~n",[?MODULE, ?LINE, Msg]),
-%% {reply, ok, State}.
-
-%% handle_cast(Msg, State) ->
-%% io:format("~p ~p: Unhandled cast ~p~n", [?MODULE, ?LINE, Msg]),
-%% {noreply, State}.
diff --git a/lib/observer/src/ttb.erl b/lib/observer/src/ttb.erl
index 1471be92e5..61fd6d1787 100644
--- a/lib/observer/src/ttb.erl
+++ b/lib/observer/src/ttb.erl
@@ -75,29 +75,41 @@ do_tracer(Nodes0,PI,Client,Traci) ->
do_tracer(Clients,PI,Traci).
do_tracer(Clients,PI,Traci) ->
- ShellOutput = proplists:get_value(shell, Traci, false),
- {ClientSucc,Succ} =
+ Shell = proplists:get_value(shell, Traci, false),
+ DefShell = fun(Trace) -> dbg:dhandler(Trace, standard_io) end,
+ {ClientSucc,Succ} =
lists:foldl(
- fun({N,{local,File},TF},{CS,S}) ->
- TF2 = case ShellOutput of
- only -> none;
- _ -> TF
- end,
- [_Sname,Host] = string:tokens(atom_to_list(N),"@"),
+ fun({N,{local,File},TF},{CS,S}) ->
+ {TF2, FileInfo, ShellOutput} =
+ case Shell of
+ only -> {none, shell_only, DefShell};
+ true -> {TF, {file,File}, DefShell};
+ {only,Fun} -> {none, shell_only, Fun};
+ Fun when is_function(Fun) -> {TF, {file,File}, Fun};
+ _ -> {TF, {file,File}, false}
+ end,
+ Host = case N of
+ nonode@nohost ->
+ {ok, H} = inet:gethostname(),
+ H;
+ _ ->
+ [_,H] = string:tokens(atom_to_list(N),"@"),
+ H
+ end,
case catch dbg:tracer(N,port,dbg:trace_port(ip,0)) of
{ok,N} ->
{ok,Port} = dbg:trace_port_control(N,get_listen_port),
{ok,T} = dbg:get_tracer(N),
rpc:call(N,seq_trace,set_system_tracer,[T]),
dbg:trace_client(ip,{Host,Port},
- {fun ip_to_file/2,{{file,File}, ShellOutput}}),
+ {fun ip_to_file/2,{FileInfo, ShellOutput}}),
{[{N,{local,File,Port},TF2}|CS], [N|S]};
Other ->
display_warning(N,{cannot_open_ip_trace_port,
Host,
Other}),
{CS, S}
- end;
+ end;
({N,C,_}=Client,{CS,S}) ->
case catch dbg:tracer(N,port,dbg:trace_port(file,C)) of
{ok,N} ->
@@ -620,7 +632,7 @@ stop_opts(Opts) ->
case {FormatData, lists:member(return_fetch_dir, Opts)} of
{false, true} ->
{fetch, FetchDir}; % if we specify return_fetch_dir, the data should be fetched
- {false, false} ->
+ {false, false} ->
case lists:member(nofetch,Opts) of
false -> {fetch, FetchDir};
true -> nofetch
@@ -1275,10 +1287,10 @@ display_warning(Item,Warning) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%% Trace client which reads an IP port and puts data directly to a file.
%%% This is used when tracing remote nodes with no file system.
-ip_to_file({metadata,_,_},{_, only} = State) ->
+ip_to_file({metadata,_,_},{shell_only, _} = State) ->
State;
-ip_to_file(Trace, {_, only} = State) ->
- dbg:dhandler(Trace, standard_io),
+ip_to_file(Trace, {shell_only, Fun} = State) ->
+ Fun(Trace),
State;
ip_to_file(Trace,{{file,File}, ShellOutput}) ->
Fun = dbg:trace_port(file,File), %File can be a filename or a wrap spec
@@ -1302,8 +1314,8 @@ ip_to_file(Trace,{Port, ShellOutput}) ->
erlang:port_command(Port,B),
{Port, ShellOutput}.
-show_trace(Trace, true) ->
- dbg:dhandler(Trace, standard_io);
+show_trace(Trace, Fun) when is_function(Fun) ->
+ Fun(Trace);
show_trace(_, _) ->
ok.