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

Ericsson AB                                       kernel 5.4.1                                   seq_trace(3erl)