appmon.erl

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

ERL
1,080
字号
    LMI = gs:create(menuitem, OptMenu, [{label, {text,"Load: linear"}},					{itemtype, radio}, {group, G2},					{data,					 {option, linear,					  [{load_scale,linear}]}}]),    NodeMenuBtn = gs:create(menubutton, MenuBar,			    [{label, {text,"Nodes"}}]),    NodeMenu = gs:create(menu, NodeMenuBtn, []),    HelpMenuBtn = gs:create(menubutton, MenuBar,			    [{label, {text,"Help"}}, {side, right}]),    HelpMenu = gs:create(menu, HelpMenuBtn, []),    gs:create(menuitem, HelpMenu, [{label, {text,"Help"}},				   {data, help}]),    %% Meter    HLed = trunc((?hMETER)/(?LEDCOUNT)),    Leds = draw_leds(?LEDCOUNT, Canvas, ?yMETER, HLed, []),    leds_down(Leds, ?LEDCOUNT, 0),    gs:create(text, Canvas, [{coords,			      [{?xMETER, ?yMETER+HLed*?LEDCOUNT}]},			     {anchor, nw},			     {font, {screen,8}},			     {text, "Load"}]),    gs:create(text, Canvas, [{coords, [{?xMETER+?wMETER, ?yMETER}]},			     {anchor, nw},			     {font, {screen,8}},			     {text, "Hi"}]),    gs:create(text, Canvas, [{coords, [{?xMETER+?wMETER,					?yMETER+HLed*?LEDCOUNT}]},			     {anchor, w},			     {font, {screen,8}},			     {text, "Lo"}]),    %% Node label    WNodeLbl = 8*length(NodeStr)+10,    NLRect = gs:create(rectangle, Canvas,		       [{coords, [{?xNODELBL,?yNODELBL},				  {?xNODELBL+WNodeLbl,				   ?yNODELBL+?hNODELBL}]},			{fill, black}]),    Xc = ?xNODELBL + round(WNodeLbl/2),    Yc = ?yNODELBL + round(?hNODELBL/2),    NLText = gs:create(text, Canvas, [{text, NodeStr},				      {fg, {250,235,215}},				      {coords, [{Xc,Yc}]},				      {anchor, c}]),    NodeLbl = {NLRect, NLText},        gs:config(Win, {map, true}),    #win{name=Node,	 window=Win, wwindow=?wWIN, hwindow=?hCANVAS,	 options=#options{single=SMI, many=MMI,			  time=TMI, queue=QMI, prog=PMI, linear=LMI},	 canvas=Canvas, wcanvas=?wCANVAS, hcanvas=?hCANVAS,	 l1=L1, l2=L2, leds=Leds, nodelabel=NodeLbl, nodemenu=NodeMenu}.draw_leds(N, Canvas, Y, HLed, Leds) when N>0 ->    Led = gs:create(rectangle, Canvas,		    [{coords,		      [{?xMETER,Y}, {?xMETER+?wMETER,Y+HLed}]}]),    draw_leds(N-1, Canvas, Y+HLed, HLed, [Led | Leds]);draw_leds(0, _Canvas, _Y, _HLed, Leds) ->    Leds.%%--Draw functions------------------------------------------------------%% Functions that modify the GUI and its data (win{})%% Display the node name in the window title%% (The name in the node label is changed by display_nodeup|nodedown)%% Used when a changing the node to displaydraw_nodename(GUI, Node) ->    NodeStr = atom_to_list(Node),    gs:config(GUI#win.window,	      {title, "APPMON: Overview on " ++ NodeStr}),    GUI#win{name=Node}.%% Resize the canvas (when the window has been resized)draw_resize(GUI, W, H) ->    Hc = H - ?hMENUBAR,    gs:config(GUI#win.canvas, [{width, W}, {height, Hc}]),    Yline1 = ?yNODELBL-?PAD,    Yline2 = ?hCANVAS-?PAD,    gs:config(GUI#win.l1, [{coords, [{0,Yline1},{W,Yline1}]}]),    gs:config(GUI#win.l2, [{coords, [{0,Yline2},{W,Yline2}]}]),    GUI#win{wwindow=W, hwindow=Hc}.%% Clear the GUI from applications and connecting linesdraw_clear(GUI) ->    draw_clear2(GUI#win.appobjs),    gs:config(GUI#win.canvas, [{hscroll, false}]),    GUI#win{appobjs=[]}.draw_clear2([CBtn | AppObjs]) when is_record(CBtn, canvasbutton) ->    gs:destroy(CBtn#canvasbutton.text),    gs:destroy(CBtn#canvasbutton.ul),    gs:destroy(CBtn#canvasbutton.ll),    gs:destroy(CBtn#canvasbutton.rect),    draw_clear2(AppObjs);draw_clear2([GSObj | AppObjs]) ->    gs:destroy(GSObj),    draw_clear2(AppObjs);draw_clear2([]) ->    ignore.%% Display the applications, which are a list of tuples: {Pid,App,Descr}%% Display them in the reversed order to get them chronologically%% from left to right.draw_apps(GUI, Apps) ->    {AppObjs, WCanvas} = draw_apps(GUI, lists:reverse(Apps), ?xNODELBL,				   undefined, 0, []),    NewGUI = GUI#win{wcanvas=WCanvas, appobjs=AppObjs},    display_scrollbar(NewGUI),    NewGUI.draw_apps(GUI, [App | Apps], X, Lx0, N, GSObjs) ->    %% Some necessary data    {_Pid, AppName, _Descr} = App,    Text = atom_to_list(AppName),    Width = max(8*length(Text)+10, ?wBTN),    %% Connect the application to the node label with a line    %% Lx0 = leftmost X coordinate (above previous application button)    %% Lx = X coordinate, Ly1, Ly2 = top and bottom Y coordinates    Lx = X + trunc(Width/2),    Line = case N of	       %% First (leftmost application) - draw a vertical line	       %% between the node label and application button	       0 ->		   Ly1 = ?yNODELBL + ?hNODELBL +?PAD,		   Ly2 = Ly1 + ?PAD2,		   gs:create(line, GUI#win.canvas,			     [{coords, [{Lx, Ly1}, {Lx, Ly2}]}]);	       %% Nth application, N>1 - draw a horizontal line from	       %% line connecting to the previous application button,	       %% to above this application button, then vertically down	       %% to the application button	       _ ->		   Ly1 = ?yNODELBL + ?hNODELBL + ?PAD + ?PAD2/2,		   Ly2 = Ly1 + ?PAD2/2,		   gs:create(line, GUI#win.canvas,			     [{coords, [{Lx0, Ly1}, {Lx, Ly1},					{Lx, Ly2}]}])	   end,        %% The application is represented using a 'canvasbutton'    Data = {application, AppName, GUI#win.name},    AppBtn = canvasbutton(GUI#win.canvas, Text, X, ?yBTN, Width, ?hBTN,			  Data),    draw_apps(GUI, Apps, X+Width+?PAD, Lx, N+1, [AppBtn, Line|GSObjs]);draw_apps(_GUI, [], X, _N, _Lx0, GSObjs) ->    {GSObjs, X}.%%--Display functions---------------------------------------------------%% Functions that modify the GUI but not its data%% Add a new node to the Nodes menu%% Used when a new node has connecteddisplay_addnode([GUI|GUIs], Node) ->    display_addnode(GUI, Node),    display_addnode(GUIs, Node);display_addnode([], _Node) ->    ignore;display_addnode(GUI, Node) ->    Txt = "Show " ++ atom_to_list(Node),    gs:create(menuitem, GUI#win.nodemenu,	      [{label, {text,Txt}},	       {data, {node, Node, GUI#win.window}}]).%% Show that a node has come back updisplay_nodeup(GUI, Node) ->    {Rect, Text} = GUI#win.nodelabel,    %% Check coordinates for the rectangle and compute the new width    [{L, T}, {_R, B}] = gs:read(Rect, coords),    NodeStr = atom_to_list(Node),    W = 8*length(NodeStr)+10,        gs:config(Rect, [{coords, [{L, T}, {L+W, B}]}, {fill, black}]),    gs:config(Text, [{text, NodeStr}, {fg, {250,235,215}},		     {coords,		      [{L+round(W/2), T+round((?hNODELBL)/2)}]}]).%% Show that a node has gone downdisplay_nodedown(GUI) ->    {Rect, Text} = GUI#win.nodelabel,        [{L, T}, {_R, B}] = gs:read(Rect, coords),    gs:config(Rect, [{coords, [{L, T}, {L+114, B}]}, {fill, gray}]),    gs:config(Text, [{text, "No connection"}, {fg, black},		     {coords, [{L+57, T+round((?hNODELBL)/2)}]}]).%% Add/remove scrollbars as necessarydisplay_scrollbar(GUI) ->    WWindow = GUI#win.wwindow,    HWindow = GUI#win.hwindow,    WCanvas = GUI#win.wcanvas,    HCanvas = GUI#win.hcanvas,    if	WCanvas>WWindow ->	    gs:config(GUI#win.canvas,		      [{hscroll, bottom},		       {scrollregion,{0,0,WCanvas,HCanvas}}]);	true ->	    gs:config(GUI#win.canvas, [{hscroll, false}])    end,    if	HCanvas>HWindow ->	    gs:config(GUI#win.canvas,		      [{vscroll, left},		       {scrollregion,{0,0,WCanvas,HCanvas}}]);						true ->	    gs:config(GUI#win.canvas, [{vscroll, false}])    end.%% Select option radio buttonsdisplay_setopt(GUI, Option) ->    gs:config(radiobutton(GUI, Option), {select,true}).radiobutton(GUI, single) -> (GUI#win.options)#options.single;radiobutton(GUI, many) ->   (GUI#win.options)#options.many;radiobutton(GUI, time) ->   (GUI#win.options)#options.time;radiobutton(GUI, queue) ->  (GUI#win.options)#options.queue;radiobutton(GUI, prog) ->   (GUI#win.options)#options.prog;radiobutton(GUI, linear) -> (GUI#win.options)#options.linear.%% Display load%% Used when load information is received from the displayed node-define(highloadfg, {255,99,71}).-define(midloadfg, yellow).-define(lowloadfg, green).-define(highloadbg, {140,157,178}).-define(midloadbg, ?highloadbg).-define(lowloadbg, ?highloadbg).display_load(GUI, {Old, New}) ->    if	Old == New ->	    true;	Old > New ->	    leds_down(GUI#win.leds, Old, New);	true ->	    leds_up(GUI#win.leds, Old, New)    end.leds_down(_Leds, Old, New) when Old == New ->     done;leds_down(Leds, Old, New) when Old > New ->     reset_led(Leds, Old),    leds_down(Leds, Old-1, New).leds_up(_Leds, Old, New) when Old == New ->     done;leds_up(Leds, Old, New) when Old < New ->     set_led(Leds, Old),    leds_up(Leds, Old+1, New).led_on_col(N) when N > 13 -> ?highloadfg;led_on_col(N) when N > 9 -> ?midloadfg;led_on_col(_) -> ?lowloadfg.led_off_col(N) when N > 13 -> ?highloadbg;led_off_col(N) when N > 9 -> ?midloadbg;led_off_col(_) -> ?lowloadbg.reset_led(_Leds, 0) -> ok;reset_led(Leds, N) ->    gs:config(lists:nth(N, Leds), [{fill, led_off_col(N)}]).set_led(_Leds, 0) -> ok;set_led(Leds, N) ->    gs:config(lists:nth(N, Leds), [{fill, led_on_col(N)}]).%%----------------------------------------------------------------------%% Utilities%%----------------------------------------------------------------------bcast(MNodes, Msg) ->    lists:foreach(fun(MNode) ->			  case MNode#mnode.status of			      alive ->				  MNode#mnode.pid ! Msg;			      dead ->				  ignore			  end		  end,		  MNodes).max(X, Y) when X>Y -> X;max(_, Y) -> Y.%% parse_nodes(MNodes) -> NodeApps%%   MNodes -> [#mnode{}]%%   NodeApps -> [{Node, Status, Apps}]%%     Node -> atom()%%     Status -> alive | dead%%     Apps -> [{Pid, App}]%%       Pid -> pid()%%       App -> atom()parse_nodes(MNodes) ->    parse_nodes(MNodes, []).parse_nodes([MNode|MNodes], NodeApps) ->    Apps = parse_apps(MNode#mnode.apps, []),    parse_nodes(MNodes,		[{MNode#mnode.name,MNode#mnode.status,Apps}|NodeApps]);parse_nodes([], NodeApps) ->    NodeApps.    parse_apps([{Pid, App, _Descr}|Rest], Apps) ->    parse_apps(Rest, [{Pid, App}|Apps]);parse_apps([], Apps) ->    Apps.%%----------------------------------------------------------------------%% Canvas buttons%%----------------------------------------------------------------------canvasbutton(Canvas, Text, X, Y, W, H, Data) ->    %% Draw a rectangle (for event catching)    Rect = gs:create(rectangle, Canvas, [{coords, [{X,Y}, {X+W,Y+H}]},					 {fill, gs:read(Canvas, bg)},					 {buttonpress, true},					 {buttonrelease, true}]),        %% Make the rectangle area look like a 3D button by using lines    Ul = gs:create(line, Canvas, [{coords, [{X,Y+H},{X,Y},{X+W,Y}]},				  {fg, white}, {width, 2}]),    Ll = gs:create(line, Canvas, [{coords, [{X,Y+H},{X+W,Y+H},{X+W,Y}]},				  {fg, {87,87,87}}, {width, 2}]),    %% Write the text in the middle    Xc = X + round(W/2),    Yc = Y + round(H/2),    T = gs:create(text, Canvas, [{text, Text}, {coords, [{Xc,Yc}]},				 {anchor, c},				 {buttonpress, true},				 {buttonrelease, true}]),    %% Create the canvasbutton object    CBtn = #canvasbutton{text=T, ul=Ul, ll=Ll, rect=Rect,			 x=X, y=Y, w=W, h=H},    %% Configure the data    gs:config(T, {data, {canvasbutton, CBtn, Data}}),    gs:config(Rect, {data, {canvasbutton, CBtn, Data}}),    CBtn.press(Canvasbutton) ->    gs:config(Canvasbutton#canvasbutton.ul, {fg, {87,87,87}}),    gs:config(Canvasbutton#canvasbutton.ll, {fg, white}).release(Canvasbutton) ->    gs:config(Canvasbutton#canvasbutton.ul, {fg, white}),    gs:config(Canvasbutton#canvasbutton.ll, {fg, {87,87,87}}).

⌨️ 快捷键说明

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