Provided by: erlang-manpages_25.3.2.8+dfsg-1ubuntu4.4_all bug

NAME

       seq_trace - Sequential tracing of information transfers.

DESCRIPTION

       Sequential  tracing  makes  it  possible  to trace information flows between processes resulting from one
       initial transfer of information. 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) -> OldVal

              Types:

                 Component = component()
                 Val = OldVal = value()
                 component() = label | serial | flag()
                 flag() =
                     send | 'receive' | print | timestamp | monotonic_timestamp |
                     strict_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  sequential traces can be active simultaneously, label is used to identify
                  the separate traces. Default is 0.

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

                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  information  sending.
                  Default is false.

                set_token('receive', Bool):
                  A  trace  token  flag  (true | false) which enables/disables tracing on information 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() =
                     (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

              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 send set to true has sent information. To may be a
           process identifier, a registered name on a node represented as {NameAtom, NodeAtom}, or a  node  name
           represented  as  an  atom.  From  may  be a process identifier or a node name represented as an atom.
           Message contains the information passed along in this information transfer. If the transfer  is  done
           via message passing, it is the actual message.

         {'receive', Serial, From, To, Message}:
           Used  when  a process To receives information with a trace token that has flag 'receive' set to true.
           To may be a process identifier, or a node name  represented  as  an  atom.  From  may  be  a  process
           identifier  or  a  node name represented as an atom. Message contains the information passed along in
           this information transfer. If the transfer is done via message passing, it is the actual message.

         {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  information  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 information transfers between different local or
       remote processes, where the sequence is initiated by a single transfer. The typical information  transfer
       is  an ordinary Erlang message passed between two processes, but information is transferred also in other
       ways. 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 when information is
       passed between processes. In most cases the information is passed in ordinary messages between processes,
       but information is also passed between processes by other means. For example, by spawning a new  process.
       An  information  transfer  between  two  processes  is  represented  by  a send event and a receive event
       regardless of how it is passed.

       To start a sequential trace, the user must explicitly set the trace token in the process that  will  send
       the first information in a sequence.

       The  trace  token  of a process is set each time the process receives information. This is typically when
       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 information 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.

DIFFERENT INFORMATION TRANSFERS

       Information flows between processes in a lot of different ways. Not all  flows  of  information  will  be
       covered  by  sequential  tracing.  One  example  is information passed via ETS tables. Below is a list of
       information paths that are covered by sequential tracing:

         Message Passing:
           All ordinary messages passed between Erlang processes.

         Exit signals:
           An exit signal is represented as an {'EXIT', Pid, Reason} tuple.

         Process Spawn:
           A process spawn is represented as multiple information transfers. At least one spawn request and  one
           spawn  reply.  The actual amount of information transfers depends on what type of spawn it is and may
           also change in future implementations. Note that this is more or less an internal protocol  that  you
           are  peeking  at.  The spawn request will be represented as a tuple with the first element containing
           the atom spawn_request, but this is more or less all that you can depend on.

   Note:
       If you do ordinary send or receive trace on the system, you will only see ordinary message  passing,  not
       the other information transfers listed above.

   Note:
       When a send event and corresponding receive event do not both correspond to ordinary Erlang messages, the
       Message  part  of the trace messages may not be identical. This since all information not necessarily are
       available when generating the trace messages.

TRACE TOKEN

       Each process has a current trace token which is "invisibly" passed from the parent process on creation of
       the process.

       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 information is received. This is typically when a received message is matched out in  a  receive
           expression, but also when information is received in other ways.

       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
       outside of a trace sequence. The counters are updated at the following occasions:

         * When the process is about to pass along information to another process and the  trace  token  is  not
           empty.  This  typically  occurs  when sending a message, but also, for example, when spawning another
           process.

           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 information passed  to  the  other
           process.

         * 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 information is received that also contains a non-empty trace token. For example, when a  message
           is matched out in a receive expression, or when a new process is spawned.

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

Ericsson AB                                      kernel 8.5.4.2                                  seq_trace(3erl)