Skip site navigation (1)Skip section navigation (2)

FreeBSD Manual Pages


home | help
seq_trace(3)		   Erlang Module Definition		  seq_trace(3)

       seq_trace - Sequential tracing of messages.

       Sequential  tracing  makes  it possible to trace	all messages resulting
       from one	initial	message. Sequential tracing is independent of the  or-
       dinary  tracing	in  Erlang,  which is controlled by the	erlang:trace/3
       BIF. For	more information about what sequential tracing is and  how  it
       can be used, see	section	Sequential Tracing.

       seq_trace  provides  functions  that  control all aspects of sequential
       tracing.	There are functions for	activation, deactivation,  inspection,
       and for collection of the trace output.

       token() = {integer(), boolean(),	term(),	term(),	term()}

	      An opaque	term (a	tuple) representing a trace token.

       set_token(Token)	-> PreviousToken | ok


		 Token = PreviousToken = [] | token()

	      Sets  the	trace token for	the calling process to Token. If Token
	      == [] then tracing is disabled, otherwise	Token should be	an Er-
	      lang  term returned from get_token/0 or set_token/1. set_token/1
	      can be used to temporarily  exclude  message  passing  from  the
	      trace by setting the trace token to empty	like this:

	      OldToken = seq_trace:set_token([]), % set	to empty and save
						  % old	value
	      %	do something that should not be	part of	the trace
	      io:format("Exclude the signalling	caused by this~n"),
	      seq_trace:set_token(OldToken), % activate	the trace token	again

	      Returns the previous value of the	trace token.

       set_token(Component, Val) -> {Component,	OldVal}


		 Component = component()
		 Val = OldVal =	value()
		 component() = label | serial |	flag()
		 flag()	=
		     send |
		     'receive' |
		     print |
		     timestamp |
		     monotonic_timestamp |
		 value() =
		     (Label :: term()) |
		     {Previous :: integer() >= 0, Current :: integer() >= 0} |
		     (Bool :: boolean())

	      Sets the individual Component of the trace token to Val. Returns
	      the previous value of the	component.

		set_token(label, Label):
		  The label component is a term	which  identifies  all	events
		  belonging  to	 the same sequential trace. If several sequen-
		  tial traces can be active simultaneously, label is  used  to
		  identify the separate	traces.	Default	is 0.

		Labels	were  restricted  to  small  signed integers (28 bits)
		prior to OTP 21. The trace token will be silenty dropped if it
		crosses	over to	a node that does not support the label.

		set_token(serial, SerialValue):
		  SerialValue =	{Previous, Current}. The serial	component con-
		  tains	counters which	enables	 the  traced  messages	to  be
		  sorted,  should never	be set explicitly by the user as these
		  counters are updated automatically. Default is {0, 0}.

		set_token(send,	Bool):
		  A trace token	flag (true  |  false)  which  enables/disables
		  tracing on message sending. Default is false.

		set_token('receive', Bool):
		  A  trace  token  flag	 (true | false)	which enables/disables
		  tracing on message reception.	Default	is false.

		set_token(print, Bool):
		  A trace token	flag (true  |  false)  which  enables/disables
		  tracing  on  explicit	calls to seq_trace:print/1. Default is

		set_token(timestamp, Bool):
		  A trace token	flag (true | false) which  enables/disables  a
		  timestamp  to	be generated for each traced event. Default is

		set_token(strict_monotonic_timestamp, Bool):
		  A trace token	flag (true | false) which  enables/disables  a
		  strict  monotonic  timestamp to be generated for each	traced
		  event. Default is false. Timestamps will consist  of	Erlang
		  monotonic  time  and a monotonically increasing integer. The
		  time-stamp has the same format and value as produced by {er-
		  lang:monotonic_time(nanosecond),	   erlang:unique_inte-

		set_token(monotonic_timestamp, Bool):
		  A trace token	flag (true | false) which  enables/disables  a
		  strict  monotonic  timestamp to be generated for each	traced
		  event. Default is false. Timestamps will  use	 Erlang	 mono-
		  tonic	 time. The time-stamp has the same format and value as
		  produced by erlang:monotonic_time(nanosecond).

	      If multiple timestamp flags are passed, timestamp	has precedence
	      over  strict_monotonic_timestamp	which  in  turn	has precedence
	      over monotonic_timestamp.	All timestamp flags are	remembered, so
	      if  two  are passed and the one with highest precedence later is
	      disabled the other one will become active.

       get_token() -> [] | token()

	      Returns the value	of the trace token for the calling process. If
	      []  is  returned,	it means that tracing is not active. Any other
	      value returned is	the value of an	active trace token. The	 value
	      returned can be used as input to the set_token/1 function.

       get_token(Component) -> {Component, Val}


		 Component = component()
		 Val = value()
		 component() = label | serial |	flag()
		 flag()	=
		     send |
		     'receive' |
		     print |
		     timestamp |
		     monotonic_timestamp |
		 value() =
		     (Label :: term()) |
		     {Previous :: integer() >= 0, Current :: integer() >= 0} |
		     (Bool :: boolean())

	      Returns  the  value  of the trace	token component	Component. See
	      set_token/2 for possible values of Component and Val.

       print(TraceInfo)	-> ok


		 TraceInfo = term()

	      Puts the Erlang term TraceInfo into the sequential trace	output
	      if  the  calling process currently is executing within a sequen-
	      tial trace and the print flag of the trace token is set.

       print(Label, TraceInfo) -> ok


		 Label = integer()
		 TraceInfo = term()

	      Same as print/1 with the additional condition that TraceInfo  is
	      output  only  if	Label  is  equal to the	label component	of the
	      trace token.

       reset_trace() ->	true

	      Sets the trace token to empty for	all  processes	on  the	 local
	      node. The	process	internal counters used to create the serial of
	      the trace	token is set to	0. The trace token is set to empty for
	      all  messages  in	message	queues.	Together this will effectively
	      stop all ongoing sequential tracing in the local node.

       set_system_tracer(Tracer) -> OldTracer


		 Tracer	= OldTracer = tracer()
		 tracer() =
		     (Pid :: pid()) |
		     port() |
		     (TracerModule :: {module(), term()}) |

	      Sets the system tracer.  The  system  tracer  can	 be  either  a
	      process,	port  or  tracer module	denoted	by Tracer. Returns the
	      previous value (which can	be false if no system  tracer  is  ac-

	      Failure: {badarg,	Info}} if Pid is not an	existing local pid.

       get_system_tracer() -> Tracer


		 Tracer	= tracer()
		 tracer() =
		     (Pid :: pid()) |
		     port() |
		     (TracerModule :: {module(), term()}) |

	      Returns the pid, port identifier or tracer module	of the current
	      system tracer or false if	no system tracer is activated.

       The format of the messages is one of the	 following,  depending	on  if
       flag timestamp of the trace token is set	to true	or false:

       {seq_trace, Label, SeqTraceInfo,	TimeStamp}


       {seq_trace, Label, SeqTraceInfo}


       Label = int()
       TimeStamp = {Seconds, Milliseconds, Microseconds}
	 Seconds = Milliseconds	= Microseconds = int()

       SeqTraceInfo can	have the following formats:

	 {send,	Serial,	From, To, Message}:
	   Used	 when  a  process  From	with its trace token flag print	set to
	   true	has sent a message.

	 {'receive', Serial, From, To, Message}:
	   Used	when a process To receives a message with a trace  token  that
	   has flag 'receive' set to true.

	 {print, Serial, From, _, Info}:
	   Used	 when  a process From has called seq_trace:print(Label,	Trace-
	   Info) and has a trace token with flag print set to true, and	 label
	   set to Label.

       Serial is a tuple {PreviousSerial, ThisSerial}, where:

	 * Integer  PreviousSerial  denotes  the  serial counter passed	in the
	   last	received message that carried a	trace token. If	the process is
	   the	first  in a new	sequential trace, PreviousSerial is set	to the
	   value of the	process	internal "trace	clock".

	 * Integer ThisSerial is the serial counter that  a  process  sets  on
	   outgoing  messages.	It  is	based  on  the process internal	"trace
	   clock", which is incremented	by one before it is  attached  to  the
	   trace token in the message.

       Sequential  tracing  is	a way to trace a sequence of messages sent be-
       tween different local or	remote processes, where	the sequence is	initi-
       ated by a single	message. In short, it works as follows:

       Each  process  has a trace token, which can be empty or not empty. When
       not empty, the trace token can be seen as the tuple {Label, Flags,  Se-
       rial, From}. The	trace token is passed invisibly	with each message.

       To start	a sequential trace, the	user must explicitly set the trace to-
       ken in the process that will send the first message in a	sequence.

       The trace token of a process is set each	time  the  process  matches  a
       message in a receive statement, according to the	trace token carried by
       the received message, empty or not.

       On each Erlang node, a process can be set as the	 system	 tracer.  This
       process	will  receive  trace messages each time	a message with a trace
       token is	sent or	received (if the trace token flag send or 'receive' is
       set).  The system tracer	can then print each trace event, write it to a
       file, or	whatever suitable.

       The system tracer only receives those trace events that	occur  locally
       within the Erlang node. To get the whole	picture	of a sequential	trace,
       involving processes on many Erlang nodes, the output  from  the	system
       tracer on each involved node must be merged (offline).

       The  following sections describe	sequential tracing and its most	funda-
       mental concepts.

       Each process has	a current trace	token. Initially, the token is	empty.
       When the	process	sends a	message	to another process, a copy of the cur-
       rent token is sent "invisibly" along with the message.

       The current token of a process is set in	one of the following two ways:

	 * Explicitly	by   the   process   itself,   through	 a   call   to

	 * When	a message is received

       In both cases, the current token	is set.	In particular, if the token of
       a received message is empty, the	current	token of the process is	set to

       A  trace	 token contains	a label	and a set of flags. Both the label and
       the flags are set in both alternatives above.

       The trace token contains	a component called serial. It consists of  two
       integers,  Previous  and	 Current.  The purpose is to uniquely identify
       each traced event within	a trace	sequence, as well as to	order the mes-
       sages chronologically and in the	different branches, if any.

       The algorithm for updating Serial can be	described as follows:

       Let each	process	have two counters, prev_cnt and	curr_cnt, both are set
       to 0 when a process is created. The counters are	updated	at the follow-
       ing occasions:

	 * When	 the process is	about to send a	message	and the	trace token is
	   not empty.

	   Let the serial of the trace token be	tprev and tcurr.

	 curr_cnt := curr_cnt +	1
	 tprev := prev_cnt
	 tcurr := curr_cnt

	   The trace token with	tprev and tcurr	is then	passed along with  the

	 * When	 the process calls seq_trace:print(Label, Info), Label matches
	   the label part of the trace token and the trace token print flag is

	   The algorithm is the	same as	for send above.

	 * When	a message is received and contains a non-empty trace token.

	   The process trace token is set to the trace token from the message.

	   Let the serial of the trace token be	tprev and tcurr.

	 if (curr_cnt <	tcurr )
	    curr_cnt :=	tcurr
	 prev_cnt := tcurr

       curr_cnt	 of a process is incremented each time the process is involved
       in a sequential trace. The counter can reach its	limit (27 bits)	 if  a
       process	is very	long-lived and is involved in much sequential tracing.
       If the counter overflows, the serial for	ordering of the	 trace	events
       cannot  be  used. To prevent the	counter	from overflowing in the	middle
       of a sequential trace, function seq_trace:reset_trace/0 can  be	called
       to  reset  prev_cnt  and	 curr_cnt of all processes in the Erlang node.
       This function also sets all trace tokens	in processes and their message
       queues to empty,	and thus stops all ongoing sequential tracing.

       The performance degradation for a system	that is	enabled	for sequential
       tracing is negligible as	long as	no tracing is activated. When  tracing
       is  activated,  there is	an extra cost for each traced message, but all
       other messages are unaffected.

       Sequential tracing is not performed across ports.

       If the user for some reason wants to pass the trace token  to  a	 port,
       this must be done manually in the code of the port controlling process.
       The port	controlling processes have to check the	appropriate sequential
       trace  settings	(as  obtained  from seq_trace:get_token/1) and include
       trace information in the	message	data sent to their respective ports.

       Similarly, for messages received	from a port, a port controller has  to
       retrieve	 trace-specific	 information,  and  set	appropriate sequential
       trace flags through calls to seq_trace:set_token/2.

       Sequential tracing between nodes	is performed transparently.  This  ap-
       plies  to  C-nodes  built  with	Erl_Interface too. A C-node built with
       Erl_Interface only maintains one	trace token, which means that  the  C-
       node appears as one process from	the sequential tracing point of	view.

       This  example  gives a rough idea of how	the new	primitives can be used
       and what	kind of	output it produces.

       Assume that you have an initiating process with Pid  ==	_0.30.0_  like


       loop(Port) ->
	       {Port,Message} ->
		   seq_trace:print(17,"**** Trace Started ****"),
		   call_server ! {self(),the_message};
	       {ack,Ack} ->

       And a registered	process	call_server with Pid ==	_0.31.0_ like this:

       loop() ->
	       {PortController,Message}	->
		   Ack = {received, Message},
		   seq_trace:print(17,"We are here now"),
		   PortController ! {ack,Ack}

       A possible output from the system's sequential_tracer can be like this:

       17:<0.30.0> Info	{0,1} WITH
       "**** Trace Started ****"
       17:<0.31.0> Received {0,2} FROM <0.30.0>	WITH
       17:<0.31.0> Info	{2,3} WITH
       "We are here now"
       17:<0.30.0> Received {2,4} FROM <0.31.0>	WITH

       The implementation of a system tracer process that produces this	print-
       out can look like this:

       tracer()	->
	       {seq_trace,Label,TraceInfo} ->
	       {seq_trace,Label,TraceInfo,Ts} ->
	       Other ->	ignore

       print_trace(Label,TraceInfo,false) ->
       print_trace(Label,TraceInfo,Ts) ->
	   io:format("~p ~p:",[Label,Ts]),

       print_trace({print,Serial,From,_,Info}) ->
	   io:format("~p Info ~p WITH~n~p~n", [From,Serial,Info]);
       print_trace({'receive',Serial,From,To,Message}) ->
	   io:format("~p Received ~p FROM ~p WITH~n~p~n",
       print_trace({send,Serial,From,To,Message}) ->
	   io:format("~p Sent ~p TO ~p WITH~n~p~n",

       The code	that creates a process that runs this tracer function and sets
       that process as the system tracer can look like this:

       start() ->
	   Pid = spawn(?MODULE,tracer,[]),
	   seq_trace:set_system_tracer(Pid), % set Pid as the system tracer

       With a function like test/0, the	whole example can be started:

       test() ->
	   P = spawn(?MODULE, loop, [port]),
	   register(call_server, spawn(?MODULE,	loop, [])),
	   P ! {port,message}.

Ericsson AB			  kernel 6.3			  seq_trace(3)


Want to link to this manual page? Use this URL:

home | help