diff options
Diffstat (limited to 'lib/observer')
-rw-r--r-- | lib/observer/src/observer_lib.erl | 82 | ||||
-rw-r--r-- | lib/observer/src/observer_sock_wx.erl | 101 | ||||
-rw-r--r-- | lib/observer/src/observer_wx.erl | 42 |
3 files changed, 129 insertions, 96 deletions
diff --git a/lib/observer/src/observer_lib.erl b/lib/observer/src/observer_lib.erl index 57a9a741a5..c2cc61af86 100644 --- a/lib/observer/src/observer_lib.erl +++ b/lib/observer/src/observer_lib.erl @@ -26,7 +26,9 @@ wait_for_progress/0, report_progress/1, user_term/3, user_term_multiline/3, interval_dialog/4, start_timer/1, start_timer/2, stop_timer/1, timer_config/1, - display_info/2, display_info/3, fill_info/2, update_info/2, to_str/1, + display_info/2, display_info/3, + fill_info/2, fill_info/3, update_info/2, + to_str/1, create_menus/3, create_menu_item/3, is_darkmode/1, colors/1, create_attrs/1, set_listctrl_col_size/2, mix/3, @@ -171,51 +173,65 @@ display_info(Panel, Sizer, Info) -> end, [Add(I) || I <- Info]. -fill_info([{dynamic, Key}|Rest], Data) +fill_info(Fields, Data) -> + fill_info(Fields, Data, undefined). + +fill_info([{dynamic, Key}|Rest], Data, Default) when is_atom(Key); is_function(Key) -> %% Special case used by crashdump_viewer when the value decides %% which header to use - case get_value(Key, Data) of - undefined -> [undefined | fill_info(Rest, Data)]; - {Str,Value} -> [{Str, Value} | fill_info(Rest, Data)] + case get_value(Key, Data, Default) of + undefined -> [undefined | fill_info(Rest, Data, Default)]; + {Str,Value} -> [{Str, Value} | fill_info(Rest, Data, Default)] end; -fill_info([{Str, Key}|Rest], Data) when is_atom(Key); is_function(Key) -> - case get_value(Key, Data) of - undefined -> [undefined | fill_info(Rest, Data)]; - Value -> [{Str, Value} | fill_info(Rest, Data)] +fill_info([{Str, Key}|Rest], Data, Default) + when is_atom(Key); is_function(Key) -> + case get_value(Key, Data, Default) of + undefined -> + [undefined | fill_info(Rest, Data, Default)]; + Value -> + [{Str, Value} | fill_info(Rest, Data, Default)] end; -fill_info([{Str,Attrib,Key}|Rest], Data) when is_atom(Key); is_function(Key) -> - case get_value(Key, Data) of - undefined -> [undefined | fill_info(Rest, Data)]; - Value -> [{Str,Attrib,Value} | fill_info(Rest, Data)] +fill_info([{Str, Attrib, Key}|Rest], Data, Default) + when is_atom(Key); is_function(Key) -> + case get_value(Key, Data, Default) of + undefined -> + [undefined | fill_info(Rest, Data, Default)]; + Value -> + [{Str,Attrib,Value} | fill_info(Rest, Data, Default)] end; -fill_info([{Str, {Format, Key}}|Rest], Data) +fill_info([{Str, {Format, Key}}|Rest], Data, Default) when is_atom(Key); is_function(Key) -> - case get_value(Key, Data) of - undefined -> [undefined | fill_info(Rest, Data)]; - Value -> [{Str, {Format, Value}} | fill_info(Rest, Data)] + case get_value(Key, Data, Default) of + undefined -> [undefined | fill_info(Rest, Data, Default)]; + Value -> [{Str, {Format, Value}} | fill_info(Rest, Data, Default)] end; -fill_info([{Str, Attrib, {Format, Key}}|Rest], Data) +fill_info([{Str, Attrib, {Format, Key}}|Rest], Data, Default) when is_atom(Key); is_function(Key) -> - case get_value(Key, Data) of - undefined -> [undefined | fill_info(Rest, Data)]; - Value -> [{Str, Attrib, {Format, Value}} | fill_info(Rest, Data)] + case get_value(Key, Data, Default) of + undefined -> [undefined | fill_info(Rest, Data, Default)]; + Value -> [{Str, Attrib, {Format, Value}} | + fill_info(Rest, Data, Default)] end; -fill_info([{Str,SubStructure}|Rest], Data) when is_list(SubStructure) -> - [{Str, fill_info(SubStructure, Data)}|fill_info(Rest,Data)]; -fill_info([{Str,Attrib,SubStructure}|Rest], Data) -> - [{Str, Attrib, fill_info(SubStructure, Data)}|fill_info(Rest,Data)]; -fill_info([{Str, Key = {K,N}}|Rest], Data) when is_atom(K), is_integer(N) -> - case get_value(Key, Data) of - undefined -> [undefined | fill_info(Rest, Data)]; - Value -> [{Str, Value} | fill_info(Rest, Data)] +fill_info([{Str,SubStructure}|Rest], Data, Default) + when is_list(SubStructure) -> + [{Str, fill_info(SubStructure, Data, Default)}| + fill_info(Rest, Data, Default)]; +fill_info([{Str,Attrib,SubStructure}|Rest], Data, Default) -> + [{Str, Attrib, fill_info(SubStructure, Data, Default)}| + fill_info(Rest, Data, Default)]; +fill_info([{Str, Key = {K,N}}|Rest], Data, Default) + when is_atom(K), is_integer(N) -> + case get_value(Key, Data, Default) of + undefined -> [undefined | fill_info(Rest, Data, Default)]; + Value -> [{Str, Value} | fill_info(Rest, Data, Default)] end; -fill_info([], _) -> []. +fill_info([], _, _Default) -> []. -get_value(Fun, Data) when is_function(Fun) -> +get_value(Fun, Data, _Default) when is_function(Fun) -> Fun(Data); -get_value(Key, Data) -> - proplists:get_value(Key,Data). +get_value(Key, Data, Default) -> + proplists:get_value(Key, Data, Default). update_info([Fields|Fs], [{_Header, SubStructure}| Rest]) -> update_info2(Fields, SubStructure), diff --git a/lib/observer/src/observer_sock_wx.erl b/lib/observer/src/observer_sock_wx.erl index dc91d0f050..c1cb161a8a 100644 --- a/lib/observer/src/observer_sock_wx.erl +++ b/lib/observer/src/observer_sock_wx.erl @@ -75,7 +75,7 @@ panel, sizer, fields, - node = {node(),true}, + node = {node(), true}, opt = #opt{}, right_clicked_socket, sockets, @@ -111,7 +111,9 @@ update_gen_socket_info(#state{node = {Node, true}, case rpc:call(Node, observer_backend, socket_info, []) of Info when is_list(Info) -> Gen = info_fields(), - observer_lib:update_info(Fields, observer_lib:fill_info(Gen, Info)), + observer_lib:update_info(Fields, + observer_lib:fill_info(Gen, Info, + "Not Supported")), wxSizer:layout(Sizer); _ -> ignore @@ -129,17 +131,35 @@ init([Notebook, Parent, Config]) -> "~n Notebook: ~p" "~n Parent: ~p" "~n Config: ~p", [Notebook, Parent, Config]), - Info = observer_backend:socket_info(), + try + begin + do_init(Notebook, Parent, Config, observer_backend:socket_info()) + end + catch + C:E:S -> + %% Current node does not support socket (windows?) + d("init -> catched: " + "~n C: ~p" + "~n E: ~p" + "~n S: ~p", [C, E, S]), + do_init(Notebook, Parent, Config, []) + end. + +do_init(Notebook, Parent, Config, Info) -> Gen = info_fields(), Panel = wxPanel:new(Notebook), Sizer = wxBoxSizer:new(?wxVERTICAL), GenSizer = wxBoxSizer:new(?wxHORIZONTAL), {GenPanel, _GenSizer, GenFields} = - observer_lib:display_info(Panel, observer_lib:fill_info(Gen, Info)), - wxSizer:add(GenSizer, GenPanel, [{flag, ?wxEXPAND}, {proportion, 1}]), + observer_lib:display_info(Panel, + observer_lib:fill_info(Gen, Info, + "Not Supported")), + wxSizer:add(GenSizer, GenPanel, + [{flag, ?wxEXPAND}, {proportion, 1}]), BorderFlags = ?wxLEFT bor ?wxRIGHT, - wxSizer:add(Sizer, GenSizer, [{flag, ?wxEXPAND bor BorderFlags bor ?wxTOP}, - {proportion, 0}, {border, 5}]), + wxSizer:add(Sizer, GenSizer, + [{flag, ?wxEXPAND bor BorderFlags bor ?wxTOP}, + {proportion, 0}, {border, 5}]), Style = ?wxLC_REPORT bor ?wxLC_HRULES, Grid = wxListCtrl:new(Panel, [{winid, ?GRID}, {style, Style}]), wxSizer:add(Sizer, Grid, [{flag, ?wxEXPAND bor ?wxALL}, @@ -371,43 +391,6 @@ handle_call(Event, From, _State) -> handle_cast(Event, _State) -> error({unhandled_cast, Event}). -%% handle_info({socketinfo_open, IdStr}, -%% State = #state{node = {ActiveNodeName, ActiveAvailable}, -%% grid = Grid, -%% opt = Opt, -%% open_wins = Opened}) -> -%% NodeName = node(list_to_port(PortIdStr)), % How do we do this for sockets? -%% Available = -%% case NodeName of -%% ActiveNodeName -> -%% ActiveAvailable; -%% _ -> -%% portinfo_available(NodeName) -%% end, -%% if Available -> -%% Sockets0 = get_sockets(NodeName, Available), -%% Sockets = lists:keyfind(SockIdStr, #socket.id_str, Sockets), -%% NewOpened = -%% case Port of -%% false -> -%% self() ! {error,"No such socket: " ++ SockIdStr}, -%% Opened; -%% _ -> -%% display_socket_info(Grid, Port, Opened) -%% end, -%% Ports = -%% case NodeName of -%% ActiveNodeName -> -%% update_grid(Grid, sel(State), Opt, Ports0); -%% _ -> -%% State#state.ports -%% end, -%% {noreply, State#state{ports=Ports, open_wins=NewOpened}}; -%% true -> -%% popup_unavailable_info(NodeName), -%% {noreply, State} -%% end; - handle_info(refresh_interval, State = #state{node = Node, grid = Grid, opt = Opt, @@ -425,12 +408,13 @@ handle_info(refresh_interval, State = #state{node = Node, {noreply, State#state{sockets = Sockets}} end; -handle_info({active, NodeName}, +handle_info({active, NodeName}, #state{parent = Parent, grid = Grid, opt = Opt, timer = Timer0} = State0) -> - Available = portinfo_available(NodeName), + d("handle_info({active, ~p}) -> entry", [NodeName]), + Available = socketinfo_available(NodeName), Available orelse popup_unavailable_info(NodeName), State1 = State0#state{node = {NodeName, Available}}, _ = update_gen_socket_info(State1), @@ -446,15 +430,18 @@ handle_info(not_active, State = #state{timer = Timer0}) -> Timer = observer_lib:stop_timer(Timer0), {noreply, State#state{timer=Timer}}; -handle_info({info, {port_info_not_available,NodeName}}, +handle_info({info, {socket_info_not_available, NodeName}}, State = #state{panel=Panel}) -> - Str = io_lib:format("Can not fetch port info from ~p.~n" - "Too old OTP version.",[NodeName]), + Str = io_lib:format("Can not fetch socket info from ~p.~n" + "Too old OTP version.", [NodeName]), observer_lib:display_info_dialog(Panel, Str), {noreply, State}; handle_info({error, Error}, #state{panel=Panel} = State) -> - Str = io_lib:format("ERROR: ~ts~n",[Error]), + ErrorStr = if is_list(Error) -> Error; + true -> f("~p", [Error]) + end, + Str = io_lib:format("ERROR: ~ts~n", [ErrorStr]), observer_lib:display_info_dialog(Panel, Str), {noreply, State}; @@ -492,9 +479,17 @@ get_sockets(NodeName) when is_atom(NodeName) -> case rpc:call(NodeName, observer_backend, get_socket_list, []) of SocketInfoMaps when is_list(SocketInfoMaps) -> [infomap_to_rec(SockInfo) || SockInfo <- SocketInfoMaps]; + {badrpc, + {'EXIT', {undef, [{observer_backend, get_socket_list, [], []}]}}} -> + d("get_sockets -> No Backend"), + {error, "No socket backend support"}; {badrpc, Error} -> + d("get_sockets -> badrpc: " + "~n ~p", [Error]), {error, Error}; {error, _} = ERROR -> + d("get_sockets -> error:" + "~n ~p", [ERROR]), ERROR end. @@ -792,16 +787,16 @@ get_indecies(Rest = [_|_], I, [_|T]) -> get_indecies(_, _, _) -> []. -portinfo_available(NodeName) -> +socketinfo_available(NodeName) -> _ = rpc:call(NodeName, code, ensure_loaded, [observer_backend]), case rpc:call(NodeName, erlang, function_exported, - [observer_backend, get_port_list, 0]) of + [observer_backend, get_socket_list, 0]) of true -> true; false -> false end. popup_unavailable_info(NodeName) -> - self() ! {info, {port_info_not_available, NodeName}}, + self() ! {info, {socket_info_not_available, NodeName}}, ok. f(F, A) -> diff --git a/lib/observer/src/observer_wx.erl b/lib/observer/src/observer_wx.erl index 04f725cb4e..b61532f5b0 100644 --- a/lib/observer/src/observer_wx.erl +++ b/lib/observer/src/observer_wx.erl @@ -200,8 +200,26 @@ setup(#state{frame = Frame} = State) -> wxNotebook:addPage(Notebook, PortPanel, "Ports", []), %% Socket Panel + %% Note that this panel should *only* be added if we have support for socket + %% Also, if we run on/with an "old" node (without this support), + %% we should also not include this! + %% SockPanel = + %% try socket:supports() of + %% _ -> + %% d("setup -> create socket panel"), + %% SP = observer_sock_wx:start_link(Notebook, + %% self(), + %% Cnf(sock_panel)), + %% wxNotebook:addPage(Notebook, SP, "Sockets", []), + %% SP + %% catch + %% _:_:_ -> + %% undefined + %% end, d("setup -> create socket panel"), - SockPanel = observer_sock_wx:start_link(Notebook, self(), Cnf(sock_panel)), + SockPanel = observer_sock_wx:start_link(Notebook, + self(), + Cnf(sock_panel)), wxNotebook:addPage(Notebook, SockPanel, "Sockets", []), %% Table Viewer Panel @@ -226,15 +244,19 @@ setup(#state{frame = Frame} = State) -> SysPid = wx_object:get_pid(SysPanel), SysPid ! {active, node()}, - Panels = [{sys_panel, SysPanel, "System"}, %% In order - {perf_panel, PerfPanel, "Load Charts"}, - {allc_panel, AllcPanel, ?ALLOC_STR}, - {app_panel, AppPanel, "Applications"}, - {pro_panel, ProPanel, "Processes"}, - {port_panel, PortPanel, "Ports"}, - {sock_panel, SockPanel, "Sockets"}, - {tv_panel, TVPanel, "Table Viewer"}, - {trace_panel, TracePanel, ?TRACE_STR}], + Panels = + [{sys_panel, SysPanel, "System"}, %% In order + {perf_panel, PerfPanel, "Load Charts"}, + {allc_panel, AllcPanel, ?ALLOC_STR}, + {app_panel, AppPanel, "Applications"}, + {pro_panel, ProPanel, "Processes"}, + {port_panel, PortPanel, "Ports"}] ++ + if (SockPanel =:= undefined) -> []; + true -> + [{sock_panel, SockPanel, "Sockets"}] + end ++ + [{tv_panel, TVPanel, "Table Viewer"}, + {trace_panel, TracePanel, ?TRACE_STR}], UpdState = State#state{main_panel = Panel, notebook = Notebook, |