appmon.erl

来自「OTP是开放电信平台的简称」· ERL 代码 · 共 1,080 行 · 第 1/3 页

ERL
1,080
字号
%% ``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 via the world wide web 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.%% %% The Initial Developer of the Original Code is Ericsson Utvecklings AB.%% Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings%% AB. All Rights Reserved.''%% %%     $Id$%%-module(appmon).-behaviour(gen_server).%%%---------------------------------------------------------------------%%% Appmon main module.%%% Creates the main window and receives load and application%%% information from all connected nodes.%%%---------------------------------------------------------------------%% External exports-export([start/0, stop/0]).%% gen_server callbacks-export([init/1, handle_cast/2, handle_info/2, terminate/2]).-export([handle_call/3, code_change/3]).        % not used%% Canvas button data-record(canvasbutton, {text, ul, ll, rect, x, y, w, h}).%% Options - all the fields are GS radio buttons-record(options, {single, many, time, queue, prog, linear}).%% Main window data-record(win, {name,                             % atom() Monitored node	      window,                           % gsobj()	      wwindow,                          % int() Window width	      hwindow,                          % int() Window height	      options,                          % #options{}	      canvas,                           % gsobj()	      wcanvas,                          % int() Canvas width	      hcanvas,                          % int() Canvas height	      l1, l2,                           % gsobj() Canvas lines	      leds,                             % [gsobj()] Load meter	      nodelabel,                        % {gsobj(),gsobj()}	      appobjs=[],                       % [gsobj()] Buttons etc.	      nodemenu}).                       % gsobj() Node menu%% Node data-record(mnode, {name,                           % atom() Node name		status,                         % alive | dead		pid,                            % pid()		apps,                           % [{Pid,App,Descr}]		load}).                         % {Old, New}%% Internal state data-record(state, {gs,                             % pid()		wins=[],                        % [#win()] GUIs		window_mode,                    % single | many		load_mode1,                     % time | queue		load_mode2,                     % prog | linear		lbpid,                          % pid()		mnodes=[]}).                    % [#mnode{}] %%%---------------------------------------------------------------------%%% External exports%%%---------------------------------------------------------------------start() ->     gen_server:start({local, appmon}, ?MODULE, [], []).stop() ->    gen_server:cast(appmon, stop).%%%---------------------------------------------------------------------%%% gen_server callbacks%%%---------------------------------------------------------------------%%----------------------------------------------------------------------%% Func: init/1%% Returns: {ok, State}          |%%          {ok, State, Timeout} |%%          ignore               |%%          {stop, Reason}%%----------------------------------------------------------------------init([]) ->    process_flag(trap_exit, true),    %% Subscribe to {nodeup,Node} and {nodedown,Node} messages    net_kernel:monitor_nodes(true),        LbPid = appmon_lb:start(self ()),    %% Check which remote nodes have appmon code available (OTP-4887)    NodesOk = lists:filter(fun(Node) -> check_node(Node) end, nodes()),    Nodes = [node()|NodesOk],    %% Start monitoring the existing nodes    MNodes = mk_mnodes(Nodes, LbPid),    %% Draw the main window    GS = gs:start([{kernel,true}]),    GUI = draw_win(GS, node()),    %% Update the Nodes menu with all known nodes    lists:foreach(fun(Node) ->			  display_addnode(GUI, Node)		  end,		  Nodes),    %% Mark the default options as selected in the Options menu    display_setopt(GUI, single),    display_setopt(GUI, time),    display_setopt(GUI, prog),    {ok, #state{gs=GS, wins=[GUI],		window_mode=single, load_mode1=time, load_mode2=prog,		lbpid=LbPid, mnodes=MNodes}}.check_node(Node) ->    case rpc:call(Node, code, which, [appmon]) of	File when is_list(File) ->	    true;	_ -> % non_existing (| cover_compiled)	    false    end.%%----------------------------------------------------------------------%% Func: handle_call/3%% Returns: {reply, Reply, State}          |%%          {reply, Reply, State, Timeout} |%%          {noreply, State}               |%%          {noreply, State, Timeout}      |%%          {stop, Reason, Reply, State}   | (terminate/2 is called)%%          {stop, Reason, State}            (terminate/2 is called)%%----------------------------------------------------------------------handle_call(norequest, _From, State) ->    {reply, null, State}.%%----------------------------------------------------------------------%% Func: handle_cast/2%% Returns: {noreply, State}          |%%          {noreply, State, Timeout} |%%          {stop, Reason, State}            (terminate/2 is called)%%----------------------------------------------------------------------handle_cast(stop, State) ->    {stop, normal, State}.    %%----------------------------------------------------------------------%% Func: handle_info/2%% Returns: {noreply, State}          |%%          {noreply, State, Timeout} |%%          {stop, Reason, State}            (terminate/2 is called)%%----------------------------------------------------------------------%% Load information from a nodehandle_info({delivery, _Serv, load, Node, Load}, State) ->        %% Update node information    MNode = get_mnode(Node, State#state.mnodes),    MNode1 = MNode#mnode{load=Load},    MNodes = replace_mnode(Node, MNode1, State#state.mnodes),    %% If Node is currently displayed, update graphics    case get_win(Node, State#state.wins) of	{ok, GUI} ->	    display_load(GUI, Load);	false ->	    ignore    end,        {noreply, State#state{mnodes=MNodes}};%% Application information from a nodehandle_info({delivery, _Serv, app_ctrl, Node, Apps}, State) ->        %% Update node information    MNode = get_mnode(Node, State#state.mnodes),    MNode1 = MNode#mnode{apps=Apps},    MNodes = replace_mnode(Node, MNode1, State#state.mnodes),    %% If Node is currently displayed, update graphics    Wins = case get_win(Node, State#state.wins) of	       {ok, GUI} ->		   draw_clear(GUI),		   GUI1 = draw_apps(GUI, Apps),		   replace_win(Node, GUI1, State#state.wins);	       false ->		   State#state.wins	   end,        appmon_lb:add_apps (State#state.lbpid, Apps, Node),    {noreply, State#state{wins=Wins, mnodes=MNodes}};handle_info({nodeup, Node}, State) ->    %% First, make sure appmon code is available at remode node,    %% or the node should be ignored (OTP-3591)    case check_node(Node) of	true ->	    %% If this is a previously unknown node, update window's	    %% 'Nodes' menu	    case get_mnode(Node, State#state.mnodes) of		false ->		    display_addnode(State#state.wins, Node);		_OldMnode ->		    ignore	    end,	    %% Update node information (=> state is automatically	    %% changed to 'alive')	    MNode = mk_mnode(Node, State#state.lbpid),	    MNodes = replace_mnode(Node, MNode, State#state.mnodes),	    %% If Node is currently displayed, update graphics	    case get_win(Node, State#state.wins) of		{ok, GUI} ->		    display_nodeup(GUI, Node);		false ->		    ignore	    end,	    appmon_lb:update_status(State#state.lbpid, Node, alive),	    {noreply, State#state{mnodes=MNodes}};	false ->	    {noreply, State}    end;handle_info({nodedown, Node}, State) ->        %% If this is a previously unknown node, ignore the message.    %% (The situation occurs when failing to connect to another node).    %% Otherwise, update the node information.    case get_mnode(Node, State#state.mnodes) of	false ->	    {noreply, State};	MNode ->	    MNode1 = MNode#mnode{status=dead},	    MNodes = replace_mnode(Node, MNode1, State#state.mnodes),	    %% If Node is currently displayed, update graphics	    Wins = case get_win(Node, State#state.wins) of		       {ok, GUI} ->			   display_nodedown(GUI),			   GUI1 = draw_clear(GUI),			   replace_win(Node, GUI1, State#state.wins);		       false ->			   State#state.wins		   end,	    appmon_lb:remove_node(State#state.lbpid, Node),	    {noreply, State#state{wins=Wins, mnodes=MNodes}}    end;%% Application 'button' eventshandle_info({gs, _Obj, buttonpress, Data, _Arg}, State) ->    {canvasbutton, CBtn, _App} = Data,    press(CBtn),    {noreply, State};handle_info({gs, _Obj, buttonrelease, Data, [_,X,Y|_]}, State) ->    {canvasbutton, CBtn, {application, App, Node}} = Data,    release(CBtn),    %% Check that mouse button was released over the button!    L = CBtn#canvasbutton.x, R = L + CBtn#canvasbutton.w,    T = CBtn#canvasbutton.y, B = T + CBtn#canvasbutton.h,    if	X>L, X<R, Y>T, Y<B ->	    MNode = get_mnode(Node, State#state.mnodes),	    {value, {Pid, _App, _Descr}} =		lists:keysearch(App, 2, MNode#mnode.apps),	    appmon_a:start(Node, App, Pid);	true ->	    ignore    end,    {noreply, State};handle_info({gs, _Button, click, Data, _Arg}, State) ->    ThisNode = node(),    case Data of		%% File menu item	listbox ->	    appmon_lb:open_win(State#state.lbpid,			       parse_nodes(State#state.mnodes)),	    {noreply, State};	{close, WinObj} ->	    {ok, GUI} = get_win2(WinObj, State#state.wins),	    gs:destroy(WinObj),	    %% Terminate if this was the only open window	    case remove_win(GUI#win.name, State#state.wins) of		[] ->		    {stop, normal, State};		Wins ->		    {noreply, State#state{wins=Wins}}	    end;	exit ->	    {stop, normal, State};	%% Actions menu item	{action, Action, WinObj} ->	    {ok, GUI} = get_win2(WinObj, State#state.wins),	    Node = GUI#win.name,	    if		Node==ThisNode ->		    case Action of			ping ->			    %% Ignore - makes no sense to ping yourself			    ignore;			_ -> % reboot | restart | stop			    apply(init, Action, [])		    end;		Node/=ThisNode ->		    case Action of			ping ->			    net_adm:ping(Node);			_ -> % reboot | restart | stop			    rpc:cast(Node, init, Action, [])		    end	    end,	    {noreply, State};	%% Options menu item	{window_mode, Mode} ->	    	    %% Update windows so they all show the same options	    lists:foreach(fun(GUI) ->				  display_setopt(GUI, Mode)			  end,			  State#state.wins),	    {noreply, State#state{window_mode=Mode}};		{option, Tag, Option} ->	    	    %% Update windows so they all show the same options	    lists:foreach(fun(GUI) ->				  display_setopt(GUI, Tag)			  end,			  State#state.wins),	    %% Update all appmon_info processes about which kind of	    %% load data is desired	    lists:foreach(fun(MNode) ->				  appmon_info:load(MNode#mnode.pid,						   MNode#mnode.name,						   true,						   Option)			  end,			  State#state.mnodes),

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?