%% %% %CopyrightBegin% %% %% Copyright Ericsson AB 2003-2018. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. %% You may obtain a copy of the License at %% %% http://www.apache.org/licenses/LICENSE-2.0 %% %% Unless required by applicable law or agreed to in writing, software %% distributed under the License is distributed on an "AS IS" BASIS, %% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %% See the License for the specific language governing permissions and %% limitations under the License. %% %% %CopyrightEnd% %% -module(observer_html_lib). %% %% This module implements the HTML generation for the crashdump %% viewer. No logic or states are kept by this module. %% -export([plain_page/1, expandable_term/3, warning/1]). -include("crashdump_viewer.hrl"). -include("observer_defs.hrl"). %%%----------------------------------------------------------------- %%% Display the given information as is, no heading %%% Empty body if no info exists. warning(Info) -> header(body(warning_body(Info))). warning_body(Info) -> [warn(Info)]. %%%----------------------------------------------------------------- %%% Display the given information as is, no heading %%% Empty body if no info exists. plain_page(Info) -> header(body(plain_body(Info))). plain_body(Info) -> [pre(href_proc_port(lists:flatten(Info)))]. %%%----------------------------------------------------------------- %%% Expanded memory expandable_term(Heading,Expanded,Tab) -> header(Heading,body(expandable_term_body(Heading,Expanded,Tab))). expandable_term_body(Heading,[],_Tab) -> [case Heading of "MsgQueue" -> "No messages were 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."; "SaslLog" -> "No log entry was found" end]; expandable_term_body(Heading,Expanded,Tab) -> Attr = "BORDER=0 CELLPADDING=0 CELLSPACING=1 WIDTH=100%", [case Heading of "MsgQueue" -> table(Attr, [tr( [th("WIDTH=70%","Message"), th("WIDTH=30%","SeqTraceToken")]) | element(1, lists:mapfoldl(fun(Msg, Even) -> {msgq_table(Tab, 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(Tab, Msg, N, Even), {not Even, N+1}} end, {true,1}, Expanded))]); "StackDump" -> table(Attr, [tr( [th("WIDTH=20%","Label"), th("WIDTH=80%","Term")]) | element(1, lists:mapfoldl(fun(Entry, Even) -> {stackdump_table(Tab, 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(Tab, Entry,Even), not Even} end, true, Expanded))]); "SaslLog" -> table(Attr, [tr("BGCOLOR=white",[td("ALIGN=left", pre(href_proc_port(Expanded)))])]) ; _ -> table(Attr, [tr( [th("WIDTH=30%","Key"), th("WIDTH=70%","Value")]) | element(1, lists:mapfoldl(fun(Entry, Even) -> {dict_table(Tab, Entry,Even), not Even} end, true, Expanded))]) end]. msgq_table(Tab,{Msg0,Token0}, Even) -> Token = case Token0 of [] -> ""; _ -> io_lib:fwrite("~w",[Token0]) end, Msg = all_or_expand(Tab,Msg0), tr(color(Even),[td(pre(Msg)), td(Token)]). msgq_table(Tab,Msg0, Id, Even) -> Msg = all_or_expand(Tab,Msg0), tr(color(Even),[td(integer_to_list(Id)), td(pre(Msg))]). stackdump_table(Tab,{Label0,Term0},Even) -> Label = io_lib:format("~w",[Label0]), Term = all_or_expand(Tab,Term0), tr(color(Even), [td("VALIGN=center",pre(Label)), td(pre(Term))]). dict_table(Tab,{Key0,Value0}, Even) -> Key = all_or_expand(Tab,Key0), Value = all_or_expand(Tab,Value0), tr(color(Even), [td("VALIGN=center",pre(Key)), td(pre(Value))]). proc_state(Tab,{Key0,Value0}, Even) -> Key = lists:flatten(io_lib:format("~ts",[Key0])), Value = all_or_expand(Tab,Value0), tr(color(Even), [td("VALIGN=center",Key), td(pre(Value))]). all_or_expand(Tab,Term) -> Preview = io_lib:format("~tP",[Term,8]), Check = io_lib:format("~tP",[Term,100]), Exp = Preview=/=Check, all_or_expand(Tab,Term,Preview,Exp). all_or_expand(_Tab,Term,Str,false) when not is_binary(Term) -> href_proc_port(lists:flatten(Str)); all_or_expand(Tab,Term,Preview,true) when not is_binary(Term) -> Key = {Key1,Key2,Key3} = {erlang:unique_integer([positive]),1,2}, 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)], "Click to expand above term")]; all_or_expand(Tab,Bin,_PreviewStr,_Expand) when is_binary(Bin) -> OBSBin = observer_lib:make_obsbin(Bin,Tab), Term = io_lib:format("~tp", [OBSBin]), href_proc_port(lists:flatten(Term), true). 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)). %%%----------------------------------------------------------------- %%% Internal library start_html() -> "\n". stop_html() -> "". start_html_body() -> "
\n". stop_html_body() -> "\n". header(Body) -> header("","",Body). header(Title,Body) -> header(Title,"",Body). header(Title,JavaScript,Body) -> [%only_http_header(), html_header(Title,JavaScript,Body)]. html_header(Title,JavaScript,Body) -> [start_html(), only_html_header(Title,JavaScript), Body, stop_html()]. only_html_header(Title,JavaScript) -> ["\n", "". stop_pre() -> "". pre(Text) -> [start_pre(),Text,stop_pre()]. href(Link,Text) -> ["",Text,""]. href(Args,Link,Text) -> ["",Text,""]. font(Args,Text) -> ["\n",Text,"\n\n"]. p(Text) -> ["
",Text,"
\n"]. br() -> "