aboutsummaryrefslogtreecommitdiffstats
path: root/erts/doc
diff options
context:
space:
mode:
Diffstat (limited to 'erts/doc')
-rw-r--r--erts/doc/src/Makefile15
-rw-r--r--erts/doc/src/erl_nif.xml3
-rw-r--r--erts/doc/src/erl_tracer.xml324
-rw-r--r--erts/doc/src/erlang.xml46
-rw-r--r--erts/doc/src/match_spec.xml11
-rw-r--r--erts/doc/src/ref_man.xml1
-rw-r--r--erts/doc/src/specs.xml1
7 files changed, 365 insertions, 36 deletions
diff --git a/erts/doc/src/Makefile b/erts/doc/src/Makefile
index e02e89238e..b96cbbce40 100644
--- a/erts/doc/src/Makefile
+++ b/erts/doc/src/Makefile
@@ -50,12 +50,14 @@ XML_REF1_FILES = epmd.xml \
XML_REF3_EFILES = \
erl_prim_loader.xml \
erlang.xml \
+ erl_tracer.xml \
init.xml \
zlib.xml
XML_REF3_FILES = \
driver_entry.xml \
erl_nif.xml \
+ erl_tracer.xml \
erl_driver.xml \
erl_prim_loader.xml \
erlang.xml \
@@ -154,18 +156,9 @@ clean:
rm -f $(SPECDIR)/*
rm -f errs core *~
-$(SPECDIR)/specs_driver_entry.xml:
+$(SPECDIR)/specs_%.xml:
escript $(SPECS_EXTRACTOR) $(SPECS_FLAGS) \
- -o$(dir $@) -module driver_entry
-$(SPECDIR)/specs_erl_nif.xml:
- escript $(SPECS_EXTRACTOR) $(SPECS_FLAGS) \
- -o$(dir $@) -module erl_nif
-$(SPECDIR)/specs_erl_driver.xml:
- escript $(SPECS_EXTRACTOR) $(SPECS_FLAGS) \
- -o$(dir $@) -module erl_driver
-$(SPECDIR)/specs_erts_alloc.xml:
- escript $(SPECS_EXTRACTOR) $(SPECS_FLAGS) \
- -o$(dir $@) -module erts_alloc
+ -o$(dir $@) -module $(patsubst $(SPECDIR)/specs_%.xml,%,$@)
# ----------------------------------------------------
# Release Target
diff --git a/erts/doc/src/erl_nif.xml b/erts/doc/src/erl_nif.xml
index 5f56d8b595..7546f7ef81 100644
--- a/erts/doc/src/erl_nif.xml
+++ b/erts/doc/src/erl_nif.xml
@@ -566,8 +566,7 @@ typedef struct {
<code type="none">
typedef void ErlNifResourceDtor(ErlNifEnv* env, void* obj);
</code>
- <p>The function prototype of a resource destructor function.
- A destructor function is not allowed to call any term-making functions.</p>
+ <p>The function prototype of a resource destructor function.</p>
</item>
<tag><marker id="ErlNifCharEncoding"/>ErlNifCharEncoding</tag>
<item>
diff --git a/erts/doc/src/erl_tracer.xml b/erts/doc/src/erl_tracer.xml
new file mode 100644
index 0000000000..1e8e78b25f
--- /dev/null
+++ b/erts/doc/src/erl_tracer.xml
@@ -0,0 +1,324 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!DOCTYPE erlref SYSTEM "erlref.dtd">
+
+<erlref>
+ <header>
+ <copyright>
+ <year>2016</year><year>2016</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ </legalnotice>
+
+ <title>erl_tracer</title>
+ <prepared></prepared>
+ <docno></docno>
+ <date></date>
+ <rev></rev>
+ </header>
+ <module>erl_tracer</module>
+ <modulesummary>Erlang Tracer Behaviour</modulesummary>
+ <description>
+ <p>A behaviour module for implementing the back end of the erlang
+ tracing system. The functions in this module will be called whenever
+ a trace probe is triggered. Both the <c>enabled</c> and <c>trace</c>
+ functions are called in the context of the entity that triggered the
+ trace probe.
+ This means that the overhead by having the tracing enabled will be
+ greatly effected by how much time is spent in these functions. So do as
+ little work as possible in these functions.</p>
+ <note>
+ <p>All functions in this behaviour have to be implemented as NIF's.
+ This is a limitation that may the lifted in the future.
+ There is an <seealso marker="#example">example tracer module nif</seealso>
+ implementation at the end of this page.</p>
+ </note>
+ <warning>
+ <p>Do not send messages or issue port commands to the <c>Tracee</c>
+ in any of the callbacks. Doing so is not allowed and can cause all
+ sorts of strange behaviour, including but not limited to infinite
+ recursions.</p>
+ </warning>
+ </description>
+
+ <datatypes>
+ <datatype>
+ <name name="trace_tag" />
+ <desc>
+ <p>The different trace tags that the tracer will be called with.
+ Each trace tag is described in greater detail in
+ <seealso marker="#trace">Module:trace/6</seealso>
+ </p>
+ </desc>
+ </datatype>
+ <datatype>
+ <name name="tracee" />
+ <desc>
+ <p>The process or port that the trace belongs to.
+ </p>
+ </desc>
+ </datatype>
+ <datatype>
+ <name name="trace_opts" />
+ <desc>
+ <p>The options for the tracee.
+ <taglist>
+ <tag><c>timestamp</c></tag>
+ <item>If not set to <c>undefined</c>, the tracer has been requested to
+ include a timestamp.</item>
+ <tag><c>match_spec_result</c></tag>
+ <item>If not set to <c>true</c>, the tracer has been requested to
+ include the output of a match specification that was run.</item>
+ <tag><c>scheduler_id</c></tag>
+ <item>Set to a number of the scheduler id is to be included by the tracer.
+ Otherwise it is set to <c>undefined</c>.</item>
+ </taglist>
+ </p>
+ </desc>
+ </datatype>
+ <datatype>
+ <name name="tracer_state" />
+ <desc>
+ <p>
+ The state which is given when calling
+ <seealso marker="erlang#trace-3"><c>erlang:trace(PidPortSpec,true,[{tracer,Module,TracerState}])</c></seealso>.
+ The tracer state is an immutable value that is passed to erl_tracer callbacks and should
+ contain all the data that is needed to generate the trace event.
+ </p>
+ </desc>
+ </datatype>
+ </datatypes>
+
+ <section>
+ <title>CALLBACK FUNCTIONS</title>
+ <p>The following functions
+ should be exported from a <c>erl_tracer</c> callback module.</p>
+ </section>
+ <marker id="enabled"></marker>
+ <funcs>
+ <func>
+ <name>Module:enabled(TraceTag, TracerState, Tracee) -> Result</name>
+ <fsummary>Check if a trace event should be generated.</fsummary>
+ <type>
+ <v>TraceTag = <seealso marker="#type-trace_tag">trace_tag()</seealso> | trace_status</v>
+ <v>TracerState = term()</v>
+ <v>Tracee = <seealso marker="#type-trace_tag">tracee()</seealso></v>
+ <v>Result = trace | discard | remove</v>
+ </type>
+ <desc>
+ <p>This callback will be called whenever a trace point is triggered. It
+ allows the tracer to decide whether a trace should be generated or not.
+ This check is made as early as possible in order to limit the amount of
+ overhead associated with tracing. If <c>trace</c> is returned the
+ necessary trace data will be created and the trace call-back of the tracer
+ will be called. If <c>discard</c> is returned, this trace call
+ will be discarded and no call to trace will be done. If
+ <c>remove</c> is returned, the VM will attempt to remove this tracer
+ from the tracee, together with any trace flags set on the tracee.
+ </p>
+ <p><c>trace_status</c> is a special type of <c>TraceTag</c> which is used
+ to check if the tracer should still be active. It is called in multiple
+ scenarios, but most significantly it is used when tracing is started
+ using this tracer.</p>
+ <p>This function may be called multiple times per trace point, so it
+ is important that it is both fast and side effect free.</p>
+ </desc>
+ </func>
+ <marker id="trace"></marker>
+ <func>
+ <name>Module:trace(TraceTag, TracerState, Tracee, FirstTraceTerm, SecondTraceTerm, Opts) -> Result</name>
+ <fsummary>Check if a trace event should be generated.</fsummary>
+ <type>
+ <v>TraceTag = <seealso marker="#type-trace_tag">trace_tag()</seealso></v>
+ <v>TracerState = term()</v>
+ <v>Tracee = <seealso marker="#type-trace_tag">tracee()</seealso></v>
+ <v>FirstTraceTerm = term()</v>
+ <v>SecondTraceTerm = term() | undefined</v>
+ <v>Opts = <seealso marker="#type-trace_opts">trace_opts()</seealso></v>
+ <v>Result = ok</v>
+ </type>
+ <desc>
+ <p>This callback will be called when a trace point is triggered and
+ the <seealso marker="#enabled">Module:enabled/3</seealso>
+ callback returned <c>trace</c>. In it any side effects needed by
+ the tracer should be done. The trace point payload is located in
+ the <c>FirstTraceTerm</c> and <c>SecondTraceTerm</c>. The content
+ of the TraceTerms depends on which <c>TraceTag</c> has been triggered.
+ The <c>FirstTraceTerm</c> and <c>SecondTraceTerm</c> correspond to the
+ fourth and fifth slot in the trace tuples described in
+ <seealso marker="erlang#trace_3_trace_messages">erlang:trace/3</seealso>.
+ If the tuple only has four elements, <c>SecondTraceTerm</c> will be
+ <c>undefined</c>.</p>
+ </desc>
+ </func>
+ <func>
+ <name name="trace">Module:trace(seq_trace, TracerState, Label, SeqTraceInfo, undefined, Opts) -> Result</name>
+ <fsummary>Check if a sequence trace event should be generated.</fsummary>
+ <type>
+ <v>TracerState = term()</v>
+ <v>Label = term()</v>
+ <v>SeqTraceInfo = term()</v>
+ <v>Opts = <seealso marker="#type-trace_opts">trace_opts()</seealso></v>
+ <v>Result = ok</v>
+ </type>
+ <desc>
+ <p>The <c>TraceTag</c> <c>seq_trace</c> is handled a little bit
+ differently. There is not <c>Tracee</c> for seq_trace, instead the
+ <c>Label</c> associated with the seq_trace event is given.
+ For more info on what <c>Label</c> and <c>SeqTraceInfo</c> can be
+ see the <seealso marker="kernel:seq_trace">seq_trace</seealso> manual.</p>
+ </desc>
+ </func>
+ </funcs>
+ <section>
+ <marker id="example"></marker>
+ <title>Erl Tracer Module example</title>
+ <p>In the example below a tracer module with a nif backend sends a message
+ for each <c>send</c> trace tag containing only the sender and receiver.
+ Using this tracer module, a much more lightweight message tracer is
+ used that only records who sent messages to who.</p>
+ <p>Here is an example session using it on Linux.</p>
+ <pre>
+$ gcc -I erts-8.0/include/ -fPIC -shared -o erl_msg_tracer.so erl_msg_tracer.c
+$ erl
+Erlang/OTP 19 [DEVELOPMENT] [erts-8.0] [source-ed2b56b] [64-bit] [smp:8:8] [async-threads:10] [hipe] [kernel-poll:false]
+
+Eshell V8.0 (abort with ^G)
+1&gt; c(erl_msg_tracer), erl_msg_tracer:load().
+ok
+2&gt; Tracer = spawn(fun F() -&gt; receive M -&gt; io:format("~p~n",[M]), F() end end).
+&lt;0.37.0&gt;
+3&gt; erlang:trace(new, true, [send,{tracer, erl_msg_tracer, Tracer}]).
+0
+{&lt;0.39.0&gt;,&lt;0.27.0&gt;}
+4&gt; {ok, D} = file:open("/tmp/tmp.data",[write]).
+{trace,#Port&lt;0.486&gt;,&lt;0.40.0&gt;}
+{trace,&lt;0.40.0&gt;,&lt;0.21.0&gt;}
+{trace,#Port&lt;0.487&gt;,&lt;0.4.0&gt;}
+{trace,#Port&lt;0.488&gt;,&lt;0.4.0&gt;}
+{trace,#Port&lt;0.489&gt;,&lt;0.4.0&gt;}
+{trace,#Port&lt;0.490&gt;,&lt;0.4.0&gt;}
+{ok,&lt;0.40.0&gt;}
+{trace,&lt;0.41.0&gt;,&lt;0.27.0&gt;}
+5&gt;
+ </pre>
+ <p>erl_msg_tracer.erl</p>
+ <pre>
+-module(erl_msg_tracer).
+
+-export([enabled/3, trace/6, load/0]).
+
+load() ->
+ erlang:load_nif("erl_msg_tracer", []).
+
+enabled(_, _, _) ->
+ error.
+
+trace(_, _, _,_, _, _) ->
+ error.
+ </pre>
+ <p>erl_msg_tracer.c</p>
+ <pre>
+#include "erl_nif.h"
+
+/* NIF interface declarations */
+static int load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info);
+static int upgrade(ErlNifEnv* env, void** priv_data, void** old_priv_data, ERL_NIF_TERM load_info);
+static void unload(ErlNifEnv* env, void* priv_data);
+
+/* The NIFs: */
+static ERL_NIF_TERM enabled(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+static ERL_NIF_TERM trace(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+
+static ErlNifFunc nif_funcs[] = {
+ {"enabled", 3, enabled},
+ {"trace", 6, trace}
+};
+
+ERL_NIF_INIT(erl_msg_tracer, nif_funcs, load, NULL, upgrade, unload)
+
+static int load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info)
+{
+ *priv_data = NULL;
+ return 0;
+}
+
+static void unload(ErlNifEnv* env, void* priv_data)
+{
+
+}
+
+static int upgrade(ErlNifEnv* env, void** priv_data, void** old_priv_data,
+ ERL_NIF_TERM load_info)
+{
+ if (*old_priv_data != NULL || *priv_data != NULL) {
+ return -1; /* Don't know how to do that */
+ }
+ if (load(env, priv_data, load_info)) {
+ return -1;
+ }
+ return 0;
+}
+
+/*
+ * argv[0]: Trace Tag
+ * argv[1]: TracerState
+ * argv[2]: Tracee
+ */
+static ERL_NIF_TERM enabled(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{
+ ErlNifPid to_pid;
+ if (enif_get_local_pid(env, argv[1], &amp;to_pid))
+ if (!enif_is_process_alive(env, &amp;to_pid))
+ /* tracer is dead so we should remove this trace point */
+ return enif_make_atom(env, "remove");
+
+ /* Only generate trace for when tracer != tracee */
+ if (enif_is_identical(argv[1], argv[2]))
+ return enif_make_atom(env, "discard");
+
+ /* Only trigger trace messages on 'send' */
+ if (enif_is_identical(enif_make_atom(env, "send"), argv[0]))
+ return enif_make_atom(env, "trace");
+
+ /* Have to answer trace_status */
+ if (enif_is_identical(enif_make_atom(env, "trace_status"), argv[0]))
+ return enif_make_atom(env, "trace");
+
+ return enif_make_atom(env, "discard");
+}
+
+/*
+ * argv[0]: Trace Tag, should only be 'send'
+ * argv[1]: TracerState, process to send {argv[2], argv[4]} to
+ * argv[2]: Tracee
+ * argv[3]: Message, ignored
+ * argv[4]: Recipient
+ * argv[5]: Options, ignored
+ */
+static ERL_NIF_TERM trace(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{
+ ErlNifPid to_pid;
+
+ if (enif_get_local_pid(env, argv[1], &amp;to_pid)) {
+ ERL_NIF_TERM msg = enif_make_tuple3(env, enif_make_atom(env, "trace"), argv[2], argv[4]);
+ enif_send(env, &amp;to_pid, NULL, msg);
+ }
+
+ return enif_make_atom(env, "ok");
+}
+ </pre>
+ </section>
+</erlref>
diff --git a/erts/doc/src/erlang.xml b/erts/doc/src/erlang.xml
index ef577c82bf..86bdb1dfe6 100644
--- a/erts/doc/src/erlang.xml
+++ b/erts/doc/src/erlang.xml
@@ -8371,7 +8371,7 @@ timestamp() ->
<taglist>
<tag><c>all</c></tag>
<item>
- <p>Sets all trace flags except <c>{tracer, Tracer}</c> and
+ <p>Sets all trace flags except <c>tracer</c> and
<c>cpu_timestamp</c>, which are in their nature different
than the others.</p>
</item>
@@ -8529,12 +8529,20 @@ timestamp() ->
<item>
<p>Specifies where to send the trace messages. <c>Tracer</c>
must be the process identifier of a local process
- or the port identifier
- of a local port. If this flag is not given, trace
- messages are sent to the process that called
- <c>erlang:trace/3</c>.</p>
+ or the port identifier of a local port.</p>
+ </item>
+ <tag><c>{tracer, TracerModule, TracerState}</c></tag>
+ <item>
+ <p>Specifies that a tracer module should be called
+ instead of sending a trace message. The tracer module
+ can then ignore or change the trace message. For more details
+ on how to write a tracer module see <seealso marker="erl_tracer">
+ erl_tracer</seealso>
+ </p>
</item>
</taglist>
+ <p>If no <c>tracer</c> is given, the calling process
+ will be receiving all of the trace messages</p>
<p>The effect of combining <c>set_on_first_link</c> with
<c>set_on_link</c> is the same as having
<c>set_on_first_link</c> alone. Likewise for
@@ -8706,9 +8714,9 @@ timestamp() ->
garbage collection.</p>
</item>
</taglist>
- <p>If the tracing process dies, the flags are silently
- removed.</p>
- <p>Only one process can trace a particular process. Therefore,
+ <p>If the tracing process/port dies or the tracer module returns
+ <c>remove</c>, the flags are silently removed.</p>
+ <p>Each process can only be traced by one tracer. Therefore,
attempts to trace an already traced process fail.</p>
<p>Returns: A number indicating the number of processes that
matched <c><anno>PidSpec</anno></c>.
@@ -8716,7 +8724,7 @@ timestamp() ->
identifier, the return value is <c>1</c>.
If <c><anno>PidSpec</anno></c>
is <c>all</c> or <c>existing</c>, the return value is
- the number of processes running, excluding tracer processes.
+ the number of processes running.
If <c><anno>PidSpec</anno></c> is <c>new</c>, the return value is
<c>0</c>.</p>
<p>Failure: <c>badarg</c> if the specified arguments are
@@ -8750,7 +8758,7 @@ timestamp() ->
has not been traced by someone, but if this is the case,
<em>no</em> trace messages have been delivered when the
<c>trace_delivered</c> message arrives.</p>
- <p>Notice that that <c><anno>Tracee</anno></c> must refer
+ <p>Notice that <c><anno>Tracee</anno></c> must refer
to a process currently,
or previously existing on the same node as the caller of
<c>erlang:trace_delivered(<anno>Tracee</anno>)</c> resides on.
@@ -8801,7 +8809,8 @@ timestamp() ->
</item>
<tag><c>tracer</c></tag>
<item>
- <p>Returns the identifier for process or port tracing this
+ <p>Returns the identifier for process, port or a tuple containing
+ the tracer module and tracer state tracing this
process. If this process is not being traced, the return
value is <c>[]</c>.</p>
</item>
@@ -8830,8 +8839,8 @@ timestamp() ->
</item>
<tag><c>meta</c></tag>
<item>
- <p>Returns the meta-trace tracer process or port for this
- function, if it has one. If the function is not
+ <p>Returns the meta-trace tracer process, port or trace module
+ for this function, if it has one. If the function is not
meta-traced, the returned value is <c>false</c>. If
the function is meta-traced but has once detected that
the tracer process is invalid, the returned value is [].</p>
@@ -8999,13 +9008,12 @@ timestamp() ->
the process, a <c>return_to</c> message is also sent
when this function returns to its caller.</p>
</item>
- <tag><c>meta | {meta, <anno>Pid</anno>}</c></tag>
+ <tag><c>meta | {meta, <anno>Pid</anno>} | {meta, <anno>TracerModule</anno>, <anno>TracerState</anno>}</c>
+ </tag>
<item>
<p>Turns on or off meta-tracing for all types of function
- calls. Trace messages are sent to the tracer process
- or port <c><anno>Pid</anno></c> whenever any of the specified
- functions are called, regardless of how they are called.
- If no <c><anno>Pid</anno></c> is specified,
+ calls. Trace messages are sent to the tracer whenever any of
+ the specified functions are called. If no tracer is specified,
<c>self()</c> is used as a default tracer process.</p>
<p>Meta-tracing traces all processes and does not care
about the process trace flags set by <c>trace/3</c>,
@@ -9013,7 +9021,7 @@ timestamp() ->
<c>[call, timestamp]</c>.</p>
<p>The match specification function <c>{return_trace}</c>
works with meta-trace and sends its trace message to the
- same tracer process.</p>
+ same tracer.</p>
</item>
<tag><c>call_count</c></tag>
<item>
diff --git a/erts/doc/src/match_spec.xml b/erts/doc/src/match_spec.xml
index 975f01cf2c..b49e1483aa 100644
--- a/erts/doc/src/match_spec.xml
+++ b/erts/doc/src/match_spec.xml
@@ -287,7 +287,7 @@
can <em>not</em> be one of the atoms <c><![CDATA[all]]></c>, <c><![CDATA[new]]></c> or
<c><![CDATA[existing]]></c> (unless, of course, they are registered names).
<c><![CDATA[P2]]></c> can <em>not</em> be <c><![CDATA[cpu_timestamp]]></c> nor
- <c><![CDATA[{tracer,_}]]></c>.
+ <c><![CDATA[tracer]]></c>.
Returns <c><![CDATA[true]]></c> and may only be used in
the <c><![CDATA[MatchBody]]></c> part when tracing.
</p>
@@ -298,7 +298,7 @@
be either a process identifier or a registered name and is given
as the first argument to the match_spec function.
<c><![CDATA[P2]]></c> can <em>not</em> be <c><![CDATA[cpu_timestamp]]></c> nor
- <c><![CDATA[{tracer,_}]]></c>. Returns
+ <c><![CDATA[tracer]]></c>. Returns
<c><![CDATA[true]]></c> and may only be used in the <c><![CDATA[MatchBody]]></c> part
when tracing.
</p>
@@ -308,11 +308,14 @@
disable list is applied first, but effectively all changes
are applied atomically. The trace flags
are the same as for <c><![CDATA[erlang:trace/3]]></c> not including
- <c><![CDATA[cpu_timestamp]]></c> but including <c><![CDATA[{tracer,_}]]></c>. If a
+ <c><![CDATA[cpu_timestamp]]></c> but including <c><![CDATA[tracer]]></c>. If a
tracer is specified in both lists, the tracer in the
enable list takes precedence. If no tracer is specified the
same tracer as the process executing the match spec is
- used. With three parameters to this function the first is
+ used. When using a <seealso marker="erl_tracer">tracer module</seealso>
+ the module has to be loaded before the match specification is executed.
+ If it is not loaded the match will fail.
+ With three parameters to this function the first is
either a process identifier or the registered name of a
process to set trace flags on, the second is the disable
list, and the third is the enable list. Returns
diff --git a/erts/doc/src/ref_man.xml b/erts/doc/src/ref_man.xml
index aa245ec08a..e45402a397 100644
--- a/erts/doc/src/ref_man.xml
+++ b/erts/doc/src/ref_man.xml
@@ -56,5 +56,6 @@
<xi:include href="driver_entry.xml"/>
<xi:include href="erts_alloc.xml"/>
<xi:include href="erl_nif.xml"/>
+ <xi:include href="erl_tracer.xml"/>
</application>
diff --git a/erts/doc/src/specs.xml b/erts/doc/src/specs.xml
index 41a3984659..ed6be650e5 100644
--- a/erts/doc/src/specs.xml
+++ b/erts/doc/src/specs.xml
@@ -2,6 +2,7 @@
<specs xmlns:xi="http://www.w3.org/2001/XInclude">
<xi:include href="../specs/specs_erl_prim_loader.xml"/>
<xi:include href="../specs/specs_erlang.xml"/>
+ <xi:include href="../specs/specs_erl_tracer.xml"/>
<xi:include href="../specs/specs_init.xml"/>
<xi:include href="../specs/specs_zlib.xml"/>
</specs>