Current section
Files
Jump to
Current section
Files
lib/wobserver/util/application.ex
defmodule Wobserver.Util.Application do
@moduledoc ~S"""
Application listing and process hierachy.
"""
alias Wobserver.Util.Process
import Wobserver.Util.Helper, only: [parallel_map: 2]
@doc ~S"""
Lists all running applications.
The application information is given as a tuple containing: `{name, description, version}`.
The `name` is an atom, while both the description and version are Strings.
"""
@spec list :: list({atom, String.t, String.t})
def list do
:application_controller.which_applications
|> Enum.filter(&alive?/1)
|> Enum.map(&structure_application/1)
end
@doc ~S"""
Retreives information about the application.
The given `app` atom is used to find the started application.
Containing:
- `pid`, the process id or port id.
- `name`, the registered name or pid/port.
- `meta`, the meta information of a process. (See: `Wobserver.Util.Process.meta/1`.)
- `children`, the children of the process.
"""
@spec info(app :: atom) :: map
def info(app) do
app_pid =
app
|> :application_controller.get_master
%{
pid: app_pid,
children: app_pid |> :application_master.get_child |> structure_pid(),
name: name(app_pid),
meta: Process.meta(app_pid),
}
end
# Helpers
defp alive?({app, _, _}) do
app
|> :application_controller.get_master
|> is_pid
catch
_, _ -> false
end
defp structure_application({name, description, version}) do
%{
name: name,
description: to_string(description),
version: to_string(version),
}
end
defp structure_pid({pid, name}) do
child = structure_pid({name, pid, :supervisor, []})
{_, dictionary} = :erlang.process_info pid, :dictionary
case Keyword.get(dictionary, :"$ancestors") do
[parent] ->
[%{
pid: parent,
children: [child],
name: name(parent),
meta: Process.meta(parent),
}]
_ ->
[child]
end
end
defp structure_pid({_, :undefined, _, _}), do: nil
defp structure_pid({_, pid, :supervisor, _}) do
{:links, links} = :erlang.process_info(pid, :links)
children =
case Enum.count(links) do
1 ->
[]
_ ->
pid
|> :supervisor.which_children
|> Kernel.++(Enum.filter(links, fn link -> is_port(link) end))
|> parallel_map(&structure_pid/1)
|> Enum.filter(&(&1 != nil))
end
%{
pid: pid,
children: children,
name: name(pid),
meta: Process.meta(pid),
}
end
defp structure_pid({_, pid, :worker, _}) do
%{
pid: pid,
children: [],
name: name(pid),
meta: Process.meta(pid),
}
end
defp structure_pid(port) when is_port(port) do
%{
pid: port,
children: [],
name: port,
meta: %{
status: :port,
init: "",
current: "",
class: :port,
}
}
end
defp structure_pid(_), do: nil
defp name(pid) do
case :erlang.process_info(pid, :registered_name) do
{_, registered_name} -> to_string(registered_name)
_ -> pid |> inspect |> String.trim_leading("#PID")
end
end
end