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 + -
显示快捷键?