observer_cli

Build Status GitHub tag MIT License Hex.pm Version Hex.pm Downloads

Visualize Erlang/Elixir Nodes On The Command Line base on recon. Document in detail.

Goal


Installation

Erlang

%% rebar.config
{deps, [observer_cli]}
%% erlang.mk
dep_observer_cli = hex 1.5.4

Elixir

# mix.exs
def deps do
[{:observer_cli, "~> 1.5"}]
end

How-To

Try in local shell.

%% rebar3 project
rebar3 shell
1> observer_cli:start().
%% mix project
iex -S mix
iex(1)> :observer_cli.start

Monitor remote node

%% rebar3 project
rebar3 shell --name 'observer_cli@127.0.0.1'
1> observer_cli:start('target@host', 'magic_cookie').
%% mix project
iex --name "observer_cli@127.0.0.1" -S mix
iex(1)> :observer_cli.start(:'target@host', :'magic_cookie')

ensure observer_cli application been loaded on target node.

Try in Elixir 1.9.x release

%% create elixir release
mix release
%% rpc current node
_build/dev/rel/example/bin/example rpc ":observer_cli.start"

ensure observer_cli application been loaded on current node.

Escriptize

  1. cd path/to/observer_cli/
  2. rebar3 escriptize to generate an escript executable containing the project's and its dependencies' BEAM files. Place script(_build/default/bin/observer_cli) anywhere in your path and use observer_cli command.
  3. observer_cli TARGETNODE [TARGETCOOKIE REFRESHMS] to monitor remote node.

DEMO

Home Network System Ets Mnesia Application Document Process Port

How to write your own plugin?

If you need to customize some of your internal metrics and integrate it into observer_ci, you only need to write a observer_cli_plugin behaviour in a few simple steps to get a nice presentation.

  1. Configure observer_cli,tell observer_cli how to find your plugin.
%% module - Specific module implements plugin behavior. It's mandatory.
%% title - Menu title. It's mandatory.
%% shortcut - Switch plugin by shortcut. It's mandatory.
%% interval - Refresh interval ms. It's optional. default is 1500ms.
%% sort_column - Sort the sheet by this index. It's optional default is 2.
{plugins,
[
#{module => observer_cli_plug_behaviour1, title => "XPlug",
interval => 1500, shortcut => "X", sort_column => 3},
#{module => observer_cli_plug_behaviour2, title => "YPlug",
interval => 1600, shortcut => "Y", sort_column => 3}
]
}

  1. Write observer_cli_plugin behaviour. observer_cli_plugin has 3 callbacks.

2.1 attributes.

-callback atributes(PrevState) -> {[Rows], NewState} when
Rows :: #{content => string()|integer()|{byte, pos_integer()},
width => pos_integer(), color => binary()}.

for example:

attributes(PrevState) ->
Attrs =
[
[
#{content => "XXX Ets Size", width => 20},
#{content => ets:info(xxx,size), width => 10},
#{content => "Pool1 Size", width => 15},
#{content => application:get_env(app,pool1_size), width => 30},
#{content => "XYZ1 Process Mem", width => 18,
#{content => {byte, element(2, erlang:process_info(xyz1, memory))}, width => 16}
],
[
#{content => "YYY Ets Size", width =>20},
#{content => ets:info(yyy,size), width => 10},
#{content => "Pool2 Size", width =>15},
#{content => application:get_env(app,pool2_size), width => 30},
#{content =>"XYZ2 Process Mem", width =>18},
#{content => {byte, element(2, erlang:process_info(xyz2, memory))}, width => 16}
],
[
#{content => "ZZZ Ets Size", width =>20},
#{content => ets:info(zzz,size), width => 10},
#{content => "Pool3 Size", width =>15},
#{content => application:get_env(app,pool3_size), width => 30},
#{content => "XYZ3 Process Mem", width =>18},
#{content => {byte, element(2, erlang:process_info(xyz3, memory))}, width => 16}
]
],
NewState = PrevState,
{Attrs, NewState}.

-callback sheet_header() -> [SheetHeader] when
SheetHeader :: #{title => string(), width => pos_integer(), shortcut => string()}.

for example:

sheet_header() ->
[
#{title => "Pid", width => 25},
#{title => "Status", width => 25},
#{title => "Memory", width => 24, shortcut => "S"},
#{title => "Reductions", width => 24, shortcut => "R"},
#{title => "Message Queue Len", width => 25, shortcut => "Q"}
].
-callback sheet_body(PrevState) -> {[SheetBody], NewState} when
PrevState :: any(),
SheetBody :: list(),
NewState :: any().

for example:

sheet_body(PrevState) ->
Body =
[begin
[
Pid,
element(2, erlang:process_info(Pid, status)),
element(2, erlang:process_info(Pid, memory)),
element(2, erlang:process_info(Pid, reductions)),
element(2, erlang:process_info(Pid, message_queue_len))
]
end||Pid <- erlang:processes()
],
NewState = PrevState,
{Body, NewState}.

Support F/B to page up/down.

A more specific plugin can collect linux system information such as kernel vsn, loadavg, disk, memory usage, cpu utilization, IO statistics.


Changelog


Contributors


zhongwencool

💻

Dimitrios Zorbas

💻

taotao

💻

Trevor Brown

💻

Zaiming Shi

💻

License

See the LICENSE file for license rights and limitations (MIT).