1erl_tracer(3)              Erlang Module Definition              erl_tracer(3)
2
3
4

NAME

6       erl_tracer - Erlang tracer behavior.
7

DESCRIPTION

9       This behavior module implements the back end of the Erlang tracing sys‐
10       tem. The functions in this module are called whenever a trace probe  is
11       triggered.  Both the enabled and trace functions are called in the con‐
12       text of the entity that triggered the trace probe. This means that  the
13       overhead  by having the tracing enabled is greatly effected by how much
14       time is spent in these functions. So, do as little work as possible  in
15       these functions.
16
17   Note:
18       All  functions in this behavior must be implemented as NIFs. This limi‐
19       tation can be removed in a future releases. An  example  tracer  module
20       NIF implementation is provided at the end of this page.
21
22
23   Warning:
24       Do not send messages or issue port commands to the Tracee in any of the
25       callbacks. This is not allowed and  can  cause  all  sorts  of  strange
26       behavior, including, but not limited to, infinite recursions.
27
28

DATA TYPES

30       trace_tag_call() =
31           call | return_to | return_from | exception_from
32
33       trace_tag_gc() =
34           gc_minor_start | gc_minor_end | gc_major_start | gc_major_end
35
36       trace_tag_ports() =
37           open | closed | link | unlink | getting_linked |
38           getting_unlinked
39
40       trace_tag_procs() =
41           spawn | spawned | exit | link | unlink | getting_linked |
42           getting_unlinked | register | unregister
43
44       trace_tag_receive() = 'receive'
45
46       trace_tag_running_ports() =
47           in | out | in_exiting | out_exiting | out_exited
48
49       trace_tag_running_procs() =
50           in | out | in_exiting | out_exiting | out_exited
51
52       trace_tag_send() = send | send_to_non_existing_process
53
54       trace_tag() =
55           trace_tag_send() |
56           trace_tag_receive() |
57           trace_tag_call() |
58           trace_tag_procs() |
59           trace_tag_ports() |
60           trace_tag_running_procs() |
61           trace_tag_running_ports() |
62           trace_tag_gc()
63
64              The  different  trace  tags that the tracer is called with. Each
65              trace tag is described in detail in Module:trace/5.
66
67       tracee() = port() | pid() | undefined
68
69              The process or port that the trace belongs to.
70
71       trace_opts() =
72           #{extra => term(),
73             match_spec_result => term(),
74             scheduler_id => integer() >= 0,
75             timestamp =>
76                 timestamp | cpu_timestamp | monotonic | strict_monotonic}
77
78              The options for the tracee:
79
80                timestamp:
81                  If set the tracer has  been  requested  to  include  a  time
82                  stamp.
83
84                extra:
85                  If set the tracepoint has included additional data about the
86                  trace event. What the additional data is  depends  on  which
87                  TraceTag  has  been  triggered.  The extra trace data corre‐
88                  sponds to the fifth element in the trace tuples described in
89                  erlang:trace/3.
90
91                match_spec_result:
92                  If  set  the tracer has been requested to include the output
93                  of a match specification that was run.
94
95                scheduler_id:
96                  If set the scheduler id is to be included by the tracer.
97
98       tracer_state() = term()
99
100              The   state   specified   when   calling   erlang:trace(PidPort‐
101              Spec,true,[{tracer,Module,TracerState}]). The tracer state is an
102              immutable value that is passed to erl_tracer callbacks and is to
103              contain all the data that is needed to generate the trace event.
104

CALLBACK FUNCTIONS

106       The  following functions are to be exported from an erl_tracer callback
107       module:
108
109         Module:enabled/3:
110           Mandatory
111
112         Module:trace/5:
113           Mandatory
114
115         Module:enabled_call/3:
116           Optional
117
118         Module:trace_call/5:
119           Optional
120
121         Module:enabled_garbage_collection/3:
122           Optional
123
124         Module:trace_garbage_collection/5:
125           Optional
126
127         Module:enabled_ports/3:
128           Optional
129
130         Module:trace_ports/5:
131           Optional
132
133         Module:enabled_procs/3:
134           Optional
135
136         Module:trace_procs/5:
137           Optional
138
139         Module:enabled_receive/3:
140           Optional
141
142         Module:trace_receive/5:
143           Optional
144
145         Module:enabled_running_ports/3:
146           Optional
147
148         Module:trace_running_ports/5:
149           Optional
150
151         Module:enabled_running_procs/3:
152           Optional
153
154         Module:trace_running_procs/5:
155           Optional
156
157         Module:enabled_send/3:
158           Optional
159
160         Module:trace_send/5:
161           Optional
162

EXPORTS

164       Module:enabled(TraceTag, TracerState, Tracee) -> Result
165
166              Types:
167
168                 TraceTag =  trace_tag() | trace_status
169                 TracerState = term()
170                 Tracee = tracee()
171                 Result = trace | discard | remove
172
173              This callback is called whenever a tracepoint is  triggered.  It
174              allows  the  tracer to decide whether a trace is to be generated
175              or not. This check is made as early as  possible  to  limit  the
176              amount   of  overhead  associated  with  tracing.  If  trace  is
177              returned, the necessary trace data  is  created  and  the  trace
178              callback  of  the tracer is called. If discard is returned, this
179              trace call is discarded and no call to trace is done.
180
181              trace_status is a special type of TraceTag,  which  is  used  to
182              check  if the tracer is still to be active. It is called in mul‐
183              tiple scenarios, but most significantly it is used when  tracing
184              is  started  using  this  tracer. If remove is returned when the
185              trace_status is checked, the tracer is removed from the tracee.
186
187              This function can be called multiple times per tracepoint, so it
188              is important that it is both fast and without side effects.
189
190       Module:enabled_call(TraceTag, TracerState, Tracee) -> Result
191
192              Types:
193
194                 TraceTag =  trace_tag_call()
195                 TracerState = term()
196                 Tracee = tracee()
197                 Result = trace | discard | remove
198
199              This  callback  is  called whenever a tracepoint with trace flag
200              call | return_to is triggered.
201
202              If  enabled_call/3  is  undefined,  Module:enabled/3  is  called
203              instead.
204
205       Module:enabled_garbage_collection(TraceTag,   TracerState,  Tracee)  ->
206       Result
207
208              Types:
209
210                 TraceTag =  trace_tag_gc()
211                 TracerState = term()
212                 Tracee = tracee()
213                 Result = trace | discard | remove
214
215              This callback is called whenever a tracepoint  with  trace  flag
216              garbage_collection is triggered.
217
218              If  enabled_garbage_collection/3  is undefined, Module:enabled/3
219              is called instead.
220
221       Module:enabled_ports(TraceTag, TracerState, Tracee) -> Result
222
223              Types:
224
225                 TraceTag =  trace_tag_ports()
226                 TracerState = term()
227                 Tracee = tracee()
228                 Result = trace | discard | remove
229
230              This callback is called whenever a tracepoint  with  trace  flag
231              ports is triggered.
232
233              If  enabled_ports/3  is  undefined,  Module:enabled/3  is called
234              instead.
235
236       Module:enabled_procs(TraceTag, TracerState, Tracee) -> Result
237
238              Types:
239
240                 TraceTag =  trace_tag_procs()
241                 TracerState = term()
242                 Tracee = tracee()
243                 Result = trace | discard | remove
244
245              This callback is called whenever a tracepoint  with  trace  flag
246              procs is triggered.
247
248              If  enabled_procs/3  is  undefined,  Module:enabled/3  is called
249              instead.
250
251       Module:enabled_receive(TraceTag, TracerState, Tracee) -> Result
252
253              Types:
254
255                 TraceTag =  trace_tag_receive()
256                 TracerState = term()
257                 Tracee = tracee()
258                 Result = trace | discard | remove
259
260              This callback is called whenever a tracepoint  with  trace  flag
261              'receive' is triggered.
262
263              If  enabled_receive/3  is  undefined, Module:enabled/3 is called
264              instead.
265
266       Module:enabled_running_ports(TraceTag, TracerState, Tracee) -> Result
267
268              Types:
269
270                 TraceTag =  trace_tag_running_ports()
271                 TracerState = term()
272                 Tracee = tracee()
273                 Result = trace | discard | remove
274
275              This callback is called whenever a tracepoint  with  trace  flag
276              running_ports is triggered.
277
278              If  enabled_running_ports/3  is  undefined,  Module:enabled/3 is
279              called instead.
280
281       Module:enabled_running_procs(TraceTag, TracerState, Tracee) -> Result
282
283              Types:
284
285                 TraceTag =  trace_tag_running_procs()
286                 TracerState = term()
287                 Tracee = tracee()
288                 Result = trace | discard | remove
289
290              This callback is called whenever a tracepoint  with  trace  flag
291              running_procs | running is triggered.
292
293              If  enabled_running_procs/3  is  undefined,  Module:enabled/3 is
294              called instead.
295
296       Module:enabled_send(TraceTag, TracerState, Tracee) -> Result
297
298              Types:
299
300                 TraceTag =  trace_tag_send()
301                 TracerState = term()
302                 Tracee = tracee()
303                 Result = trace | discard | remove
304
305              This callback is called whenever a tracepoint  with  trace  flag
306              send is triggered.
307
308              If  enabled_send/3  is  undefined,  Module:enabled/3  is  called
309              instead.
310
311       Module:trace(TraceTag, TracerState, Tracee, TraceTerm, Opts) -> Result
312
313              Types:
314
315                 TraceTag =  trace_tag()
316                 TracerState = term()
317                 Tracee = tracee()
318                 TraceTerm = term()
319                 Opts = trace_opts()
320                 Result = ok
321
322              This callback is called when a tracepoint is triggered  and  the
323              Module:enabled/3 callback returned trace. In it any side effects
324              needed by the tracer are to be done. The tracepoint  payload  is
325              located  in  the TraceTerm. The content of the TraceTerm depends
326              on which TraceTag is triggered.  TraceTerm  corresponds  to  the
327              fourth element in the trace tuples described in erlang:trace/3.
328
329              If  the trace tuple has five elements, the fifth element will be
330              sent as the extra value in the Opts maps.
331
332       Module:trace(seq_trace,  TracerState,  Label,  SeqTraceInfo,  Opts)  ->
333       Result
334
335              Types:
336
337                 TracerState = term()
338                 Label = term()
339                 SeqTraceInfo = term()
340                 Opts = trace_opts()
341                 Result = ok
342
343              The TraceTag seq_trace is handled slightly differently. There is
344              no Tracee for seq_trace, instead the Label associated  with  the
345              seq_trace event is specified.
346
347              For  more information on what Label and SeqTraceInfo can be, see
348              seq_trace(3).
349
350       Module:trace_call(TraceTag, TracerState, Tracee,  TraceTerm,  Opts)  ->
351       Result
352
353              Types:
354
355                 TraceTag =  trace_tag_call()
356                 TracerState = term()
357                 Tracee = tracee()
358                 TraceTerm = term()
359                 Opts = trace_opts()
360                 Result = ok
361
362              This  callback  is called when a tracepoint is triggered and the
363              Module:enabled_call/3 callback returned trace.
364
365              If trace_call/5 is undefined, Module:trace/5 is called instead.
366
367       Module:trace_garbage_collection(TraceTag,     TracerState,      Tracee,
368       TraceTerm, Opts) -> Result
369
370              Types:
371
372                 TraceTag =  trace_tag_gc()
373                 TracerState = term()
374                 Tracee = tracee()
375                 TraceTerm = term()
376                 Opts = trace_opts()
377                 Result = ok
378
379              This  callback  is called when a tracepoint is triggered and the
380              Module:enabled_garbage_collection/3 callback returned trace.
381
382              If trace_garbage_collection/5 is  undefined,  Module:trace/5  is
383              called instead.
384
385       Module:trace_ports(TraceTag,  TracerState,  Tracee, TraceTerm, Opts) ->
386       Result
387
388              Types:
389
390                 TraceTag =  trace_tag()
391                 TracerState = term()
392                 Tracee = tracee()
393                 TraceTerm = term()
394                 Opts = trace_opts()
395                 Result = ok
396
397              This callback is called when a tracepoint is triggered  and  the
398              Module:enabled_ports/3 callback returned trace.
399
400              If trace_ports/5 is undefined, Module:trace/5 is called instead.
401
402       Module:trace_procs(TraceTag,  TracerState,  Tracee, TraceTerm, Opts) ->
403       Result
404
405              Types:
406
407                 TraceTag =  trace_tag()
408                 TracerState = term()
409                 Tracee = tracee()
410                 TraceTerm = term()
411                 Opts = trace_opts()
412                 Result = ok
413
414              This callback is called when a tracepoint is triggered  and  the
415              Module:enabled_procs/3 callback returned trace.
416
417              If trace_procs/5 is undefined, Module:trace/5 is called instead.
418
419       Module:trace_receive(TraceTag, TracerState, Tracee, TraceTerm, Opts) ->
420       Result
421
422              Types:
423
424                 TraceTag =  trace_tag_receive()
425                 TracerState = term()
426                 Tracee = tracee()
427                 TraceTerm = term()
428                 Opts = trace_opts()
429                 Result = ok
430
431              This callback is called when a tracepoint is triggered  and  the
432              Module:enabled_receive/3 callback returned trace.
433
434              If   trace_receive/5  is  undefined,  Module:trace/5  is  called
435              instead.
436
437       Module:trace_running_ports(TraceTag,  TracerState,  Tracee,  TraceTerm,
438       Opts) -> Result
439
440              Types:
441
442                 TraceTag =  trace_tag_running_ports()
443                 TracerState = term()
444                 Tracee = tracee()
445                 TraceTerm = term()
446                 Opts = trace_opts()
447                 Result = ok
448
449              This  callback  is called when a tracepoint is triggered and the
450              Module:enabled_running_ports/3 callback returned trace.
451
452              If trace_running_ports/5 is undefined, Module:trace/5 is  called
453              instead.
454
455       Module:trace_running_procs(TraceTag,  TracerState,  Tracee,  TraceTerm,
456       Opts) -> Result
457
458              Types:
459
460                 TraceTag =  trace_tag_running_procs()
461                 TracerState = term()
462                 Tracee = tracee()
463                 TraceTerm = term()
464                 Opts = trace_opts()
465                 Result = ok
466
467              This callback is called when a tracepoint is triggered  and  the
468              Module:enabled_running_procs/3 callback returned trace.
469
470              If  trace_running_procs/5 is undefined, Module:trace/5 is called
471              instead.
472
473       Module:trace_send(TraceTag, TracerState, Tracee,  TraceTerm,  Opts)  ->
474       Result
475
476              Types:
477
478                 TraceTag =  trace_tag_send()
479                 TracerState = term()
480                 Tracee = tracee()
481                 TraceTerm = term()
482                 Opts = trace_opts()
483                 Result = ok
484
485              This  callback  is called when a tracepoint is triggered and the
486              Module:enabled_send/3 callback returned trace.
487
488              If trace_send/5 is undefined, Module:trace/5 is called instead.
489

ERL TRACER MODULE EXAMPLE

491       In this example, a tracer module with a NIF back end  sends  a  message
492       for  each send trace tag containing only the sender and receiver. Using
493       this tracer module, a much more lightweight  message  tracer  is  used,
494       which only records who sent messages to who.
495
496       The following is an example session using it on Linux:
497
498       $ gcc -I erts-8.0/include/ -fPIC -shared -o erl_msg_tracer.so erl_msg_tracer.c
499       $ erl
500       Erlang/OTP 19 [DEVELOPMENT] [erts-8.0] [source-ed2b56b] [64-bit] [smp:8:8] [async-threads:10] [hipe] [kernel-poll:false]
501
502       Eshell V8.0  (abort with ^G)
503       1> c(erl_msg_tracer), erl_msg_tracer:load().
504       ok
505       2> Tracer = spawn(fun F() -> receive M -> io:format("~p~n",[M]), F() end end).
506       <0.37.0>
507       3> erlang:trace(new, true, [send,{tracer, erl_msg_tracer, Tracer}]).
508       0
509       {trace,<0.39.0>,<0.27.0>}
510       4> {ok, D} = file:open("/tmp/tmp.data",[write]).
511       {trace,#Port<0.486>,<0.40.0>}
512       {trace,<0.40.0>,<0.21.0>}
513       {trace,#Port<0.487>,<0.4.0>}
514       {trace,#Port<0.488>,<0.4.0>}
515       {trace,#Port<0.489>,<0.4.0>}
516       {trace,#Port<0.490>,<0.4.0>}
517       {ok,<0.40.0>}
518       {trace,<0.41.0>,<0.27.0>}
519       5>
520
521       erl_msg_tracer.erl:
522
523       -module(erl_msg_tracer).
524
525       -export([enabled/3, trace/5, load/0]).
526
527       load() ->
528           erlang:load_nif("erl_msg_tracer", []).
529
530       enabled(_, _, _) ->
531           error.
532
533       trace(_, _, _, _, _) ->
534           error.
535
536       erl_msg_tracer.c:
537
538       #include <erl_nif.h>
539
540       /* NIF interface declarations */
541       static int load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info);
542       static int upgrade(ErlNifEnv* env, void** priv_data, void** old_priv_data, ERL_NIF_TERM load_info);
543       static void unload(ErlNifEnv* env, void* priv_data);
544
545       /* The NIFs: */
546       static ERL_NIF_TERM enabled(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
547       static ERL_NIF_TERM trace(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
548
549       static ErlNifFunc nif_funcs[] = {
550           {"enabled", 3, enabled},
551           {"trace", 5, trace}
552       };
553
554       ERL_NIF_INIT(erl_msg_tracer, nif_funcs, load, NULL, upgrade, unload)
555
556       static int load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info)
557       {
558           *priv_data = NULL;
559           return 0;
560       }
561
562       static void unload(ErlNifEnv* env, void* priv_data)
563       {
564
565       }
566
567       static int upgrade(ErlNifEnv* env, void** priv_data, void** old_priv_data,
568                    ERL_NIF_TERM load_info)
569       {
570           if (*old_priv_data != NULL || *priv_data != NULL) {
571            return -1; /* Don't know how to do that */
572           }
573           if (load(env, priv_data, load_info)) {
574            return -1;
575           }
576           return 0;
577       }
578
579       /*
580        * argv[0]: TraceTag
581        * argv[1]: TracerState
582        * argv[2]: Tracee
583        */
584       static ERL_NIF_TERM enabled(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
585       {
586           ErlNifPid to_pid;
587           if (enif_get_local_pid(env, argv[1], &to_pid))
588               if (!enif_is_process_alive(env, &to_pid))
589                   if (enif_is_identical(enif_make_atom(env, "trace_status"), argv[0]))
590                       /* tracer is dead so we should remove this tracepoint */
591                       return enif_make_atom(env, "remove");
592                   else
593                       return enif_make_atom(env, "discard");
594
595           /* Only generate trace for when tracer != tracee */
596           if (enif_is_identical(argv[1], argv[2]))
597               return enif_make_atom(env, "discard");
598
599           /* Only trigger trace messages on 'send' */
600           if (enif_is_identical(enif_make_atom(env, "send"), argv[0]))
601               return enif_make_atom(env, "trace");
602
603           /* Have to answer trace_status */
604           if (enif_is_identical(enif_make_atom(env, "trace_status"), argv[0]))
605               return enif_make_atom(env, "trace");
606
607           return enif_make_atom(env, "discard");
608       }
609
610       /*
611        * argv[0]: TraceTag, should only be 'send'
612        * argv[1]: TracerState, process to send {Tracee, Recipient} to
613        * argv[2]: Tracee
614        * argv[3]: Message
615        * argv[4]: Options, map containing Recipient
616        */
617       static ERL_NIF_TERM trace(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
618       {
619           ErlNifPid to_pid;
620           ERL_NIF_TERM recipient, msg;
621
622           if (enif_get_local_pid(env, argv[1], &to_pid)) {
623             if (enif_get_map_value(env, argv[4], enif_make_atom(env, "extra"), &recipient)) {
624               msg = enif_make_tuple3(env, enif_make_atom(env, "trace"), argv[2], recipient);
625               enif_send(env, &to_pid, NULL, msg);
626             }
627           }
628
629           return enif_make_atom(env, "ok");
630       }
631
632
633
634Ericsson AB                       erts 10.5.6                    erl_tracer(3)
Impressum