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
26 behavior, 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 |
38 closed |
39 link |
40 unlink |
41 getting_linked |
42 getting_unlinked
43
44 trace_tag_procs() =
45 spawn |
46 spawned |
47 exit |
48 link |
49 unlink |
50 getting_linked |
51 getting_unlinked |
52 register |
53 unregister
54
55 trace_tag_receive() = 'receive'
56
57 trace_tag_running_ports() =
58 in | out | in_exiting | out_exiting | out_exited
59
60 trace_tag_running_procs() =
61 in | out | in_exiting | out_exiting | out_exited
62
63 trace_tag_send() = send | send_to_non_existing_process
64
65 trace_tag() =
66 trace_tag_send() |
67 trace_tag_receive() |
68 trace_tag_call() |
69 trace_tag_procs() |
70 trace_tag_ports() |
71 trace_tag_running_procs() |
72 trace_tag_running_ports() |
73 trace_tag_gc()
74
75 The different trace tags that the tracer is called with. Each
76 trace tag is described in detail in Module:trace/5.
77
78 tracee() = port() | pid() | undefined
79
80 The process or port that the trace belongs to.
81
82 trace_opts() =
83 #{extra => term(),
84 match_spec_result => term(),
85 scheduler_id => integer() >= 0,
86 timestamp =>
87 timestamp | cpu_timestamp | monotonic | strict_monotonic}
88
89 The options for the tracee:
90
91 timestamp:
92 If set the tracer has been requested to include a time
93 stamp.
94
95 extra:
96 If set the tracepoint has included additional data about the
97 trace event. What the additional data is depends on which
98 TraceTag has been triggered. The extra trace data corre‐
99 sponds to the fifth element in the trace tuples described in
100 erlang:trace/3.
101
102 match_spec_result:
103 If set the tracer has been requested to include the output
104 of a match specification that was run.
105
106 scheduler_id:
107 If set the scheduler id is to be included by the tracer.
108
109 tracer_state() = term()
110
111 The state specified when calling erlang:trace(PidPort‐
112 Spec,true,[{tracer,Module,TracerState}]). The tracer state is an
113 immutable value that is passed to erl_tracer callbacks and is to
114 contain all the data that is needed to generate the trace event.
115
117 The following functions are to be exported from an erl_tracer callback
118 module:
119
120 Module:enabled/3:
121 Mandatory
122
123 Module:trace/5:
124 Mandatory
125
126 Module:enabled_call/3:
127 Optional
128
129 Module:trace_call/5:
130 Optional
131
132 Module:enabled_garbage_collection/3:
133 Optional
134
135 Module:trace_garbage_collection/5:
136 Optional
137
138 Module:enabled_ports/3:
139 Optional
140
141 Module:trace_ports/5:
142 Optional
143
144 Module:enabled_procs/3:
145 Optional
146
147 Module:trace_procs/5:
148 Optional
149
150 Module:enabled_receive/3:
151 Optional
152
153 Module:trace_receive/5:
154 Optional
155
156 Module:enabled_running_ports/3:
157 Optional
158
159 Module:trace_running_ports/5:
160 Optional
161
162 Module:enabled_running_procs/3:
163 Optional
164
165 Module:trace_running_procs/5:
166 Optional
167
168 Module:enabled_send/3:
169 Optional
170
171 Module:trace_send/5:
172 Optional
173
175 Module:enabled(TraceTag, TracerState, Tracee) -> Result
176
177 Types:
178
179 TraceTag = trace_tag() | trace_status
180 TracerState = term()
181 Tracee = tracee()
182 Result = trace | discard | remove
183
184 This callback is called whenever a tracepoint is triggered. It
185 allows the tracer to decide whether a trace is to be generated
186 or not. This check is made as early as possible to limit the
187 amount of overhead associated with tracing. If trace is
188 returned, the necessary trace data is created and the trace
189 callback of the tracer is called. If discard is returned, this
190 trace call is discarded and no call to trace is done.
191
192 trace_status is a special type of TraceTag, which is used to
193 check if the tracer is still to be active. It is called in mul‐
194 tiple scenarios, but most significantly it is used when tracing
195 is started using this tracer. If remove is returned when the
196 trace_status is checked, the tracer is removed from the tracee.
197
198 This function can be called multiple times per tracepoint, so it
199 is important that it is both fast and without side effects.
200
201 Module:enabled_call(TraceTag, TracerState, Tracee) -> Result
202
203 Types:
204
205 TraceTag = trace_tag_call()
206 TracerState = term()
207 Tracee = tracee()
208 Result = trace | discard | remove
209
210 This callback is called whenever a tracepoint with trace flag
211 call | return_to is triggered.
212
213 If enabled_call/3 is undefined, Module:enabled/3 is called
214 instead.
215
216 Module:enabled_garbage_collection(TraceTag, TracerState, Tracee) ->
217 Result
218
219 Types:
220
221 TraceTag = trace_tag_gc()
222 TracerState = term()
223 Tracee = tracee()
224 Result = trace | discard | remove
225
226 This callback is called whenever a tracepoint with trace flag
227 garbage_collection is triggered.
228
229 If enabled_garbage_collection/3 is undefined, Module:enabled/3
230 is called instead.
231
232 Module:enabled_ports(TraceTag, TracerState, Tracee) -> Result
233
234 Types:
235
236 TraceTag = trace_tag_ports()
237 TracerState = term()
238 Tracee = tracee()
239 Result = trace | discard | remove
240
241 This callback is called whenever a tracepoint with trace flag
242 ports is triggered.
243
244 If enabled_ports/3 is undefined, Module:enabled/3 is called
245 instead.
246
247 Module:enabled_procs(TraceTag, TracerState, Tracee) -> Result
248
249 Types:
250
251 TraceTag = trace_tag_procs()
252 TracerState = term()
253 Tracee = tracee()
254 Result = trace | discard | remove
255
256 This callback is called whenever a tracepoint with trace flag
257 procs is triggered.
258
259 If enabled_procs/3 is undefined, Module:enabled/3 is called
260 instead.
261
262 Module:enabled_receive(TraceTag, TracerState, Tracee) -> Result
263
264 Types:
265
266 TraceTag = trace_tag_receive()
267 TracerState = term()
268 Tracee = tracee()
269 Result = trace | discard | remove
270
271 This callback is called whenever a tracepoint with trace flag
272 'receive' is triggered.
273
274 If enabled_receive/3 is undefined, Module:enabled/3 is called
275 instead.
276
277 Module:enabled_running_ports(TraceTag, TracerState, Tracee) -> Result
278
279 Types:
280
281 TraceTag = trace_tag_running_ports()
282 TracerState = term()
283 Tracee = tracee()
284 Result = trace | discard | remove
285
286 This callback is called whenever a tracepoint with trace flag
287 running_ports is triggered.
288
289 If enabled_running_ports/3 is undefined, Module:enabled/3 is
290 called instead.
291
292 Module:enabled_running_procs(TraceTag, TracerState, Tracee) -> Result
293
294 Types:
295
296 TraceTag = trace_tag_running_procs()
297 TracerState = term()
298 Tracee = tracee()
299 Result = trace | discard | remove
300
301 This callback is called whenever a tracepoint with trace flag
302 running_procs | running is triggered.
303
304 If enabled_running_procs/3 is undefined, Module:enabled/3 is
305 called instead.
306
307 Module:enabled_send(TraceTag, TracerState, Tracee) -> Result
308
309 Types:
310
311 TraceTag = trace_tag_send()
312 TracerState = term()
313 Tracee = tracee()
314 Result = trace | discard | remove
315
316 This callback is called whenever a tracepoint with trace flag
317 send is triggered.
318
319 If enabled_send/3 is undefined, Module:enabled/3 is called
320 instead.
321
322 Module:trace(TraceTag, TracerState, Tracee, TraceTerm, Opts) -> Result
323
324 Types:
325
326 TraceTag = trace_tag()
327 TracerState = term()
328 Tracee = tracee()
329 TraceTerm = term()
330 Opts = trace_opts()
331 Result = ok
332
333 This callback is called when a tracepoint is triggered and the
334 Module:enabled/3 callback returned trace. In it any side effects
335 needed by the tracer are to be done. The tracepoint payload is
336 located in the TraceTerm. The content of the TraceTerm depends
337 on which TraceTag is triggered. TraceTerm corresponds to the
338 fourth element in the trace tuples described in erlang:trace/3.
339
340 If the trace tuple has five elements, the fifth element will be
341 sent as the extra value in the Opts maps.
342
343 Module:trace(seq_trace, TracerState, Label, SeqTraceInfo, Opts) ->
344 Result
345
346 Types:
347
348 TracerState = term()
349 Label = term()
350 SeqTraceInfo = term()
351 Opts = trace_opts()
352 Result = ok
353
354 The TraceTag seq_trace is handled slightly differently. There is
355 no Tracee for seq_trace, instead the Label associated with the
356 seq_trace event is specified.
357
358 For more information on what Label and SeqTraceInfo can be, see
359 seq_trace(3).
360
361 Module:trace_call(TraceTag, TracerState, Tracee, TraceTerm, Opts) ->
362 Result
363
364 Types:
365
366 TraceTag = trace_tag_call()
367 TracerState = term()
368 Tracee = tracee()
369 TraceTerm = term()
370 Opts = trace_opts()
371 Result = ok
372
373 This callback is called when a tracepoint is triggered and the
374 Module:enabled_call/3 callback returned trace.
375
376 If trace_call/5 is undefined, Module:trace/5 is called instead.
377
378 Module:trace_garbage_collection(TraceTag, TracerState, Tracee,
379 TraceTerm, Opts) -> Result
380
381 Types:
382
383 TraceTag = trace_tag_gc()
384 TracerState = term()
385 Tracee = tracee()
386 TraceTerm = term()
387 Opts = trace_opts()
388 Result = ok
389
390 This callback is called when a tracepoint is triggered and the
391 Module:enabled_garbage_collection/3 callback returned trace.
392
393 If trace_garbage_collection/5 is undefined, Module:trace/5 is
394 called instead.
395
396 Module:trace_ports(TraceTag, TracerState, Tracee, TraceTerm, Opts) ->
397 Result
398
399 Types:
400
401 TraceTag = trace_tag()
402 TracerState = term()
403 Tracee = tracee()
404 TraceTerm = term()
405 Opts = trace_opts()
406 Result = ok
407
408 This callback is called when a tracepoint is triggered and the
409 Module:enabled_ports/3 callback returned trace.
410
411 If trace_ports/5 is undefined, Module:trace/5 is called instead.
412
413 Module:trace_procs(TraceTag, TracerState, Tracee, TraceTerm, Opts) ->
414 Result
415
416 Types:
417
418 TraceTag = trace_tag()
419 TracerState = term()
420 Tracee = tracee()
421 TraceTerm = term()
422 Opts = trace_opts()
423 Result = ok
424
425 This callback is called when a tracepoint is triggered and the
426 Module:enabled_procs/3 callback returned trace.
427
428 If trace_procs/5 is undefined, Module:trace/5 is called instead.
429
430 Module:trace_receive(TraceTag, TracerState, Tracee, TraceTerm, Opts) ->
431 Result
432
433 Types:
434
435 TraceTag = trace_tag_receive()
436 TracerState = term()
437 Tracee = tracee()
438 TraceTerm = term()
439 Opts = trace_opts()
440 Result = ok
441
442 This callback is called when a tracepoint is triggered and the
443 Module:enabled_receive/3 callback returned trace.
444
445 If trace_receive/5 is undefined, Module:trace/5 is called
446 instead.
447
448 Module:trace_running_ports(TraceTag, TracerState, Tracee, TraceTerm,
449 Opts) -> Result
450
451 Types:
452
453 TraceTag = trace_tag_running_ports()
454 TracerState = term()
455 Tracee = tracee()
456 TraceTerm = term()
457 Opts = trace_opts()
458 Result = ok
459
460 This callback is called when a tracepoint is triggered and the
461 Module:enabled_running_ports/3 callback returned trace.
462
463 If trace_running_ports/5 is undefined, Module:trace/5 is called
464 instead.
465
466 Module:trace_running_procs(TraceTag, TracerState, Tracee, TraceTerm,
467 Opts) -> Result
468
469 Types:
470
471 TraceTag = trace_tag_running_procs()
472 TracerState = term()
473 Tracee = tracee()
474 TraceTerm = term()
475 Opts = trace_opts()
476 Result = ok
477
478 This callback is called when a tracepoint is triggered and the
479 Module:enabled_running_procs/3 callback returned trace.
480
481 If trace_running_procs/5 is undefined, Module:trace/5 is called
482 instead.
483
484 Module:trace_send(TraceTag, TracerState, Tracee, TraceTerm, Opts) ->
485 Result
486
487 Types:
488
489 TraceTag = trace_tag_send()
490 TracerState = term()
491 Tracee = tracee()
492 TraceTerm = term()
493 Opts = trace_opts()
494 Result = ok
495
496 This callback is called when a tracepoint is triggered and the
497 Module:enabled_send/3 callback returned trace.
498
499 If trace_send/5 is undefined, Module:trace/5 is called instead.
500
502 In this example, a tracer module with a NIF back end sends a message
503 for each send trace tag containing only the sender and receiver. Using
504 this tracer module, a much more lightweight message tracer is used,
505 which only records who sent messages to who.
506
507 The following is an example session using it on Linux:
508
509 $ gcc -I erts-8.0/include/ -fPIC -shared -o erl_msg_tracer.so erl_msg_tracer.c
510 $ erl
511 Erlang/OTP 19 [DEVELOPMENT] [erts-8.0] [source-ed2b56b] [64-bit] [smp:8:8] [async-threads:10] [hipe] [kernel-poll:false]
512
513 Eshell V8.0 (abort with ^G)
514 1> c(erl_msg_tracer), erl_msg_tracer:load().
515 ok
516 2> Tracer = spawn(fun F() -> receive M -> io:format("~p~n",[M]), F() end end).
517 <0.37.0>
518 3> erlang:trace(new, true, [send,{tracer, erl_msg_tracer, Tracer}]).
519 0
520 {trace,<0.39.0>,<0.27.0>}
521 4> {ok, D} = file:open("/tmp/tmp.data",[write]).
522 {trace,#Port<0.486>,<0.40.0>}
523 {trace,<0.40.0>,<0.21.0>}
524 {trace,#Port<0.487>,<0.4.0>}
525 {trace,#Port<0.488>,<0.4.0>}
526 {trace,#Port<0.489>,<0.4.0>}
527 {trace,#Port<0.490>,<0.4.0>}
528 {ok,<0.40.0>}
529 {trace,<0.41.0>,<0.27.0>}
530 5>
531
532 erl_msg_tracer.erl:
533
534 -module(erl_msg_tracer).
535
536 -export([enabled/3, trace/5, load/0]).
537
538 load() ->
539 erlang:load_nif("erl_msg_tracer", []).
540
541 enabled(_, _, _) ->
542 error.
543
544 trace(_, _, _, _, _) ->
545 error.
546
547 erl_msg_tracer.c:
548
549 #include <erl_nif.h>
550
551 /* NIF interface declarations */
552 static int load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info);
553 static int upgrade(ErlNifEnv* env, void** priv_data, void** old_priv_data, ERL_NIF_TERM load_info);
554 static void unload(ErlNifEnv* env, void* priv_data);
555
556 /* The NIFs: */
557 static ERL_NIF_TERM enabled(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
558 static ERL_NIF_TERM trace(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
559
560 static ErlNifFunc nif_funcs[] = {
561 {"enabled", 3, enabled},
562 {"trace", 5, trace}
563 };
564
565 ERL_NIF_INIT(erl_msg_tracer, nif_funcs, load, NULL, upgrade, unload)
566
567 static int load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info)
568 {
569 *priv_data = NULL;
570 return 0;
571 }
572
573 static void unload(ErlNifEnv* env, void* priv_data)
574 {
575
576 }
577
578 static int upgrade(ErlNifEnv* env, void** priv_data, void** old_priv_data,
579 ERL_NIF_TERM load_info)
580 {
581 if (*old_priv_data != NULL || *priv_data != NULL) {
582 return -1; /* Don't know how to do that */
583 }
584 if (load(env, priv_data, load_info)) {
585 return -1;
586 }
587 return 0;
588 }
589
590 /*
591 * argv[0]: TraceTag
592 * argv[1]: TracerState
593 * argv[2]: Tracee
594 */
595 static ERL_NIF_TERM enabled(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
596 {
597 ErlNifPid to_pid;
598 if (enif_get_local_pid(env, argv[1], &to_pid))
599 if (!enif_is_process_alive(env, &to_pid))
600 if (enif_is_identical(enif_make_atom(env, "trace_status"), argv[0]))
601 /* tracer is dead so we should remove this tracepoint */
602 return enif_make_atom(env, "remove");
603 else
604 return enif_make_atom(env, "discard");
605
606 /* Only generate trace for when tracer != tracee */
607 if (enif_is_identical(argv[1], argv[2]))
608 return enif_make_atom(env, "discard");
609
610 /* Only trigger trace messages on 'send' */
611 if (enif_is_identical(enif_make_atom(env, "send"), argv[0]))
612 return enif_make_atom(env, "trace");
613
614 /* Have to answer trace_status */
615 if (enif_is_identical(enif_make_atom(env, "trace_status"), argv[0]))
616 return enif_make_atom(env, "trace");
617
618 return enif_make_atom(env, "discard");
619 }
620
621 /*
622 * argv[0]: TraceTag, should only be 'send'
623 * argv[1]: TracerState, process to send {Tracee, Recipient} to
624 * argv[2]: Tracee
625 * argv[3]: Message
626 * argv[4]: Options, map containing Recipient
627 */
628 static ERL_NIF_TERM trace(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
629 {
630 ErlNifPid to_pid;
631 ERL_NIF_TERM recipient, msg;
632
633 if (enif_get_local_pid(env, argv[1], &to_pid)) {
634 if (enif_get_map_value(env, argv[4], enif_make_atom(env, "extra"), &recipient)) {
635 msg = enif_make_tuple3(env, enif_make_atom(env, "trace"), argv[2], recipient);
636 enif_send(env, &to_pid, NULL, msg);
637 }
638 }
639
640 return enif_make_atom(env, "ok");
641 }
642
643
644
645Ericsson AB erts 9.3.3.10 erl_tracer(3)