Current section

Files

Jump to
observer_cli src observer_cli_port.erl
Raw

src/observer_cli_port.erl

-module(observer_cli_port).
-include("observer_cli.hrl").
-export([start/2]).
-spec start(pid(), view_opts()) -> no_return.
start(Port, Opts) ->
#view_opts{port = RefreshMs} = Opts,
RenderPid = spawn_link(fun() ->
?output(?CLEAR),
render_worker(Port, RefreshMs, ?INIT_TIME_REF)
end),
manager(RenderPid, Opts).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%% Private
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
manager(RenderPid, Opts) ->
case parse_cmd(Opts, RenderPid) of
quit ->
erlang:send(RenderPid, quit);
{new_interval, NewInterval} ->
erlang:send(RenderPid, {new_interval, NewInterval}),
manager(RenderPid, Opts#view_opts{port = NewInterval});
ViewAction ->
erlang:send(RenderPid, ViewAction),
manager(RenderPid, Opts)
end.
render_worker(Port, Interval, TimeRef) ->
PortInfo = recon:port_info(Port),
Meta = proplists:get_value(meta, PortInfo),
case lists:member(undefined, Meta) of
true ->
output_die_view(Port, Interval),
next_draw_view(TimeRef, Interval, Port);
false ->
Id = proplists:get_value(id, Meta),
Name = proplists:get_value(name, Meta),
OsPid = proplists:get_value(os_pid, Meta),
Signals = proplists:get_value(signals, PortInfo),
Link = proplists:get_value(links, Signals),
Monitors = proplists:get_value(monitors, Signals),
Connected = proplists:get_value(connected, Signals),
IO = proplists:get_value(io, PortInfo),
Input = proplists:get_value(input, IO),
Output = proplists:get_value(output, IO),
MemoryUsed = proplists:get_value(memory_used, PortInfo),
Memory = proplists:get_value(memory, MemoryUsed),
QueueSize = proplists:get_value(queue_size, MemoryUsed),
Menu = render_menu(info, Interval),
Line1 = render_port_info(
Port,
Id,
Name,
OsPid,
Input,
Output,
Memory,
QueueSize,
Connected
),
Line2 = render_link_monitor(Link, Monitors),
Line3 = render_type_line(proplists:get_value(type, PortInfo)),
LastLine = render_last_line(),
?output([?CURSOR_TOP, Menu, Line1, Line2, Line3, LastLine]),
next_draw_view(TimeRef, Interval, Port)
end.
next_draw_view(TimeRef, Interval, Port) ->
NewTimeRef = observer_cli_lib:next_redraw(TimeRef, Interval),
next_draw_view_2(NewTimeRef, Interval, Port).
next_draw_view_2(TimeRef, Interval, Port) ->
receive
quit ->
quit;
{new_interval, NewInterval} ->
?output(?CLEAR),
render_worker(Port, NewInterval, TimeRef);
_ ->
?output(?CLEAR),
render_worker(Port, Interval, TimeRef)
end.
render_port_info(
Port,
Id,
Name,
OsPid,
Input,
Output,
Memory,
QueueSize,
Connected
) ->
QueueSizeColor =
case QueueSize > 0 of
true -> ?RED;
false -> ?GREEN
end,
Title =
?render([
?GRAY_BG,
?W("Attr", 18),
?W("Value", 20),
?W("Attr", 18),
?W("Value", 20),
?W("Attr", 19),
?W("Value", 21)
]),
Rows =
?render([
?W("port", 18),
?W(Port, 20),
?W("id", 18),
?W(Id, 20),
?W("name", 19),
?W(Name, 21),
?NEW_LINE,
?W("queue_size", 18),
?W2(QueueSizeColor, QueueSize, 21),
?W(" input", 19),
?W({byte, Input}, 20),
?W("output", 19),
?W({byte, Output}, 21),
?NEW_LINE,
?W("connected", 18),
?W(Connected, 20),
?W("memory", 18),
?W({byte, Memory}, 20),
?W("os_pid", 19),
?W(OsPid, 21)
]),
[Title, Rows].
render_link_monitor(Link, Monitors) ->
LinkStr = [
begin
observer_cli_lib:to_list(P)
end
|| P <- lists:sublist(Link, 30)
],
MonitorsStr = [
begin
case P of
{process, Pid} ->
observer_cli_lib:to_list(Pid);
{RegName, Node} ->
observer_cli_lib:to_list(RegName) ++ "/" ++ observer_cli_lib:to_list(Node)
end
end
|| P <- lists:sublist(Monitors, 30)
],
LinkInfo = "Links(" ++ erlang:integer_to_list(erlang:length(Link)) ++ ")",
MonitorInfo = "Monitors(" ++ erlang:integer_to_list(erlang:length(Monitors)) ++ ")",
?render([
?W(LinkInfo, 18),
?W(LinkStr, 110),
?NEW_LINE,
?W2(?UNDERLINE, MonitorInfo, 19),
?W2(?UNDERLINE, MonitorsStr, 111)
]).
render_type_line(List) ->
PeerName =
case lists:keyfind(peername, 1, List) of
{_, Peer} -> addr_to_str(Peer);
false -> "undefined"
end,
SockName =
case lists:keyfind(sockname, 1, List) of
{_, Sock} -> addr_to_str(Sock);
false -> "undefined"
end,
Line1 =
?render([
?UNDERLINE,
?W(" " ++ SockName ++ "(sockname)", 55),
?W("<=============>", 15),
?W(" " ++ PeerName ++ "(peername)", 55)
]),
Line2 =
case lists:keyfind(statistics, 1, List) of
{_, Stats} -> [Line1, render_stats(Stats)];
false -> Line1
end,
case lists:keyfind(options, 1, List) of
{_, Opts} -> Line2 ++ [render_opts(Opts)];
false -> Line2
end.
render_stats(Stats) ->
RecvOct = proplists:get_value(recv_oct, Stats),
RecvCnt = proplists:get_value(recv_cnt, Stats),
RecvMax = proplists:get_value(recv_max, Stats),
RecvAvg = proplists:get_value(recv_avg, Stats),
RecvDvi = proplists:get_value(recv_dvi, Stats),
SendOct = proplists:get_value(send_oct, Stats),
SendCnt = proplists:get_value(send_cnt, Stats),
SendMax = proplists:get_value(send_max, Stats),
SendAvg = proplists:get_value(send_avg, Stats),
SendPend = proplists:get_value(send_pend, Stats),
?render([
?W("recv_cnt", 9),
?W(RecvCnt, 12),
?W("recv_oct", 8),
?W({byte, RecvOct}, 12),
?W("recv_max", 9),
?W({byte, RecvMax}, 12),
?W("recv_avg", 9),
?W({byte, RecvAvg}, 12),
?W("recv_dvi", 9),
?W({byte, RecvDvi}, 12),
?NEW_LINE,
?W("send_cnt", 9),
?W(SendCnt, 12),
?W("send_oct", 8),
?W({byte, SendOct}, 12),
?W("send_max", 9),
?W({byte, SendMax}, 12),
?W("send_avg", 9),
?W({byte, SendAvg}, 12),
?W("send_pend", 9),
?W(SendPend, 12)
]).
render_opts(Opts) ->
Active = proplists:get_value(active, Opts),
Broadcast = proplists:get_value(broadcast, Opts),
Buffer = proplists:get_value(buffer, Opts),
DelaySend = proplists:get_value(delay_send, Opts),
DontRoute = proplists:get_value(dontroute, Opts),
ExitOnClose = proplists:get_value(exit_on_close, Opts),
Header = proplists:get_value(header, Opts),
HighWatermark = proplists:get_value(high_watermark, Opts),
KeepAlive = proplists:get_value(keepalive, Opts),
Linger = io_lib:format("~p", [proplists:get_value(linger, Opts)]),
LowWatermark = proplists:get_value(low_watermark, Opts),
Mode = proplists:get_value(mode, Opts),
NoDelay = proplists:get_value(nodelay, Opts),
Packet = proplists:get_value(packet, Opts),
PacketSize = proplists:get_value(packet_size, Opts),
Priority = proplists:get_value(priority, Opts),
RecBuf = proplists:get_value(recbuf, Opts),
ReuseAddr = proplists:get_value(reuseaddr, Opts),
SendTimeout = proplists:get_value(send_timeout, Opts),
SndBuf = proplists:get_value(sndbuf, Opts),
Title =
?render([
?GRAY_BG,
?W("Option", 9),
?W("Value", 6),
?W("Option", 14),
?W("Value", 12),
?W("Option", 9),
?W("Value", 12),
?W("Option", 13),
?W("Value", 8),
?W("Option", 9),
?W("Value", 12)
]),
Rows =
?render([
?W("mode", 9),
?W(Mode, 6),
?W("recbuf", 14),
?W({byte, RecBuf}, 12),
?W("sndbuf", 9),
?W({byte, SndBuf}, 12),
?W("delay_send", 13),
?W(DelaySend, 8),
?W("dontroute", 9),
?W(DontRoute, 12),
?NEW_LINE,
?W("reuseaddr", 9),
?W(ReuseAddr, 6),
?W("packet_size", 14),
?W({byte, PacketSize}, 12),
?W("buffer", 9),
?W({byte, Buffer}, 12),
?W("exit_on_close", 13),
?W(ExitOnClose, 8),
?W("priority", 9),
?W(Priority, 12),
?NEW_LINE,
?W("active", 9),
?W(Active, 6),
?W("low_watermark", 14),
?W({byte, LowWatermark}, 12),
?W("header", 9),
?W(Header, 12),
?W("keepalive", 13),
?W(KeepAlive, 8),
?W("linger", 9),
?W(Linger, 12),
?NEW_LINE,
?W("nodelay", 9),
?W(NoDelay, 6),
?W("high_watermark", 14),
?W({byte, HighWatermark}, 12),
?W("broadcast", 9),
?W(Broadcast, 12),
?W("send_timeout", 13),
?W(SendTimeout, 8),
?W("packet", 9),
?W(Packet, 12)
]),
[Title, Rows].
render_last_line() ->
io_lib:format("|\e[7mq(quit) ~124.124s\e[0m|~n", [" "]).
render_menu(Type, Interval) ->
Text = "Interval: " ++ integer_to_list(Interval) ++ "ms",
Title = get_menu_title(Type),
UpTime = observer_cli_lib:uptime(),
TitleWidth = ?COLUMN + 41 - erlang:length(UpTime),
?render([?W([Title | Text], TitleWidth) | UpTime]).
get_menu_title(Type) ->
[Home, Net, Port] = get_menu_title2(Type),
[Home, "|", Net, "|", Port].
get_menu_title2(info) ->
[?UNSELECT("Home(H)"), ?UNSELECT("Network(N)"), ?SELECT("Port Info(P)")].
parse_cmd(ViewOpts, Pid) ->
case observer_cli_lib:to_list(io:get_line("")) of
"q\n" ->
quit;
"Q\n" ->
quit;
"P\n" ->
info_view;
"H\n" ->
erlang:exit(Pid, stop),
observer_cli:start(ViewOpts);
"N\n" ->
erlang:exit(Pid, stop),
observer_cli_inet:start(ViewOpts);
Number ->
observer_cli_lib:parse_integer(Number)
end.
output_die_view(Port, Interval) ->
Menu = render_menu(info, Interval),
Line = io_lib:format("\e[31mPort(~p) has already die.\e[0m~n", [Port]),
LastLine = render_last_line(),
?output([?CURSOR_TOP, Menu, Line, LastLine]).
addr_to_str({Addr, Port}) ->
AddrList = [
begin
erlang:integer_to_list(A)
end
|| A <- erlang:tuple_to_list(Addr)
],
string:join(AddrList, ".") ++ ":" ++ erlang:integer_to_list(Port).