From 5a30dd40a691d610def7b1f00cf39ed0d78eb900 Mon Sep 17 00:00:00 2001 From: Dan Gudmundsson Date: Tue, 19 Nov 2013 11:00:32 +0100 Subject: observer: Use crashdump_viewer's term viewer to display large terms and binaries --- lib/observer/src/cdv_bin_wx.erl | 5 +- lib/observer/src/cdv_html_page.erl | 19 +++-- lib/observer/src/cdv_term_wx.erl | 45 +++++++----- lib/observer/src/crashdump_viewer_html.erl | 97 +++++++++++++++++-------- lib/observer/src/observer_procinfo.erl | 49 ++++++++----- lib/observer/src/observer_term_wx.erl | 113 ----------------------------- 6 files changed, 142 insertions(+), 186 deletions(-) delete mode 100644 lib/observer/src/observer_term_wx.erl (limited to 'lib/observer/src') diff --git a/lib/observer/src/cdv_bin_wx.erl b/lib/observer/src/cdv_bin_wx.erl index d2cbcfb747..6cf344f945 100644 --- a/lib/observer/src/cdv_bin_wx.erl +++ b/lib/observer/src/cdv_bin_wx.erl @@ -21,7 +21,10 @@ detail_pages/0]). %% Callbacks for cdv_detail_win -get_details(Id) -> +get_details({_, {T,Key}}) -> + [{Key,Term}] = ets:lookup(T,Key), + {ok,{"Expanded Binary", Term, []}}; +get_details({cdv, Id}) -> {ok,Bin} = crashdump_viewer:expand_binary(Id), {ok,{"Expanded Binary", Bin, []}}. diff --git a/lib/observer/src/cdv_html_page.erl b/lib/observer/src/cdv_html_page.erl index b2d059f7f8..d77238c6cf 100644 --- a/lib/observer/src/cdv_html_page.erl +++ b/lib/observer/src/cdv_html_page.erl @@ -84,16 +84,23 @@ handle_event(#wx{event=#wxHtmlLink{type=command_html_link_clicked, "#Binary?" ++ BinSpec -> [{"offset",Off},{"size",Size},{"pos",Pos}] = httpd:parse_query(BinSpec), - Id = {list_to_integer(Off), - list_to_integer(Size), - list_to_integer(Pos)}, + Id = {cdv, {list_to_integer(Off), + list_to_integer(Size), + list_to_integer(Pos)}}, + expand(Id,cdv_bin_wx,State); + "#OBSBinary?" ++ BinSpec -> + [{"offset",Off},{"size",Size},{"pos",Pos}] = + httpd:parse_query(BinSpec), + Id = {obs, {Tab, {list_to_integer(Off), + list_to_integer(Size), + list_to_integer(Pos)}}}, expand(Id,cdv_bin_wx,State); "#Term?" ++ TermKeys -> [{"key1",Key1},{"key2",Key2},{"key3",Key3}] = httpd:parse_query(TermKeys), - Id = {Tab,{list_to_integer(Key1), - list_to_integer(Key2), - list_to_integer(Key3)}}, + Id = {cdv, {Tab,{list_to_integer(Key1), + list_to_integer(Key2), + list_to_integer(Key3)}}}, expand(Id,cdv_term_wx,State); _ -> cdv_virtual_list:start_detail_win(Target), diff --git a/lib/observer/src/cdv_term_wx.erl b/lib/observer/src/cdv_term_wx.erl index e029a75b29..9b83249eae 100644 --- a/lib/observer/src/cdv_term_wx.erl +++ b/lib/observer/src/cdv_term_wx.erl @@ -21,26 +21,28 @@ detail_pages/0]). %% Callbacks for cdv_detail_win -get_details({T,Key}) -> +get_details({_, {T,Key}}) -> [{Key,Term}] = ets:lookup(T,Key), - {ok,{"Expanded Term", Term, []}}. + {ok,{"Expanded Term", [Term, T], []}}. detail_pages() -> [{"Term", fun init_term_page/2}]. -init_term_page(ParentWin, Term) -> +init_term_page(ParentWin, [Term, Tab]) -> + Expanded = expand(Term, true), + BinSaved = expand(Term, Tab), cdv_multi_panel:start_link( ParentWin, - [{"Format \~p",cdv_html_page,format_term_fun("~p",Term)}, - {"Format \~tp",cdv_html_page,format_term_fun("~tp",Term)}, - {"Format \~w",cdv_html_page,format_term_fun("~w",Term)}, - {"Format \~s",cdv_html_page,format_term_fun("~s",expand(Term))}, - {"Format \~ts",cdv_html_page,format_term_fun("~ts",expand(Term))}]). + [{"Format \~p",cdv_html_page,format_term_fun("~p",BinSaved,Tab)}, + {"Format \~tp",cdv_html_page,format_term_fun("~tp",BinSaved,Tab)}, + {"Format \~w",cdv_html_page,format_term_fun("~w",BinSaved,Tab)}, + {"Format \~s",cdv_html_page,format_term_fun("~s",Expanded,Tab)}, + {"Format \~ts",cdv_html_page,format_term_fun("~ts",Expanded,Tab)}]). -format_term_fun(Format,Term) -> +format_term_fun(Format,Term,Tab) -> fun() -> try io_lib:format(Format,[Term]) of - Str -> plain_html(Str) + Str -> {expand, plain_html(Str), Tab} catch error:badarg -> Warning = "This term can not be formatted with " ++ Format, crashdump_viewer_html:warning(Warning) @@ -50,17 +52,24 @@ format_term_fun(Format,Term) -> plain_html(Text) -> crashdump_viewer_html:plain_page(Text). -expand(['#CDVBin',Offset,Size,Pos]) -> +expand(['#CDVBin',Offset,Size,Pos], true) -> {ok,Bin} = crashdump_viewer:expand_binary({Offset,Size,Pos}), Bin; -expand([H|T]) -> - case expand(T) of +expand(Bin, Tab) when is_binary(Bin), not is_boolean(Tab) -> + <> = Bin, + Size = byte_size(Bin), + Hash = erlang:phash2(Bin), + Key = {Preview, Size, Hash}, + ets:insert(Tab, {Key,Bin}), + ['#OBSBin',Preview,Size,Hash]; +expand([H|T], Expand) -> + case expand(T, Expand) of ET when is_list(ET) -> - [expand(H)|ET]; + [expand(H, Expand)|ET]; ET -> % The tail is an expanded binary - cannot append with | - [expand(H),ET] + [expand(H, Expand),ET] end; -expand(Tuple) when is_tuple(Tuple) -> - list_to_tuple(expand(tuple_to_list(Tuple))); -expand(Term) -> +expand(Tuple, Expand) when is_tuple(Tuple) -> + list_to_tuple(expand(tuple_to_list(Tuple), Expand)); +expand(Term, _) -> Term. diff --git a/lib/observer/src/crashdump_viewer_html.erl b/lib/observer/src/crashdump_viewer_html.erl index 9cd4d6748a..2cc28d04be 100644 --- a/lib/observer/src/crashdump_viewer_html.erl +++ b/lib/observer/src/crashdump_viewer_html.erl @@ -590,15 +590,31 @@ all_or_expand(Tab,Term) -> all_or_expand(Tab,Term,Preview,Exp). all_or_expand(_Tab,_Term,Str,false) -> href_proc_port(lists:flatten(Str)); -all_or_expand(Tab,Term,Preview,true) -> +all_or_expand(Tab,Term,Preview,true) + when not is_binary(Term) -> Key = {Key1,Key2,Key3} = now(), ets:insert(Tab,{Key,Term}), - [href_proc_port(lists:flatten(Preview),false), $\n, - href("TARGET=\"expanded\"",["#Term?key1="++integer_to_list(Key1)++ - "&key2="++integer_to_list(Key2)++ - "&key3="++integer_to_list(Key3)], + [href_proc_port(lists:flatten(Preview), false), $\n, + href("TARGET=\"expanded\"", + ["#Term?key1="++integer_to_list(Key1)++ + "&key2="++integer_to_list(Key2)++ + "&key3="++integer_to_list(Key3)], + "Click to expand above term")]; +all_or_expand(Tab,Bin,PreviewStr,true) when is_binary(Bin) -> + <> = Bin, + Size = byte_size(Bin), + Hash = erlang:phash2(Bin), + Key = {Preview, Size, Hash}, + ets:insert(Tab,{Key,Bin}), + [href_proc_port(lists:flatten(PreviewStr), false), $\n, + href("TARGET=\"expanded\"", + ["#OBSBinary?key1="++integer_to_list(Preview)++ + "&key2="++integer_to_list(Size)++ + "&key3="++integer_to_list(Hash)], "Click to expand above term")]. + + 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)). @@ -1131,31 +1147,10 @@ href_proc_port("<"++([C|_]=T),Acc,LTB) when $0 =< C, C =< $9 -> href_proc_port(Rest,[href(Pid,Pid)|Acc],LTB); href_proc_port("['#CDVBin'"++T,Acc,LTB) -> %% Binary written by crashdump_viewer:parse_heap_term(...) - {OffsetSizePos,Rest} = split($],T), - BinStr = - case string:tokens(OffsetSizePos,",.|") of - [Offset,Size,Pos] -> - Id = {list_to_integer(Offset),10,list_to_integer(Pos)}, - {ok,PreviewBin} = crashdump_viewer:expand_binary(Id), - PreviewBytes = binary_to_list(PreviewBin), - PreviewStr = ["<<", - [integer_to_list(X)++"," || X <- PreviewBytes], - "...(", - observer_lib:to_str({bytes,Size}), - ")>>"], - if LTB -> - href("TARGET=\"expanded\"", - ["#Binary?offset="++Offset++ - "&size="++Size++ - "&pos="++Pos], - PreviewStr); - true -> - PreviewStr - end; - _ -> - "<< ... >>" - end, - href_proc_port(Rest,[BinStr|Acc],LTB); + href_proc_bin(cdv, T, Acc, LTB); +href_proc_port("['#OBSBin'"++T,Acc,LTB) -> + %% Binary written by crashdump_viewer:parse_heap_term(...) + href_proc_bin(obs, T, Acc, LTB); href_proc_port("['#CDVPort'"++T,Acc,LTB) -> %% Port written by crashdump_viewer:parse_term(...) {Port0,Rest} = split($],T), @@ -1211,6 +1206,48 @@ href_proc_port([H|T],Acc,LTB) -> href_proc_port([],Acc,_) -> lists:reverse(Acc). +href_proc_bin(From, T, Acc, LTB) -> + {OffsetSizePos,Rest} = split($],T), + BinStr = + case string:tokens(OffsetSizePos,",.| \n") of + [Offset,Size,Pos] when From =:= cdv -> + Id = {list_to_integer(Offset),10,list_to_integer(Pos)}, + {ok,PreviewBin} = crashdump_viewer:expand_binary(Id), + PreviewStr = ["<<", + [integer_to_list(X)++"," || <> <= PreviewBin], + "...(", + observer_lib:to_str({bytes,Size}), + ")>>"], + if LTB -> + href("TARGET=\"expanded\"", + ["#Binary?offset="++Offset++ + "&size="++Size++ + "&pos="++Pos], + PreviewStr); + true -> + PreviewStr + end; + [Preview,Size,Md5] when From =:= obs -> + PreviewBin = <<(list_to_integer(Preview)):80>>, + PreviewStr = ["<<", + [integer_to_list(X)++"," || <> <= PreviewBin], + "...(", + observer_lib:to_str({bytes,list_to_integer(Size)}), + ")>>"], + if LTB -> + href("TARGET=\"expanded\"", + ["#OBSBinary?offset="++Preview++ + "&size="++Size++ + "&pos="++Md5], + PreviewStr); + true -> + PreviewStr + end; + _ -> + "<< ... >>" + end, + href_proc_port(Rest,[BinStr|Acc],LTB). + split(Char,Str) -> split(Char,Str,[]). split(Char,[Char|Str],Acc) -> % match Char diff --git a/lib/observer/src/observer_procinfo.erl b/lib/observer/src/observer_procinfo.erl index cfc22e7093..af2b8dda2e 100644 --- a/lib/observer/src/observer_procinfo.erl +++ b/lib/observer/src/observer_procinfo.erl @@ -49,7 +49,7 @@ start(Process, ParentFrame, Parent) -> init([Pid, ParentFrame, Parent]) -> try - Table = ets:new(observer_expand,[set,protected]), + Table = ets:new(observer_expand,[set,public]), Title=case observer_wx:try_rpc(node(Pid), erlang, process_info, [Pid, registered_name]) of [] -> io_lib:format("~p",[Pid]); {registered_name, Registered} -> io_lib:format("~p (~p)",[Registered, Pid]); @@ -123,20 +123,33 @@ 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="#Term?"++Keys}}}, +handle_event(#wx{event=#wxHtmlLink{linkInfo=#wxHtmlLinkInfo{href=Href}}}, #state{frame=Frame,expand_table=T,expand_wins=Opened0}=State) -> - [{"key1",Key1},{"key2",Key2},{"key3",Key3}] = httpd:parse_query(Keys), - Id = {T,{list_to_integer(Key1),list_to_integer(Key2),list_to_integer(Key3)}}, - Opened = - case lists:keyfind(Id,1,Opened0) of - false -> - Win = observer_term_wx:start(Id,Frame), - [{Id,Win}|Opened0]; - {_,Win} -> - wxFrame:raise(Win), - Opened0 - end, - {noreply,State#state{expand_wins=Opened}}; + {Type, Rest} = case Href of + "#Term?"++Keys -> {cdv_term_wx, Keys}; + "#OBSBinary?"++Keys -> {cdv_bin_wx, Keys}; + _ -> {other, Href} + end, + case Type of + other -> + observer ! {open_link, Href}, + {noreply, State}; + Callback -> + [{"key1",Key1},{"key2",Key2},{"key3",Key3}] = httpd:parse_query(Rest), + Id = {observer, {T,{list_to_integer(Key1), + list_to_integer(Key2), + list_to_integer(Key3)}}}, + Opened = + case lists:keyfind(Id,1,Opened0) of + false -> + Win = cdv_detail_win:start_link(Id,Frame,Callback), + [{Id,Win}|Opened0]; + {_,Win} -> + wxFrame:raise(Win), + Opened0 + end, + {noreply,State#state{expand_wins=Opened}} + end; handle_event(#wx{event=#wxHtmlLink{linkInfo=#wxHtmlLinkInfo{href=Info}}}, State) -> observer ! {open_link, Info}, @@ -145,10 +158,6 @@ handle_event(#wx{event=#wxHtmlLink{linkInfo=#wxHtmlLinkInfo{href=Info}}}, State) handle_event(Event, _State) -> error({unhandled_event, Event}). -handle_info({expand_win_closed,Id}, #state{expand_wins=Opened0}=State) -> - Opened = lists:keydelete(Id,1,Opened0), - {noreply,State#state{expand_wins=Opened}}; - handle_info(_Info, State) -> %% io:format("~p: ~p, Handle info: ~p~n", [?MODULE, ?LINE, Info]), {noreply, State}. @@ -156,6 +165,10 @@ handle_info(_Info, State) -> handle_call(Call, From, _State) -> error({unhandled_call, Call, From}). +handle_cast({detail_win_closed,Id}, #state{expand_wins=Opened0}=State) -> + Opened = lists:keydelete(Id,1,Opened0), + {noreply,State#state{expand_wins=Opened}}; + handle_cast(Cast, _State) -> error({unhandled_cast, Cast}). diff --git a/lib/observer/src/observer_term_wx.erl b/lib/observer/src/observer_term_wx.erl deleted file mode 100644 index 58cb650bef..0000000000 --- a/lib/observer/src/observer_term_wx.erl +++ /dev/null @@ -1,113 +0,0 @@ -%% -%% %CopyrightBegin% -%% -%% 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 -%% 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% - --module(observer_term_wx). - --behaviour(wx_object). - --export([start/2]). - --export([init/1, handle_event/2, handle_cast/2, terminate/2, code_change/3, - handle_call/3, handle_info/2]). - --include_lib("wx/include/wx.hrl"). --include("observer_defs.hrl"). - --define(REFRESH, 601). - --record(state, {parent, - frame, - id - }). - -start(Id, ParentFrame) -> - wx_object:start_link(?MODULE, [Id, ParentFrame, self()], []). - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -init([{T,Key}=Id, ParentFrame, Parent]) -> - case ets:lookup(T,Key) of - [{Key,Term}] -> - init(Id, ParentFrame, Parent, Term); - [] -> - observer_lib:display_info_dialog( - "The term does no longer exist.\n" - "Please refresh the process window!"), - {stop, normal} - end. - - - -init(Id, ParentFrame, Parent, Term) -> - Frame=wxFrame:new(ParentFrame, ?wxID_ANY, ["Expanded Term"], - [{style, ?wxDEFAULT_FRAME_STYLE}, {size, {850,600}}]), - MenuBar = wxMenuBar:new(), - Menus = [{"File", [#create_menu{id=?wxID_CLOSE, text="Close"}]}], - observer_lib:create_menus(Menus, MenuBar, new_window), - wxFrame:setMenuBar(Frame, MenuBar), - Panel = wxPanel:new(Frame), - Sizer = wxBoxSizer:new(?wxHORIZONTAL), - - Window = observer_lib:html_window(Panel), - Html = crashdump_viewer_html:plain_page(io_lib:format("~p~n",[Term])), - wxHtmlWindow:setPage(Window, Html), - - wxSizer:add(Sizer, Window, [{flag, ?wxEXPAND bor ?wxALL}, - {proportion, 1}, - {border, 5}]), - wxPanel:setSizer(Panel, Sizer), - wxFrame:show(Frame), - {Frame, #state{parent=Parent, - frame=Frame, - id=Id - }}. - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%Callbacks%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -handle_event(#wx{event=#wxClose{type=close_window}}, State) -> - {stop, normal, State}; - -handle_event(#wx{id=?wxID_CLOSE, event=#wxCommand{type=command_menu_selected}}, State) -> - {stop, normal, 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}). - -handle_info(_Info, State) -> - %% io:format("~p: ~p, Handle info: ~p~n", [?MODULE, ?LINE, Info]), - {noreply, State}. - -handle_call(Call, From, _State) -> - error({unhandled_call, Call, From}). - -handle_cast(Cast, _State) -> - error({unhandled_cast, Cast}). - -terminate(_Reason, #state{parent=Parent,id=Id,frame=Frame}) -> - Parent ! {expand_win_closed, Id}, - case Frame of - undefined -> ok; - _ -> wxFrame:destroy(Frame) - end, - ok. - -code_change(_, _, State) -> - {ok, State}. -- cgit v1.2.3