From 7e3bbc9f57bab238d04545bc0cda70ca0bb0b9f8 Mon Sep 17 00:00:00 2001
From: Piotr Dorobisz Even though the intention of the Trace Tool Builder is to serve
- as a base for tailor made trace tools, it is of course possible
- to use it directly from the erlang shell. The application only
- allows the use of file port tracer, so if you would like would
- like to use other types of trace clients you will be better off
+ The intention of the Trace Tool Builder is to serve
+ as a base for tailor made trace tools, but you may use it directly
+ from the erlang shell (it may mimic
The following example shows the basic use of
(tiger@durin)50>
(tiger@durin)50> %% Here I set a trace pattern on erlang:now/0
(tiger@durin)50> %% The trace pattern is a simple match spec
-(tiger@durin)50> %% generated by dbg:fun2ms/1. It indicates that
-(tiger@durin)50> %% the return value shall be traced.
-(tiger@durin)50> MS = dbg:fun2ms(fun(_) -> return_trace() end).
-[{'_',[],[{return_trace}]}]
-(tiger@durin)51> ttb:tp(erlang,now,MS).
+(tiger@durin)50> %% indicating that the return value should be
+(tiger@durin)50> %% traced. Refer to the reference_manual for
+(tiger@durin)50> %% the full list of match spec shortcuts
+(tiger@durin)50> %% available.
+(tiger@durin)51> ttb:tp(erlang,now,return).
{ok,[{matched,tiger@durin,1},{saved,1}]}
(tiger@durin)52>
(tiger@durin)52> %% I run my test (i.e. send a message to
@@ -145,11 +149,11 @@ f() ->
(tiger@durin)53>
(tiger@durin)53> %% And then I have to stop ttb in order to flush
(tiger@durin)53> %% the trace port buffer
-(tiger@durin)53> ttb:stop().
-stopped
+(tiger@durin)53> ttb:stop([return, {fetch_dir, "fetch"}]).
+{stopped, "fetch"}
(tiger@durin)54>
(tiger@durin)54> %% Finally I format my trace log
-(tiger@durin)54> ttb:format("tiger@durin-ttb").
+(tiger@durin)54> ttb:format("fetch").
({<0.125.0>,{m,f,0},tiger@durin}) call erlang:now()
({<0.125.0>,{m,f,0},tiger@durin}) returned from erlang:now/0 ->
{1031,133451,667611}
@@ -167,10 +171,6 @@ ok ]]>
-export([start/0,trc/1,stop/0,format/1]).
-export([print/4]).
-%% Include ms_transform.hrl so that I can use dbg:fun2ms/2 to
-%% generate match specifications.
--include_lib("stdlib/include/ms_transform.hrl").
-
%%% -------------Tool API-------------
%%% ----------------------------------
%%% Star the "mydebug" tool
@@ -180,28 +180,28 @@ start() ->
%% module shall be used as format handler
ttb:tracer(all,[{file,"debug_log"},{handler,{{?MODULE,print},0}}]),
%% All processes (existing and new) shall trace function calls
- %% and include a timestamp in each trace message
- ttb:p(all,[call,timestamp]).
+ %% We want trace messages to be sorted upon format, which requires
+ %% timestamp flag. The flag is however enabled by default in ttb.
+ ttb:p(all,call).
%%% Set trace pattern on function(s)
-trc(M) when atom(M) ->
+trc(M) when is_atom(M) ->
trc({M,'_','_'});
-trc({M,F}) when atom(M), atom(F) ->
+trc({M,F}) when is_atom(M), is_atom(F) ->
trc({M,F,'_'});
-trc({M,F,_A}=MFA) when atom(M), atom(F) ->
- %% This match spec specifies that return values shall
- %% be traced. NOTE that ms_transform.hrl must be included
- %% if dbg:fun2ms/1 shall be used!
+trc({M,F,_A}=MFA) when is_atom(M), is_atom(F) ->
+ %% This match spec shortcut specifies that return values shall
+ %% be traced.
MatchSpec = dbg:fun2ms(fun(_) -> return_trace() end),
ttb:tpl(MFA,MatchSpec).
%%% Format a binary trace log
-format(File) ->
- ttb:format(File).
+format(Dir) ->
+ ttb:format(Dir).
%%% Stop the "mydebug" tool
stop() ->
- ttb:stop().
+ ttb:stop(return).
%%% --------Internal functions--------
%%% ----------------------------------
@@ -226,9 +226,9 @@ do_print(Out,{trace_ts,P,return_from,{M,F,A},R,Ts},N) ->
[N,Ts,P,M,F,A,R]). ]]>
To distinguish trace logs produced with this tool from other
logs, the
By using the
-(trace_control@durin)1> ttb:tracer(mynode@diskless,[{file,{local,
-{wrap,"mytrace"}}}]).
+(trace_control@durin)1> ttb:tracer(mynode@diskless,{file,{local,
+{wrap,"mytrace"}}}).
{ok,[mynode@diskless]}
+ When setting up a trace, several features may be turned on:
+Sometimes, it may be helpful to enable trace for a
+ given period of time (i.e. to monitor a system for 24 hours
+ or half of a second). This may be done by issuing additional
+
+(tiger@durin)1>ttb:start_trace([node()],
+ [{erlang, now,[]}],
+ {all, call},
+ [{timer, {5000, format}}]).
+
+ When tracing live systems, special care needs to be always taken
+ not to overload a node with too heavy tracing.
Overload protection activated on one node does not
+ affect other nodes, where the tracing continues as normal.
+
+-module(overload).
+-export([check/1]).
+
+check(init) ->
+ Pid = sophisticated_module:start(),
+ put(pid, Pid);
+check(check) ->
+ get(pid) ! is_overloaded,
+ receive
+ Reply ->
+ Reply
+ after 5000 ->
+ true
+ end;
+check(stop) ->
+ get(pid) ! stop.
+ It is possible that a node (probably a buggy one, hence traced)
+ crashes. In order to automatically resume tracing on the node
+ as soon as it gets back,
In order not to loose the data that the failing node stored
+ up to the point of crash, the control node will try to fetch
+ it before restarting trace. This must happen within the allowed
+ time frame or is aborted (default is 10 seconds, can be customized with
+
Autostart feature requires additional data to be stored on
+ traced nodes. By default, the data is stored automatically
+ to the file called "ttb_autostart.bin" in the traced node's cwd.
+ Users may decide to change this behaviour (i.e. on diskless
+ nodes) by specifying their own module to handle autostart data
+ storage and retrieval (
+-module(ttb_autostart).
+-export([read_config/0,
+ write_config/1,
+ delete_config/0]).
+
+-define(AUTOSTART_FILENAME, "ttb_autostart.bin").
+
+delete_config() ->
+ file:delete(?AUTOSTART_FILENAME).
+
+read_config() ->
+ case file:read_file(?AUTOSTART_FILENAME) of
+ {ok, Data} -> {ok, binary_to_term(Data)};
+ Error -> Error
+ end.
+
+write_config(Data) ->
+ file:write_file(?AUTOSTART_FILENAME, term_to_binary(Data)).
+
+ Remember that file trace ports buffer the data
+ by default. If the node crashes, trace messages are not
+ flushed to the binary log. If the chance of failure is
+ high, it might be a good idea to automatically flush
+ the buffers every now and then. Passing
The
The command
To be able to use all this information during formatting, it is
- important that the trace information file exists in the same
- directory as the trace log, and that it has the same name as the
- trace log with the additional extension
Except for the process information, everything in the trace
information file is passed on to the handler function when
formatting. The
Note that the overall size of data generated by ttb may be greater + than the wrap specification would suggest - if a traced node restarts + and autoresume is enabled, old wrap log is always stored and + a new one is created. +
Wrap logs can be formatted one by one or all at once. See
The first argument to
The second argument to
A format handler is a fun taking four arguments. This fun will
be called for each trace message in the binary log(s). A simple
@@ -396,10 +542,24 @@ end
By giving the format handler
The actual trace message is passed as the second argument (
By giving the format handler
You may always decide not to format the whole trace data contained
+ in the fetch directory, but analyze single files instead. In order
+ to do so, a single file (or list of files) have to be passed as
+ the first argument to
Wrap logs can be formatted one by one or all in one go. To format one of the wrap logs in a set, give the exact name of the file. To format the whole set of wrap logs, give the name with '*' @@ -407,7 +567,7 @@ end
Start tracing:
-(tiger@durin)1> ttb:tracer(node(),[{file,{wrap,"trace"}}]).
+(tiger@durin)1> ttb:tracer(node(),{file,{wrap,"trace"}}).
{ok,[tiger@durin]}
(tiger@durin)2> ttb:p(...)
...
@@ -443,7 +603,7 @@ ok
to the User's Guide and Reference Manuals for the By giving the format handler
By giving the format handler
As an example this module is used, and the function
-
In the next example, modules
+-module(foo).
+-export([start/0,go/0]).
+
+start() ->
+ spawn(?MODULE, go, []).
+
+go() ->
+ receive
+ stop ->
+ ok;
+ go ->
+ bar:f1(),
+ go()
+ end.
+
-module(bar).
-export([f1/0,f3/0]).
f1() ->
@@ -506,12 +680,23 @@ f1() ->
f2() ->
spawn(?MODULE,f3,[]).
f3() ->
- ok.
- The
Now let's set up the trace.
+
+(tiger@durin)1>%%First we retrieve the Pid to limit traced processes set
+(tiger@durin)1>Pid = foo:start().
+(tiger@durin)2>%%Now we set up tracing
+(tiger@durin)2>ttb:tracer().
+(tiger@durin)3>ttb:p(Pid, [call, return_to, procs, set_on_spawn]).
+(tiger@durin)4>ttb:tpl(bar, []).
+(tiger@durin)5>%%Invoke our test function and see output with et viewer
+(tiger@durin)5>Pid ! go.
+(tiger@durin)6>ttb:stop({format, {handler, ttb:get_et_handler()}}).
+
+
+ This shoud render a result similar to the + following:
Note, that we can use
+(tiger@durin)1>Pid = foo:start().
+(tiger@durin)2>ttb:start_trace([node()],
+ [{bar,[]}],
+ {Pid, [call, return_to, procs, set_on_spawn]}
+ {handler, ttb:get_et_handler()}).
+(tiger@durin)3>Pid ! go.
+(tiger@durin)4>ttb:stop(format).
+
+
If the option
By default
If the option
For the tracing functionality,
+
Use
User defined entries can also be written to a config file by calling the function @@ -720,9 +923,7 @@ ok {ok,[{matched,1},{saved,1}]} (tiger@durin)113> dbg:get_tracer(), seq_trace:reset_trace(). true -(tiger@durin)114> ttb:stop(). -ok -(tiger@durin)115> ttb:format("tiger@durin-ttb"). +(tiger@durin)114> ttb:stop(format). ({<0.158.0>,{shell,evaluator,3},tiger@durin}) call dbg:get_tracer() SeqTrace [0]: ({<0.158.0>,{shell,evaluator,3},tiger@durin}) {<0.237.0>,dbg,tiger@durin} ! {<0.158.0>,{get_tracer,tiger@durin}} @@ -743,9 +944,7 @@ ok (tiger@durin)117> seq_trace:set_token(send,true), dbg:get_tracer(), seq_trace:reset_trace(). true -(tiger@durin)118> ttb:stop(). -ok -(tiger@durin)119> ttb:format("tiger@durin-ttb"). +(tiger@durin)118> ttb:stop(format). SeqTrace [0]: ({<0.158.0>,{shell,evaluator,3},tiger@durin}) {<0.246.0>,dbg,tiger@durin} ! {<0.158.0>,{get_tracer,tiger@durin}} [Serial: {0,1}] -- cgit v1.2.3