Skip to content
Permalink
Browse files
Merge pull request #27 from cloudant/custom-formatters
Add an ability to pass custom formatter function
  • Loading branch information
ferd committed Aug 6, 2015
2 parents a567348 + 2b2ad0a commit e209456398b1a563f256870894dc505a1ae9eed1
Showing 1 changed file with 47 additions and 36 deletions.
@@ -39,7 +39,7 @@
%%% | -, ,- |
%%% '-, '-, ,-' ,-'
%%% '-,_ _,-''-,_ _,-'
%%% '--------' '--------'
%%% '--------' '--------'
%%% '''
%%%
%%% If either the pid specification excludes a process or a trace pattern
@@ -156,32 +156,35 @@
-module(recon_trace).

%% API
-export([clear/0, calls/2, calls/3]).
-export([clear/0, calls/2, calls/3, calls/4]).

-export([format/1]).

%% Internal exports
-export([count_tracer/1, rate_tracer/2, formatter/3]).
-export([count_tracer/1, rate_tracer/2, formatter/4]).

-type matchspec() :: [{[term()], [term()], [term()]}].
-type shellfun() :: fun((_) -> term()).
-type millisecs() :: non_neg_integer().
-type pidspec() :: all | existing | new | recon:pid_term().
-type max_traces() :: non_neg_integer().
-type max_rate() :: {max_traces(), millisecs()}.
-type matchspec() :: [{[term()], [term()], [term()]}].
-type shellfun() :: fun((_) -> term()).
-type formatterfun() :: fun((_) -> iodata()).
-type millisecs() :: non_neg_integer().
-type pidspec() :: all | existing | new | recon:pid_term().
-type max_traces() :: non_neg_integer().
-type max_rate() :: {max_traces(), millisecs()}.

%% trace options
-type options() :: [ {pid, pidspec() | [pidspec(),...]} % default: all
| {timestamp, formatter | trace} % default: formatter
| {args, args | arity} % default: args
-type options() :: [ {pid, pidspec() | [pidspec(),...]} % default: all
| {timestamp, formatter | trace} % default: formatter
| {args, args | arity} % default: args
%% match pattern options
| {scope, global | local} % default: global
].
| {scope, global | local} % default: global
].

-type mod() :: '_' | module().
-type fn() :: '_' | atom().
-type args() :: '_' | 0..255 | matchspec() | shellfun().
-type tspec() :: {mod(), fn(), args()}.
-type max() :: max_traces() | max_rate().
-type num_matches() :: non_neg_integer().
-type mod() :: '_' | module().
-type fn() :: '_' | atom().
-type args() :: '_' | 0..255 | matchspec() | shellfun().
-type tspec() :: {mod(), fn(), args()}.
-type max() :: max_traces() | max_rate().
-type num_matches() :: non_neg_integer().

-export_type([mod/0, fn/0, args/0, tspec/0, num_matches/0, options/0,
max_traces/0, max_rate/0]).
@@ -207,6 +210,12 @@ calls({Mod, Fun, Args}, Max) ->
calls(TSpecs = [_|_], Max) ->
calls(TSpecs, Max, []).

%% @equiv calls(Spec, Max, Opts, fun recon_trace:format/1)
-spec calls(tspec() | [tspec(),...], max(), options()) -> num_matches().
calls(Spec, Max, Opts) ->
calls(Spec, Max, Opts, fun format/1).


%% @doc Allows to set trace patterns and pid specifications to trace
%% function calls.
%%
@@ -228,7 +237,7 @@ calls(TSpecs = [_|_], Max) ->
%% of trace messages to be received, or a maximal frequency (`{Num, Millisecs}').
%%
%% Here are examples of things to trace:
%%
%%
%% <ul>
%% <li>All calls from the `queue' module, with 10 calls printed at most:
%% ``recon_trace:calls({queue, '_', '_'}, 10)''</li>
@@ -290,14 +299,16 @@ calls(TSpecs = [_|_], Max) ->
%% can be risky if more trace messages are generated than any process on
%% the node could ever handle, despite the precautions taken by this library.
%% @end
-spec calls(tspec() | [tspec(),...], max(), options()) -> num_matches().
calls({Mod, Fun, Args}, Max, Opts) ->
calls([{Mod,Fun,Args}], Max,Opts);
calls(TSpecs = [_|_], {Max, Time}, Opts) ->
Pid = setup(rate_tracer, [Max, Time]),
-spec calls(tspec() | [tspec(),...], max(), options(), formatterfun()) ->
num_matches().

calls({Mod, Fun, Args}, Max, Opts, FormatterFun) ->
calls([{Mod,Fun,Args}], Max, Opts, FormatterFun);
calls(TSpecs = [_|_], {Max, Time}, Opts, FormatterFun) ->
Pid = setup(rate_tracer, [Max, Time], FormatterFun),
trace_calls(TSpecs, Pid, Opts);
calls(TSpecs = [_|_], Max, Opts) ->
Pid = setup(count_tracer, [Max]),
calls(TSpecs = [_|_], Max, Opts, FormatterFun) ->
Pid = setup(count_tracer, [Max], FormatterFun),
trace_calls(TSpecs, Pid, Opts).

%%%%%%%%%%%%%%%%%%%%%%%
@@ -334,22 +345,22 @@ rate_tracer(Max, Time, Count, Start) ->
end.

%% @private Formats traces to be output
formatter(Tracer, Parent, Ref) ->
formatter(Tracer, Parent, Ref, FormatterFun) ->
process_flag(trap_exit, true),
link(Tracer),
Parent ! {Ref, linked},
formatter(Tracer, group_leader()).
formatter(Tracer, group_leader(), FormatterFun).

formatter(Tracer, Leader) ->
formatter(Tracer, Leader, FormatterFun) ->
receive
{'EXIT', Tracer, normal} ->
io:format("Recon tracer rate limit tripped.~n"),
exit(normal);
{'EXIT', Tracer, Reason} ->
exit(Reason);
TraceMsg ->
io:format(Leader, format(TraceMsg), []),
formatter(Tracer, Leader)
io:format(Leader, FormatterFun(TraceMsg), []),
formatter(Tracer, Leader, FormatterFun)
end.


@@ -359,12 +370,12 @@ formatter(Tracer, Leader) ->

%% starts the tracer and formatter processes, and
%% cleans them up before each call.
setup(TracerFun, TracerArgs) ->
setup(TracerFun, TracerArgs, FormatterFun) ->
clear(),
Ref = make_ref(),
Tracer = spawn_link(?MODULE, TracerFun, TracerArgs),
register(recon_trace_tracer, Tracer),
Format = spawn(?MODULE, formatter, [Tracer, self(), Ref]),
Format = spawn(?MODULE, formatter, [Tracer, self(), Ref, FormatterFun]),
register(recon_trace_formatter, Format),
receive
{Ref, linked} -> Tracer
@@ -577,4 +588,4 @@ fun_to_ms(ShellFun) when is_function(ShellFun) ->
end;
false ->
exit(shell_funs_only)
end.
end.

0 comments on commit e209456

Please sign in to comment.