README.md

# Etop - A Unix like top library for Elixir Applications

[license-img]: http://img.shields.io/badge/license-MIT-brightgreen.svg
[license]: http://opensource.org/licenses/MIT

A Unix top like functionality for Elixir Applications.

## Features

* Configurable number of listed processes
* Configurable interval
* Start, Stop, Pause, and change configuration options
* Remote Node (Not working yet)
* Print results to
  * IO leader
  * text file
  * exs file
* exs file logging allow loading and post processing results
* ascii charting of results
* Monitors
  * Add 1 or monitors with configured data fields, thresholds, and callbacks

### Example output

```
===========================================================================================================================
nonode@nohost                                                                                                      08:22:56
Load:  cpu     2.9%                      Memory:  total           42812208     binary    197472
       procs     92                               processes       23093664     code    10223211
       runq       0                                atom             512625      ets      791672

Pid                        Name or Initial Func  Percent     Reds    Memory MssQ      State Current Function
---------------------------------------------------------------------------------------------------------------------------
<0.9.0>                         :erlang.apply/2    47.66   901851    284652    0    waiting :erl_prim_loader.loop/3
<0.49.0>                        :erlang.apply/2    12.57   237834    163492    0    waiting :code_server.loop/1
<0.43.0>        :application_controller.start/1     8.13   153862    264396    0    waiting :gen_server.loop/7
<0.1.0>               :erts_code_purger.start/0     7.44   140798     25848    0    waiting :erts_code_purger.wait_for_request/0
<0.2.0>     :erts_literal_area_collector.start/     7.11   134526      2688    0    waiting :erts_literal_area_collector.msg_loop/4
<0.57.0>                    :file_server.init/1     6.18   116917    426596    0    waiting :gen_server.loop/7
<0.64.0>                        :group.server/3     3.46    65443  10784016    0    waiting :group.more_data/6
<0.79.0>                       :disk_log.init/2     1.85    34950    197252    0    waiting :disk_log.loop/1
<0.228.0>                           Etop.init/1     1.77    33584   6781840    0    running Process.info/1
<0.3.0>     :erts_dirty_process_signal_handler.     1.26    23850      2688    0    waiting :erts_dirty_process_signal_handler.msg_loop/0
===========================================================================================================================
```

### Graphs

Plot CPU usage from a .exs log file.

```
iex(1)> Etop.start(file: "/tmp/etop.exs", interval: 2000)
iex(2)> Etop.load() |> Etop.Report.plot_cpu()

                       CPU Utilization
                       ---------------
  10% |
   9% |           *
   8% |             * *
   7% |                 *
   6% |                   *
   5% |
   4% |         *
   3% | *
   2% |   * *                 *   *       *     *
   1% |       *             *   *   * * *   * *   * * *
   0% |
      +-------------------+-------------------+----------
                      08:36:31            08:36:52
```

Plot memory usage from a .exs log file.

```
iex(1)> Etop.start(file: "/tmp/etop.exs", interval: 2000)
iex(2)> Etop.load |> Etop.Report.plot_memory(height: 15)

                         Memory Usage
                         ------------
 162MB |                                 *
 153MB |                               *
 144MB |                           * *               * *
 135MB |                   * *   *           * *   *
 126MB |                 *     *           *     *
 117MB |               *
 108MB |
  99MB |
  90MB |
  81MB |             *
  72MB |       *   *
  63MB |   * *   *
  54MB |
  45MB |
  36MB | *
   0MB |
       +-------------------+-------------------+----------
```

### Monitors

Two types of monitors are supported:

* `:summary` monitors apply to general informaton like `load` or `memory`.
* `:process` montitors apply to any process in the process list.

Monitor callbacks are arity 3 functions and can be specified as an function or
{module, function} tuple. The are called with the Etop state map and can
optionally return a modified version of the state. i.e. toggle reporting field.

Add a monitor to trigger when total cpu load exceeds 50%.

```elixir
iex> monitor = fn info, value, state ->
...>   IO.inspect({info, state})
...>   %{state | reporting: true}
...> end
iex> Etop.add_monitor(:summary, [:load, :total], 50.0, monitor)
```

Add a monitor to trigger when the msgq length of a process is below 10.

```elixir
iex> monitor = fn info, value, state ->
...>   IO.inspect({info, state})
...>   %{state | reporting: false}
...> end
iex> Etop.add_monitor(:process, :message_queue_len, {&</2, 10}, monitor)
iex> # or
iex> Etop.add_monitor(:process, :message_queue_len, & &1 < 10, monitor)
```

Add a monitor to trigger when memory is > 1M and < 2M bytes

```elixir
iex> Etop.add_monitor(:summary, :message_queue_len, & &1 > 1_000_000 and
...> &1 < 2_000_000, {MyMod, :callback})
```

## Why not use erlang's :etop library?

There are 2 reasons why I created this library

* Our default production installations don't have etop or observer included
* This version supports loading and post processing log files

## Installation

If [available in Hex](https://hex.pm/docs/publish), the package can be installed
by adding `etop` to your list of dependencies in `mix.exs`:

```elixir
def deps do
  [
    {:etop, "~> 0.7"}
  ]
end
```

Documentation can be generated with [ExDoc](https://github.com/elixir-lang/ex_doc)
and published on [HexDocs](https://hexdocs.pm). Once published, the docs can
be found at [https://hexdocs.pm/etop](https://hexdocs.pm/etop).

## License

`Etop` is Copyright (c) 2020-2021 E-MetroTel

The source code is released under the MIT License.

Check [LICENSE](LICENSE.md) for more information.