%% %% %CopyrightBegin% %% %% Copyright Ericsson AB 2001-2011. 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% %% %%%--------------------------------------------------------------------- %%% File : webappmon.erl %%% Author : Martin G. %%% Purpose : Frontend to the webbased version of appmon. %%% Created : 24 Apr 2001 by Martin G. %%%--------------------------------------------------------------------- -module(appmon_web). %% The functions that the user can call to interact with the genserver -export([init/1,handle_call/3,handle_cast/2,handle_info/2]). -export([terminate/2,code_change/3]). -export([node_info/2,application_info/2,application_env/2]). -export([proc_info/2,trace/2]). -export([start/0,stop/0,start_link/0]). %% Export the function that returns the configuration data needed by %% webtool -export([configData/0]). -behaviour(gen_server). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Start the genserver % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% start_link()-> gen_server:start_link({local,webappmon_server},appmon_web,[],[]). start()-> gen_server:start({local,webappmon_server},appmon_web,[],[]). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Stop the genserver % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% stop()-> gen_server:call(webappmon_server,stop,1000). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Get the page that shows the nodes and the apps on the sel node % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% node_info(Env,Input)-> gen_server:call(webappmon_server,{node_data,Env,Input}). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Get the application process tree % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% application_info(Env,Input)-> gen_server:call(webappmon_server,{app_data,Env,Input}). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Get the page that shows the data about the process % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% proc_info(Env,Input)-> gen_server:call(webappmon_server,{proc_data,Env,Input}). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Get the spec on the app % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% application_env(Env,Input)-> gen_server:call(webappmon_server,{app_env,Env,Input}). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Toggle the trace flag for the selected process % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% trace(Env,Input)-> gen_server:call(webappmon_server,{trace,Env,Input}). configData()-> {appmon,[{web_data,{"WebAppmon","/appmon/main_frame.html"}}, {alias,{"/appmon",code:priv_dir(appmon)}}, {alias,{erl_alias,"/erl",[appmon_web]}}, {start,{child,{backend,{process_info,start_link,[]}, permanent,100,worker,[process_info]}}}, {start,{child,{{local,webappmon_server}, {appmon_web,start_link,[]}, permanent,100,worker,[appmon_web]}}} ]}. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % Callback functions for the genserver % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% init(_Arg)-> {ok,[]}. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Create the different pages % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% handle_call({node_data,_Env,Input},_From,State)-> {reply,app_and_node_sel_page(Input),State}; handle_call({app_data,_Env,Input},_From,State)-> {reply,process_tree_page(Input),State}; handle_call({proc_data,_Env,Input},_From,State)-> {reply,process_specifickation_page(Input),State}; handle_call({app_env,_Env,Input},_From,State)-> {reply,application_specifickation_page(Input),State}; handle_call({trace,_Env,Input},_From,State)-> {reply,toggle_trace(Input),State}. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Shutdown the genserver % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% terminate(_,_State)-> ok. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Callback function currently not used ... % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% handle_cast(_,State)-> {noreply,State}. handle_info(_,State)-> {noreply,State}. code_change(_OldVsn,State,_Extra)-> {ok,State}. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% %% %% Private functions to create the part of the sides that is common %% %% to all sides %% %% %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Create the Header for the page If we now the mimetype use that type%% %% otherwise use text %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% header() -> header("text/html"). header(MimeType) -> "Content-type: " ++ MimeType ++ "\r\n\r\n". %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Create the Htmlheader sett the title of the side to nothing if %% %% we dont know the name of the side %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% html_header()-> html_header(""). html_header(Part) -> "\n" ++ "\n" ++ "Appmon " ++ Part ++ "\n" ++ "\n". %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Close the Html tag and if neccessay add some clean upp %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% html_end()-> "". %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% %% %% The functions that creates the whole pages by collecting %% %% the necessary data %% %% %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Returns the page where the user see's which nodes and apps that %% %% are availible for monitoring %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% app_and_node_sel_page(Input)-> [header(), html_header(), node_body(httpd:parse_query(Input)), html_end()]. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Returns the process tree for the application whose name is %% %% the first value in the Inputs key/value list %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% process_tree_page(Input)-> [header(), html_header(), application_javascript(httpd:parse_query(Input)), application_body(httpd:parse_query(Input)), html_end()]. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Send trace on or off to the process thats pid is the third arg of %% %% the inputs key/val list. Then it returns the process tree for the %% %% the application that is the first key/val pair of input %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% toggle_trace(Input)-> send_trace(httpd:parse_query(Input)), [header(), html_header(), application_javascript(httpd:parse_query(Input)), application_body(httpd:parse_query(Input)), html_end()]. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Creates the page that shows all information about the process that %% %% that is the first arg of th input key/val pairs %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% process_specifickation_page(Input)-> [header(), html_header(), process_body(httpd:parse_query(Input)), html_end()]. application_specifickation_page(Input)-> [header(), html_header(), application_env_body(httpd:parse_query(Input)), html_end()]. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% The Private functions that do the job %% %% To build the the page that shows the applications %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Build the body of the side that shows the node name and %% %% the application list %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% node_body([{"node",Node}|_Rest])-> case process_info:is_node(Node) of {true,Controlled_node,Name} -> "" ++ node_selections_javascripts() ++ node_selection(Controlled_node) ++ node_title() ++ application_tree(Controlled_node,Name) ++ ""; {false,Server_node,Name} -> "" ++ node_selections_javascripts() ++ node_selection(Server_node) ++ node_title() ++ application_tree(Server_node,Name) ++ "" end; node_body(_Whatever)-> node_body([{atom_to_list(node),atom_to_list(node())}]). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Returns the javascript that sets a new node to monitor %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% node_selections_javascripts()-> "". %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Insert the html code that shows the combobox where the user can %% %% select another node to monitor %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% node_selection(Node)-> "
\n \n \n
\n \n
\n
". %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Add the node we are working with in the beginning of the list and %% %% remove it from other places so its always the first in the listbox %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% order_nodes(Node,Node_list)-> [Node|lists:delete(Node,Node_list)]. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Take the list of nodes and make it to a list of options to the %% %% the combobox %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% print_nodes([])-> []; print_nodes([Node|Rest])-> "