Skip to content

Instantly share code, notes, and snippets.

@erszcz
Created March 4, 2016 12:12
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save erszcz/902f3d2658aed790ba0b to your computer and use it in GitHub Desktop.
Save erszcz/902f3d2658aed790ba0b to your computer and use it in GitHub Desktop.
Erlang et (Event Tracer)
-module(et_helper).
-compile([export_all]).
-include_lib("et/include/et.hrl").
start() ->
start([]).
start(ExtraOptions) ->
Options = [{trace_global, true},
{parent_pid, undefined},
{max_actors, infinity},
{max_events, 1000},
{active_filter, module_as_actor}],
et_viewer:start_link(filters() ++ Options ++ ExtraOptions).
trace(Mod) ->
dbg:p(all, [call, timestamp]),
dbg:tpl(Mod, [{'_', [], [{message, {caller}}, {return_trace}]}]).
filters() ->
[{dict_insert, {filter, module_as_actor},
fun module_as_actor/1},
{dict_insert, {filter, plain_process_info},
fun plain_process_info/1},
{dict_insert, {filter, named_process_info},
fun named_process_info/1}].
module_as_actor(E) when is_record(E, event) ->
case lists:keysearch(mfa, 1, E#event.contents) of
{value, {mfa, {M, F, _A}}} ->
case lists:keysearch(pam_result, 1, E#event.contents) of
{value, {pam_result, {M2, _F2, _A2}}} ->
{true, E#event{label = F, from = M2, to = M}};
_ ->
{true, E#event{label = F, from = M, to = M}}
end;
_ ->
false
end.
named_process_info(E) when is_record(E, event) ->
case plain_process_info(E) of
true ->
{true, E#event{to = pid_to_name(E#event.to),
from = pid_to_name(E#event.from),
label = msg_to_label(E)}};
false ->
false
end.
plain_process_info(E) when is_record(E, event) ->
case E#event.label of
send -> true;
send_to_non_existing_process -> true;
'receive' -> true;
spawn -> true;
exit -> true;
link -> true;
unlink -> true;
getting_linked -> true;
{seq_send, _Label} -> true;
{seq_receive, _Label} -> true;
{seq_print, _Label} -> true;
{drop, _N} -> true;
_ -> false
end.
pid_to_name(Pid) when is_pid(Pid) ->
case process_info(Pid, registered_name) of
{registered_name, Name} ->
Name;
_ ->
Pid
end;
pid_to_name({Name, Node}) when Node == node() ->
Name;
pid_to_name(Other) ->
Other.
msg_to_label(E) when is_record(E, event) ->
case lists:keysearch(msg, 1, E#event.contents) of
{value, {msg, Msg}} ->
mnesia_msg_to_label(Msg, E#event.label);
false ->
E#event.label
end.
mnesia_msg_to_label(Msg, Label) ->
case Msg of
{mnesia_tm, _Node, Reply} ->
case Reply of
ok -> ok;
store_erased -> store_erased;
unblocked -> unblocked;
{_From, _Ref, start_outer} -> start_outer;
{aborted, _Tid} -> aborted;
{committed, _Tid} -> committed;
{dirty_res, _Res} -> dirty_res;
{error, _Reason} -> error;
{info, _Part, _Coord} -> info;
{mnesia_tm, _Node, {'EXIT', _Reason}} -> 'EXIT';
{mnesia_tm, _Node, {dirty_res, _Reply}} -> dirty_res;
{new_store, _Etab} -> new_store;
{new_tid, _Tid, _Etab} -> new_tid;
{ok, _Name, _IgnoreNew, _Node} -> ok;
{restarted, _Tid} -> restarted;
{vote_yes, _Tid, _Self} -> vote_yes;
{vote_yes, _Tid} -> vote_yes;
{acc_pre_commit, _Tid, _Self, _Expect} -> acc_pre_commit;
{schema_commit, _Tid, _Self} -> schema_commit;
{vote_no, _Tid, _Reason} -> vote_no
end;
{'$gen_cast', allow_garb} -> allow_garb;
{'$gen_cast', {release_schema_commit_lock, _Pid}} -> release_schema_commit_lock;
{'$gen_call', _Ref, {mktab, _Name,_Args}} -> mktab;
{'$gen_call', _Ref, wait_for_schema_commit_lock} -> wait_for_schema_commit_lock;
{'$gen_call', _Ref, {set_lock, _Key}} -> set_global_lock;
{'$gen_call', _Ref, {del_lock, _Key}} -> del_global_lock;
{'$gen_call', _Ref, {what_happened, _Decision, _Tid}} -> what_happened;
{async_dump_log, _Reason} -> async_dump_log;
check_overload -> check_overload;
{dumper_done, _Pid, dumped} -> dumper_done;
garb_decisions -> garb_decisions;
timeout -> timeout;
{mnesia_locker, _Node, granted} -> granted;
{mnesia_locker, _Node, {granted, _Lookup}} -> granted;
{'EXIT', _Pid, _Reason} -> 'EXIT';
{_From, info} -> info;
{_From, start_outer} -> start_outer;
{_From, {add_store, _Tid}} -> add_store;
{_From, {ask_commit, _Prot, _Tid, _Commit, _DiscNs, _RamNs}} -> ask_commit;
{_From, {async_dirty, _Tid, _Commit, _Tab}} -> async_dirty;
{_From, {block_tab, _Tab}} -> block_tab;
{_From, {del_store, _Tid, _Current, _Obsolete, _Prop}} -> del_store;
{_From, {prepare_checkpoint, _Cp}} ->prepare_checkpoint;
{_From, {read, _Tid, _Oid}} -> try_read_lock;
{_From, {read_write, _Tid, _Oid}} -> try_read_write_lock;
{_From, {restart, _Tid, _Store}} -> restart;
{_From, {sync_dirty, _Tid, _Commit, _Tab}} -> sync_dirty;
{_From, {unblock_me, _Tab}} -> unblock_me;
{_From, {unblock_tab, _Tab}} -> unblock_tab;
{_From, {write, _Tid, _Oid}} -> try_write_lock;
{_Tid, committed} -> committed;
{_Tid, do_commit} -> do_commit;
{_Tid, pre_commit} -> pre_commit;
{_Tid, simple_commit} -> simple_commit;
{_Tid, {do_abort, _Reason}} -> do_abort;
{activity_ended, _, _Pid} -> activity_ended;
{ask_commit, _Protocol, _Tid, _Bin, _DiscNs, _RamNs} -> ask_commit;
{delete_transaction, _Tid} -> delete_transaction;
{mnesia_down, _Node} -> mnesia_down;
{release_tid, _Tid} -> release_tid;
{sync_trans_serial, _Tid} -> sync_trans_serial;
{system, _From, _Msg} -> system;
{transaction_done, _Res, _Pid} -> transaction_done;
{_Tid, {do_abort, _Reason}} -> do_abort;
{_Ref, granted} -> granted;
_ -> Label
end.
code:add_path("/path/to/et_helper").
et_helper:start([]).
InitialModule = ejabberd_c2s.
et_helper:trace(InitialModule).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment