%%%------------------------------------------------------------------- %%% @author Torbjorn Tornkvist %%% @copyright (C) 2022, Torbjorn Tornkvist %%% Good to have utilities when debugging code. %%% %%% Created : 13 Dec 2022 by Torbjorn Tornkvist %%%------------------------------------------------------------------- -module(edbg_utils). -export([all_sup_trees/0 , start/0 , supervisors/0 , supervisors/1 ]). -define(SERVER, ?MODULE). -ifdef(USE_COLORS). -define(info_msg(Fmt,Args), edbg_color_srv:info_msg(Fmt,Args)). -define(att_msg(Fmt,Args), edbg_color_srv:att_msg(Fmt,Args)). -define(warn_msg(Fmt,Args), edbg_color_srv:warn_msg(Fmt,Args)). -define(err_msg(Fmt,Args), edbg_color_srv:err_msg(Fmt,Args)). -define(cur_line_msg(Fmt,Args), edbg_color_srv:cur_line_msg(Fmt,Args)). -define(c_hi(Str), edbg_color_srv:c_hi(Str)). -define(c_warn(Str), edbg_color_srv:c_warn(Str)). -define(c_err(Str), edbg_color_srv:c_err(Str)). -define(help_hi(Str), edbg_color_srv:help_hi(Str)). -define(edbg_color_srv_init(), edbg_color_srv:init()). -else. -define(info_msg(Fmt,Args), io:format(Fmt,Args)). -define(att_msg(Fmt,Args), io:format(Fmt,Args)). -define(warn_msg(Fmt,Args), io:format(Fmt,Args)). -define(err_msg(Fmt,Args), io:format(Fmt,Args)). -define(cur_line_msg(Fmt,Args), io:format(Fmt,Args)). -define(c_hi(Str), Str). -define(c_warn(Str), Str). -define(c_err(Str), Str). -define(help_hi(Str), Str). -define(edbg_color_srv_init(), ok). -endif. -record(state, { expand_levels = [], sup_trees = [] }). -record(sup_tree, {id, pid, children = [] }). %% @private start() -> Self = self(), Prompt = spawn_link(fun() -> prompt(Self) end), Prompt ! show, ploop(Prompt). ploop(Prompt) -> receive {'EXIT', Prompt, _} -> true; quit -> true; _ -> ?MODULE:ploop(Prompt) end. prompt(Pid) when is_pid(Pid) -> process_flag(trap_exit, true), State = #state{sup_trees = all_sup_trees()}, Prompt = "suptrees> ", print_help(), loop(Pid, Prompt, State). loop(Pid, Prompt, State0) -> State = case string:tokens(io:get_line(Prompt), "\n") of ["h"++X] -> help(X, State0); ["s"++X] -> show(X, State0); ["x"++X] -> expand(X, State0); ["q"++_] -> Pid ! quit, exit(normal); _X -> ?info_msg("prompt got: ~p~n",[_X]), State0 end, ?MODULE:loop(Pid, Prompt, State). show(Chars, State) -> show(Chars, State, 1). show(Chars, [#sup_tree{id = Id, pid = Pid}|Tail], N) -> io:format("~p:s ~p ~p~n", [N, Id, Pid]), show(Chars, Tail, N+1); show(Chars, [{Name,Pid,worker,_Mods}|Tail], N) -> io:format("~p:w ~p ~p~n", [N, Name, Pid]), show(Chars, Tail, N+1); show(_, [], _) -> ok. help(_,_) -> tbd. expand(_,_) -> tbd. print_help() -> S1 = " (h)elp e(x)pand [] (s)how (q)uit", S = io_lib:format("~n~s~n",[S1]), ?info_msg(?help_hi(S), []). %% @private supervisors() -> supervisors(kernel_sup). %% @private supervisors(Supervisor) when is_atom(Supervisor) -> supervisors(Supervisor, new_sup_tree(Supervisor)). %% supervisors(user = Supervisor, SupTree) -> % eternal loop? %% SupTree; %% supervisors(standard_error = Supervisor, SupTree) -> % eternal loop? %% SupTree; supervisors(Supervisor, SupTree) -> io:format(">>> Supervisor=~p~n",[Supervisor]), case supervisor:which_children(SupTree#sup_tree.pid) of Children when is_list(Children) -> lists:foldl(fun({Id, Pid, Type, _Modules}, AccTree) when (Type == supervisor) andalso is_pid(Pid) -> Cs = AccTree#sup_tree.children, AccTree#sup_tree{children = Cs ++ [supervisors(Id, new_sup_tree(Id, Pid))]}; (Entry, AccTree) -> Cs = AccTree#sup_tree.children, AccTree#sup_tree{children = Cs ++ [Entry]} end, SupTree, Children); _ -> SupTree end. %% @private all_sup_trees() -> Sups = lists:foldr( fun(Id,Acc) -> case process_info(whereis(Id), dictionary) of {dictionary,L} -> case lists:keyfind('$initial_call', 1, L) of {'$initial_call',{supervisor,_,_}} -> [Id|Acc]; _ -> Acc end; _ -> Acc end end, [], erlang:registered()), [supervisors(Id) || Id <- Sups]. %% SupTree#sup_tree{children = %% [supervisors(Id, new_sup_tree(Id, Pid)) || %% {Id, Pid, Type, _Modules} %% <- supervisor:which_children(SupTree#sup_tree.pid), %% Type == supervisor, %% is_pid(Pid) == true]}. new_sup_tree(SupervisorId) -> new_sup_tree(SupervisorId, erlang:whereis(SupervisorId)). new_sup_tree(SupervisorId, Pid) -> #sup_tree{id = SupervisorId, pid = Pid}.