user_default
Martin Bjorklund
mbj@REDACTED
Fri Feb 25 22:22:25 CET 2000
o did you like the old c() better?
o would you like to be able to use bt() in production environments?
o tired of writing loops on funs in the shell to get info on ports?
o ever wondered why you can't use registered names in
process_info()?
... then put this module in your code path, e.g. in your .erlang file,
and try i(), pi(), etc in the shell.
?mbj
-------------- next part --------------
%%%----------------------------------------------------------------------
%%% File : user_default.erl
%%% Author : Martin Bjorklund <mbj@REDACTED>
%%% Purpose : Nice shell features.
%%% Created : 24 Feb 2000 by Martin Bjorklund <mbj@REDACTED>
%%%----------------------------------------------------------------------
-module(user_default).
%% We Don't Believe in Authors
%% -author('mbj@REDACTED').
-export([i/0, i/1, i/3, ni/0, ci/0, ci/3, cni/0, bt/1, bt/3]).
-export([pi/0, pi/1, pi2/0]).
-import(lists, [filter/2, foreach/2, flatmap/2]).
-define(mbj, /martin).
%% Good ol' i() but includes zooombie support
i() -> i1(processes()).
ni() -> i1(all_procs()).
i(Pid) when pid(Pid) -> pinfo(Pid);
i(Name) when atom(Name) ->
case whereis(Name) of
undefined -> undefined;
Pid -> i(Pid)
end.
i(X,Y,Z) -> pinfo(c:pid(X,Y,Z)).
%% If you like the new one
ci() ->
c:i().
ci(X,Y,Z) ->
c:i(X,Y,Z).
cni() ->
c:ni().
%% Code modified from c.erl
i1(Ps) ->
Alive = filter(fun palive/1, Ps),
i2(Alive),
case filter(fun pzombie/1, Ps) of
[] ->
ok;
Zombies ->
%% Zombies is not the same as Ps-Alive, since the remote
%% process that fetched Ps is included among Alive, but has
%% exited (for ni/0).
io:format("\nDead processes:\n"),
i2(Zombies)
end.
i2(Ps) ->
iformat("Pid", "Initial Call", "Current Function", "Reds", "Msgs"),
{R,M} = lists:foldl(fun display_info/2, {0,0}, Ps),
iformat("Total", "", "", io_lib:write(R), io_lib:write(M)).
palive(Pid) ->
case pinfo(Pid, status) of
undefined -> false;
{status, exiting} -> false;
_ -> true
end.
pzombie(Pid) ->
case pinfo(Pid, status) of
undefined -> false;
{status, exiting} -> true;
_ -> false
end.
pinfo(Pid) ->
case is_alive() of
true -> rpc:call(node(Pid), erlang, process_info, [Pid]);
false -> process_info(Pid)
end.
pinfo(Pid, Item) ->
case is_alive() of
true -> rpc:call(node(Pid), erlang, process_info, [Pid, Item]);
false -> process_info(Pid, Item)
end.
all_procs() ->
case is_alive() of
true -> flatmap(fun (N) -> rpc:call(N, erlang, processes, []) end,
[node() | nodes()]);
false -> processes()
end.
display_info(Pid, {R,M}) ->
case pinfo(Pid) of
undefined ->
{R, M};
Info ->
Call = initial_call(Info),
Curr = fetch(current_function, Info),
Reds = fetch(reductions, Info),
LM = fetch(message_queue_len, Info),
iformat(io_lib:write(Pid),
mfa_string(Call),
mfa_string(Curr),
io_lib:write(Reds),
io_lib:write(LM)),
{R+Reds, M+LM}
end.
%% We can do some assumptions about the initial call.
%% If the initial call is proc_lib:init_p/5 we can find more information
%% by calling the function proc_lib:translate_initial_call/1.
initial_call(Info) ->
case fetch(initial_call, Info) of
{proc_lib, init_p, 5} ->
proc_lib:translate_initial_call(Info);
ICall ->
ICall
end.
mfa_string({M, F, A}) ->
io_lib:format("~w:~w/~w", [M, F, A]);
mfa_string(X) ->
io_lib:write(X).
fetch(Key, Info) ->
case lists:keysearch(Key, 1, Info) of
{value, {_, Val}} -> Val;
false -> 0
end.
iformat(A1, A2, A3, A4, A5) ->
io:format("~-12s ~-23s ~-23s ~12s ~4s\n", [A1,A2,A3,A4,A5]).
%% Port info
%% I don't really know which info is most relevent, so I included
%% both pi() and pi2().
pi() ->
piformat("Id", "Name", "Connected", "Initial Call", "Current Function"),
do_pi(fun(Info) ->
Pid = fetch(connected, Info),
{ICall, Curr} =
case pinfo(Pid) of
undefined ->
{[], []};
ProcInfo ->
{initial_call(ProcInfo),
fetch(current_function, ProcInfo)}
end,
Id = fetch(id, Info),
Name = fetch(name, Info),
piformat(io_lib:write(Id),
Name,
io_lib:write(Pid),
mfa_string(ICall),
mfa_string(Curr))
end).
piformat(A1, A2, A3, A4, A5) ->
io:format("~-6s ~-10s ~-12s ~-23s ~-23s\n", [A1,A2,A3,A4,A5]).
pi2() ->
pi2format("Id", "Name", "Connected", "Recv", "Sent"),
do_pi(fun(Info) ->
Id = fetch(id, Info),
Name = fetch(name, Info),
Pid = fetch(connected, Info),
Recv = fetch(input, Info),
Sent = fetch(output, Info),
pi2format(io_lib:write(Id),
Name,
io_lib:write(Pid),
io_lib:write(Recv),
io_lib:write(Sent))
end).
pi2format(A1, A2, A3, A4, A5) ->
io:format("~-6s ~-20s ~-12s ~-10s ~-10s\n", [A1,A2,A3,A4,A5]).
do_pi(Print) ->
Ps = erlang:ports(),
foreach(
fun(P) ->
case erlang:port_info(P) of
undefined ->
ok;
Info ->
Print(Info);
_ ->
ok
end
end, erlang:ports()).
pi(Id) ->
pi(erlang:ports(), Id).
pi([P | Ps], Id) ->
case erlang:port_info(P, id) of
{id, Id} ->
erlang:port_info(P);
_ ->
pi(Ps, Id)
end;
pi([], _Id) ->
undefined.
%% Doesn't do process_display, which means it can be used when
%% remotely connecting to a node.
bt(Pid) when pid(Pid) ->
case pinfo(Pid, backtrace) of
{backtrace, Bin} ->
io:format("~s\n", [binary_to_list(Bin)]);
_ ->
undefined
end;
bt(Name) when atom(Name) ->
case whereis(Name) of
undefined -> undefined;
Pid -> bt(Pid)
end.
bt(X,Y,Z) ->
bt(c:pid(X,Y,Z)).
More information about the erlang-questions
mailing list