1erl_tracer(3) Erlang Module Definition erl_tracer(3)
2
3
4
6 erl_tracer - Erlang tracer behavior.
7
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 be‐
26 havior, including, but not limited to, infinite recursions.
27
28
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
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
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 re‐
177 turned, the necessary trace data is created and the trace call‐
178 back of the tracer is called. If discard is returned, this trace
179 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 in‐
203 stead.
204
205 Module:enabled_garbage_collection(TraceTag, TracerState, Tracee) -> Re‐
206 sult
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 in‐
234 stead.
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 in‐
249 stead.
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 in‐
309 stead.
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) -> Re‐
333 sult
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 in‐
435 stead.
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
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 14.1.1 erl_tracer(3)