1seq_trace(3) Erlang Module Definition seq_trace(3)
2
3
4
6 seq_trace - Sequential tracing of messages.
7
9 Sequential tracing makes it possible to trace all messages resulting
10 from one initial message. Sequential tracing is independent of the
11 ordinary tracing in Erlang, which is controlled by the erlang:trace/3
12 BIF. For more information about what sequential tracing is and how it
13 can be used, see section Sequential Tracing.
14
15 seq_trace provides functions that control all aspects of sequential
16 tracing. There are functions for activation, deactivation, inspection,
17 and for collection of the trace output.
18
20 token() = {integer(), boolean(), term(), term(), term()}
21
22 An opaque term (a tuple) representing a trace token.
23
25 set_token(Token) -> PreviousToken | ok
26
27 Types:
28
29 Token = PreviousToken = [] | token()
30
31 Sets the trace token for the calling process to Token. If Token
32 == [] then tracing is disabled, otherwise Token should be an
33 Erlang term returned from get_token/0 or set_token/1.
34 set_token/1 can be used to temporarily exclude message passing
35 from the trace by setting the trace token to empty like this:
36
37 OldToken = seq_trace:set_token([]), % set to empty and save
38 % old value
39 % do something that should not be part of the trace
40 io:format("Exclude the signalling caused by this~n"),
41 seq_trace:set_token(OldToken), % activate the trace token again
42
43 Returns the previous value of the trace token.
44
45 set_token(Component, Val) -> {Component, OldVal}
46
47 Types:
48
49 Component = component()
50 Val = OldVal = value()
51 component() = label | serial | flag()
52 flag() =
53 send |
54 'receive' |
55 print |
56 timestamp |
57 monotonic_timestamp |
58 strict_monotonic_timestamp
59 value() =
60 (Integer :: integer() >= 0) |
61 {Previous :: integer() >= 0, Current :: integer() >= 0} |
62 (Bool :: boolean())
63
64 Sets the individual Component of the trace token to Val. Returns
65 the previous value of the component.
66
67 set_token(label, Integer):
68 The label component is an integer which identifies all
69 events belonging to the same sequential trace. If several
70 sequential traces can be active simultaneously, label is
71 used to identify the separate traces. Default is 0.
72
73 set_token(serial, SerialValue):
74 SerialValue = {Previous, Current}. The serial component con‐
75 tains counters which enables the traced messages to be
76 sorted, should never be set explicitly by the user as these
77 counters are updated automatically. Default is {0, 0}.
78
79 set_token(send, Bool):
80 A trace token flag (true | false) which enables/disables
81 tracing on message sending. Default is false.
82
83 set_token('receive', Bool):
84 A trace token flag (true | false) which enables/disables
85 tracing on message reception. Default is false.
86
87 set_token(print, Bool):
88 A trace token flag (true | false) which enables/disables
89 tracing on explicit calls to seq_trace:print/1. Default is
90 false.
91
92 set_token(timestamp, Bool):
93 A trace token flag (true | false) which enables/disables a
94 timestamp to be generated for each traced event. Default is
95 false.
96
97 set_token(strict_monotonic_timestamp, Bool):
98 A trace token flag (true | false) which enables/disables a
99 strict monotonic timestamp to be generated for each traced
100 event. Default is false. Timestamps will consist of Erlang
101 monotonic time and a monotonically increasing integer. The
102 time-stamp has the same format and value as produced by
103 {erlang:monotonic_time(nanosecond), erlang:unique_inte‐
104 ger([monotonic])}.
105
106 set_token(monotonic_timestamp, Bool):
107 A trace token flag (true | false) which enables/disables a
108 strict monotonic timestamp to be generated for each traced
109 event. Default is false. Timestamps will use Erlang mono‐
110 tonic time. The time-stamp has the same format and value as
111 produced by erlang:monotonic_time(nanosecond).
112
113 If multiple timestamp flags are passed, timestamp has precedence
114 over strict_monotonic_timestamp which in turn has precedence
115 over monotonic_timestamp. All timestamp flags are remembered, so
116 if two are passed and the one with highest precedence later is
117 disabled the other one will become active.
118
119 get_token() -> [] | token()
120
121 Returns the value of the trace token for the calling process. If
122 [] is returned, it means that tracing is not active. Any other
123 value returned is the value of an active trace token. The value
124 returned can be used as input to the set_token/1 function.
125
126 get_token(Component) -> {Component, Val}
127
128 Types:
129
130 Component = component()
131 Val = value()
132 component() = label | serial | flag()
133 flag() =
134 send |
135 'receive' |
136 print |
137 timestamp |
138 monotonic_timestamp |
139 strict_monotonic_timestamp
140 value() =
141 (Integer :: integer() >= 0) |
142 {Previous :: integer() >= 0, Current :: integer() >= 0} |
143 (Bool :: boolean())
144
145 Returns the value of the trace token component Component. See
146 set_token/2 for possible values of Component and Val.
147
148 print(TraceInfo) -> ok
149
150 Types:
151
152 TraceInfo = term()
153
154 Puts the Erlang term TraceInfo into the sequential trace output
155 if the calling process currently is executing within a sequen‐
156 tial trace and the print flag of the trace token is set.
157
158 print(Label, TraceInfo) -> ok
159
160 Types:
161
162 Label = integer()
163 TraceInfo = term()
164
165 Same as print/1 with the additional condition that TraceInfo is
166 output only if Label is equal to the label component of the
167 trace token.
168
169 reset_trace() -> true
170
171 Sets the trace token to empty for all processes on the local
172 node. The process internal counters used to create the serial of
173 the trace token is set to 0. The trace token is set to empty for
174 all messages in message queues. Together this will effectively
175 stop all ongoing sequential tracing in the local node.
176
177 set_system_tracer(Tracer) -> OldTracer
178
179 Types:
180
181 Tracer = OldTracer = tracer()
182 tracer() =
183 (Pid :: pid()) |
184 port() |
185 (TracerModule :: {module(), term()}) |
186 false
187
188 Sets the system tracer. The system tracer can be either a
189 process, port or tracer module denoted by Tracer. Returns the
190 previous value (which can be false if no system tracer is
191 active).
192
193 Failure: {badarg, Info}} if Pid is not an existing local pid.
194
195 get_system_tracer() -> Tracer
196
197 Types:
198
199 Tracer = tracer()
200 tracer() =
201 (Pid :: pid()) |
202 port() |
203 (TracerModule :: {module(), term()}) |
204 false
205
206 Returns the pid, port identifier or tracer module of the current
207 system tracer or false if no system tracer is activated.
208
210 The format of the messages is one of the following, depending on if
211 flag timestamp of the trace token is set to true or false:
212
213 {seq_trace, Label, SeqTraceInfo, TimeStamp}
214
215 or
216
217 {seq_trace, Label, SeqTraceInfo}
218
219 Where:
220
221 Label = int()
222 TimeStamp = {Seconds, Milliseconds, Microseconds}
223 Seconds = Milliseconds = Microseconds = int()
224
225 SeqTraceInfo can have the following formats:
226
227 {send, Serial, From, To, Message}:
228 Used when a process From with its trace token flag print set to
229 true has sent a message.
230
231 {'receive', Serial, From, To, Message}:
232 Used when a process To receives a message with a trace token that
233 has flag 'receive' set to true.
234
235 {print, Serial, From, _, Info}:
236 Used when a process From has called seq_trace:print(Label, Trace‐
237 Info) and has a trace token with flag print set to true, and label
238 set to Label.
239
240 Serial is a tuple {PreviousSerial, ThisSerial}, where:
241
242 * Integer PreviousSerial denotes the serial counter passed in the
243 last received message that carried a trace token. If the process is
244 the first in a new sequential trace, PreviousSerial is set to the
245 value of the process internal "trace clock".
246
247 * Integer ThisSerial is the serial counter that a process sets on
248 outgoing messages. It is based on the process internal "trace
249 clock", which is incremented by one before it is attached to the
250 trace token in the message.
251
253 Sequential tracing is a way to trace a sequence of messages sent
254 between different local or remote processes, where the sequence is ini‐
255 tiated by a single message. In short, it works as follows:
256
257 Each process has a trace token, which can be empty or not empty. When
258 not empty, the trace token can be seen as the tuple {Label, Flags,
259 Serial, From}. The trace token is passed invisibly with each message.
260
261 To start a sequential trace, the user must explicitly set the trace
262 token in the process that will send the first message in a sequence.
263
264 The trace token of a process is set each time the process matches a
265 message in a receive statement, according to the trace token carried by
266 the received message, empty or not.
267
268 On each Erlang node, a process can be set as the system tracer. This
269 process will receive trace messages each time a message with a trace
270 token is sent or received (if the trace token flag send or 'receive' is
271 set). The system tracer can then print each trace event, write it to a
272 file, or whatever suitable.
273
274 Note:
275 The system tracer only receives those trace events that occur locally
276 within the Erlang node. To get the whole picture of a sequential trace,
277 involving processes on many Erlang nodes, the output from the system
278 tracer on each involved node must be merged (offline).
279
280
281 The following sections describe sequential tracing and its most funda‐
282 mental concepts.
283
285 Each process has a current trace token. Initially, the token is empty.
286 When the process sends a message to another process, a copy of the cur‐
287 rent token is sent "invisibly" along with the message.
288
289 The current token of a process is set in one of the following two ways:
290
291 * Explicitly by the process itself, through a call to
292 seq_trace:set_token/1,2
293
294 * When a message is received
295
296 In both cases, the current token is set. In particular, if the token of
297 a received message is empty, the current token of the process is set to
298 empty.
299
300 A trace token contains a label and a set of flags. Both the label and
301 the flags are set in both alternatives above.
302
304 The trace token contains a component called serial. It consists of two
305 integers, Previous and Current. The purpose is to uniquely identify
306 each traced event within a trace sequence, as well as to order the mes‐
307 sages chronologically and in the different branches, if any.
308
309 The algorithm for updating Serial can be described as follows:
310
311 Let each process have two counters, prev_cnt and curr_cnt, both are set
312 to 0 when a process is created. The counters are updated at the follow‐
313 ing occasions:
314
315 * When the process is about to send a message and the trace token is
316 not empty.
317
318 Let the serial of the trace token be tprev and tcurr.
319
320 curr_cnt := curr_cnt + 1
321 tprev := prev_cnt
322 tcurr := curr_cnt
323
324 The trace token with tprev and tcurr is then passed along with the
325 message.
326
327 * When the process calls seq_trace:print(Label, Info), Label matches
328 the label part of the trace token and the trace token print flag is
329 true.
330
331 The algorithm is the same as for send above.
332
333 * When a message is received and contains a non-empty trace token.
334
335 The process trace token is set to the trace token from the message.
336
337 Let the serial of the trace token be tprev and tcurr.
338
339 if (curr_cnt < tcurr )
340 curr_cnt := tcurr
341 prev_cnt := tcurr
342
343 curr_cnt of a process is incremented each time the process is involved
344 in a sequential trace. The counter can reach its limit (27 bits) if a
345 process is very long-lived and is involved in much sequential tracing.
346 If the counter overflows, the serial for ordering of the trace events
347 cannot be used. To prevent the counter from overflowing in the middle
348 of a sequential trace, function seq_trace:reset_trace/0 can be called
349 to reset prev_cnt and curr_cnt of all processes in the Erlang node.
350 This function also sets all trace tokens in processes and their message
351 queues to empty, and thus stops all ongoing sequential tracing.
352
354 The performance degradation for a system that is enabled for sequential
355 tracing is negligible as long as no tracing is activated. When tracing
356 is activated, there is an extra cost for each traced message, but all
357 other messages are unaffected.
358
360 Sequential tracing is not performed across ports.
361
362 If the user for some reason wants to pass the trace token to a port,
363 this must be done manually in the code of the port controlling process.
364 The port controlling processes have to check the appropriate sequential
365 trace settings (as obtained from seq_trace:get_token/1) and include
366 trace information in the message data sent to their respective ports.
367
368 Similarly, for messages received from a port, a port controller has to
369 retrieve trace-specific information, and set appropriate sequential
370 trace flags through calls to seq_trace:set_token/2.
371
373 Sequential tracing between nodes is performed transparently. This
374 applies to C-nodes built with Erl_Interface too. A C-node built with
375 Erl_Interface only maintains one trace token, which means that the C-
376 node appears as one process from the sequential tracing point of view.
377
379 This example gives a rough idea of how the new primitives can be used
380 and what kind of output it produces.
381
382 Assume that you have an initiating process with Pid == <0.30.0> like
383 this:
384
385 -module(seqex).
386 -compile(export_all).
387
388 loop(Port) ->
389 receive
390 {Port,Message} ->
391 seq_trace:set_token(label,17),
392 seq_trace:set_token('receive',true),
393 seq_trace:set_token(print,true),
394 seq_trace:print(17,"**** Trace Started ****"),
395 call_server ! {self(),the_message};
396 {ack,Ack} ->
397 ok
398 end,
399 loop(Port).
400
401 And a registered process call_server with Pid == <0.31.0> like this:
402
403 loop() ->
404 receive
405 {PortController,Message} ->
406 Ack = {received, Message},
407 seq_trace:print(17,"We are here now"),
408 PortController ! {ack,Ack}
409 end,
410 loop().
411
412 A possible output from the system's sequential_tracer can be like this:
413
414 17:<0.30.0> Info {0,1} WITH
415 "**** Trace Started ****"
416 17:<0.31.0> Received {0,2} FROM <0.30.0> WITH
417 {<0.30.0>,the_message}
418 17:<0.31.0> Info {2,3} WITH
419 "We are here now"
420 17:<0.30.0> Received {2,4} FROM <0.31.0> WITH
421 {ack,{received,the_message}}
422
423 The implementation of a system tracer process that produces this print‐
424 out can look like this:
425
426 tracer() ->
427 receive
428 {seq_trace,Label,TraceInfo} ->
429 print_trace(Label,TraceInfo,false);
430 {seq_trace,Label,TraceInfo,Ts} ->
431 print_trace(Label,TraceInfo,Ts);
432 Other -> ignore
433 end,
434 tracer().
435
436 print_trace(Label,TraceInfo,false) ->
437 io:format("~p:",[Label]),
438 print_trace(TraceInfo);
439 print_trace(Label,TraceInfo,Ts) ->
440 io:format("~p ~p:",[Label,Ts]),
441 print_trace(TraceInfo).
442
443 print_trace({print,Serial,From,_,Info}) ->
444 io:format("~p Info ~p WITH~n~p~n", [From,Serial,Info]);
445 print_trace({'receive',Serial,From,To,Message}) ->
446 io:format("~p Received ~p FROM ~p WITH~n~p~n",
447 [To,Serial,From,Message]);
448 print_trace({send,Serial,From,To,Message}) ->
449 io:format("~p Sent ~p TO ~p WITH~n~p~n",
450 [From,Serial,To,Message]).
451
452 The code that creates a process that runs this tracer function and sets
453 that process as the system tracer can look like this:
454
455 start() ->
456 Pid = spawn(?MODULE,tracer,[]),
457 seq_trace:set_system_tracer(Pid), % set Pid as the system tracer
458 ok.
459
460 With a function like test/0, the whole example can be started:
461
462 test() ->
463 P = spawn(?MODULE, loop, [port]),
464 register(call_server, spawn(?MODULE, loop, [])),
465 start(),
466 P ! {port,message}.
467
468
469
470Ericsson AB kernel 5.4.3.2 seq_trace(3)