Current section
Files
Jump to
Current section
Files
src/observer_cli_inet.erl
%%% @author zhongwen <zhongwencool@gmail.com>
-module(observer_cli_inet).
-include("observer_cli.hrl").
%% API
-export([start/2]).
%%for rpc call
-export([get_inet_info/6]).
-define(INET_COLUMN_WIDTH, 85).
-spec start(atom(), view_opts()) -> no_return.
start(Node, #view_opts{inet = #inet{interval = Interval,
rows = Rows,
func = Function,
type = Type}} = ViewOpts) ->
ParentPid = self(),
Pid = spawn(fun() -> observer_cli_lib:clear_screen(),
loop(Node, Function, Type, Interval, Rows, erlang:make_ref(), ParentPid, 0)
end),
waiting(Node, Pid, ViewOpts).
%%for fetching data from remote data by rpc:call/4
-spec get_inet_info(Node, Function, Type, Rows, Ms, Count) -> [tuple()] when
Node:: atom(),
Function:: atom(),
Type:: atom(),
Rows:: integer(),
Count:: integer(),
Ms:: integer().
get_inet_info(local_node, Function, Type, Rows, Ms, Count) ->
inet_info(Function, Type, Rows, Ms, Count);
get_inet_info(_Node, _Function, _Type, _Rows, _Ms, _Count) ->
io:format("\e[48;2;184;0;0mDon't Support remote node. erlang:port_info/2 badarg if Port is not a local port identifier.\e[0m~n"),
io:format("You can see Net by observer_cli:start/0 on local node.~n"),
[].
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%% Private
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
waiting(Node, ChildPid, ViewOpts = #view_opts{inet = InetOpts}) ->
Input = observer_cli_lib:get_line(""),
case Input of
"q\n" ->
erlang:send(ChildPid, quit),
"";
"o\n" ->
erlang:exit(ChildPid, stop),
observer_cli:start_node(Node, ViewOpts);
"e\n" ->
erlang:exit(ChildPid, stop),
observer_cli_system:start(Node, ViewOpts);
"h\n" ->
erlang:exit(ChildPid, stop),
observer_cli_help:start(Node, ViewOpts);
"db\n" ->
erlang:exit(ChildPid, stop),
observer_cli_mnesia:start(Node, ViewOpts);
"a\n" ->
erlang:exit(ChildPid, stop),
observer_cli_allocator:start(Node, ViewOpts);
"ic\n" ->
erlang:exit(ChildPid, stop),
observer_cli_inet:start(Node, ViewOpts#view_opts{inet = InetOpts#inet{func = inet_count}});
"iw\n" ->
erlang:exit(ChildPid, stop),
observer_cli_inet:start(Node, ViewOpts#view_opts{inet = InetOpts#inet{func = inet_window}});
"rc\n" ->
erlang:exit(ChildPid, stop),
observer_cli_inet:start(Node, ViewOpts#view_opts{inet = InetOpts#inet{type = recv_cnt}});
"ro\n" ->
erlang:exit(ChildPid, stop),
observer_cli_inet:start(Node, ViewOpts#view_opts{inet = InetOpts#inet{type = recv_oct}});
"sc\n" ->
erlang:exit(ChildPid, stop),
observer_cli_inet:start(Node, ViewOpts#view_opts{inet = InetOpts#inet{type = send_cnt}});
"so\n" ->
erlang:exit(ChildPid, stop),
observer_cli_inet:start(Node, ViewOpts#view_opts{inet = InetOpts#inet{type = send_oct}});
"cnt\n" ->
erlang:exit(ChildPid, stop),
observer_cli_inet:start(Node, ViewOpts#view_opts{inet = InetOpts#inet{type = cnt}});
"oct\n" ->
erlang:exit(ChildPid, stop),
observer_cli_inet:start(Node, ViewOpts#view_opts{inet = InetOpts#inet{type = oct}});
[$i| Interval] ->
case string:to_integer(Interval) of
{error, no_integer} -> waiting(Node, ChildPid, ViewOpts);
{NewInterval, _} when NewInterval >= ?INET_MIN_INTERVAL ->
erlang:send(ChildPid, {new_interval, NewInterval}),
waiting(Node, ChildPid, ViewOpts#view_opts{inet = InetOpts#inet{interval = NewInterval}});
{_Interval, _} -> waiting(Node, ChildPid, ViewOpts)
end;
[$r, $o, $w| Rows] ->
case string:to_integer(Rows) of
{error, no_integer} -> waiting(Node, ChildPid, ViewOpts);
{NewRows, _} ->
erlang:send(ChildPid, {new_rows, NewRows}),
waiting(Node, ChildPid, ViewOpts#view_opts{inet = InetOpts#inet{rows = NewRows}})
end;
_ -> waiting(Node, ChildPid, ViewOpts)
end.
loop(Node, Function, Type, Interval, Rows, LastTimeRef, ParentPid, Count) ->
observer_cli_lib:move_cursor_to_top_line(),
draw_menu(Node, Function, Type, Interval, Rows),
Inets = get_inet_info(Node, Function, Type, Rows, Interval, Count),
draw_inet_rows(Inets, Type, Function, Interval, Rows),
draw_last_line(Interval),
erlang:cancel_timer(LastTimeRef),
NextInterval = case Function of inet_count -> Interval; inet_window -> 10 end,
TimeRef = erlang:send_after(NextInterval, self(), refresh),
receive
quit ->
quit;
{new_interval, NewInterval} ->
observer_cli_lib:clear_screen(),
loop(Node, Function, Type, NewInterval, Rows, TimeRef, ParentPid, Count + 1);
{new_rows, NewRows} ->
observer_cli_lib:clear_screen(),
loop(Node, Function, Type, Interval, NewRows, TimeRef, ParentPid, Count + 1);
_ ->
loop(Node, Function, Type, Interval, Rows, TimeRef, ParentPid, Count + 1)
end.
draw_menu(Node, Func, Type, Interval, Rows) ->
Title = observer_cli_lib:get_menu_title(inet),
RefreshStr = get_refresh_str(Func, Type, Interval, Rows),
UpTime = observer_cli_lib:green(" " ++ observer_cli_lib:uptime(Node)) ++ "|",
NewTitle = lists:flatten([Title, RefreshStr]),
SpaceLen = ?COLUMN_WIDTH - erlang:length(NewTitle) - erlang:length(UpTime) + 130,
Space = case SpaceLen > 0 of true -> lists:duplicate(SpaceLen, " "); false -> [] end,
io:format("~s~n", [NewTitle ++ Space ++ UpTime]).
draw_inet_rows([], Type, inet_count, _Interval, Rows) ->
io:format("Get nothing for recon:inet_count(~p, ~p)~n", [Type, Rows]);
draw_inet_rows([], Type, inet_window, Interval, Rows) ->
io:format("Get nothing for recon:inet_window(~p, ~p, ~p)~n", [Type, Rows, Interval]);
draw_inet_rows(Inets, Type, Function, _, _) ->
NewType = case Type of
cnt -> "cnt(recv_cnt+send_cnt)";
oct -> "oct(recv_oct+send_oct)";
_ -> atom_to_list(Type)
end,
io:format("\e[0m\e[44m|~-12.12s|~12.12s| ~-28.28s|~15.15s| ~-15.15s|~20.20s| ~-20.20s\e[49m|~n",
["Port", "Name", NewType, "QueueSize", "Memory", "Input", "Output"]),
[begin
{meta, Meta} = recon:port_info(Port, meta),
{memory_used, MemoryUsed} = recon:port_info(Port, memory_used),
{io, IO} = recon:port_info(Port, io),
Name = observer_cli_lib:to_list(proplists:get_value(name, Meta)),
Input = observer_cli_lib:to_list(proplists:get_value(input, IO)),
Output = observer_cli_lib:to_list(proplists:get_value(output, IO)),
QueueSize = observer_cli_lib:to_list(proplists:get_value(queue_size, MemoryUsed)),
Memory = observer_cli_lib:to_list(proplists:get_value(memory, MemoryUsed)),
NewValue = case {Function, Info} of
{inet_window, [{Type, Value1}]} -> io_lib:format("Diff:~w Now:~w)", [Value, Value1]);
{inet_count, [{Type, Value}]} -> observer_cli_lib:to_list(Value);
{_, [{_, Value1}, {_, Value2}]}-> io_lib:format("~w(~w+~w)", [Value, Value1, Value2])
end,
io:format("|~-12.12s|~12.12s| ~-28.28s|~15.15s| ~-15.15s|~20.20s| ~-20.20s|~n",
[observer_cli_lib:to_list(Port), Name, NewValue, QueueSize, Memory, Input, Output])
end|| {Port, Value, Info} <- Inets].
draw_last_line(Interval) ->
Format = "i~w(Interval ~wms must>=1000) ic(inet_count) iw(inet_window) rc(recv_cnt) ro(recv_oct) sc(send_cnt) so(send_oct) cnt oct",
Text = io_lib:format(Format, [Interval, Interval]),
io:format("|\e[31;1mINPUT: \e[0m\e[44m~-124.124s\e[49m|~n", [Text]).
get_refresh_str(inet_count, Type, Interval, Rows) ->
io_lib:format("recon:inet_count(~p,~w) Interval:~wms", [Type, Rows, Interval]);
get_refresh_str(inet_window, Type, Interval, Rows) ->
io_lib:format("recon:inet_window(~p,~w,~w) Interval:~wms", [Type, Rows, Interval, Interval]).
inet_info(inet_count, Type, Num, _, _) ->
recon:inet_count(Type, Num);
inet_info(inet_window, Type, Num, _, 0) ->
recon:inet_count(Type, Num);
inet_info(inet_window, Type, Num, Ms, _) ->
recon:inet_window(Type, Num, Ms).