Today I played with custom live dashboard pages, That's a short documentation how to use it. We will implement a page that shows the currently running system processes on the box running our elixir system.
Documentation can be found on hexdocs.
Most up to date code is attached in the gist.
First we need to create a new module:
defmodule Phoenix.LiveDashboard.OsProcesses do
@moduledoc false
use Phoenix.LiveDashboard.PageBuilder
end
To get the list I'll use the output of ps aux
command.
I'll cheat here a bit and use jq
to convert the page to json which later can be easily decoded by Jason. This also shows how to use more complicated commands. We can of course parse the string in elixir.
To use pipes inside the command I had to use the os module with a character list passed as an option. In the gist the ps
parser is written in pure elixir but for simplicity I'll leave the jq
version here. On windows you can play with tasklist
the output is a bit similar but there are spaces on the first line so you may want to parse it a bit different.
defp fetch_processes(_params, _node) do
data =
:os.cmd('ps aux | jq -sR \'[sub("\n$";"") | splits("\n") | sub("^ +";"") | [splits(" +")]] | .[0] as $header | .[1:] | [.[] | [. as $x | range($header | length) | {"key": $header[.], "value": $x[.]}] | from_entries]\'')
|> Jason.decode!(%{keys: :atoms!})
{data, length(data)}
end
The return value of this function must be a tuple with rows and the length of the rows.
Next function we need to write is the columns definitions
defp columns() do
[
%{
field: :"PID",
sortable: :asc
},
%{
field: :"TTY"
},
%{
field: :"TIME",
cell_attrs: [class: "text-right"],
},
%{
field: :"USER",
},
%{
field: :"%CPU",
sortable: :desc
},
%{
field: :"%MEM",
sortable: :desc
},
%{
field: :"VSZ",
sortable: :asc
},
%{
field: :"RSS",
sortable: :asc
},
%{
field: :"STAT",
},
%{
field: :"START",
sortable: :asc
},
%{
field: :"COMMAND",
},
]
end
Both of this functions need to be passed to the render_page/1 callback
@impl true
def render_page(_assigns) do
table(
columns: columns(),
id: :os_processes,
row_attrs: &row_attrs/1,
row_fetcher: &fetch_processes/2,
rows_name: "tables",
title: "OS processes",
sort_by: :"PID"
)
end
as we see there is another function required, the row_attrs that returns html attributes for our table rows.
And thats basically it.
Last two pieces of code is the menu_link/2 callback
@impl true
def menu_link(_, _) do
{:ok, "OS Processes"}
end
and the router entry for our page
scope "/" do
pipe_through :browser
live_dashboard "/dashboard", metrics: ChatterWeb.Telemetry,
additional_pages: [
os_processes: Phoenix.LiveDashboard.OsProcesses
]
and that basically it - The code can be found on github, with the params used for sorting, limiting and search. Have fun and link any pages you have created.
Top comments (2)
Excellent Great article!!!!
Thanks Allan. I updated it so jq is not needed, I'm parsing the ps output in elixir and I also hooked up the search and filter params