aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lib/observer/src/cdv_proc_wx.erl4
-rw-r--r--lib/observer/src/crashdump_viewer_html.erl100
-rw-r--r--lib/observer/src/observer_app_wx.erl10
-rw-r--r--lib/observer/src/observer_lib.erl120
-rw-r--r--lib/observer/src/observer_pro_wx.erl34
-rw-r--r--lib/observer/src/observer_procinfo.erl167
-rw-r--r--lib/observer/src/observer_wx.erl16
7 files changed, 276 insertions, 175 deletions
diff --git a/lib/observer/src/cdv_proc_wx.erl b/lib/observer/src/cdv_proc_wx.erl
index a0f42b5e6b..1320afce28 100644
--- a/lib/observer/src/cdv_proc_wx.erl
+++ b/lib/observer/src/cdv_proc_wx.erl
@@ -99,6 +99,7 @@ init_stack_page(Parent, Pid, _Info) ->
init_memory_page(Parent, Pid, "StackDump").
init_memory_page(Parent, Pid, What) ->
+ Win = observer_lib:html_window(Parent),
Html =
case crashdump_viewer:expand_memory(Pid,What) of
{ok,Memory} ->
@@ -106,7 +107,8 @@ init_memory_page(Parent, Pid, What) ->
{error,Reason} ->
crashdump_viewer_html:warning(Reason)
end,
- observer_lib:html_window(Parent,Html).
+ wxHtmlWindow:setPage(Win,Html),
+ Win.
init_ets_page(Parent, Pid, _Info) ->
cdv_virtual_list:start_link(Parent, cdv_ets_wx, Pid).
diff --git a/lib/observer/src/crashdump_viewer_html.erl b/lib/observer/src/crashdump_viewer_html.erl
index 23d6fd6b16..038126288b 100644
--- a/lib/observer/src/crashdump_viewer_html.erl
+++ b/lib/observer/src/crashdump_viewer_html.erl
@@ -53,6 +53,7 @@
chunk/3]).
-include("crashdump_viewer.hrl").
+-include("observer_defs.hrl").
%%%-----------------------------------------------------------------
%%% Welcome frame
@@ -497,51 +498,94 @@ expanded_memory(Heading,Expanded) ->
expanded_memory_body(Heading,[]) ->
[case Heading of
"MsgQueue" -> "No messages were found";
- "StackDump" -> "No stack dump was found";
- "Dictionary" -> "No dictionary was found"
+ "Message Queue" -> "No messages were found";
+ "StackDump" -> "No stack dump was found";
+ "Dictionary" -> "No dictionary was found";
+ "ProcState" -> "Information could not be retrieved,"
+ " system messages may not be handled by this process."
end];
expanded_memory_body(Heading,Expanded) ->
+ Attr = "BORDER=0 CELLPADDING=0 CELLSPACING=1 WIDTH=100%",
[case Heading of
"MsgQueue" ->
- table(
- "BORDER=4 CELLPADDING=4",
- [tr(
- [th("Message"),
- th("SeqTraceToken")]) |
- lists:map(fun(Msg) -> msgq_table(Msg) end, Expanded)]);
+ table(Attr,
+ [tr(
+ [th("WIDTH=70%","Message"),
+ th("WIDTH=30%","SeqTraceToken")]) |
+ element(1, lists:mapfoldl(fun(Msg, Even) ->
+ {msgq_table(Msg, Even),
+ not Even}
+ end,
+ true, Expanded))]);
+ "Message Queue" ->
+ table(Attr,
+ [tr(
+ [th("WIDTH=10%","Id"),
+ th("WIDTH=90%","Message")]) |
+ element(1, lists:mapfoldl(fun(Msg, {Even,N}) ->
+ {msgq_table(Msg, N, Even),
+ {not Even, N+1}}
+ end,
+ {true,1}, Expanded))]);
"StackDump" ->
- table(
- "BORDER=4 CELLPADDING=4",
- [tr(
- [th("Label"),
- th("Term")]) |
- lists:map(fun(Entry) -> stackdump_table(Entry) end, Expanded)]);
+ table(Attr,
+ [tr(
+ [th("WIDTH=20%","Label"),
+ th("WIDTH=80%","Term")]) |
+ element(1, lists:mapfoldl(fun(Entry, Even) ->
+ {stackdump_table(Entry, Even),
+ not Even}
+ end, true, Expanded))]);
+ "ProcState" ->
+ table(Attr,
+ [tr(
+ [th("WIDTH=20%","Label"),
+ th("WIDTH=80%","Information")]) |
+ element(1, lists:mapfoldl(fun(Entry, Even) ->
+ {proc_state(Entry,Even),
+ not Even}
+ end, true, Expanded))]);
_ ->
- table(
- "BORDER=4 CELLPADDING=4",
- [tr(
- [th("Key"),
- th("Value")]) |
- lists:map(fun(Entry) -> dict_table(Entry) end, Expanded)])
+ table(Attr,
+ [tr(
+ [th("WIDTH=30%","Key"),
+ th("WIDTH=70%","Value")]) |
+ element(1, lists:mapfoldl(fun(Entry, Even) ->
+ {dict_table(Entry,Even),
+ not Even}
+ end, true, Expanded))])
end].
-msgq_table({Msg0,Token0}) ->
+msgq_table({Msg0,Token0}, Even) ->
Token = case Token0 of
[] -> "";
_ -> io_lib:fwrite("~w",[Token0])
end,
Msg = href_proc_port(lists:flatten(io_lib:format("~p",[Msg0]))),
- tr([td(pre(Msg)), td(Token)]).
-
-stackdump_table({Label0,Term0}) ->
+ tr(color(Even),[td(pre(Msg)), td(Token)]).
+
+msgq_table(Msg0, Id, Even) ->
+ Msg = href_proc_port(lists:flatten(io_lib:format("~p",[Msg0]))),
+ tr(color(Even),[td(integer_to_list(Id)), td(pre(Msg))]).
+
+stackdump_table({Label0,Term0},Even) ->
Label = io_lib:format("~w",[Label0]),
Term = href_proc_port(lists:flatten(io_lib:format("~p",[Term0]))),
- tr([td("VALIGN=top",Label), td(pre(Term))]).
-
-dict_table({Key0,Value0}) ->
+ tr(color(Even), [td("VALIGN=center",pre(Label)), td(pre(Term))]).
+
+dict_table({Key0,Value0}, Even) ->
Key = href_proc_port(lists:flatten(io_lib:format("~p",[Key0]))),
Value = href_proc_port(lists:flatten(io_lib:format("~p",[Value0]))),
- tr([td("VALIGN=top",pre(Key)), td(pre(Value))]).
+ tr(color(Even), [td("VALIGN=center",pre(Key)), td(pre(Value))]).
+
+proc_state({Key0,Value0}, Even) ->
+ Key = lists:flatten(io_lib:format("~s",[Key0])),
+ Value = href_proc_port(lists:flatten(io_lib:format("~p",[Value0]))),
+ tr(color(Even), [td("VALIGN=center",Key), td(pre(Value))]).
+
+
+color(true) -> io_lib:format("BGCOLOR=\"#~2.16.0B~2.16.0B~2.16.0B\"", tuple_to_list(?BG_EVEN));
+color(false) -> io_lib:format("BGCOLOR=\"#~2.16.0B~2.16.0B~2.16.0B\"", tuple_to_list(?BG_ODD)).
%%%-----------------------------------------------------------------
diff --git a/lib/observer/src/observer_app_wx.erl b/lib/observer/src/observer_app_wx.erl
index 72bafcc5e0..82395fbe08 100644
--- a/lib/observer/src/observer_app_wx.erl
+++ b/lib/observer/src/observer_app_wx.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2011-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2011-2013. 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
@@ -190,8 +190,8 @@ handle_event(#wx{event=#wxCommand{type=command_menu_selected}},
{noreply, State};
handle_event(#wx{id=?ID_PROC_INFO, event=#wxCommand{type=command_menu_selected}},
- State = #state{panel=Panel, sel={#box{s1=#str{pid=Pid}},_}}) ->
- observer_procinfo:start(Pid, Panel, self()),
+ State = #state{sel={#box{s1=#str{pid=Pid}},_}}) ->
+ observer ! {open_link, Pid},
{noreply, State};
handle_event(#wx{id=?ID_PROC_MSG, event=#wxCommand{type=command_menu_selected}},
@@ -337,8 +337,8 @@ code_change(_, _, State) ->
handle_mouse_click(Node = {#box{s1=#str{pid=Pid}},_}, Type,
State=#state{app_w=AppWin,panel=Panel}) ->
case Type of
- left_dclick -> observer_procinfo:start(Pid, Panel, self());
- right_down -> popup_menu(Panel);
+ left_dclick -> observer ! {open_link, Pid};
+ right_down -> popup_menu(Panel);
_ -> ok
end,
observer_wx:set_status(io_lib:format("Pid: ~p", [Pid])),
diff --git a/lib/observer/src/observer_lib.erl b/lib/observer/src/observer_lib.erl
index ce85fb4af6..159afae487 100644
--- a/lib/observer/src/observer_lib.erl
+++ b/lib/observer/src/observer_lib.erl
@@ -27,7 +27,7 @@
create_attrs/0,
set_listctrl_col_size/2,
create_status_bar/1,
- html_window/2
+ html_window/1, html_window/2
]).
-include_lib("wx/include/wx.hrl").
@@ -185,11 +185,27 @@ update_info([Fields|Fs], [{_Header, _Attrib, SubStructure}| Rest]) ->
update_info([], []) ->
ok.
+update_info2([Scroll = {_, _, _}|Fs], [{_, NewInfo}|Rest]) ->
+ update_scroll_boxes(Scroll, NewInfo),
+ update_info2(Fs, Rest);
+update_info2([Field|Fs], [{_Str, {click, Value}}|Rest]) ->
+ wxTextCtrl:setValue(Field, to_str(Value)),
+ update_info2(Fs, Rest);
update_info2([Field|Fs], [{_Str, Value}|Rest]) ->
wxTextCtrl:setValue(Field, to_str(Value)),
update_info2(Fs, Rest);
update_info2([], []) -> ok.
+update_scroll_boxes({_, _, 0}, {_, []}) -> ok;
+update_scroll_boxes({Win, Sizer, _}, {Type, List}) ->
+ [wxSizerItem:deleteWindows(Child) || Child <- wxSizer:getChildren(Sizer)],
+ BC = wxWindow:getBackgroundColour(Win),
+ Cursor = wxCursor:new(?wxCURSOR_HAND),
+ add_entries(Type, List, Win, Sizer, BC, Cursor),
+ wxCursor:destroy(Cursor),
+ wxSizer:recalcSizes(Sizer),
+ wxWindow:refresh(Win),
+ ok.
to_str(Value) when is_atom(Value) ->
atom_to_list(Value);
@@ -333,45 +349,51 @@ get_box_info({Title, List}) when is_list(List) -> {Title, ?wxALIGN_LEFT, List};
get_box_info({Title, left, List}) -> {Title, ?wxALIGN_LEFT, List};
get_box_info({Title, right, List}) -> {Title, ?wxALIGN_RIGHT, List}.
+add_box(Panel, OuterBox, Cursor, Title, Proportion, {Format, List}) ->
+ Box = wxStaticBoxSizer:new(?wxVERTICAL, Panel, [{label, Title}]),
+ Scroll = wxScrolledWindow:new(Panel),
+ wxScrolledWindow:enableScrolling(Scroll,true,true),
+ wxScrolledWindow:setScrollbars(Scroll,1,1,0,0),
+ ScrollSizer = wxBoxSizer:new(?wxVERTICAL),
+ wxScrolledWindow:setSizer(Scroll, ScrollSizer),
+ BC = wxWindow:getBackgroundColour(Panel),
+ wxWindow:setBackgroundColour(Scroll,BC),
+ add_entries(Format, List, Scroll, ScrollSizer, BC, Cursor),
+ wxSizer:add(Box,Scroll,[{proportion,1},{flag,?wxEXPAND}]),
+ wxSizer:add(OuterBox,Box,[{proportion,Proportion},{flag,?wxEXPAND}]),
+ {Scroll,ScrollSizer,length(List)}.
+
+add_entries(click, List, Scroll, ScrollSizer, BC, Cursor) ->
+ Add = fun(Link) ->
+ TC = link_entry(Scroll, Link, Cursor),
+ wxWindow:setBackgroundColour(TC,BC),
+ wxSizer:add(ScrollSizer,TC,[{flag,?wxEXPAND}])
+ end,
+ [Add(Link) || Link <- List];
+add_entries(plain, List, Scroll, ScrollSizer, _, _) ->
+ Add = fun(String) ->
+ TC = wxTextCtrl:new(Scroll, ?wxID_ANY,
+ [{style,?SINGLE_LINE_STYLE},
+ {value,String}]),
+ wxSizer:add(ScrollSizer,TC,[{flag,?wxEXPAND}])
+ end,
+ [Add(String) || String <- List].
+
+
create_box(_Panel, {scroll_boxes,[]}) ->
undefined;
create_box(Panel, {scroll_boxes,Data}) ->
OuterBox = wxBoxSizer:new(?wxHORIZONTAL),
Cursor = wxCursor:new(?wxCURSOR_HAND),
- AddBox = fun({Title,Proportion,{Format,List}}) ->
- Box = wxStaticBoxSizer:new(?wxVERTICAL, Panel,
- [{label, Title}]),
- Scroll = wxScrolledWindow:new(Panel),
- wxScrolledWindow:enableScrolling(Scroll,true,true),
- wxScrolledWindow:setScrollbars(Scroll,1,1,0,0),
- ScrollSizer = wxBoxSizer:new(?wxVERTICAL),
- wxScrolledWindow:setSizer(Scroll, ScrollSizer),
- BC = wxWindow:getBackgroundColour(Panel),
- wxWindow:setBackgroundColour(Scroll,BC),
- case Format of
- click ->
- [begin
- TC = link_entry(Scroll, Link, Cursor),
- wxWindow:setBackgroundColour(TC,BC),
- wxSizer:add(ScrollSizer,TC,[{flag,?wxEXPAND}])
- end || Link <- List];
- plain ->
- [begin
- TC = wxTextCtrl:new(Scroll, ?wxID_ANY,
- [{style,?SINGLE_LINE_STYLE},
- {value,String}]),
- wxSizer:add(ScrollSizer,TC,[{flag,?wxEXPAND}])
- end || String <- List]
- end,
- wxSizer:add(Box,Scroll,[{flag,?wxEXPAND}]),
- wxSizer:add(OuterBox,Box,
- [{proportion,Proportion},{flag,?wxEXPAND}]),
- {Scroll,length(List)}
+ AddBox = fun({Title,Proportion,Format = {_,_}}) ->
+ add_box(Panel, OuterBox, Cursor, Title, Proportion, Format);
+ ({Title, Format = {_,_}}) ->
+ add_box(Panel, OuterBox, Cursor, Title, 1, Format)
end,
Boxes = [AddBox(Entry) || Entry <- Data],
wxCursor:destroy(Cursor),
- MaxL = lists:foldl(fun({_,L},Max) when L>Max -> L;
+ MaxL = lists:foldl(fun({_,_,L},Max) when L>Max -> L;
(_,Max) -> Max
end,
0,
@@ -384,9 +406,9 @@ create_box(Panel, {scroll_boxes,Data}) ->
MaxH = if MaxL > 8 -> 8*H;
true -> MaxL*H
end,
- [wxWindow:setMinSize(B,{0,MaxH}) || {B,_} <- Boxes],
+ [wxWindow:setMinSize(B,{0,MaxH}) || {B,_,_} <- Boxes],
wxSizer:layout(OuterBox),
- {OuterBox, []};
+ {OuterBox, Boxes};
create_box(Panel, Data) ->
{Title, Align, Info} = get_box_info(Data),
@@ -410,7 +432,7 @@ create_box(Panel, Data) ->
[{style,?MULTI_LINE_STYLE},
{value,"unknown"}]);
{click,Value} ->
- link_entry(Panel,{Value,Value});
+ link_entry(Panel,Value);
_ ->
Value = to_str(Value0),
wxTextCtrl:new(Panel, ?wxID_ANY,
@@ -431,28 +453,44 @@ create_box(Panel, Data) ->
link_entry(Panel, Link) ->
Cursor = wxCursor:new(?wxCURSOR_HAND),
- TC = link_entry(Panel, Link, Cursor),
+ TC = link_entry2(Panel, to_link(Link), Cursor),
wxCursor:destroy(Cursor),
TC.
-link_entry(Panel,{Target,Str},Cursor) ->
- TC = wxTextCtrl:new(Panel, ?wxID_ANY,
- [{style, ?SINGLE_LINE_STYLE}]),
+link_entry(Panel, Link, Cursor) ->
+ link_entry2(Panel, to_link(Link), Cursor).
+
+link_entry2(Panel,{Target,Str},Cursor) ->
+ TC = wxTextCtrl:new(Panel, ?wxID_ANY, [{style, ?SINGLE_LINE_STYLE}]),
wxTextCtrl:setForegroundColour(TC,?wxBLUE),
wxTextCtrl:appendText(TC, Str),
wxWindow:setCursor(TC, Cursor),
wxTextCtrl:connect(TC, left_down, [{userData,Target}]),
wxTextCtrl:connect(TC, enter_window),
wxTextCtrl:connect(TC, leave_window),
- ToolTip = wxToolTip:new("Click to see properties for " ++ Target),
+ ToolTip = wxToolTip:new("Click to see properties for " ++ Str),
wxWindow:setToolTip(TC, ToolTip),
TC.
-html_window(Panel,Html) ->
+to_link(Tuple = {_Target, _Str}) -> Tuple;
+to_link(Target) -> {Target, to_str(Target)}.
+
+html_window(Panel) ->
Win = wxHtmlWindow:new(Panel, [{style, ?wxHW_SCROLLBAR_AUTO}]),
- wxHtmlWindow:setPage(Win,Html),
+ FixedName = case whereis(observer) of
+ undefined -> "courier";
+ _Pid ->
+ Fixed = observer_wx:get_attrib({font,fixed}),
+ wxFont:getFaceName(Fixed)
+ end,
+ wxHtmlWindow:setFonts(Win, "", FixedName),
wxHtmlWindow:connect(Win,command_html_link_clicked),
Win.
+html_window(Panel, Html) ->
+ Win = html_window(Panel),
+ wxHtmlWindow:setPage(Win, Html),
+ Win.
+
get_max_size(Panel,Info) ->
Txt = wxTextCtrl:new(Panel, ?wxID_ANY, []),
Size = get_max_size(Txt,Info,0,0),
diff --git a/lib/observer/src/observer_pro_wx.erl b/lib/observer/src/observer_pro_wx.erl
index 9aaf648ea2..10e2f12e0f 100644
--- a/lib/observer/src/observer_pro_wx.erl
+++ b/lib/observer/src/observer_pro_wx.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2011-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2011-2013. 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
@@ -191,20 +191,16 @@ dump_to_file(Parent, FileName, Holder) ->
start_procinfo(undefined, _Frame, Opened) ->
Opened;
start_procinfo(Pid, Frame, Opened) ->
- %% This code doesn't work until we collect which windows have been
- %% closed maybe it should moved to observer_wx.erl
- %% and add a global menu which remembers windows.
- %% case lists:keyfind(Pid, 1, Opened) of
- %% false ->
- case observer_procinfo:start(Pid, Frame, self()) of
- {error, _} -> Opened;
- PI -> [{Pid, PI} | Opened]
+ case lists:keyfind(Pid, 1, Opened) of
+ false ->
+ case observer_procinfo:start(Pid, Frame, self()) of
+ {error, _} -> Opened;
+ PI -> [{Pid, PI} | Opened]
+ end;
+ {_, PI} ->
+ wxFrame:raise(PI),
+ Opened
end.
- %%;
- %% {_, PI} ->
- %% wxFrame:raise(PI),
- %% Opened
- %% end.
call(Holder, What) ->
Ref = erlang:monitor(process, Holder),
@@ -235,9 +231,14 @@ handle_info(refresh_interval, #state{holder=Holder}=State) ->
handle_info({procinfo_menu_closed, Pid},
#state{procinfo_menu_pids=Opened}=State) ->
- NewPids = lists:delete(Pid, Opened),
+ NewPids = lists:keydelete(Pid, 1, Opened),
{noreply, State#state{procinfo_menu_pids=NewPids}};
+handle_info({procinfo_open, Pid},
+ #state{panel=Panel, procinfo_menu_pids=Opened}=State) ->
+ Opened2 = start_procinfo(Pid, Panel, Opened),
+ {noreply, State#state{procinfo_menu_pids=Opened2}};
+
handle_info({active, Node},
#state{holder=Holder, timer=Timer, parent=Parent}=State) ->
create_pro_menu(Parent, Holder),
@@ -378,8 +379,7 @@ handle_event(#wx{event=#wxList{type=command_list_col_click, col=Col}},
handle_event(#wx{event=#wxList{type=command_list_item_activated}},
#state{panel=Panel, procinfo_menu_pids=Opened,
- sel={_, [Pid|_]}}=State)
- when Pid =/= undefined ->
+ sel={_, [Pid|_]}}=State) ->
Opened2 = start_procinfo(Pid, Panel, Opened),
{noreply, State#state{procinfo_menu_pids=Opened2}};
diff --git a/lib/observer/src/observer_procinfo.erl b/lib/observer/src/observer_procinfo.erl
index 98d0403139..db5eefaa6c 100644
--- a/lib/observer/src/observer_procinfo.erl
+++ b/lib/observer/src/observer_procinfo.erl
@@ -106,6 +106,22 @@ handle_event(#wx{id=?REFRESH}, #state{frame=Frame, pid=Pid, pages=Pages}=State)
end,
{noreply, State};
+handle_event(#wx{event=#wxMouse{type=left_down}, userData=TargetPid}, State) ->
+ observer ! {open_link, TargetPid},
+ {noreply, State};
+
+handle_event(#wx{obj=Obj, event=#wxMouse{type=enter_window}}, State) ->
+ wxTextCtrl:setForegroundColour(Obj,{0,0,100,255}),
+ {noreply, State};
+
+handle_event(#wx{obj=Obj, event=#wxMouse{type=leave_window}}, State) ->
+ wxTextCtrl:setForegroundColour(Obj,?wxBLUE),
+ {noreply, State};
+
+handle_event(#wx{event=#wxHtmlLink{linkInfo=#wxHtmlLinkInfo{href=Info}}}, State) ->
+ observer ! {open_link, Info},
+ {noreply, State};
+
handle_event(Event, _State) ->
error({unhandled_event, Event}).
@@ -139,58 +155,37 @@ init_process_page(Panel, Pid) ->
observer_lib:update_info(UpFields, Fields)
end}.
-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, fixed}),
- Attr = wxTextAttr:new(?wxBLACK, [{font, Font}]),
- true = wxTextCtrl:setDefaultStyle(Text, Attr),
- wxTextAttr:destroy(Attr),
- Text.
init_message_page(Parent, Pid) ->
- Text = init_text_page(Parent),
- Format = fun(Message, Number) ->
- {io_lib:format("~-4.w ~p~n", [Number, Message]),
- Number+1}
- end,
+ Win = observer_lib:html_window(Parent),
Update = fun() ->
case observer_wx:try_rpc(node(Pid), erlang, process_info,
[Pid, messages])
of
- {messages,RawMessages} ->
- {Messages,_} = lists:mapfoldl(Format, 1, RawMessages),
- Last = wxTextCtrl:getLastPosition(Text),
- wxTextCtrl:remove(Text, 0, Last),
- case Messages =:= [] of
- true ->
- wxTextCtrl:writeText(Text, "No messages");
- false ->
- wxTextCtrl:writeText(Text, Messages)
- end;
+ {messages, Messages} ->
+ Html = crashdump_viewer_html:expanded_memory("Message Queue", Messages),
+ wxHtmlWindow:setPage(Win, Html);
_ ->
throw(process_undefined)
end
end,
Update(),
- {Text, Update}.
+ {Win, Update}.
init_dict_page(Parent, Pid) ->
- Text = init_text_page(Parent),
+ Win = observer_lib:html_window(Parent),
Update = fun() ->
case observer_wx:try_rpc(node(Pid), erlang, process_info, [Pid, dictionary])
of
- {dictionary,RawDict} ->
- Dict = [io_lib:format("~-20.w ~p~n", [K, V]) || {K, V} <- RawDict],
- Last = wxTextCtrl:getLastPosition(Text),
- wxTextCtrl:remove(Text, 0, Last),
- wxTextCtrl:writeText(Text, Dict);
+ {dictionary,Dict} ->
+ Html = crashdump_viewer_html:expanded_memory("Dictionary", Dict),
+ wxHtmlWindow:setPage(Win, Html);
_ ->
throw(process_undefined)
end
end,
Update(),
- {Text, Update}.
+ {Win, Update}.
init_stack_page(Parent, Pid) ->
LCtrl = wxListCtrl:new(Parent, [{style, ?wxLC_REPORT bor ?wxLC_HRULES}]),
@@ -236,58 +231,58 @@ init_stack_page(Parent, Pid) ->
Update(),
{LCtrl, Update}.
-
init_state_page(Parent, Pid) ->
- Text = init_text_page(Parent),
+ Win = observer_lib:html_window(Parent),
Update = fun() ->
- %% First, test if sys:get_status/2 have any chance to return an answer
- case rpc:call(node(Pid), proc_lib, translate_initial_call, [Pid])
- of
- %% Not a gen process
- {proc_lib,init_p,5} -> Misc = [{"Information", "Not available"}];
- %% May be a gen process
- {M, _F, _A} ->
- %% Get the behavio(u)r
- I = rpc:call(node(Pid), M, module_info, [attributes]),
- case lists:keyfind(behaviour, 1, I) of
- false -> case lists:keyfind(behavior, 1, I) of
- false -> B = undefined;
- {behavior, [B]} -> B
- end;
- {behaviour, [B]} -> B
- end,
- %% but not sure that system messages are treated by this process
- %% so using a rpc with a small timeout in order not to lag the display
- case rpc:call(node(Pid), sys, get_status, [Pid, 200])
- of
- {status, _, {module, _}, [_PDict, _SysState, _Parent, _Dbg,
- [Header,{data, First},{data, Second}]]} ->
- Misc = [{"Behaviour", B}] ++ [Header] ++ First ++ Second;
- {status, _, {module, _}, [_PDict, _SysState, _Parent, _Dbg,
- [Header,{data, First}, OtherFormat]]} ->
- Misc = [{"Behaviour", B}] ++ [Header] ++ First ++ [{"State",OtherFormat}];
- {status, _, {module, _}, [_PDict, _SysState, _Parent, _Dbg,
- OtherFormat]} ->
- %% Formatted status ?
- case lists:keyfind(format_status, 1, rpc:call(node(Pid), M, module_info, [exports])) of
- false -> Opt = {"Format", unknown};
- _ -> Opt = {"Format", overriden}
- end,
- Misc = [{"Behaviour", B}] ++ [Opt, {"State",OtherFormat}];
- {badrpc,{'EXIT',{timeout, _}}} ->
- Misc = [{"Information","Timed out"},
- {"Tip","system messages are probably not treated by this process"}]
- end;
- _ -> Misc=[], throw(process_undefined)
- end,
- Dict = [io_lib:format("~-20.s ~tp~n", [K, V]) || {K, V} <- Misc],
- Last = wxTextCtrl:getLastPosition(Text),
- wxTextCtrl:remove(Text, 0, Last),
- wxTextCtrl:writeText(Text, Dict)
+ StateInfo = fetch_state_info(Pid),
+ Html = crashdump_viewer_html:expanded_memory("ProcState", StateInfo),
+ wxHtmlWindow:setPage(Win, Html)
end,
Update(),
- {Text, Update}.
+ {Win, Update}.
+
+fetch_state_info(Pid) ->
+ %% First, test if sys:get_status/2 have any chance to return an answer
+ case rpc:call(node(Pid), proc_lib, translate_initial_call, [Pid]) of
+ %% Not a gen process
+ {proc_lib,init_p,5} -> [];
+ %% May be a gen process
+ {M, _F, _A} -> fetch_state_info2(Pid, M);
+ _ -> throw(process_undefined)
+ end.
+fetch_state_info2(Pid, M) ->
+ %% Get the behavio(u)r
+ I = rpc:call(node(Pid), M, module_info, [attributes]),
+ case lists:keyfind(behaviour, 1, I) of
+ false -> case lists:keyfind(behavior, 1, I) of
+ false -> B = undefined;
+ {behavior, [B]} -> B
+ end;
+ {behaviour, [B]} -> B
+ end,
+ %% but not sure that system messages are treated by this process
+ %% so using a rpc with a small timeout in order not to lag the display
+ case rpc:call(node(Pid), sys, get_status, [Pid, 200])
+ of
+ {status, _, {module, _},
+ [_PDict, _SysState, _Parent, _Dbg,
+ [Header,{data, First},{data, Second}]]} ->
+ [{"Behaviour", B}, Header] ++ First ++ Second;
+ {status, _, {module, _},
+ [_PDict, _SysState, _Parent, _Dbg,
+ [Header,{data, First}, OtherFormat]]} ->
+ [{"Behaviour", B}, Header] ++ First ++ [{"State",OtherFormat}];
+ {status, _, {module, _},
+ [_PDict, _SysState, _Parent, _Dbg, OtherFormat]} ->
+ %% Formatted status ?
+ case lists:keyfind(format_status, 1, rpc:call(node(Pid), M, module_info, [exports])) of
+ false -> Opt = {"Format", unknown};
+ _ -> Opt = {"Format", overriden}
+ end,
+ [{"Behaviour", B}, Opt, {"State",OtherFormat}];
+ {badrpc,{'EXIT',{timeout, _}}} -> []
+ end.
create_menus(MenuBar) ->
Menus = [{"File", [#create_menu{id=?wxID_CLOSE, text="Close"}]},
@@ -301,6 +296,7 @@ process_info_fields(Pid) ->
{"Registered Name", registered_name},
{"Status", status},
{"Message Queue Len",message_queue_len},
+ {"Group Leader", {click, group_leader}},
{"Priority", priority},
{"Trap Exit", trap_exit},
{"Reductions", reductions},
@@ -311,11 +307,10 @@ process_info_fields(Pid) ->
{"Suspending", suspending},
{"Sequential Trace Token", sequential_trace_token},
{"Error Handler", error_handler}]},
- {"Connections",
- [{"Group Leader", group_leader},
- {"Links", links},
- {"Monitors", monitors},
- {"Monitored by", monitored_by}]},
+ {scroll_boxes,
+ [{"Links", {click, links}},
+ {"Monitors", {click, filter_monitor_info()}},
+ {"Monitored by", {click, monitored_by}}]},
{"Memory and Garbage Collection", right,
[{"Memory", {bytes, memory}},
{"Stack and Heaps", {bytes, total_heap_size}},
@@ -365,3 +360,9 @@ get_gc_info(Arg) ->
GC = proplists:get_value(garbage_collection, Data),
proplists:get_value(Arg, GC)
end.
+
+filter_monitor_info() ->
+ fun(Data) ->
+ Ms = proplists:get_value(monitors, Data),
+ [Pid || {process, Pid} <- Ms]
+ end.
diff --git a/lib/observer/src/observer_wx.erl b/lib/observer/src/observer_wx.erl
index 3afe933e5a..9839f8bf7b 100644
--- a/lib/observer/src/observer_wx.erl
+++ b/lib/observer/src/observer_wx.erl
@@ -346,6 +346,22 @@ handle_info({nodedown, Node},
create_txt_dialog(Frame, Msg, "Node down", ?wxICON_EXCLAMATION),
{noreply, State3};
+handle_info({open_link, Pid0}, State = #state{pro_panel=ProcViewer, frame=Frame}) ->
+ Pid = case Pid0 of
+ [_|_] -> try list_to_pid(Pid0) catch _:_ -> Pid0 end;
+ _ -> Pid0
+ end,
+ %% Forward to process tab
+ case is_pid(Pid) of
+ true -> wx_object:get_pid(ProcViewer) ! {procinfo_open, Pid};
+ false ->
+ Msg = io_lib:format("Information about ~p is not available or implemented",[Pid]),
+ Info = wxMessageDialog:new(Frame, Msg),
+ wxMessageDialog:showModal(Info),
+ wxMessageDialog:destroy(Info)
+ end,
+ {noreply, State};
+
handle_info({'EXIT', Pid, _Reason}, State) ->
io:format("Child (~s) crashed exiting: ~p ~p~n",
[pid2panel(Pid, State), Pid,_Reason]),