Provided by: erlang-manpages_20.2.2+dfsg-1ubuntu2_all bug

NAME

       seq_trace - Sequential tracing of messages.

DESCRIPTION

       Sequential  tracing  makes  it  possible  to trace all messages resulting from one initial
       message. Sequential tracing is independent of the ordinary 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.

DATA TYPES

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

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

EXPORTS

       set_token(Token) -> PreviousToken | ok

              Types:

                 Token = PreviousToken = [] | token()

              Sets the trace token for the calling process to Token. If Token == [] then  tracing
              is  disabled, otherwise Token should be an Erlang 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}

              Types:

                 Component = component()
                 Val = OldVal = value()
                 component() = label | serial | flag()
                 flag() =
                     send |
                     'receive' |
                     print |
                     timestamp |
                     monotonic_timestamp |
                     strict_monotonic_timestamp
                 value() =
                     (Integer :: integer() >= 0) |
                     {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, Integer):
                  The label component is an integer which identifies all events belonging to  the
                  same   sequential   trace.   If   several   sequential  traces  can  be  active
                  simultaneously, label is used to identify the separate traces. Default is 0.

                set_token(serial, SerialValue):
                  SerialValue = {Previous, Current}. The serial component contains 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 false.

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

                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
                  {erlang:monotonic_time(nanosecond), erlang:unique_integer([monotonic])}.

                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 monotonic 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}

              Types:

                 Component = component()
                 Val = value()
                 component() = label | serial | flag()
                 flag() =
                     send |
                     'receive' |
                     print |
                     timestamp |
                     monotonic_timestamp |
                     strict_monotonic_timestamp
                 value() =
                     (Integer :: integer() >= 0) |
                     {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

              Types:

                 TraceInfo = term()

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

       print(Label, TraceInfo) -> ok

              Types:

                 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

              Types:

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

              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 active).

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

       get_system_tracer() -> Tracer

              Types:

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

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

TRACE MESSAGES SENT TO THE SYSTEM TRACER

       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}

       or

       {seq_trace, Label, SeqTraceInfo}

       Where:

       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, TraceInfo) 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

       Sequential  tracing  is a way to trace a sequence of messages sent between different local
       or remote processes, where the sequence is initiated 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, Serial, From}. The  trace  token  is  passed
       invisibly with each message.

       To  start  a sequential trace, the user must explicitly set the trace token 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.

   Note:
       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 fundamental concepts.

TRACE TOKEN

       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 current 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 seq_trace:set_token/1,2

         * 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 empty.

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

SERIAL

       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 messages 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 following 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 message.

         * 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 true.

           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.

PERFORMANCE CONSIDERATIONS

       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.

PORTS

       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.

DISTRIBUTION

       Sequential tracing between nodes is performed transparently. This applies 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.

EXAMPLE OF USE

       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 this:

       -module(seqex).
       -compile(export_all).

       loop(Port) ->
           receive
               {Port,Message} ->
                   seq_trace:set_token(label,17),
                   seq_trace:set_token('receive',true),
                   seq_trace:set_token(print,true),
                   seq_trace:print(17,"**** Trace Started ****"),
                   call_server ! {self(),the_message};
               {ack,Ack} ->
                   ok
           end,
           loop(Port).

       And a registered process call_server with Pid == <0.31.0> like this:

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

       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
       {<0.30.0>,the_message}
       17:<0.31.0> Info {2,3} WITH
       "We are here now"
       17:<0.30.0> Received {2,4} FROM <0.31.0> WITH
       {ack,{received,the_message}}

       The implementation of a system tracer process that produces this printout  can  look  like
       this:

       tracer() ->
           receive
               {seq_trace,Label,TraceInfo} ->
                  print_trace(Label,TraceInfo,false);
               {seq_trace,Label,TraceInfo,Ts} ->
                  print_trace(Label,TraceInfo,Ts);
               Other -> ignore
           end,
           tracer().

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

       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",
                     [To,Serial,From,Message]);
       print_trace({send,Serial,From,To,Message}) ->
           io:format("~p Sent ~p TO ~p WITH~n~p~n",
                     [From,Serial,To,Message]).

       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
           ok.

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

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