aboutsummaryrefslogtreecommitdiffstats
path: root/lib/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'lib/kernel')
-rw-r--r--lib/kernel/doc/src/application.xml74
-rw-r--r--lib/kernel/doc/src/auth.xml12
-rw-r--r--lib/kernel/doc/src/code.xml84
-rw-r--r--lib/kernel/doc/src/disk_log.xml74
-rw-r--r--lib/kernel/doc/src/erl_boot_server.xml12
-rw-r--r--lib/kernel/doc/src/erl_ddll.xml32
-rw-r--r--lib/kernel/doc/src/erl_epmd.xml16
-rw-r--r--lib/kernel/doc/src/error_handler.xml8
-rw-r--r--lib/kernel/doc/src/error_logger.xml46
-rw-r--r--lib/kernel/doc/src/file.xml122
-rw-r--r--lib/kernel/doc/src/gen_sctp.xml42
-rw-r--r--lib/kernel/doc/src/gen_tcp.xml24
-rw-r--r--lib/kernel/doc/src/gen_udp.xml16
-rw-r--r--lib/kernel/doc/src/global.xml42
-rw-r--r--lib/kernel/doc/src/global_group.xml22
-rw-r--r--lib/kernel/doc/src/heart.xml18
-rw-r--r--lib/kernel/doc/src/inet.xml101
-rw-r--r--lib/kernel/doc/src/inet_res.xml38
-rw-r--r--lib/kernel/doc/src/logger.xml168
-rw-r--r--lib/kernel/doc/src/logger_disk_log_h.xml4
-rw-r--r--lib/kernel/doc/src/logger_filters.xml10
-rw-r--r--lib/kernel/doc/src/logger_formatter.xml8
-rw-r--r--lib/kernel/doc/src/logger_std_h.xml4
-rw-r--r--lib/kernel/doc/src/net_adm.xml22
-rw-r--r--lib/kernel/doc/src/net_kernel.xml28
-rw-r--r--lib/kernel/doc/src/notes.xml117
-rw-r--r--lib/kernel/doc/src/os.xml38
-rw-r--r--lib/kernel/doc/src/pg2.xml22
-rw-r--r--lib/kernel/doc/src/rpc.xml56
-rw-r--r--lib/kernel/doc/src/seq_trace.xml20
-rw-r--r--lib/kernel/doc/src/wrap_log_reader.xml12
-rw-r--r--lib/kernel/src/kernel.appup.src49
-rw-r--r--lib/kernel/src/logger_config.erl4
-rw-r--r--lib/kernel/src/logger_disk_log_h.erl707
-rw-r--r--lib/kernel/src/logger_h_common.erl653
-rw-r--r--lib/kernel/src/logger_h_common.hrl16
-rw-r--r--lib/kernel/src/logger_simple_h.erl7
-rw-r--r--lib/kernel/src/logger_std_h.erl781
-rw-r--r--lib/kernel/src/seq_trace.erl2
-rw-r--r--lib/kernel/test/gen_tcp_misc_SUITE.erl21
-rw-r--r--lib/kernel/test/init_SUITE.erl23
-rw-r--r--lib/kernel/test/logger_disk_log_h_SUITE.erl138
-rw-r--r--lib/kernel/test/logger_std_h_SUITE.erl89
-rw-r--r--lib/kernel/test/sendfile_SUITE.erl26
-rw-r--r--lib/kernel/test/seq_trace_SUITE.erl39
-rw-r--r--lib/kernel/vsn.mk2
46 files changed, 1831 insertions, 2018 deletions
diff --git a/lib/kernel/doc/src/application.xml b/lib/kernel/doc/src/application.xml
index 38c7b5acf1..4e32c1a3a5 100644
--- a/lib/kernel/doc/src/application.xml
+++ b/lib/kernel/doc/src/application.xml
@@ -28,7 +28,7 @@
<date></date>
<rev></rev>
</header>
- <module>application</module>
+ <module since="">application</module>
<modulesummary>Generic OTP application functions</modulesummary>
<description>
<p>In OTP, <em>application</em> denotes a component implementing
@@ -67,8 +67,8 @@
</datatypes>
<funcs>
<func>
- <name name="ensure_all_started" arity="1"/>
- <name name="ensure_all_started" arity="2"/>
+ <name name="ensure_all_started" arity="1" since="OTP R16B02"/>
+ <name name="ensure_all_started" arity="2" since="OTP R16B02"/>
<fsummary>Load and start an application and its dependencies, recursively.</fsummary>
<desc>
<p>Equivalent to calling
@@ -85,8 +85,8 @@
</desc>
</func>
<func>
- <name name="ensure_started" arity="1"/>
- <name name="ensure_started" arity="2"/>
+ <name name="ensure_started" arity="1" since="OTP R16B01"/>
+ <name name="ensure_started" arity="2" since="OTP R16B01"/>
<fsummary>Load and start an application.</fsummary>
<desc>
<p>Equivalent to
@@ -95,8 +95,8 @@
</desc>
</func>
<func>
- <name name="get_all_env" arity="0"/>
- <name name="get_all_env" arity="1"/>
+ <name name="get_all_env" arity="0" since=""/>
+ <name name="get_all_env" arity="1" since=""/>
<fsummary>Get the configuration parameters for an application.</fsummary>
<desc>
<p>Returns the configuration parameters and their values for
@@ -108,8 +108,8 @@
</desc>
</func>
<func>
- <name name="get_all_key" arity="0"/>
- <name name="get_all_key" arity="1"/>
+ <name name="get_all_key" arity="0" since=""/>
+ <name name="get_all_key" arity="1" since=""/>
<fsummary>Get the application specification keys.</fsummary>
<desc>
<p>Returns the application specification keys and their values
@@ -122,8 +122,8 @@
</desc>
</func>
<func>
- <name name="get_application" arity="0"/>
- <name name="get_application" arity="1"/>
+ <name name="get_application" arity="0" since=""/>
+ <name name="get_application" arity="1" since=""/>
<fsummary>Get the name of an application containing a certain process or module.</fsummary>
<desc>
<p>Returns the name of the application to which the process
@@ -136,8 +136,8 @@
</desc>
</func>
<func>
- <name name="get_env" arity="1"/>
- <name name="get_env" arity="2"/>
+ <name name="get_env" arity="1" since=""/>
+ <name name="get_env" arity="2" since=""/>
<fsummary>Get the value of a configuration parameter.</fsummary>
<desc>
<p>Returns the value of configuration parameter <c><anno>Par</anno></c>
@@ -153,7 +153,7 @@
</desc>
</func>
<func>
- <name name="get_env" arity="3"/>
+ <name name="get_env" arity="3" since="OTP R16B"/>
<fsummary>Get the value of a configuration parameter using a default.</fsummary>
<desc>
<p>Works like <seealso marker="#get_env/2"><c>get_env/2</c></seealso> but returns
@@ -162,8 +162,8 @@
</desc>
</func>
<func>
- <name name="get_key" arity="1"/>
- <name name="get_key" arity="2"/>
+ <name name="get_key" arity="1" since=""/>
+ <name name="get_key" arity="2" since=""/>
<fsummary>Get the value of an application specification key.</fsummary>
<desc>
<p>Returns the value of the application specification key
@@ -180,8 +180,8 @@
</desc>
</func>
<func>
- <name name="load" arity="1"/>
- <name name="load" arity="2"/>
+ <name name="load" arity="1" since=""/>
+ <name name="load" arity="2" since=""/>
<fsummary>Load an application.</fsummary>
<type name="application_spec"/>
<type name="application_opt"/>
@@ -226,7 +226,7 @@ Nodes = [cp1@cave, {cp2@cave, cp3@cave}]</code>
</desc>
</func>
<func>
- <name name="loaded_applications" arity="0"/>
+ <name name="loaded_applications" arity="0" since=""/>
<fsummary>Get the currently loaded applications.</fsummary>
<desc>
<p>Returns a list with information about the applications, and included
@@ -238,7 +238,7 @@ Nodes = [cp1@cave, {cp2@cave, cp3@cave}]</code>
</desc>
</func>
<func>
- <name name="permit" arity="2"/>
+ <name name="permit" arity="2" since=""/>
<fsummary>Change the permission for an application to run at a node.</fsummary>
<desc>
<p>Changes the permission for <c><anno>Application</anno></c> to run at
@@ -271,8 +271,8 @@ Nodes = [cp1@cave, {cp2@cave, cp3@cave}]</code>
</desc>
</func>
<func>
- <name name="set_env" arity="3"/>
- <name name="set_env" arity="4"/>
+ <name name="set_env" arity="3" since=""/>
+ <name name="set_env" arity="4" since=""/>
<fsummary>Set the value of a configuration parameter.</fsummary>
<desc>
<p>Sets the value of configuration parameter <c><anno>Par</anno></c> for
@@ -302,8 +302,8 @@ Nodes = [cp1@cave, {cp2@cave, cp3@cave}]</code>
</desc>
</func>
<func>
- <name name="start" arity="1"/>
- <name name="start" arity="2"/>
+ <name name="start" arity="1" since=""/>
+ <name name="start" arity="2" since=""/>
<fsummary>Load and start an application.</fsummary>
<desc>
<p>Starts <c><anno>Application</anno></c>. If it is not loaded,
@@ -353,7 +353,7 @@ Nodes = [cp1@cave, {cp2@cave, cp3@cave}]</code>
</desc>
</func>
<func>
- <name name="start_type" arity="0"/>
+ <name name="start_type" arity="0" since=""/>
<fsummary>Get the start type of an ongoing application startup.</fsummary>
<desc>
<p>This function is intended to be called by a process belonging
@@ -370,7 +370,7 @@ Nodes = [cp1@cave, {cp2@cave, cp3@cave}]</code>
</desc>
</func>
<func>
- <name name="stop" arity="1"/>
+ <name name="stop" arity="1" since=""/>
<fsummary>Stop an application.</fsummary>
<desc>
<p>Stops <c><anno>Application</anno></c>. The application master calls
@@ -399,7 +399,7 @@ Nodes = [cp1@cave, {cp2@cave, cp3@cave}]</code>
</desc>
</func>
<func>
- <name name="takeover" arity="2"/>
+ <name name="takeover" arity="2" since=""/>
<fsummary>Take over a distributed application.</fsummary>
<desc>
<p>Takes over the distributed application
@@ -424,7 +424,7 @@ Nodes = [cp1@cave, {cp2@cave, cp3@cave}]</code>
</desc>
</func>
<func>
- <name name="unload" arity="1"/>
+ <name name="unload" arity="1" since=""/>
<fsummary>Unload an application.</fsummary>
<desc>
<p>Unloads the application specification for <c><anno>Application</anno></c>
@@ -435,8 +435,8 @@ Nodes = [cp1@cave, {cp2@cave, cp3@cave}]</code>
</desc>
</func>
<func>
- <name name="unset_env" arity="2"/>
- <name name="unset_env" arity="3"/>
+ <name name="unset_env" arity="2" since=""/>
+ <name name="unset_env" arity="3" since=""/>
<fsummary>Unset the value of a configuration parameter.</fsummary>
<desc>
<p>Removes the configuration parameter <c><anno>Par</anno></c> and its value
@@ -459,8 +459,8 @@ Nodes = [cp1@cave, {cp2@cave, cp3@cave}]</code>
</desc>
</func>
<func>
- <name name="which_applications" arity="0"/>
- <name name="which_applications" arity="1"/>
+ <name name="which_applications" arity="0" since=""/>
+ <name name="which_applications" arity="1" since=""/>
<fsummary>Get the currently running applications.</fsummary>
<desc>
<p>Returns a list with information about the applications that
@@ -484,7 +484,7 @@ Nodes = [cp1@cave, {cp2@cave, cp3@cave}]</code>
</section>
<funcs>
<func>
- <name>Module:start(StartType, StartArgs) -> {ok, Pid} | {ok, Pid, State} | {error, Reason}</name>
+ <name since="">Module:start(StartType, StartArgs) -> {ok, Pid} | {ok, Pid, State} | {error, Reason}</name>
<fsummary>Start an application.</fsummary>
<type>
<v>StartType = <seealso marker="#type-start_type"><c>start_type()</c></seealso></v>
@@ -526,7 +526,7 @@ Nodes = [cp1@cave, {cp2@cave, cp3@cave}]</code>
</desc>
</func>
<func>
- <name>Module:start_phase(Phase, StartType, PhaseArgs) -> ok | {error, Reason}</name>
+ <name since="">Module:start_phase(Phase, StartType, PhaseArgs) -> ok | {error, Reason}</name>
<fsummary>Extended start of an application.</fsummary>
<type>
<v>Phase = atom()</v>
@@ -551,7 +551,7 @@ Nodes = [cp1@cave, {cp2@cave, cp3@cave}]</code>
</desc>
</func>
<func>
- <name>Module:prep_stop(State) -> NewState</name>
+ <name since="">Module:prep_stop(State) -> NewState</name>
<fsummary>Prepare an application for termination.</fsummary>
<type>
<v>State = NewState = term()</v>
@@ -569,7 +569,7 @@ Nodes = [cp1@cave, {cp2@cave, cp3@cave}]</code>
</desc>
</func>
<func>
- <name>Module:stop(State)</name>
+ <name since="">Module:stop(State)</name>
<fsummary>Clean up after termination of an application.</fsummary>
<type>
<v>State = term()</v>
@@ -585,7 +585,7 @@ Nodes = [cp1@cave, {cp2@cave, cp3@cave}]</code>
</desc>
</func>
<func>
- <name>Module:config_change(Changed, New, Removed) -> ok</name>
+ <name since="">Module:config_change(Changed, New, Removed) -> ok</name>
<fsummary>Update the configuration parameters for an application.</fsummary>
<type>
<v>Changed = [{Par,Val}]</v>
diff --git a/lib/kernel/doc/src/auth.xml b/lib/kernel/doc/src/auth.xml
index 5901446960..a57da18de9 100644
--- a/lib/kernel/doc/src/auth.xml
+++ b/lib/kernel/doc/src/auth.xml
@@ -28,7 +28,7 @@
<date></date>
<rev></rev>
</header>
- <module>auth</module>
+ <module since="">auth</module>
<modulesummary>Erlang network authentication server.</modulesummary>
<description>
<p>This module is deprecated. For a description of the Magic
@@ -42,7 +42,7 @@
</datatypes>
<funcs>
<func>
- <name name="cookie" arity="0"/>
+ <name name="cookie" arity="0" since=""/>
<fsummary>Magic cookie for local node (deprecated).</fsummary>
<desc>
<p>Use
@@ -51,7 +51,7 @@
</desc>
</func>
<func>
- <name name="cookie" arity="1"/>
+ <name name="cookie" arity="1" since=""/>
<fsummary>Set the magic for the local node (deprecated).</fsummary>
<type_desc variable="TheCookie">
The cookie can also be specified as a list with a single atom element.
@@ -63,7 +63,7 @@
</desc>
</func>
<func>
- <name name="is_auth" arity="1"/>
+ <name name="is_auth" arity="1" since=""/>
<fsummary>Status of communication authorization (deprecated).</fsummary>
<desc>
<p>Returns <c>yes</c> if communication with <c><anno>Node</anno></c> is
@@ -76,7 +76,7 @@
</desc>
</func>
<func>
- <name>node_cookie([Node, Cookie]) -> yes | no</name>
+ <name since="">node_cookie([Node, Cookie]) -> yes | no</name>
<fsummary>Set the magic cookie for a node and verify authorization (deprecated).</fsummary>
<type>
<v>Node = node()</v>
@@ -88,7 +88,7 @@
</desc>
</func>
<func>
- <name name="node_cookie" arity="2"/>
+ <name name="node_cookie" arity="2" since=""/>
<fsummary>Set the magic cookie for a node and verify authorization (deprecated).</fsummary>
<desc>
<p>Sets the magic cookie of <c><anno>Node</anno></c> to
diff --git a/lib/kernel/doc/src/code.xml b/lib/kernel/doc/src/code.xml
index 69ce4da61c..4aa9e8b9d2 100644
--- a/lib/kernel/doc/src/code.xml
+++ b/lib/kernel/doc/src/code.xml
@@ -28,7 +28,7 @@
<date></date>
<rev></rev>
</header>
- <module>code</module>
+ <module since="">code</module>
<modulesummary>Erlang code server.</modulesummary>
<description>
<p>This module contains the interface to the Erlang
@@ -322,7 +322,7 @@ zip:create("mnesia-4.4.7.ez",
<funcs>
<func>
- <name name="set_path" arity="1"/>
+ <name name="set_path" arity="1" since=""/>
<fsummary>Set the code server search path.</fsummary>
<desc>
<p>Sets the code path to the list of directories <c><anno>Path</anno></c>.</p>
@@ -336,15 +336,15 @@ zip:create("mnesia-4.4.7.ez",
</desc>
</func>
<func>
- <name name="get_path" arity="0"/>
+ <name name="get_path" arity="0" since=""/>
<fsummary>Return the code server search path.</fsummary>
<desc>
<p>Returns the code path.</p>
</desc>
</func>
<func>
- <name name="add_path" arity="1"/>
- <name name="add_pathz" arity="1"/>
+ <name name="add_path" arity="1" since=""/>
+ <name name="add_pathz" arity="1" since=""/>
<fsummary>Add a directory to the end of the code path.</fsummary>
<type name="add_path_ret"/>
<desc>
@@ -357,7 +357,7 @@ zip:create("mnesia-4.4.7.ez",
</desc>
</func>
<func>
- <name name="add_patha" arity="1"/>
+ <name name="add_patha" arity="1" since=""/>
<fsummary>Add a directory to the beginning of the code path.</fsummary>
<type name="add_path_ret"/>
<desc>
@@ -370,8 +370,8 @@ zip:create("mnesia-4.4.7.ez",
</desc>
</func>
<func>
- <name name="add_paths" arity="1"/>
- <name name="add_pathsz" arity="1"/>
+ <name name="add_paths" arity="1" since=""/>
+ <name name="add_pathsz" arity="1" since=""/>
<fsummary>Add directories to the end of the code path.</fsummary>
<desc>
<p>Adds the directories in <c><anno>Dirs</anno></c> to the end of the code
@@ -381,7 +381,7 @@ zip:create("mnesia-4.4.7.ez",
</desc>
</func>
<func>
- <name name="add_pathsa" arity="1"/>
+ <name name="add_pathsa" arity="1" since=""/>
<fsummary>Add directories to the beginning of the code path.</fsummary>
<desc>
<p>Traverses <c><anno>Dirs</anno></c> and adds
@@ -397,7 +397,7 @@ zip:create("mnesia-4.4.7.ez",
</desc>
</func>
<func>
- <name name="del_path" arity="1"/>
+ <name name="del_path" arity="1" since=""/>
<fsummary>Delete a directory from the code path.</fsummary>
<desc>
<p>Deletes a directory from the code path. The argument can be
@@ -417,7 +417,7 @@ zip:create("mnesia-4.4.7.ez",
</desc>
</func>
<func>
- <name name="replace_path" arity="2"/>
+ <name name="replace_path" arity="2" since=""/>
<fsummary>Replace a directory with another in the code path.</fsummary>
<desc>
<p>Replaces an old occurrence of a directory
@@ -441,7 +441,7 @@ zip:create("mnesia-4.4.7.ez",
</desc>
</func>
<func>
- <name name="load_file" arity="1"/>
+ <name name="load_file" arity="1" since=""/>
<fsummary>Load a module.</fsummary>
<type name="load_ret"/>
<desc>
@@ -460,7 +460,7 @@ zip:create("mnesia-4.4.7.ez",
</desc>
</func>
<func>
- <name name="load_abs" arity="1"/>
+ <name name="load_abs" arity="1" since=""/>
<fsummary>Load a module, residing in a specified file.</fsummary>
<type name="load_ret"/>
<type name="loaded_filename"/>
@@ -477,7 +477,7 @@ zip:create("mnesia-4.4.7.ez",
</desc>
</func>
<func>
- <name name="ensure_loaded" arity="1"/>
+ <name name="ensure_loaded" arity="1" since=""/>
<fsummary>Ensure that a module is loaded.</fsummary>
<desc>
<p>Tries to load a module in the same way as
@@ -489,7 +489,7 @@ zip:create("mnesia-4.4.7.ez",
</desc>
</func>
<func>
- <name name="load_binary" arity="3"/>
+ <name name="load_binary" arity="3" since=""/>
<fsummary>Load object code for a module.</fsummary>
<type name="loaded_filename"/>
<type name="loaded_ret_atoms"/>
@@ -507,7 +507,7 @@ zip:create("mnesia-4.4.7.ez",
</desc>
</func>
<func>
- <name name="atomic_load" arity="1"/>
+ <name name="atomic_load" arity="1" since="OTP 19.0"/>
<fsummary>Load a list of modules atomically</fsummary>
<desc>
<p>Tries to load all of the modules in the list
@@ -566,7 +566,7 @@ ok = code:finish_loading(Prepared),
</desc>
</func>
<func>
- <name name="prepare_loading" arity="1"/>
+ <name name="prepare_loading" arity="1" since="OTP 19.0"/>
<fsummary>Prepare a list of modules atomically</fsummary>
<desc>
<p>Prepares to load the modules in the list
@@ -598,7 +598,7 @@ ok = code:finish_loading(Prepared),
</desc>
</func>
<func>
- <name name="finish_loading" arity="1"/>
+ <name name="finish_loading" arity="1" since="OTP 19.0"/>
<fsummary>Finish loading a list of prepared modules atomically</fsummary>
<desc>
<p>Tries to load code for all modules that have been previously
@@ -627,7 +627,7 @@ ok = code:finish_loading(Prepared),
</desc>
</func>
<func>
- <name name="ensure_modules_loaded" arity="1"/>
+ <name name="ensure_modules_loaded" arity="1" since="OTP 19.0"/>
<fsummary>Ensure that a list of modules is loaded</fsummary>
<desc>
<p>Tries to load any modules not already loaded in the list
@@ -639,7 +639,7 @@ ok = code:finish_loading(Prepared),
</desc>
</func>
<func>
- <name name="delete" arity="1"/>
+ <name name="delete" arity="1" since=""/>
<fsummary>Remove current code for a module.</fsummary>
<desc>
<p>Removes the current code for <c><anno>Module</anno></c>, that is,
@@ -652,7 +652,7 @@ ok = code:finish_loading(Prepared),
</desc>
</func>
<func>
- <name name="purge" arity="1"/>
+ <name name="purge" arity="1" since=""/>
<fsummary>Remove old code for a module.</fsummary>
<desc>
<p>Purges the code for <c><anno>Module</anno></c>, that is, removes code
@@ -668,7 +668,7 @@ ok = code:finish_loading(Prepared),
</desc>
</func>
<func>
- <name name="soft_purge" arity="1"/>
+ <name name="soft_purge" arity="1" since=""/>
<fsummary>Remove old code for a module, unless no process uses it.</fsummary>
<desc>
<p>Purges the code for <c><anno>Module</anno></c>, that is, removes code
@@ -683,7 +683,7 @@ ok = code:finish_loading(Prepared),
</desc>
</func>
<func>
- <name name="is_loaded" arity="1"/>
+ <name name="is_loaded" arity="1" since=""/>
<fsummary>Check if a module is loaded.</fsummary>
<type name="loaded_filename"/>
<type name="loaded_ret_atoms"/>
@@ -702,7 +702,7 @@ ok = code:finish_loading(Prepared),
</desc>
</func>
<func>
- <name name="all_loaded" arity="0"/>
+ <name name="all_loaded" arity="0" since=""/>
<fsummary>Get all loaded modules.</fsummary>
<type name="loaded_filename"/>
<type name="loaded_ret_atoms"/>
@@ -716,7 +716,7 @@ ok = code:finish_loading(Prepared),
</desc>
</func>
<func>
- <name name="which" arity="1"/>
+ <name name="which" arity="1" since=""/>
<fsummary>The object code file of a module.</fsummary>
<type name="loaded_ret_atoms"/>
<desc>
@@ -731,7 +731,7 @@ ok = code:finish_loading(Prepared),
</desc>
</func>
<func>
- <name name="get_object_code" arity="1"/>
+ <name name="get_object_code" arity="1" since=""/>
<fsummary>Gets the object code for a module.</fsummary>
<desc>
<p>Searches the code path for the object code of module
@@ -750,7 +750,7 @@ rpc:call(Node, code, load_binary, [Module, Filename, Binary]),
</desc>
</func>
<func>
- <name name="root_dir" arity="0"/>
+ <name name="root_dir" arity="0" since=""/>
<fsummary>Root directory of Erlang/OTP.</fsummary>
<desc>
<p>Returns the root directory of Erlang/OTP, which is
@@ -762,7 +762,7 @@ rpc:call(Node, code, load_binary, [Module, Filename, Binary]),
</desc>
</func>
<func>
- <name name="lib_dir" arity="0"/>
+ <name name="lib_dir" arity="0" since=""/>
<fsummary>Library directory of Erlang/OTP.</fsummary>
<desc>
<p>Returns the library directory, <c>$OTPROOT/lib</c>, where
@@ -774,7 +774,7 @@ rpc:call(Node, code, load_binary, [Module, Filename, Binary]),
</desc>
</func>
<func>
- <name name="lib_dir" arity="1"/>
+ <name name="lib_dir" arity="1" since=""/>
<fsummary>Library directory for an application.</fsummary>
<desc>
<p>Returns the path
@@ -807,7 +807,7 @@ rpc:call(Node, code, load_binary, [Module, Filename, Binary]),
</desc>
</func>
<func>
- <name name="lib_dir" arity="2"/>
+ <name name="lib_dir" arity="2" since=""/>
<fsummary>Subdirectory for an application.</fsummary>
<desc>
<p>Returns the path to a subdirectory directly under the top
@@ -827,7 +827,7 @@ rpc:call(Node, code, load_binary, [Module, Filename, Binary]),
</desc>
</func>
<func>
- <name name="compiler_dir" arity="0"/>
+ <name name="compiler_dir" arity="0" since=""/>
<fsummary>Library directory for the compiler.</fsummary>
<desc>
<p>Returns the compiler library directory. Equivalent to
@@ -835,7 +835,7 @@ rpc:call(Node, code, load_binary, [Module, Filename, Binary]),
</desc>
</func>
<func>
- <name name="priv_dir" arity="1"/>
+ <name name="priv_dir" arity="1" since=""/>
<fsummary>Priv directory for an application.</fsummary>
<desc>
<p>Returns the path to the <c>priv</c> directory in an
@@ -846,7 +846,7 @@ rpc:call(Node, code, load_binary, [Module, Filename, Binary]),
</desc>
</func>
<func>
- <name name="objfile_extension" arity="0"/>
+ <name name="objfile_extension" arity="0" since=""/>
<fsummary>Object code file extension.</fsummary>
<desc>
<p>Returns the object code file extension corresponding to
@@ -854,7 +854,7 @@ rpc:call(Node, code, load_binary, [Module, Filename, Binary]),
</desc>
</func>
<func>
- <name name="stick_dir" arity="1"/>
+ <name name="stick_dir" arity="1" since=""/>
<fsummary>Mark a directory as sticky.</fsummary>
<desc>
<p>Marks <c><anno>Dir</anno></c> as sticky.</p>
@@ -862,7 +862,7 @@ rpc:call(Node, code, load_binary, [Module, Filename, Binary]),
</desc>
</func>
<func>
- <name name="unstick_dir" arity="1"/>
+ <name name="unstick_dir" arity="1" since=""/>
<fsummary>Remove a sticky directory mark.</fsummary>
<desc>
<p>Unsticks a directory that is marked as
@@ -871,7 +871,7 @@ rpc:call(Node, code, load_binary, [Module, Filename, Binary]),
</desc>
</func>
<func>
- <name name="is_sticky" arity="1"/>
+ <name name="is_sticky" arity="1" since=""/>
<fsummary>Test if a module is sticky.</fsummary>
<desc>
<p>Returns <c>true</c> if <c><anno>Module</anno></c> is the
@@ -882,7 +882,7 @@ rpc:call(Node, code, load_binary, [Module, Filename, Binary]),
</desc>
</func>
<func>
- <name name="where_is_file" arity="1"/>
+ <name name="where_is_file" arity="1" since=""/>
<fsummary>Full name of a file located in the code path.</fsummary>
<desc>
<p>Searches the code path for <c><anno>Filename</anno></c>, a file of
@@ -893,7 +893,7 @@ rpc:call(Node, code, load_binary, [Module, Filename, Binary]),
</desc>
</func>
<func>
- <name name="clash" arity="0"/>
+ <name name="clash" arity="0" since=""/>
<fsummary>Search for modules with identical names.</fsummary>
<desc>
<p>Searches all directories in the code path for module names with
@@ -901,7 +901,7 @@ rpc:call(Node, code, load_binary, [Module, Filename, Binary]),
</desc>
</func>
<func>
- <name name="module_status" arity="1"/>
+ <name name="module_status" arity="1" since="OTP 20.0"/>
<fsummary>Return the status of the module in relation to object file on disk.</fsummary>
<desc>
<p>Returns:</p>
@@ -934,7 +934,7 @@ rpc:call(Node, code, load_binary, [Module, Filename, Binary]),
</desc>
</func>
<func>
- <name name="modified_modules" arity="0"/>
+ <name name="modified_modules" arity="0" since="OTP 20.0"/>
<fsummary>Return a list of all modules modified on disk.</fsummary>
<desc>
<p>Returns the list of all currently loaded modules for which
@@ -943,7 +943,7 @@ rpc:call(Node, code, load_binary, [Module, Filename, Binary]),
</desc>
</func>
<func>
- <name name="is_module_native" arity="1"/>
+ <name name="is_module_native" arity="1" since=""/>
<fsummary>Test if a module has native code.</fsummary>
<desc>
<p>Returns:</p>
@@ -961,7 +961,7 @@ rpc:call(Node, code, load_binary, [Module, Filename, Binary]),
</func>
<func>
- <name name="get_mode" arity="0"/>
+ <name name="get_mode" arity="0" since="OTP R16B"/>
<fsummary>The mode of the code server.</fsummary>
<desc>
<p>Returns an atom describing the mode of the code server:
diff --git a/lib/kernel/doc/src/disk_log.xml b/lib/kernel/doc/src/disk_log.xml
index 884cb32c0c..e308b06f3c 100644
--- a/lib/kernel/doc/src/disk_log.xml
+++ b/lib/kernel/doc/src/disk_log.xml
@@ -34,7 +34,7 @@
<rev>D</rev>
<file>disk_log.sgml</file>
</header>
- <module>disk_log</module>
+ <module since="">disk_log</module>
<modulesummary>A disk-based term logging facility.</modulesummary>
<description>
<p><c>disk_log</c> is a disk-based term logger that enables
@@ -238,7 +238,7 @@
</datatypes>
<funcs>
<func>
- <name name="accessible_logs" arity="0"/>
+ <name name="accessible_logs" arity="0" since=""/>
<fsummary>Return the accessible disk logs on the current node.</fsummary>
<desc>
<p>Returns the names of the disk logs accessible on the current node.
@@ -248,8 +248,8 @@
</desc>
</func>
<func>
- <name name="alog" arity="2"/>
- <name name="balog" arity="2"/>
+ <name name="alog" arity="2" since=""/>
+ <name name="balog" arity="2" since=""/>
<fsummary>Asynchronously log an item on to a disk log.</fsummary>
<type variable="Log"/>
<type variable="Term" name_i="1"/>
@@ -275,8 +275,8 @@
</desc>
</func>
<func>
- <name name="alog_terms" arity="2"/>
- <name name="balog_terms" arity="2"/>
+ <name name="alog_terms" arity="2" since=""/>
+ <name name="balog_terms" arity="2" since=""/>
<fsummary>Asynchronously log many items on to a disk log.</fsummary>
<type variable="Log"/>
<type variable="TermList" name_i="1"/>
@@ -303,8 +303,8 @@
</desc>
</func>
<func>
- <name name="block" arity="1"/>
- <name name="block" arity="2"/>
+ <name name="block" arity="1" since=""/>
+ <name name="block" arity="2" since=""/>
<fsummary>Block a disk log.</fsummary>
<type name="block_error_rsn"/>
<desc>
@@ -330,21 +330,21 @@
</desc>
</func>
<func>
- <name name="change_header" arity="2"/>
+ <name name="change_header" arity="2" since=""/>
<fsummary>Change option head or head_func for an owner of a disk log.</fsummary>
<desc>
<p>Changes the value of option <c>head</c> or <c>head_func</c> for an owner of a disk log.</p>
</desc>
</func>
<func>
- <name name="change_notify" arity="3"/>
+ <name name="change_notify" arity="3" since=""/>
<fsummary>Change option notify for an owner of a disk log.</fsummary>
<desc>
<p>Changes the value of option <c>notify</c> for an owner of a disk log. </p>
</desc>
</func>
<func>
- <name name="change_size" arity="2"/>
+ <name name="change_size" arity="2" since=""/>
<fsummary>Change the size of an open disk log.</fsummary>
<desc>
<p>Changes the size of an open log.
@@ -384,10 +384,10 @@
</desc>
</func>
<func>
- <name name="chunk" arity="2"/>
- <name name="chunk" arity="3"/>
- <name name="bchunk" arity="2"/>
- <name name="bchunk" arity="3"/>
+ <name name="chunk" arity="2" since=""/>
+ <name name="chunk" arity="3" since=""/>
+ <name name="bchunk" arity="2" since=""/>
+ <name name="bchunk" arity="3" since=""/>
<fsummary>Read a chunk of items written to a disk log.</fsummary>
<type variable="Log"/>
<type variable="Continuation"/>
@@ -447,7 +447,7 @@
</desc>
</func>
<func>
- <name name="chunk_info" arity="1"/>
+ <name name="chunk_info" arity="1" since=""/>
<fsummary>Return information about a chunk continuation of a disk log.</fsummary>
<desc>
<p>Returns the pair <c>{node, <anno>Node</anno>}</c>,
@@ -457,7 +457,7 @@
</desc>
</func>
<func>
- <name name="chunk_step" arity="3"/>
+ <name name="chunk_step" arity="3" since=""/>
<fsummary>Step forward or backward among the wrap log files of a disk log.</fsummary>
<desc>
<p>Can be used with <c>chunk/2,3</c> and <c>bchunk/2,3</c>
@@ -480,7 +480,7 @@
</desc>
</func>
<func>
- <name name="close" arity="1"/>
+ <name name="close" arity="1" since=""/>
<fsummary>Close a disk log.</fsummary>
<type name="close_error_rsn"/>
<desc>
@@ -505,7 +505,7 @@
</desc>
</func>
<func>
- <name name="format_error" arity="1"/>
+ <name name="format_error" arity="1" since=""/>
<fsummary>Return an English description of a disk log error reply.</fsummary>
<desc>
<p>Given the error returned by any function in this module,
@@ -517,7 +517,7 @@
</desc>
</func>
<func>
- <name name="inc_wrap_file" arity="1"/>
+ <name name="inc_wrap_file" arity="1" since=""/>
<fsummary>Change to the next wrap log file of a disk log.</fsummary>
<type name="inc_wrap_error_rsn"/>
<type name="invalid_header"/>
@@ -534,7 +534,7 @@
</desc>
</func>
<func>
- <name name="info" arity="1"/>
+ <name name="info" arity="1" since=""/>
<fsummary>Return information about a disk log.</fsummary>
<type name="dlog_info"/>
<desc>
@@ -685,8 +685,8 @@
</desc>
</func>
<func>
- <name name="lclose" arity="1"/>
- <name name="lclose" arity="2"/>
+ <name name="lclose" arity="1" since=""/>
+ <name name="lclose" arity="2" since=""/>
<fsummary>Close a disk log on one node.</fsummary>
<type name="lclose_error_rsn"/>
<desc>
@@ -704,8 +704,8 @@
</desc>
</func>
<func>
- <name name="log" arity="2"/>
- <name name="blog" arity="2"/>
+ <name name="log" arity="2" since=""/>
+ <name name="blog" arity="2" since=""/>
<fsummary>Log an item onto a disk log.</fsummary>
<type variable="Log"/>
<type variable="Term" name_i="1"/>
@@ -739,8 +739,8 @@
</desc>
</func>
<func>
- <name name="log_terms" arity="2"/>
- <name name="blog_terms" arity="2"/>
+ <name name="log_terms" arity="2" since=""/>
+ <name name="blog_terms" arity="2" since=""/>
<fsummary>Log many items onto a disk log.</fsummary>
<type variable="Log"/>
<type variable="TermList" name_i="1"/>
@@ -768,7 +768,7 @@
</desc>
</func>
<func>
- <name name="open" arity="1"/>
+ <name name="open" arity="1" since=""/>
<fsummary>Open a disk log file.</fsummary>
<type name="dlog_options"/>
<type name="dlog_option"/>
@@ -1041,7 +1041,7 @@
</desc>
</func>
<func>
- <name name="pid2name" arity="1"/>
+ <name name="pid2name" arity="1" since=""/>
<fsummary>Return the name of the disk log handled by a pid.</fsummary>
<desc>
<p>Returns the log name
@@ -1053,9 +1053,9 @@
</desc>
</func>
<func>
- <name name="reopen" arity="2"/>
- <name name="reopen" arity="3"/>
- <name name="breopen" arity="3"/>
+ <name name="reopen" arity="2" since=""/>
+ <name name="reopen" arity="3" since=""/>
+ <name name="breopen" arity="3" since=""/>
<fsummary>Reopen a disk log and save the old log.</fsummary>
<type variable="Log"/>
<type variable="File" name_i="1"/>
@@ -1087,7 +1087,7 @@
</desc>
</func>
<func>
- <name name="sync" arity="1"/>
+ <name name="sync" arity="1" since=""/>
<fsummary>Flush the contents of a disk log to the disk.</fsummary>
<type name="sync_error_rsn"/>
<desc>
@@ -1097,9 +1097,9 @@
</desc>
</func>
<func>
- <name name="truncate" arity="1"/>
- <name name="truncate" arity="2"/>
- <name name="btruncate" arity="2"/>
+ <name name="truncate" arity="1" since=""/>
+ <name name="truncate" arity="2" since=""/>
+ <name name="btruncate" arity="2" since=""/>
<fsummary>Truncate a disk log.</fsummary>
<type variable="Log"/>
<type variable="Head" name_i="2"/>
@@ -1129,7 +1129,7 @@
</desc>
</func>
<func>
- <name name="unblock" arity="1"/>
+ <name name="unblock" arity="1" since=""/>
<fsummary>Unblock a disk log.</fsummary>
<type name="unblock_error_rsn"/>
<desc>
diff --git a/lib/kernel/doc/src/erl_boot_server.xml b/lib/kernel/doc/src/erl_boot_server.xml
index 4109251387..89f9855c49 100644
--- a/lib/kernel/doc/src/erl_boot_server.xml
+++ b/lib/kernel/doc/src/erl_boot_server.xml
@@ -28,7 +28,7 @@
<date></date>
<rev></rev>
</header>
- <module>erl_boot_server</module>
+ <module since="">erl_boot_server</module>
<modulesummary>Boot server for other Erlang machines.</modulesummary>
<description>
<p>This server is used to assist diskless Erlang nodes that fetch
@@ -52,14 +52,14 @@
</description>
<funcs>
<func>
- <name name="add_slave" arity="1"/>
+ <name name="add_slave" arity="1" since=""/>
<fsummary>Add a slave to the list of allowed slaves.</fsummary>
<desc>
<p>Adds a <c><anno>Slave</anno></c> node to the list of allowed slave hosts.</p>
</desc>
</func>
<func>
- <name name="delete_slave" arity="1"/>
+ <name name="delete_slave" arity="1" since=""/>
<fsummary>Delete a slave from the list of allowed slaves.</fsummary>
<desc>
<p>Deletes a <c><anno>Slave</anno></c> node from the list of allowed slave
@@ -67,7 +67,7 @@
</desc>
</func>
<func>
- <name name="start" arity="1"/>
+ <name name="start" arity="1" since=""/>
<fsummary>Start the boot server.</fsummary>
<desc>
<p>Starts the boot server. <c><anno>Slaves</anno></c> is a list of
@@ -76,7 +76,7 @@
</desc>
</func>
<func>
- <name name="start_link" arity="1"/>
+ <name name="start_link" arity="1" since=""/>
<fsummary>Start the boot server and link to the the caller.</fsummary>
<desc>
<p>Starts the boot server and links to the caller. This function
@@ -85,7 +85,7 @@
</desc>
</func>
<func>
- <name name="which_slaves" arity="0"/>
+ <name name="which_slaves" arity="0" since=""/>
<fsummary>Return the current list of allowed slave hosts.</fsummary>
<desc>
<p>Returns the current list of allowed slave hosts.</p>
diff --git a/lib/kernel/doc/src/erl_ddll.xml b/lib/kernel/doc/src/erl_ddll.xml
index 75114e015c..f2d5e1b397 100644
--- a/lib/kernel/doc/src/erl_ddll.xml
+++ b/lib/kernel/doc/src/erl_ddll.xml
@@ -28,7 +28,7 @@
<date></date>
<rev></rev>
</header>
- <module>erl_ddll</module>
+ <module since="">erl_ddll</module>
<modulesummary>Dynamic driver loader and linker.</modulesummary>
<description>
<p>This module provides an interface for loading
@@ -196,7 +196,7 @@
</datatypes>
<funcs>
<func>
- <name name="demonitor" arity="1"/>
+ <name name="demonitor" arity="1" since=""/>
<fsummary>Remove a monitor for a driver.</fsummary>
<desc>
<p>Removes a driver monitor in much the same way as
@@ -212,7 +212,7 @@
</desc>
</func>
<func>
- <name name="format_error" arity="1"/>
+ <name name="format_error" arity="1" since=""/>
<fsummary>Format an error descriptor.</fsummary>
<desc>
<p>Takes an <c><anno>ErrorDesc</anno></c> returned by load, unload, or
@@ -229,7 +229,7 @@
</desc>
</func>
<func>
- <name name="info" arity="0"/>
+ <name name="info" arity="0" since=""/>
<fsummary>Retrieve information about all drivers.</fsummary>
<desc>
<p>Returns a list of tuples <c>{<anno>DriverName</anno>, <anno>InfoList</anno>}</c>,
@@ -240,7 +240,7 @@
</desc>
</func>
<func>
- <name name="info" arity="1"/>
+ <name name="info" arity="1" since=""/>
<fsummary>Retrieve information about one driver.</fsummary>
<desc>
<p>Returns a list of tuples <c>{<anno>Tag</anno>, <anno>Value</anno>}</c>,
@@ -266,7 +266,7 @@
</desc>
</func>
<func>
- <name name="info" arity="2"/>
+ <name name="info" arity="2" since=""/>
<fsummary>Retrieve specific information about one driver.</fsummary>
<desc>
<p>Returns specific information about one aspect of a driver.
@@ -328,7 +328,7 @@
</desc>
</func>
<func>
- <name name="load" arity="2"/>
+ <name name="load" arity="2" since=""/>
<fsummary>Load a driver.</fsummary>
<desc>
<p>Loads and links the dynamic driver <c><anno>Name</anno></c>.
@@ -390,7 +390,7 @@
</desc>
</func>
<func>
- <name name="load_driver" arity="2"/>
+ <name name="load_driver" arity="2" since=""/>
<fsummary>Load a driver.</fsummary>
<desc>
<p>Works essentially as <c>load/2</c>, but loads the driver
@@ -413,7 +413,7 @@
</desc>
</func>
<func>
- <name name="loaded_drivers" arity="0"/>
+ <name name="loaded_drivers" arity="0" since=""/>
<fsummary>List loaded drivers.</fsummary>
<desc>
<p>Returns a list of all the available drivers, both
@@ -425,7 +425,7 @@
</desc>
</func>
<func>
- <name name="monitor" arity="2"/>
+ <name name="monitor" arity="2" since=""/>
<fsummary>Create a monitor for a driver.</fsummary>
<desc>
<p>Creates a driver monitor and works in many
@@ -588,7 +588,7 @@
</desc>
</func>
<func>
- <name name="reload" arity="2"/>
+ <name name="reload" arity="2" since=""/>
<fsummary>Replace a driver.</fsummary>
<desc>
<p>Reloads the driver named <c><anno>Name</anno></c> from a possibly
@@ -626,7 +626,7 @@
</desc>
</func>
<func>
- <name name="reload_driver" arity="2"/>
+ <name name="reload_driver" arity="2" since=""/>
<fsummary>Replace a driver.</fsummary>
<desc>
<p>Works exactly as <seealso marker="#reload/2"><c>reload/2</c></seealso>,
@@ -644,7 +644,7 @@
</desc>
</func>
<func>
- <name name="try_load" arity="3"/>
+ <name name="try_load" arity="3" since=""/>
<fsummary>Load a driver.</fsummary>
<desc>
<p>Provides more control than the
@@ -931,7 +931,7 @@
</desc>
</func>
<func>
- <name name="try_unload" arity="2"/>
+ <name name="try_unload" arity="2" since=""/>
<fsummary>Unload a driver.</fsummary>
<desc>
<p>This is the low-level function to unload (or decrement
@@ -1116,7 +1116,7 @@
</desc>
</func>
<func>
- <name name="unload" arity="1"/>
+ <name name="unload" arity="1" since=""/>
<fsummary>Unload a driver.</fsummary>
<desc>
<p>Unloads, or at least dereferences the driver named
@@ -1143,7 +1143,7 @@
</desc>
</func>
<func>
- <name name="unload_driver" arity="1"/>
+ <name name="unload_driver" arity="1" since=""/>
<fsummary>Unload a driver.</fsummary>
<desc>
<p>Unloads, or at least dereferences the driver named
diff --git a/lib/kernel/doc/src/erl_epmd.xml b/lib/kernel/doc/src/erl_epmd.xml
index 8b076cd2d7..2adbf11a28 100644
--- a/lib/kernel/doc/src/erl_epmd.xml
+++ b/lib/kernel/doc/src/erl_epmd.xml
@@ -28,7 +28,7 @@
<date>2018-02-19</date>
<rev>A</rev>
</header>
- <module>erl_epmd</module>
+ <module since="OTP R14B">erl_epmd</module>
<modulesummary>
Erlang interface towards epmd
</modulesummary>
@@ -41,7 +41,7 @@
<funcs>
<func>
- <name name="start_link" arity="0"/>
+ <name name="start_link" arity="0" since="OTP 21.0"/>
<fsummary>Callback for erl_distribution supervisor.</fsummary>
<desc>
<p>This function is invoked as this module is added as a child of the
@@ -50,8 +50,8 @@
</func>
<func>
- <name name="register_node" arity="2"/>
- <name name="register_node" arity="3"/>
+ <name name="register_node" arity="2" since="OTP 21.0"/>
+ <name name="register_node" arity="3" since="OTP 21.0"/>
<fsummary>Registers the node with <c>epmd</c>.</fsummary>
<desc>
<p>Registers the node with <c>epmd</c> and tells epmd what port will be
@@ -62,8 +62,8 @@
</func>
<func>
- <name name="port_please" arity="2"/>
- <name name="port_please" arity="3"/>
+ <name name="port_please" arity="2" since="OTP 21.0"/>
+ <name name="port_please" arity="3" since="OTP 21.0"/>
<fsummary>Returns the port number for a given node.</fsummary>
<desc>
<p>Requests the distribution port for the given node of an EPMD
@@ -73,7 +73,7 @@
</func>
<func>
- <name name="address_please" arity="3"/>
+ <name name="address_please" arity="3" since="OTP 21.0"/>
<fsummary>Returns address and port.</fsummary>
<desc>
<p>Called by the distribution module. Resolves the <c>Host</c> to an IP
@@ -84,7 +84,7 @@
</func>
<func>
- <name name="names" arity="1"/>
+ <name name="names" arity="1" since="OTP 21.0"/>
<fsummary>Names of Erlang nodes at a host.</fsummary>
<desc>
<p>Called by <seealso marker="net_adm"><c>net_adm:names/0</c></seealso>.
diff --git a/lib/kernel/doc/src/error_handler.xml b/lib/kernel/doc/src/error_handler.xml
index e5639487dc..eb01e87aee 100644
--- a/lib/kernel/doc/src/error_handler.xml
+++ b/lib/kernel/doc/src/error_handler.xml
@@ -30,7 +30,7 @@
<date></date>
<rev></rev>
</header>
- <module>error_handler</module>
+ <module since="">error_handler</module>
<modulesummary>Default system error handler.</modulesummary>
<description>
<p>This module defines what happens when certain types
@@ -38,7 +38,7 @@
</description>
<funcs>
<func>
- <name name="raise_undef_exception" arity="3"/>
+ <name name="raise_undef_exception" arity="3" since="OTP R16B"/>
<fsummary>Raise an undef exception.</fsummary>
<type_desc variable="Args">
A (possibly empty) list of arguments <c>Arg1,..,ArgN</c>
@@ -51,7 +51,7 @@
</desc>
</func>
<func>
- <name name="undefined_function" arity="3"/>
+ <name name="undefined_function" arity="3" since=""/>
<fsummary>Called when an undefined function is encountered.</fsummary>
<type_desc variable="Args">
A (possibly empty) list of arguments <c>Arg1,..,ArgN</c>
@@ -93,7 +93,7 @@
</desc>
</func>
<func>
- <name name="undefined_lambda" arity="3"/>
+ <name name="undefined_lambda" arity="3" since=""/>
<fsummary>Called when an undefined lambda (fun) is encountered.</fsummary>
<type_desc variable="Args">
A (possibly empty) list of arguments <c>Arg1,..,ArgN</c>
diff --git a/lib/kernel/doc/src/error_logger.xml b/lib/kernel/doc/src/error_logger.xml
index c3d68fd79f..c170b4fa34 100644
--- a/lib/kernel/doc/src/error_logger.xml
+++ b/lib/kernel/doc/src/error_logger.xml
@@ -28,7 +28,7 @@
<date></date>
<rev></rev>
</header>
- <module>error_logger</module>
+ <module since="">error_logger</module>
<modulesummary>Erlang error logger.</modulesummary>
<description>
@@ -76,8 +76,8 @@
</datatypes>
<funcs>
<func>
- <name name="add_report_handler" arity="1"/>
- <name name="add_report_handler" arity="2"/>
+ <name name="add_report_handler" arity="1" since=""/>
+ <name name="add_report_handler" arity="2" since=""/>
<fsummary>Add an event handler to the error logger.</fsummary>
<desc>
<p>Adds a new event handler to the error logger. The event
@@ -96,7 +96,7 @@
</desc>
</func>
<func>
- <name name="delete_report_handler" arity="1"/>
+ <name name="delete_report_handler" arity="1" since=""/>
<fsummary>Delete an event handler from the error logger.</fsummary>
<desc>
<p>Deletes an event handler from the error logger by calling
@@ -108,9 +108,9 @@
</desc>
</func>
<func>
- <name name="error_msg" arity="1"/>
- <name name="error_msg" arity="2"/>
- <name name="format" arity="2"/>
+ <name name="error_msg" arity="1" since=""/>
+ <name name="error_msg" arity="2" since=""/>
+ <name name="format" arity="2" since=""/>
<fsummary>Log a standard error event.</fsummary>
<desc>
<p>Log a standard error event. The <c><anno>Format</anno></c>
@@ -142,7 +142,7 @@ ok</pre>
</desc>
</func>
<func>
- <name name="error_report" arity="1"/>
+ <name name="error_report" arity="1" since=""/>
<fsummary>Log a standard error event.</fsummary>
<desc>
<p>Log a standard error event. Error logger forwards the event
@@ -169,7 +169,7 @@ ok</pre>
</desc>
</func>
<func>
- <name name="error_report" arity="2"/>
+ <name name="error_report" arity="2" since=""/>
<fsummary>Log a user-defined error event.</fsummary>
<desc>
<p>Log a user-defined error event. Error logger forwards the
@@ -191,7 +191,7 @@ ok</pre>
</desc>
</func>
<func>
- <name name="get_format_depth" arity="0"/>
+ <name name="get_format_depth" arity="0" since="OTP 20.0"/>
<fsummary>Get the value of the Kernel application variable
<c>error_logger_format_depth</c>.</fsummary>
<desc>
@@ -211,8 +211,8 @@ ok</pre>
</desc>
</func>
<func>
- <name name="info_msg" arity="1"/>
- <name name="info_msg" arity="2"/>
+ <name name="info_msg" arity="1" since=""/>
+ <name name="info_msg" arity="2" since=""/>
<fsummary>Log a standard information event.</fsummary>
<desc>
<p>Log a standard information event. The <c><anno>Format</anno></c>
@@ -244,7 +244,7 @@ ok</pre>
</desc>
</func>
<func>
- <name name="info_report" arity="1"/>
+ <name name="info_report" arity="1" since=""/>
<fsummary>Log a standard information event.</fsummary>
<desc>
<p>Log a standard information event. Error logger forwards the
@@ -271,7 +271,7 @@ ok</pre>
</desc>
</func>
<func>
- <name name="info_report" arity="2"/>
+ <name name="info_report" arity="2" since=""/>
<fsummary>Log a user-defined information event.</fsummary>
<desc>
<p>Log a user-defined information event. Error logger forwards
@@ -294,9 +294,9 @@ ok</pre>
</desc>
</func>
<func>
- <name name="logfile" arity="1" clause_i="1"/>
- <name name="logfile" arity="1" clause_i="2"/>
- <name name="logfile" arity="1" clause_i="3"/>
+ <name name="logfile" arity="1" clause_i="1" since=""/>
+ <name name="logfile" arity="1" clause_i="2" since=""/>
+ <name name="logfile" arity="1" clause_i="3" since=""/>
<fsummary>Enable or disable error printouts to a file.</fsummary>
<type variable="Filename"/>
<type variable="OpenReason" name_i="1"/>
@@ -346,7 +346,7 @@ ok</pre>
</desc>
</func>
<func>
- <name name="tty" arity="1"/>
+ <name name="tty" arity="1" since=""/>
<fsummary>Enable or disable printouts to the terminal.</fsummary>
<desc>
<p>Enables (<c><anno>Flag</anno> == true</c>) or disables
@@ -363,7 +363,7 @@ ok</pre>
</desc>
</func>
<func>
- <name name="warning_map" arity="0"/>
+ <name name="warning_map" arity="0" since=""/>
<fsummary>Return the current mapping for warning events.</fsummary>
<desc>
<p>Returns the current mapping for warning events. Events sent
@@ -400,8 +400,8 @@ ok</pre>
</desc>
</func>
<func>
- <name name="warning_msg" arity="1"/>
- <name name="warning_msg" arity="2"/>
+ <name name="warning_msg" arity="1" since=""/>
+ <name name="warning_msg" arity="2" since=""/>
<fsummary>Log a standard warning event.</fsummary>
<desc>
<p>Log a standard warning event. The <c><anno>Format</anno></c>
@@ -429,7 +429,7 @@ ok</pre>
</desc>
</func>
<func>
- <name name="warning_report" arity="1"/>
+ <name name="warning_report" arity="1" since=""/>
<fsummary>Log a standard warning event.</fsummary>
<desc>
<p>Log a standard warning event. Error logger forwards the event
@@ -446,7 +446,7 @@ ok</pre>
</desc>
</func>
<func>
- <name name="warning_report" arity="2"/>
+ <name name="warning_report" arity="2" since=""/>
<fsummary>Log a user-defined warning event.</fsummary>
<desc>
<p>Log a user-defined warning event. Error logger forwards the
diff --git a/lib/kernel/doc/src/file.xml b/lib/kernel/doc/src/file.xml
index 9acaf6b41e..fc25e83d40 100644
--- a/lib/kernel/doc/src/file.xml
+++ b/lib/kernel/doc/src/file.xml
@@ -28,7 +28,7 @@
<date></date>
<rev></rev>
</header>
- <module>file</module>
+ <module since="">file</module>
<modulesummary>File interface module.</modulesummary>
<description>
<p>This module provides an interface to the file system.</p>
@@ -186,7 +186,7 @@
<funcs>
<func>
- <name name="advise" arity="4"/>
+ <name name="advise" arity="4" since="OTP R14B"/>
<fsummary>Predeclare an access pattern for file data.</fsummary>
<type name="posix_file_advise"/>
<desc>
@@ -197,7 +197,7 @@
</desc>
</func>
<func>
- <name name="allocate" arity="3"/>
+ <name name="allocate" arity="3" since="OTP R16B"/>
<fsummary>Allocate file space.</fsummary>
<desc>
<p><c>allocate/3</c> can be used to preallocate space for a file.</p>
@@ -209,7 +209,7 @@
</desc>
</func>
<func>
- <name name="change_group" arity="2"/>
+ <name name="change_group" arity="2" since=""/>
<fsummary>Change group of a file.</fsummary>
<desc>
<p>Changes group of a file. See
@@ -217,7 +217,7 @@
</desc>
</func>
<func>
- <name name="change_mode" arity="2"/>
+ <name name="change_mode" arity="2" since="OTP R14B"/>
<fsummary>Change permissions of a file.</fsummary>
<desc>
<p>Changes permissions of a file. See
@@ -225,7 +225,7 @@
</desc>
</func>
<func>
- <name name="change_owner" arity="2"/>
+ <name name="change_owner" arity="2" since=""/>
<fsummary>Change owner of a file.</fsummary>
<desc>
<p>Changes owner of a file. See
@@ -233,7 +233,7 @@
</desc>
</func>
<func>
- <name name="change_owner" arity="3"/>
+ <name name="change_owner" arity="3" since=""/>
<fsummary>Change owner and group of a file.</fsummary>
<desc>
<p>Changes owner and group of a file. See
@@ -241,7 +241,7 @@
</desc>
</func>
<func>
- <name name="change_time" arity="2"/>
+ <name name="change_time" arity="2" since=""/>
<fsummary>Change the modification time of a file.</fsummary>
<desc>
<p>Changes the modification and access times of a file. See
@@ -249,7 +249,7 @@
</desc>
</func>
<func>
- <name name="change_time" arity="3"/>
+ <name name="change_time" arity="3" since=""/>
<fsummary>Change the modification and last access time of a file.</fsummary>
<desc>
<p>Changes the modification and last access times of a file. See
@@ -257,7 +257,7 @@
</desc>
</func>
<func>
- <name name="close" arity="1"/>
+ <name name="close" arity="1" since=""/>
<fsummary>Close a file.</fsummary>
<desc>
<p>Closes the file referenced by <c><anno>IoDevice</anno></c>. It mostly
@@ -270,7 +270,7 @@
</desc>
</func>
<func>
- <name name="consult" arity="1"/>
+ <name name="consult" arity="1" since=""/>
<fsummary>Read Erlang terms from a file.</fsummary>
<desc>
<p>Reads Erlang terms, separated by '.', from
@@ -308,8 +308,8 @@ f.txt: {person, "kalle", 25}.
</desc>
</func>
<func>
- <name name="copy" arity="2"/>
- <name name="copy" arity="3"/>
+ <name name="copy" arity="2" since=""/>
+ <name name="copy" arity="3" since=""/>
<fsummary>Copy file contents.</fsummary>
<desc>
<p>Copies <c><anno>ByteCount</anno></c> bytes from
@@ -346,7 +346,7 @@ f.txt: {person, "kalle", 25}.
</desc>
</func>
<func>
- <name name="datasync" arity="1"/>
+ <name name="datasync" arity="1" since="OTP R14B"/>
<fsummary>Synchronize the in-memory data of a file, ignoring most of its metadata, with that on the physical medium.</fsummary>
<desc>
<p>Ensures that any buffers kept by the operating system
@@ -369,7 +369,7 @@ f.txt: {person, "kalle", 25}.
</desc>
</func>
<func>
- <name name="del_dir" arity="1"/>
+ <name name="del_dir" arity="1" since=""/>
<fsummary>Delete a directory.</fsummary>
<desc>
<p>Tries to delete directory <c><anno>Dir</anno></c>.
@@ -405,7 +405,7 @@ f.txt: {person, "kalle", 25}.
</desc>
</func>
<func>
- <name name="delete" arity="1"/>
+ <name name="delete" arity="1" since=""/>
<fsummary>Delete a file.</fsummary>
<desc>
<p>Tries to delete file <c><anno>Filename</anno></c>.
@@ -442,7 +442,7 @@ f.txt: {person, "kalle", 25}.
</desc>
</func>
<func>
- <name name="eval" arity="1"/>
+ <name name="eval" arity="1" since=""/>
<fsummary>Evaluate Erlang expressions in a file.</fsummary>
<desc>
<p>Reads and evaluates Erlang expressions, separated by '.' (or
@@ -476,7 +476,7 @@ f.txt: {person, "kalle", 25}.
</desc>
</func>
<func>
- <name name="eval" arity="2"/>
+ <name name="eval" arity="2" since=""/>
<fsummary>Evaluate Erlang expressions in a file.</fsummary>
<desc>
<p>The same as <c>eval/1</c>, but the variable bindings
@@ -486,7 +486,7 @@ f.txt: {person, "kalle", 25}.
</desc>
</func>
<func>
- <name name="format_error" arity="1"/>
+ <name name="format_error" arity="1" since=""/>
<fsummary>Return a descriptive string for an error reason.</fsummary>
<desc>
<p>Given the error reason returned by any function in this
@@ -494,7 +494,7 @@ f.txt: {person, "kalle", 25}.
</desc>
</func>
<func>
- <name name="get_cwd" arity="0"/>
+ <name name="get_cwd" arity="0" since=""/>
<fsummary>Get the current working directory.</fsummary>
<desc>
<p>Returns <c>{ok, <anno>Dir</anno>}</c>, where <c><anno>Dir</anno></c>
@@ -516,7 +516,7 @@ f.txt: {person, "kalle", 25}.
</desc>
</func>
<func>
- <name name="get_cwd" arity="1"/>
+ <name name="get_cwd" arity="1" since=""/>
<fsummary>Get the current working directory for the specified drive.</fsummary>
<desc>
<p>Returns <c>{ok, <anno>Dir</anno>}</c> or
@@ -547,7 +547,7 @@ f.txt: {person, "kalle", 25}.
</desc>
</func>
<func>
- <name name="list_dir" arity="1"/>
+ <name name="list_dir" arity="1" since=""/>
<fsummary>List files in a directory.</fsummary>
<desc>
<p>Lists all files in a directory, <em>except</em> files
@@ -578,7 +578,7 @@ f.txt: {person, "kalle", 25}.
</desc>
</func>
<func>
- <name name="list_dir_all" arity="1"/>
+ <name name="list_dir_all" arity="1" since="OTP R16B"/>
<fsummary>List all files in a directory.</fsummary>
<desc>
<p><marker id="list_dir_all"/>Lists all the files in a directory,
@@ -603,7 +603,7 @@ f.txt: {person, "kalle", 25}.
</desc>
</func>
<func>
- <name name="make_dir" arity="1"/>
+ <name name="make_dir" arity="1" since=""/>
<fsummary>Make a directory.</fsummary>
<desc>
<p>Tries to create directory <c><anno>Dir</anno></c>. Missing parent
@@ -637,7 +637,7 @@ f.txt: {person, "kalle", 25}.
</desc>
</func>
<func>
- <name name="make_link" arity="2"/>
+ <name name="make_link" arity="2" since=""/>
<fsummary>Make a hard link to a file.</fsummary>
<desc>
<p>Makes a hard link from <c><anno>Existing</anno></c> to
@@ -666,7 +666,7 @@ f.txt: {person, "kalle", 25}.
</desc>
</func>
<func>
- <name name="make_symlink" arity="2"/>
+ <name name="make_symlink" arity="2" since=""/>
<fsummary>Make a symbolic link to a file or directory.</fsummary>
<desc>
<p>Creates a symbolic link <c><anno>New</anno></c> to
@@ -702,7 +702,7 @@ f.txt: {person, "kalle", 25}.
</desc>
</func>
<func>
- <name name="native_name_encoding" arity="0"/>
+ <name name="native_name_encoding" arity="0" since="OTP R14B01"/>
<fsummary>Return the configured filename encoding of the VM.</fsummary>
<desc>
<p><marker id="native_name_encoding"/>Returns
@@ -714,7 +714,7 @@ f.txt: {person, "kalle", 25}.
</desc>
</func>
<func>
- <name name="open" arity="2"/>
+ <name name="open" arity="2" since=""/>
<fsummary>Open a file.</fsummary>
<desc>
<p>Opens file <c><anno>File</anno></c> in the mode determined
@@ -997,7 +997,7 @@ f.txt: {person, "kalle", 25}.
</desc>
</func>
<func>
- <name name="path_consult" arity="2"/>
+ <name name="path_consult" arity="2" since=""/>
<fsummary>Read Erlang terms from a file.</fsummary>
<desc>
<p>Searches the path <c><anno>Path</anno></c> (a list of directory
@@ -1039,7 +1039,7 @@ f.txt: {person, "kalle", 25}.
</desc>
</func>
<func>
- <name name="path_eval" arity="2"/>
+ <name name="path_eval" arity="2" since=""/>
<fsummary>Evaluate Erlang expressions in a file.</fsummary>
<desc>
<p>Searches the path <c><anno>Path</anno></c> (a list of directory
@@ -1085,7 +1085,7 @@ f.txt: {person, "kalle", 25}.
</desc>
</func>
<func>
- <name name="path_open" arity="3"/>
+ <name name="path_open" arity="3" since=""/>
<fsummary>Open a file.</fsummary>
<desc>
<p>Searches the path <c><anno>Path</anno></c> (a list of directory
@@ -1114,7 +1114,7 @@ f.txt: {person, "kalle", 25}.
</desc>
</func>
<func>
- <name name="path_script" arity="2"/>
+ <name name="path_script" arity="2" since=""/>
<fsummary>Evaluate and return the value of Erlang expressions in a file.</fsummary>
<desc>
<p>Searches the path <c><anno>Path</anno></c> (a list of directory
@@ -1158,7 +1158,7 @@ f.txt: {person, "kalle", 25}.
</desc>
</func>
<func>
- <name name="path_script" arity="3"/>
+ <name name="path_script" arity="3" since=""/>
<fsummary>Evaluate and return the value of Erlang expressions in a file.</fsummary>
<desc>
<p>The same as <c>path_script/2</c> but the variable bindings
@@ -1168,7 +1168,7 @@ f.txt: {person, "kalle", 25}.
</desc>
</func>
<func>
- <name name="pid2name" arity="1"/>
+ <name name="pid2name" arity="1" since=""/>
<fsummary>Return the name of the file handled by a pid.</fsummary>
<desc>
<p>If <c><anno>Pid</anno></c> is an I/O device, that is, a pid returned from
@@ -1193,7 +1193,7 @@ f.txt: {person, "kalle", 25}.
</desc>
</func>
<func>
- <name name="position" arity="2"/>
+ <name name="position" arity="2" since=""/>
<fsummary>Set position in a file.</fsummary>
<desc>
<p>Sets the position of the file referenced by <c><anno>IoDevice</anno></c>
@@ -1245,7 +1245,7 @@ f.txt: {person, "kalle", 25}.
</desc>
</func>
<func>
- <name name="pread" arity="2"/>
+ <name name="pread" arity="2" since=""/>
<fsummary>Read from a file at certain positions.</fsummary>
<desc>
<p>Performs a sequence of <c>pread/3</c> in one operation,
@@ -1263,7 +1263,7 @@ f.txt: {person, "kalle", 25}.
</desc>
</func>
<func>
- <name name="pread" arity="3"/>
+ <name name="pread" arity="3" since=""/>
<fsummary>Read from a file at a certain position.</fsummary>
<desc>
<p>Combines <c>position/2</c> and <c>read/2</c> in one
@@ -1283,7 +1283,7 @@ f.txt: {person, "kalle", 25}.
</desc>
</func>
<func>
- <name name="pwrite" arity="2"/>
+ <name name="pwrite" arity="2" since=""/>
<fsummary>Write to a file at certain positions.</fsummary>
<desc>
<p>Performs a sequence of <c>pwrite/3</c> in one operation,
@@ -1298,7 +1298,7 @@ f.txt: {person, "kalle", 25}.
</desc>
</func>
<func>
- <name name="pwrite" arity="3"/>
+ <name name="pwrite" arity="3" since=""/>
<fsummary>Write to a file at a certain position.</fsummary>
<desc>
<p>Combines <c>position/2</c> and <c>write/2</c> in one
@@ -1317,7 +1317,7 @@ f.txt: {person, "kalle", 25}.
</desc>
</func>
<func>
- <name name="read" arity="2"/>
+ <name name="read" arity="2" since=""/>
<fsummary>Read from a file.</fsummary>
<desc>
<p>Reads <c><anno>Number</anno></c> bytes/characters from the file
@@ -1371,7 +1371,7 @@ f.txt: {person, "kalle", 25}.
</desc>
</func>
<func>
- <name name="read_file" arity="1"/>
+ <name name="read_file" arity="1" since=""/>
<fsummary>Read a file.</fsummary>
<desc>
<p>Returns <c>{ok, <anno>Binary</anno>}</c>, where
@@ -1407,8 +1407,8 @@ f.txt: {person, "kalle", 25}.
</desc>
</func>
<func>
- <name name="read_file_info" arity="1"/>
- <name name="read_file_info" arity="2"/>
+ <name name="read_file_info" arity="1" since=""/>
+ <name name="read_file_info" arity="2" since="OTP R15B"/>
<fsummary>Retrieve information about a file.</fsummary>
<desc>
<p>Retrieves information about a file. Returns
@@ -1562,7 +1562,7 @@ f.txt: {person, "kalle", 25}.
</desc>
</func>
<func>
- <name name="read_line" arity="1"/>
+ <name name="read_line" arity="1" since=""/>
<fsummary>Read a line from a file.</fsummary>
<desc>
<p>Reads a line of bytes/characters from the file referenced by
@@ -1619,7 +1619,7 @@ f.txt: {person, "kalle", 25}.
</desc>
</func>
<func>
- <name name="read_link" arity="1"/>
+ <name name="read_link" arity="1" since=""/>
<fsummary>See what a link is pointing to.</fsummary>
<desc>
<p><marker id="read_link_all"/>Returns
@@ -1649,7 +1649,7 @@ f.txt: {person, "kalle", 25}.
</desc>
</func>
<func>
- <name name="read_link_all" arity="1"/>
+ <name name="read_link_all" arity="1" since="OTP R16B"/>
<fsummary>See what a link is pointing to.</fsummary>
<desc>
<p>Returns <c>{ok, <anno>Filename</anno>}</c> if
@@ -1677,8 +1677,8 @@ f.txt: {person, "kalle", 25}.
</desc>
</func>
<func>
- <name name="read_link_info" arity="1"/>
- <name name="read_link_info" arity="2"/>
+ <name name="read_link_info" arity="1" since=""/>
+ <name name="read_link_info" arity="2" since="OTP R15B"/>
<fsummary>Retrieve information about a link or file.</fsummary>
<desc>
<p>Works like
@@ -1699,7 +1699,7 @@ f.txt: {person, "kalle", 25}.
</desc>
</func>
<func>
- <name name="rename" arity="2"/>
+ <name name="rename" arity="2" since=""/>
<fsummary>Rename a file.</fsummary>
<desc>
<p>Tries to rename the file <c><anno>Source</anno></c> to
@@ -1762,7 +1762,7 @@ f.txt: {person, "kalle", 25}.
</desc>
</func>
<func>
- <name name="script" arity="1"/>
+ <name name="script" arity="1" since=""/>
<fsummary>Evaluate and return the value of Erlang expressions in a file.</fsummary>
<desc>
<p>Reads and evaluates Erlang expressions, separated by '.' (or
@@ -1797,7 +1797,7 @@ f.txt: {person, "kalle", 25}.
</desc>
</func>
<func>
- <name name="script" arity="2"/>
+ <name name="script" arity="2" since=""/>
<fsummary>Evaluate and return the value of Erlang expressions in a file.</fsummary>
<desc>
<p>The same as <c>script/1</c> but the variable bindings
@@ -1807,7 +1807,7 @@ f.txt: {person, "kalle", 25}.
</desc>
</func>
<func>
- <name name="sendfile" arity="2"/>
+ <name name="sendfile" arity="2" since="OTP R15B"/>
<fsummary>Send a file to a socket.</fsummary>
<desc>
<p>Sends the file <c>Filename</c> to <c>Socket</c>.
@@ -1816,7 +1816,7 @@ f.txt: {person, "kalle", 25}.
</desc>
</func>
<func>
- <name name="sendfile" arity="5"/>
+ <name name="sendfile" arity="5" since="OTP R15B"/>
<fsummary>Send a file to a socket.</fsummary>
<type name="sendfile_option"/>
<desc>
@@ -1843,7 +1843,7 @@ f.txt: {person, "kalle", 25}.
</desc>
</func>
<func>
- <name name="set_cwd" arity="1"/>
+ <name name="set_cwd" arity="1" since=""/>
<fsummary>Set the current working directory.</fsummary>
<desc>
<p>Sets the current working directory of the file server to
@@ -1890,7 +1890,7 @@ f.txt: {person, "kalle", 25}.
</desc>
</func>
<func>
- <name name="sync" arity="1"/>
+ <name name="sync" arity="1" since=""/>
<fsummary>Synchronize the in-memory state of a file with that on the physical medium.</fsummary>
<desc>
<p>Ensures that any buffers kept by the operating system
@@ -1906,7 +1906,7 @@ f.txt: {person, "kalle", 25}.
</desc>
</func>
<func>
- <name name="truncate" arity="1"/>
+ <name name="truncate" arity="1" since=""/>
<fsummary>Truncate a file.</fsummary>
<desc>
<p>Truncates the file referenced by <c><anno>IoDevice</anno></c> at
@@ -1915,7 +1915,7 @@ f.txt: {person, "kalle", 25}.
</desc>
</func>
<func>
- <name name="write" arity="2"/>
+ <name name="write" arity="2" since=""/>
<fsummary>Write to a file.</fsummary>
<desc>
<p>Writes <c><anno>Bytes</anno></c> to the file referenced by
@@ -1941,7 +1941,7 @@ f.txt: {person, "kalle", 25}.
</desc>
</func>
<func>
- <name name="write_file" arity="2"/>
+ <name name="write_file" arity="2" since=""/>
<fsummary>Write a file.</fsummary>
<desc>
<p>Writes the contents of the <c>iodata</c> term <c><anno>Bytes</anno></c>
@@ -1978,7 +1978,7 @@ f.txt: {person, "kalle", 25}.
</desc>
</func>
<func>
- <name name="write_file" arity="3"/>
+ <name name="write_file" arity="3" since=""/>
<fsummary>Write a file.</fsummary>
<desc>
<p>Same as <c>write_file/2</c>, but takes a third argument
@@ -1989,8 +1989,8 @@ f.txt: {person, "kalle", 25}.
</desc>
</func>
<func>
- <name name="write_file_info" arity="2"/>
- <name name="write_file_info" arity="3"/>
+ <name name="write_file_info" arity="2" since=""/>
+ <name name="write_file_info" arity="3" since="OTP R15B"/>
<fsummary>Change file information.</fsummary>
<desc>
<p>Changes file information. Returns <c>ok</c> if successful,
diff --git a/lib/kernel/doc/src/gen_sctp.xml b/lib/kernel/doc/src/gen_sctp.xml
index 1e08b25f66..1e7009b3a8 100644
--- a/lib/kernel/doc/src/gen_sctp.xml
+++ b/lib/kernel/doc/src/gen_sctp.xml
@@ -32,7 +32,7 @@
<rev>A</rev>
<file>gen_sctp.xml</file>
</header>
- <module>gen_sctp</module>
+ <module since="">gen_sctp</module>
<modulesummary>Functions for communicating with sockets using the SCTP
protocol.</modulesummary>
<description>
@@ -100,7 +100,7 @@
<funcs>
<func>
- <name name="abort" arity="2"/>
+ <name name="abort" arity="2" since=""/>
<fsummary>Abnormally terminate the association specified by
<c>Assoc</c>, without flushing of unsent data.</fsummary>
<desc>
@@ -113,7 +113,7 @@
</func>
<func>
- <name name="close" arity="1"/>
+ <name name="close" arity="1" since=""/>
<fsummary>Close the socket and all associations on it.</fsummary>
<desc>
<p>Closes the socket and all associations on it. The unsent
@@ -128,7 +128,7 @@
</func>
<func>
- <name name="connect" arity="4"/>
+ <name name="connect" arity="4" since=""/>
<fsummary>Same as <c>connect(Socket, Addr, Port, Opts, infinity)</c>.</fsummary>
<desc>
<p>Same as <c>connect(<anno>Socket</anno>, <anno>Addr</anno>,
@@ -137,7 +137,7 @@
</func>
<func>
- <name name="connect" arity="5"/>
+ <name name="connect" arity="5" since=""/>
<fsummary>Establish a new association for socket <c>Socket</c>, with a
peer (SCTP server socket).</fsummary>
<desc>
@@ -213,7 +213,7 @@ connect(Socket, Ip, Port>,
</func>
<func>
- <name name="connect_init" arity="4"/>
+ <name name="connect_init" arity="4" since="OTP R13B04"/>
<fsummary>Same as <c>connect_init(Socket, Addr, Port, Opts, infinity)</c>..</fsummary>
<desc>
<p>Same as <c>connect_init(<anno>Socket</anno>, <anno>Addr</anno>,
@@ -222,7 +222,7 @@ connect(Socket, Ip, Port>,
</func>
<func>
- <name name="connect_init" arity="5"/>
+ <name name="connect_init" arity="5" since="OTP R13B04"/>
<fsummary>Initiate a new association for socket <c>Socket</c>, with a
peer (SCTP server socket).</fsummary>
<desc>
@@ -248,7 +248,7 @@ connect(Socket, Ip, Port>,
</func>
<func>
- <name name="controlling_process" arity="2"/>
+ <name name="controlling_process" arity="2" since=""/>
<fsummary>Assign a new controlling process pid to the socket.</fsummary>
<desc>
<p>Assigns a new controlling process <c><anno>Pid</anno></c> to
@@ -259,7 +259,7 @@ connect(Socket, Ip, Port>,
</func>
<func>
- <name name="eof" arity="2"/>
+ <name name="eof" arity="2" since=""/>
<fsummary>Gracefully terminate the association specified by <c>Assoc</c>,
with flushing of all unsent data.</fsummary>
<desc>
@@ -272,7 +272,7 @@ connect(Socket, Ip, Port>,
</func>
<func>
- <name name="error_string" arity="1"/>
+ <name name="error_string" arity="1" since=""/>
<fsummary>Translate an SCTP error number into a string.</fsummary>
<desc>
<p>Translates an SCTP error number from, for example,
@@ -283,8 +283,8 @@ connect(Socket, Ip, Port>,
</func>
<func>
- <name name="listen" arity="2" clause_i="1"/>
- <name name="listen" arity="2" clause_i="2"/>
+ <name name="listen" arity="2" clause_i="1" since=""/>
+ <name name="listen" arity="2" clause_i="2" since=""/>
<fsummary>Set up a socket to listen.</fsummary>
<desc>
<p>Sets up a socket to listen on the IP address and port number
@@ -300,10 +300,10 @@ connect(Socket, Ip, Port>,
</func>
<func>
- <name name="open" arity="0"/>
- <name name="open" arity="1" clause_i="1"/>
- <name name="open" arity="1" clause_i="2"/>
- <name name="open" arity="2"/>
+ <name name="open" arity="0" since=""/>
+ <name name="open" arity="1" clause_i="1" since=""/>
+ <name name="open" arity="1" clause_i="2" since=""/>
+ <name name="open" arity="2" since=""/>
<fsummary>Create an SCTP socket and binds it to local addresses.</fsummary>
<desc>
<p>Creates an SCTP socket and binds it to the local addresses
@@ -366,7 +366,7 @@ connect(Socket, Ip, Port>,
</func>
<func>
- <name name="peeloff" arity="2"/>
+ <name name="peeloff" arity="2" since="OTP R15B"/>
<fsummary>Peel off a type <c>stream</c> socket from a type
<c>seqpacket</c> one.</fsummary>
<desc>
@@ -387,8 +387,8 @@ connect(Socket, Ip, Port>,
</func>
<func>
- <name name="recv" arity="1"/>
- <name name="recv" arity="2"/>
+ <name name="recv" arity="1" since=""/>
+ <name name="recv" arity="2" since=""/>
<fsummary>Receive a message from a socket.</fsummary>
<desc>
<p>Receives the <c><anno>Data</anno></c> message from any association
@@ -532,7 +532,7 @@ connect(Socket, Ip, Port>,
</func>
<func>
- <name name="send" arity="3"/>
+ <name name="send" arity="3" since=""/>
<fsummary>Send a message using an <c>#sctp_sndrcvinfo{}</c>record.</fsummary>
<desc>
<p>Sends the <c><anno>Data</anno></c> message with all sending
@@ -547,7 +547,7 @@ connect(Socket, Ip, Port>,
</func>
<func>
- <name name="send" arity="4"/>
+ <name name="send" arity="4" since=""/>
<fsummary>Send a message over an existing association and specified
stream.</fsummary>
<desc>
diff --git a/lib/kernel/doc/src/gen_tcp.xml b/lib/kernel/doc/src/gen_tcp.xml
index 24d63693fd..fc16473393 100644
--- a/lib/kernel/doc/src/gen_tcp.xml
+++ b/lib/kernel/doc/src/gen_tcp.xml
@@ -27,7 +27,7 @@
<date>1997-10-24</date>
<rev>A</rev>
</header>
- <module>gen_tcp</module>
+ <module since="">gen_tcp</module>
<modulesummary>Interface to TCP/IP sockets.</modulesummary>
<description>
<p>This module provides functions for communicating
@@ -116,8 +116,8 @@ do_recv(Sock, Bs) ->
<funcs>
<func>
- <name name="accept" arity="1"/>
- <name name="accept" arity="2"/>
+ <name name="accept" arity="1" since=""/>
+ <name name="accept" arity="2" since=""/>
<fsummary>Accept an incoming connection request on a listening socket.</fsummary>
<type_desc variable="ListenSocket">Returned by
<seealso marker="#listen/2"><c>listen/2</c></seealso>.
@@ -163,7 +163,7 @@ do_recv(Sock, Bs) ->
</func>
<func>
- <name name="close" arity="1"/>
+ <name name="close" arity="1" since=""/>
<fsummary>Close a TCP socket.</fsummary>
<desc>
<p>Closes a TCP socket.</p>
@@ -188,8 +188,8 @@ do_recv(Sock, Bs) ->
</func>
<func>
- <name name="connect" arity="3"/>
- <name name="connect" arity="4"/>
+ <name name="connect" arity="3" since=""/>
+ <name name="connect" arity="4" since=""/>
<fsummary>Connect to a TCP port.</fsummary>
<desc>
<p>Connects to a server on TCP port <c><anno>Port</anno></c> on the host
@@ -268,7 +268,7 @@ do_recv(Sock, Bs) ->
</func>
<func>
- <name name="controlling_process" arity="2"/>
+ <name name="controlling_process" arity="2" since=""/>
<fsummary>Change controlling process of a socket.</fsummary>
<desc>
<p>Assigns a new controlling process <c><anno>Pid</anno></c> to
@@ -292,7 +292,7 @@ do_recv(Sock, Bs) ->
</func>
<func>
- <name name="listen" arity="2"/>
+ <name name="listen" arity="2" since=""/>
<fsummary>Set up a socket to listen on a port.</fsummary>
<desc>
<p>Sets up a socket to listen on port <c><anno>Port</anno></c> on
@@ -349,8 +349,8 @@ do_recv(Sock, Bs) ->
</func>
<func>
- <name name="recv" arity="2"/>
- <name name="recv" arity="3"/>
+ <name name="recv" arity="2" since=""/>
+ <name name="recv" arity="3" since=""/>
<fsummary>Receive a packet from a passive socket.</fsummary>
<type_desc variable="HttpPacket">See the description of
<c>HttpPacket</c> in
@@ -375,7 +375,7 @@ do_recv(Sock, Bs) ->
</func>
<func>
- <name name="send" arity="2"/>
+ <name name="send" arity="2" since=""/>
<fsummary>Send a packet.</fsummary>
<desc>
<p>Sends a packet on a socket.</p>
@@ -386,7 +386,7 @@ do_recv(Sock, Bs) ->
</func>
<func>
- <name name="shutdown" arity="2"/>
+ <name name="shutdown" arity="2" since=""/>
<fsummary>Asynchronously close a socket.</fsummary>
<desc>
<p>Closes a socket in one or two directions.</p>
diff --git a/lib/kernel/doc/src/gen_udp.xml b/lib/kernel/doc/src/gen_udp.xml
index 840ca3c188..d20fc1fdfd 100644
--- a/lib/kernel/doc/src/gen_udp.xml
+++ b/lib/kernel/doc/src/gen_udp.xml
@@ -28,7 +28,7 @@
<date>1997-12-03</date>
<rev>A</rev>
</header>
- <module>gen_udp</module>
+ <module since="">gen_udp</module>
<modulesummary>Interface to UDP sockets.</modulesummary>
<description>
<p>This module provides functions for communicating
@@ -53,7 +53,7 @@
<funcs>
<func>
- <name name="close" arity="1"/>
+ <name name="close" arity="1" since=""/>
<fsummary>Close a UDP socket.</fsummary>
<desc>
<p>Closes a UDP socket.</p>
@@ -61,7 +61,7 @@
</func>
<func>
- <name name="controlling_process" arity="2"/>
+ <name name="controlling_process" arity="2" since=""/>
<fsummary>Change controlling process of a socket.</fsummary>
<desc>
<p>Assigns a new controlling process <c><anno>Pid</anno></c> to
@@ -77,8 +77,8 @@
</func>
<func>
- <name name="open" arity="1"/>
- <name name="open" arity="2"/>
+ <name name="open" arity="1" since=""/>
+ <name name="open" arity="2" since=""/>
<fsummary>Associate a UDP port number with the process calling it.</fsummary>
<desc>
<p>Associates a UDP port number (<c><anno>Port</anno></c>) with the
@@ -189,8 +189,8 @@
</func>
<func>
- <name name="recv" arity="2"/>
- <name name="recv" arity="3"/>
+ <name name="recv" arity="2" since=""/>
+ <name name="recv" arity="3" since=""/>
<fsummary>Receive a packet from a passive socket.</fsummary>
<desc>
<p>
@@ -213,7 +213,7 @@
</func>
<func>
- <name name="send" arity="4"/>
+ <name name="send" arity="4" since=""/>
<fsummary>Send a packet.</fsummary>
<desc>
<p>
diff --git a/lib/kernel/doc/src/global.xml b/lib/kernel/doc/src/global.xml
index 4442741f54..dfe71de5ce 100644
--- a/lib/kernel/doc/src/global.xml
+++ b/lib/kernel/doc/src/global.xml
@@ -28,7 +28,7 @@
<date>1997-11-17</date>
<rev></rev>
</header>
- <module>global</module>
+ <module since="">global</module>
<modulesummary>A global name registration facility.</modulesummary>
<description>
<p>This module consists of the following services:</p>
@@ -100,8 +100,8 @@
<funcs>
<func>
- <name name="del_lock" arity="1"/>
- <name name="del_lock" arity="2"/>
+ <name name="del_lock" arity="1" since=""/>
+ <name name="del_lock" arity="2" since=""/>
<fsummary>Delete a lock.</fsummary>
<desc>
<p>Deletes the lock <c><anno>Id</anno></c> synchronously.</p>
@@ -109,7 +109,7 @@
</func>
<func>
- <name name="notify_all_name" arity="3"/>
+ <name name="notify_all_name" arity="3" since=""/>
<fsummary>Name resolving function that notifies both pids.</fsummary>
<desc>
<p>Can be used as a name resolving function for
@@ -123,7 +123,7 @@
</func>
<func>
- <name name="random_exit_name" arity="3"/>
+ <name name="random_exit_name" arity="3" since=""/>
<fsummary>Name resolving function that kills one pid.</fsummary>
<desc>
<p>Can be used as a name resolving function for
@@ -136,7 +136,7 @@
</func>
<func>
- <name name="random_notify_name" arity="3"/>
+ <name name="random_notify_name" arity="3" since=""/>
<fsummary>Name resolving function that notifies one pid.</fsummary>
<desc>
<p>Can be used as a name resolving function for
@@ -150,8 +150,8 @@
</func>
<func>
- <name name="re_register_name" arity="2"/>
- <name name="re_register_name" arity="3"/>
+ <name name="re_register_name" arity="2" since=""/>
+ <name name="re_register_name" arity="3" since=""/>
<fsummary>Atomically re-register a name.</fsummary>
<type name="method"/>
<type_desc name="method">{<c>Module</c>, <c>Function</c>}
@@ -167,8 +167,8 @@
</func>
<func>
- <name name="register_name" arity="2"/>
- <name name="register_name" arity="3"/>
+ <name name="register_name" arity="2" since=""/>
+ <name name="register_name" arity="3" since=""/>
<fsummary>Globally register a name for a pid.</fsummary>
<type name="method"/>
<type_desc name="method">{<c>Module</c>, <c>Function</c>} is also
@@ -221,7 +221,7 @@
</func>
<func>
- <name name="registered_names" arity="0"/>
+ <name name="registered_names" arity="0" since=""/>
<fsummary>All globally registered names.</fsummary>
<desc>
<p>Returns a list of all globally registered names.</p>
@@ -229,7 +229,7 @@
</func>
<func>
- <name name="send" arity="2"/>
+ <name name="send" arity="2" since=""/>
<fsummary>Send a message to a globally registered pid.</fsummary>
<desc>
<p>Sends message <c><anno>Msg</anno></c> to the pid globally registered
@@ -241,9 +241,9 @@
</func>
<func>
- <name name="set_lock" arity="1"/>
- <name name="set_lock" arity="2"/>
- <name name="set_lock" arity="3"/>
+ <name name="set_lock" arity="1" since=""/>
+ <name name="set_lock" arity="2" since=""/>
+ <name name="set_lock" arity="3" since=""/>
<fsummary>Set a lock on the specified nodes.</fsummary>
<type name="id"/>
<type name="retries"/>
@@ -287,7 +287,7 @@
</func>
<func>
- <name name="sync" arity="0"/>
+ <name name="sync" arity="0" since=""/>
<fsummary>Synchronize the global name server.</fsummary>
<desc>
<p>Synchronizes the global name server with all nodes known to
@@ -302,9 +302,9 @@
</func>
<func>
- <name name="trans" arity="2"/>
- <name name="trans" arity="3"/>
- <name name="trans" arity="4"/>
+ <name name="trans" arity="2" since=""/>
+ <name name="trans" arity="3" since=""/>
+ <name name="trans" arity="4" since=""/>
<fsummary>Micro transaction facility.</fsummary>
<type name="retries"/>
<type name="trans_fun"/>
@@ -322,7 +322,7 @@
</func>
<func>
- <name name="unregister_name" arity="1"/>
+ <name name="unregister_name" arity="1" since=""/>
<fsummary>Remove a globally registered name for a pid.</fsummary>
<desc>
<p>Removes the globally registered name <c><anno>Name</anno></c> from
@@ -331,7 +331,7 @@
</func>
<func>
- <name name="whereis_name" arity="1"/>
+ <name name="whereis_name" arity="1" since=""/>
<fsummary>Get the pid with a specified globally registered name.</fsummary>
<desc>
<p>Returns the pid with the globally registered name
diff --git a/lib/kernel/doc/src/global_group.xml b/lib/kernel/doc/src/global_group.xml
index 8f947b9adf..74d15cd476 100644
--- a/lib/kernel/doc/src/global_group.xml
+++ b/lib/kernel/doc/src/global_group.xml
@@ -28,7 +28,7 @@
<date>1998-12-18</date>
<rev>B</rev>
</header>
- <module>global_group</module>
+ <module since="">global_group</module>
<modulesummary>Grouping nodes to global name registration groups.</modulesummary>
<description>
<p>This module makes it possible to partition the nodes of a
@@ -105,7 +105,7 @@
<funcs>
<func>
- <name name="global_groups" arity="0"/>
+ <name name="global_groups" arity="0" since=""/>
<fsummary>Return the global group names.</fsummary>
<desc>
<p>Returns a tuple containing the name of the global group that
@@ -116,7 +116,7 @@
</func>
<func>
- <name name="info" arity="0"/>
+ <name name="info" arity="0" since=""/>
<fsummary>Information about global groups.</fsummary>
<type name="info_item"/>
<type name="sync_state"/>
@@ -173,7 +173,7 @@
</func>
<func>
- <name name="monitor_nodes" arity="1"/>
+ <name name="monitor_nodes" arity="1" since=""/>
<fsummary>Subscribe to node status changes.</fsummary>
<desc>
<p>Depending on <c><anno>Flag</anno></c>, the calling process
@@ -187,7 +187,7 @@
</func>
<func>
- <name name="own_nodes" arity="0"/>
+ <name name="own_nodes" arity="0" since=""/>
<fsummary>Return the group nodes.</fsummary>
<desc>
<p>Returns the names of all group nodes, regardless of their
@@ -196,7 +196,7 @@
</func>
<func>
- <name name="registered_names" arity="1"/>
+ <name name="registered_names" arity="1" since=""/>
<fsummary>Return globally registered names.</fsummary>
<desc>
<p>Returns a list of all names that are globally registered
@@ -205,8 +205,8 @@
</func>
<func>
- <name name="send" arity="2"/>
- <name name="send" arity="3"/>
+ <name name="send" arity="2" since=""/>
+ <name name="send" arity="3" since=""/>
<fsummary>Send a message to a globally registered pid.</fsummary>
<desc>
<p>Searches for <c><anno>Name</anno></c>, globally registered on
@@ -224,7 +224,7 @@
</func>
<func>
- <name name="sync" arity="0"/>
+ <name name="sync" arity="0" since=""/>
<fsummary>Synchronize the group nodes.</fsummary>
<desc>
<p>Synchronizes the group nodes, that is, the global name
@@ -242,8 +242,8 @@
</func>
<func>
- <name name="whereis_name" arity="1"/>
- <name name="whereis_name" arity="2"/>
+ <name name="whereis_name" arity="1" since=""/>
+ <name name="whereis_name" arity="2" since=""/>
<fsummary>Get the pid with a specified globally registered name.</fsummary>
<desc>
<p>Searches for <c><anno>Name</anno></c>, globally registered on
diff --git a/lib/kernel/doc/src/heart.xml b/lib/kernel/doc/src/heart.xml
index ad1a2ffeb9..4243b1ffe8 100644
--- a/lib/kernel/doc/src/heart.xml
+++ b/lib/kernel/doc/src/heart.xml
@@ -28,7 +28,7 @@
<date>1998-01-28</date>
<rev>A</rev>
</header>
- <module>heart</module>
+ <module since="">heart</module>
<modulesummary>Heartbeat monitoring of an Erlang runtime system.</modulesummary>
<description>
<p>This modules contains the interface to the <c>heart</c> process.
@@ -119,7 +119,7 @@
<funcs>
<func>
- <name name="set_cmd" arity="1"/>
+ <name name="set_cmd" arity="1" since=""/>
<fsummary>Set a temporary reboot command.</fsummary>
<desc>
<p>Sets a temporary reboot command. This command is used if
@@ -136,7 +136,7 @@
</func>
<func>
- <name name="clear_cmd" arity="0"/>
+ <name name="clear_cmd" arity="0" since=""/>
<fsummary>Clear the temporary boot command.</fsummary>
<desc>
<p>Clears the temporary boot command. If the system terminates,
@@ -145,7 +145,7 @@
</func>
<func>
- <name name="get_cmd" arity="0"/>
+ <name name="get_cmd" arity="0" since=""/>
<fsummary>Get the temporary reboot command.</fsummary>
<desc>
<p>Gets the temporary reboot command. If the command is cleared,
@@ -154,7 +154,7 @@
</func>
<func>
- <name name="set_callback" arity="2"/>
+ <name name="set_callback" arity="2" since="OTP 18.3"/>
<fsummary>Set a validation callback</fsummary>
<desc>
<p> This validation callback will be executed before any
@@ -166,14 +166,14 @@
</desc>
</func>
<func>
- <name name="clear_callback" arity="0"/>
+ <name name="clear_callback" arity="0" since="OTP 18.3"/>
<fsummary>Clear the validation callback</fsummary>
<desc>
<p>Removes the validation callback call before heartbeats.</p>
</desc>
</func>
<func>
- <name name="get_callback" arity="0"/>
+ <name name="get_callback" arity="0" since="OTP 18.3"/>
<fsummary>Get the validation callback</fsummary>
<desc>
<p>Get the validation callback. If the callback is cleared, <c>none</c> will be returned.</p>
@@ -181,7 +181,7 @@
</func>
<func>
- <name name="set_options" arity="1"/>
+ <name name="set_options" arity="1" since="OTP 18.3"/>
<fsummary>Set a list of options</fsummary>
<desc>
<p> Valid options <c>set_options</c> are: </p>
@@ -199,7 +199,7 @@
</desc>
</func>
<func>
- <name name="get_options" arity="0"/>
+ <name name="get_options" arity="0" since="OTP 18.3"/>
<fsummary>Get the temporary reboot command</fsummary>
<desc>
<p>Returns <c>{ok, Options}</c> where <c>Options</c> is a list of current options enabled for heart.
diff --git a/lib/kernel/doc/src/inet.xml b/lib/kernel/doc/src/inet.xml
index 87b08e4e36..709ba8e8fd 100644
--- a/lib/kernel/doc/src/inet.xml
+++ b/lib/kernel/doc/src/inet.xml
@@ -28,7 +28,7 @@
<date>1998-02-04</date>
<rev>A</rev>
</header>
- <module>inet</module>
+ <module since="">inet</module>
<modulesummary>Access to TCP/IP protocols.</modulesummary>
<description>
<p>This module provides access to TCP/IP protocols.</p>
@@ -298,7 +298,7 @@ fe80::204:acff:fe17:bf38
<funcs>
<func>
- <name name="close" arity="1"/>
+ <name name="close" arity="1" since=""/>
<fsummary>Close a socket of any type.</fsummary>
<desc>
<p>Closes a socket of any type.</p>
@@ -306,7 +306,7 @@ fe80::204:acff:fe17:bf38
</func>
<func>
- <name name="format_error" arity="1"/>
+ <name name="format_error" arity="1" since=""/>
<fsummary>Return a descriptive string for an error reason.</fsummary>
<desc>
<p>Returns a diagnostic error string. For possible POSIX values and
@@ -316,7 +316,7 @@ fe80::204:acff:fe17:bf38
</func>
<func>
- <name name="get_rc" arity="0"/>
+ <name name="get_rc" arity="0" since=""/>
<fsummary>Return a list of IP configuration parameters.</fsummary>
<desc>
<p>
@@ -335,7 +335,7 @@ fe80::204:acff:fe17:bf38
</func>
<func>
- <name name="getaddr" arity="2"/>
+ <name name="getaddr" arity="2" since=""/>
<fsummary>Return the IP address for a host.</fsummary>
<desc>
<p>Returns the IP address for <c><anno>Host</anno></c> as a tuple of
@@ -345,7 +345,7 @@ fe80::204:acff:fe17:bf38
</func>
<func>
- <name name="getaddrs" arity="2"/>
+ <name name="getaddrs" arity="2" since=""/>
<fsummary>Return the IP addresses for a host.</fsummary>
<desc>
<p>Returns a list of all IP addresses for <c><anno>Host</anno></c>.
@@ -355,7 +355,7 @@ fe80::204:acff:fe17:bf38
</func>
<func>
- <name name="gethostbyaddr" arity="1"/>
+ <name name="gethostbyaddr" arity="1" since=""/>
<fsummary>Return a hostent record for the host with the specified
address.</fsummary>
<desc>
@@ -364,7 +364,7 @@ fe80::204:acff:fe17:bf38
</func>
<func>
- <name name="gethostbyname" arity="1"/>
+ <name name="gethostbyname" arity="1" since=""/>
<fsummary>Return a hostent record for the host with the specified name.
</fsummary>
<desc>
@@ -376,7 +376,7 @@ fe80::204:acff:fe17:bf38
</func>
<func>
- <name name="gethostbyname" arity="2"/>
+ <name name="gethostbyname" arity="2" since=""/>
<fsummary>Return a hostent record for the host with the specified name.
</fsummary>
<desc>
@@ -386,7 +386,7 @@ fe80::204:acff:fe17:bf38
</func>
<func>
- <name name="gethostname" arity="0"/>
+ <name name="gethostname" arity="0" since=""/>
<fsummary>Return the local hostname.</fsummary>
<desc>
<p>Returns the local hostname. Never fails.</p>
@@ -394,7 +394,7 @@ fe80::204:acff:fe17:bf38
</func>
<func>
- <name name="getifaddrs" arity="0"/>
+ <name name="getifaddrs" arity="0" since="OTP R14B01"/>
<fsummary>Return a list of interfaces and their addresses.</fsummary>
<desc>
<p>
@@ -416,7 +416,7 @@ fe80::204:acff:fe17:bf38
</func>
<func>
- <name>getifaddrs(Opts) ->
+ <name since="OTP 21.2">getifaddrs(Opts) ->
{ok, [{Ifname, Ifopts}]} | {error, Posix}
</name>
<fsummary>Return a list of interfaces and their addresses.</fsummary>
@@ -459,7 +459,7 @@ fe80::204:acff:fe17:bf38
</func>
<func>
- <name name="getopts" arity="2"/>
+ <name name="getopts" arity="2" since=""/>
<fsummary>Get one or more options for a socket.</fsummary>
<desc>
<p>Gets one or more options for a socket. For a list of available
@@ -529,8 +529,8 @@ get_tcpi_sacked(Sock) ->
</func>
<func>
- <name name="getstat" arity="1"/>
- <name name="getstat" arity="2"/>
+ <name name="getstat" arity="1" since=""/>
+ <name name="getstat" arity="2" since=""/>
<fsummary>Get one or more statistic options for a socket.</fsummary>
<type name="stat_option"/>
<desc>
@@ -586,9 +586,9 @@ get_tcpi_sacked(Sock) ->
</func>
<func>
- <name name="i" arity="0" />
- <name name="i" arity="1" />
- <name name="i" arity="2" />
+ <name name="i" arity="0" since="OTP 21.0"/>
+ <name name="i" arity="1" since="OTP 21.0"/>
+ <name name="i" arity="2" since="OTP 21.0"/>
<fsummary>Displays information and statistics about sockets on the terminal</fsummary>
<desc>
<p>
@@ -641,7 +641,7 @@ get_tcpi_sacked(Sock) ->
</func>
<func>
- <name name="ntoa" arity="1" />
+ <name name="ntoa" arity="1" since="OTP R16B02"/>
<fsummary>Convert IPv6/IPV4 address to ASCII.</fsummary>
<desc>
<p>Parses an
@@ -651,7 +651,7 @@ get_tcpi_sacked(Sock) ->
</func>
<func>
- <name name="parse_address" arity="1" />
+ <name name="parse_address" arity="1" since="OTP R16B"/>
<fsummary>Parse an IPv4 or IPv6 address.</fsummary>
<desc>
<p>Parses an IPv4 or IPv6 address string and returns an
@@ -662,7 +662,7 @@ get_tcpi_sacked(Sock) ->
</func>
<func>
- <name name="parse_ipv4_address" arity="1" />
+ <name name="parse_ipv4_address" arity="1" since="OTP R16B"/>
<fsummary>Parse an IPv4 address.</fsummary>
<desc>
<p>Parses an IPv4 address string and returns an
@@ -672,7 +672,7 @@ get_tcpi_sacked(Sock) ->
</func>
<func>
- <name name="parse_ipv4strict_address" arity="1" />
+ <name name="parse_ipv4strict_address" arity="1" since="OTP R16B"/>
<fsummary>Parse an IPv4 address strict.</fsummary>
<desc>
<p>Parses an IPv4 address string containing four fields, that is,
@@ -683,7 +683,7 @@ get_tcpi_sacked(Sock) ->
</func>
<func>
- <name name="parse_ipv6_address" arity="1" />
+ <name name="parse_ipv6_address" arity="1" since="OTP R16B"/>
<fsummary>Parse an IPv6 address.</fsummary>
<desc>
<p>Parses an IPv6 address string and returns an
@@ -694,7 +694,7 @@ get_tcpi_sacked(Sock) ->
</func>
<func>
- <name name="parse_ipv6strict_address" arity="1" />
+ <name name="parse_ipv6strict_address" arity="1" since="OTP R16B"/>
<fsummary>Parse an IPv6 address strict.</fsummary>
<desc>
<p>Parses an IPv6 address string and returns an
@@ -704,7 +704,7 @@ get_tcpi_sacked(Sock) ->
</func>
<func>
- <name name="ipv4_mapped_ipv6_address" arity="1" />
+ <name name="ipv4_mapped_ipv6_address" arity="1" since="OTP 21.0"/>
<fsummary>Convert to and from IPv4-mapped IPv6 address.</fsummary>
<desc>
<p>
@@ -717,7 +717,7 @@ get_tcpi_sacked(Sock) ->
</func>
<func>
- <name name="parse_strict_address" arity="1" />
+ <name name="parse_strict_address" arity="1" since="OTP R16B"/>
<fsummary>Parse an IPv4 or IPv6 address strict.</fsummary>
<desc>
<p>Parses an IPv4 or IPv6 address string and returns an
@@ -728,7 +728,7 @@ get_tcpi_sacked(Sock) ->
</func>
<func>
- <name name="peername" arity="1"/>
+ <name name="peername" arity="1" since=""/>
<fsummary>Return the address and port for the other end of a connection.
</fsummary>
<desc>
@@ -741,7 +741,7 @@ get_tcpi_sacked(Sock) ->
</func>
<func>
- <name name="peernames" arity="1"/>
+ <name name="peernames" arity="1" since="OTP R16B03"/>
<fsummary>Return all address/port numbers for the other end of a
connection.</fsummary>
<desc>
@@ -755,7 +755,7 @@ get_tcpi_sacked(Sock) ->
</func>
<func>
- <name name="peernames" arity="2"/>
+ <name name="peernames" arity="2" since="OTP R16B03"/>
<fsummary>Return all address/port numbers for the other end of a
connection.</fsummary>
<desc>
@@ -774,7 +774,7 @@ get_tcpi_sacked(Sock) ->
</func>
<func>
- <name name="port" arity="1"/>
+ <name name="port" arity="1" since=""/>
<fsummary>Return the local port number for a socket.</fsummary>
<desc>
<p>Returns the local port number for a socket.</p>
@@ -782,7 +782,7 @@ get_tcpi_sacked(Sock) ->
</func>
<func>
- <name name="setopts" arity="2"/>
+ <name name="setopts" arity="2" since=""/>
<fsummary>Set one or more options for a socket.</fsummary>
<desc>
<p>Sets one or more options for a socket.</p>
@@ -1007,13 +1007,34 @@ get_tcpi_sacked(Sock) ->
<marker id="option-linger"></marker>
</item>
<tag><c>{linger, {true|false, Seconds}}</c></tag>
- <item>
+ <item>
<p>Determines the time-out, in seconds, for flushing unsent data
- in the <c>close/1</c> socket call. If the first component of
- the value tuple is <c>false</c>, the second is ignored. This
- means that <c>close/1</c> returns immediately, not waiting
- for data to be flushed. Otherwise, the second component is
- the flushing time-out, in seconds.</p>
+ in the <c>close/1</c> socket call. </p>
+ <p>The first component is if linger is enabled, the second component
+ is the flushing time-out, in seconds. There are 3 alternatives:</p>
+ <taglist>
+ <tag><c>{false, _}</c></tag>
+ <item>
+ <p>close/1 or shutdown/2 returns immediately,
+ not waiting for data to be flushed, with closing
+ happening in the background.</p>
+ </item>
+ <tag><c>{true, 0}</c></tag>
+ <item>
+ <p>Aborts the connection when it is closed.
+ Discards any data still remaining in the send buffers
+ and sends RST to the peer.</p>
+ <p>This avoids TCP's TIME_WAIT state, but leaves open
+ the possibility that another "incarnation" of this connection
+ being created.</p>
+ </item>
+ <tag><c>{true, Time} when Time > 0</c></tag>
+ <item>
+ <p>close/1 or shutdown/2 will not return until
+ all queued messages for the socket have been successfully
+ sent or the linger timeout (Time) has been reached.</p>
+ </item>
+ </taglist>
</item>
<tag><c>{low_msgq_watermark, Size}</c></tag>
<item>
@@ -1486,7 +1507,7 @@ inet:setopts(Sock,[{raw,6,8,<<30:32/native>>}]),]]></code>
</func>
<func>
- <name name="sockname" arity="1"/>
+ <name name="sockname" arity="1" since=""/>
<fsummary>Return the local address and port number for a socket.
</fsummary>
<desc>
@@ -1499,7 +1520,7 @@ inet:setopts(Sock,[{raw,6,8,<<30:32/native>>}]),]]></code>
</func>
<func>
- <name name="socknames" arity="1"/>
+ <name name="socknames" arity="1" since="OTP R16B03"/>
<fsummary>Return all local address/port numbers for a socket.</fsummary>
<desc>
<p>Equivalent to
@@ -1509,7 +1530,7 @@ inet:setopts(Sock,[{raw,6,8,<<30:32/native>>}]),]]></code>
</func>
<func>
- <name name="socknames" arity="2"/>
+ <name name="socknames" arity="2" since="OTP R16B03"/>
<fsummary>Return all local address/port numbers for a socket.</fsummary>
<desc>
<p>Returns a list of all local address/port number pairs for a socket
diff --git a/lib/kernel/doc/src/inet_res.xml b/lib/kernel/doc/src/inet_res.xml
index 351d86a93a..1904e371f7 100644
--- a/lib/kernel/doc/src/inet_res.xml
+++ b/lib/kernel/doc/src/inet_res.xml
@@ -28,7 +28,7 @@
<date>2009-09-11</date>
<rev>A</rev>
</header>
- <module>inet_res</module>
+ <module since="">inet_res</module>
<modulesummary>A rudimentary DNS client.</modulesummary>
<description>
<p>This module performs DNS name resolving to recursive name servers.</p>
@@ -185,8 +185,8 @@ inet_dns:record_type(_) -> undefined.</pre>
<funcs>
<func>
- <name name="getbyname" arity="2"/>
- <name name="getbyname" arity="3"/>
+ <name name="getbyname" arity="2" since=""/>
+ <name name="getbyname" arity="3" since=""/>
<fsummary>Resolve a DNS record of the specified type for the specified
host.</fsummary>
<desc>
@@ -205,8 +205,8 @@ inet_dns:record_type(_) -> undefined.</pre>
</func>
<func>
- <name name="gethostbyaddr" arity="1"/>
- <name name="gethostbyaddr" arity="2"/>
+ <name name="gethostbyaddr" arity="1" since=""/>
+ <name name="gethostbyaddr" arity="2" since=""/>
<fsummary>Return a hostent record for the host with the specified
address.</fsummary>
<desc>
@@ -217,9 +217,9 @@ inet_dns:record_type(_) -> undefined.</pre>
</func>
<func>
- <name name="gethostbyname" arity="1"/>
- <name name="gethostbyname" arity="2"/>
- <name name="gethostbyname" arity="3"/>
+ <name name="gethostbyname" arity="1" since=""/>
+ <name name="gethostbyname" arity="2" since=""/>
+ <name name="gethostbyname" arity="3" since=""/>
<fsummary>Return a hostent record for the host with the specified name.
</fsummary>
<desc>
@@ -235,9 +235,9 @@ inet_dns:record_type(_) -> undefined.</pre>
</func>
<func>
- <name name="lookup" arity="3"/>
- <name name="lookup" arity="4"/>
- <name name="lookup" arity="5"/>
+ <name name="lookup" arity="3" since=""/>
+ <name name="lookup" arity="4" since=""/>
+ <name name="lookup" arity="5" since=""/>
<fsummary>Resolve the DNS data for the record of the specified type
and class for the specified name.</fsummary>
<desc>
@@ -257,9 +257,9 @@ inet_dns:record_type(_) -> undefined.</pre>
</func>
<func>
- <name name="resolve" arity="3"/>
- <name name="resolve" arity="4"/>
- <name name="resolve" arity="5"/>
+ <name name="resolve" arity="3" since=""/>
+ <name name="resolve" arity="4" since=""/>
+ <name name="resolve" arity="5" since=""/>
<fsummary>Resolve a DNS record of the specified type and class
for the specified name.</fsummary>
<desc>
@@ -326,9 +326,9 @@ example_lookup(Name, Class, Type) ->
<funcs>
<func>
- <name name="nslookup" arity="3"/>
- <name name="nslookup" arity="4" clause_i="1"/>
- <name name="nslookup" arity="4" clause_i="2"/>
+ <name name="nslookup" arity="3" since=""/>
+ <name name="nslookup" arity="4" clause_i="1" since=""/>
+ <name name="nslookup" arity="4" clause_i="2" since=""/>
<fsummary>Resolve a DNS record of the specified type and class for the
specified name.</fsummary>
<type variable="Name"/>
@@ -344,8 +344,8 @@ example_lookup(Name, Class, Type) ->
</func>
<func>
- <name name="nnslookup" arity="4"/>
- <name name="nnslookup" arity="5"/>
+ <name name="nnslookup" arity="4" since=""/>
+ <name name="nnslookup" arity="5" since=""/>
<fsummary>Resolve a DNS record of the specified type and class
for the specified name.</fsummary>
<desc>
diff --git a/lib/kernel/doc/src/logger.xml b/lib/kernel/doc/src/logger.xml
index e0b95fa4ad..e09c5db5e3 100644
--- a/lib/kernel/doc/src/logger.xml
+++ b/lib/kernel/doc/src/logger.xml
@@ -32,7 +32,7 @@
<rev>A</rev>
<file>logger.xml</file>
</header>
- <module>logger</module>
+ <module since="OTP 21.0">logger</module>
<modulesummary>API module for Logger, the standard logging facility
in Erlang/OTP.</modulesummary>
@@ -334,9 +334,9 @@ logger:error("error happened because: ~p", [Reason]). % Without macro
</section>
<funcs>
<func>
- <name>emergency(StringOrReport[,Metadata])</name>
- <name>emergency(Format,Args[,Metadata])</name>
- <name>emergency(Fun,FunArgs[,Metadata])</name>
+ <name since="OTP 21.0">emergency(StringOrReport[,Metadata])</name>
+ <name since="OTP 21.0">emergency(Format,Args[,Metadata])</name>
+ <name since="OTP 21.0">emergency(Fun,FunArgs[,Metadata])</name>
<fsummary>Logs the given message as level <c>emergency</c>.</fsummary>
<desc>
<p>Equivalent to
@@ -345,9 +345,9 @@ logger:error("error happened because: ~p", [Reason]). % Without macro
</func>
<func>
- <name>alert(StringOrReport[,Metadata])</name>
- <name>alert(Format,Args[,Metadata])</name>
- <name>alert(Fun,FunArgs[,Metadata])</name>
+ <name since="OTP 21.0">alert(StringOrReport[,Metadata])</name>
+ <name since="OTP 21.0">alert(Format,Args[,Metadata])</name>
+ <name since="OTP 21.0">alert(Fun,FunArgs[,Metadata])</name>
<fsummary>Logs the given message as level <c>alert</c>.</fsummary>
<desc>
<p>Equivalent to
@@ -356,9 +356,9 @@ logger:error("error happened because: ~p", [Reason]). % Without macro
</func>
<func>
- <name>critical(StringOrReport[,Metadata])</name>
- <name>critical(Format,Args[,Metadata])</name>
- <name>critical(Fun,FunArgs[,Metadata])</name>
+ <name since="OTP 21.0">critical(StringOrReport[,Metadata])</name>
+ <name since="OTP 21.0">critical(Format,Args[,Metadata])</name>
+ <name since="OTP 21.0">critical(Fun,FunArgs[,Metadata])</name>
<fsummary>Logs the given message as level <c>critical</c>.</fsummary>
<desc>
<p>Equivalent to
@@ -367,9 +367,9 @@ logger:error("error happened because: ~p", [Reason]). % Without macro
</func>
<func>
- <name>error(StringOrReport[,Metadata])</name>
- <name>error(Format,Args[,Metadata])</name>
- <name>error(Fun,FunArgs[,Metadata])</name>
+ <name since="OTP 21.0">error(StringOrReport[,Metadata])</name>
+ <name since="OTP 21.0">error(Format,Args[,Metadata])</name>
+ <name since="OTP 21.0">error(Fun,FunArgs[,Metadata])</name>
<fsummary>Logs the given message as level <c>error</c>.</fsummary>
<desc>
<p>Equivalent to
@@ -378,9 +378,9 @@ logger:error("error happened because: ~p", [Reason]). % Without macro
</func>
<func>
- <name>warning(StringOrReport[,Metadata])</name>
- <name>warning(Format,Args[,Metadata])</name>
- <name>warning(Fun,FunArgs[,Metadata])</name>
+ <name since="OTP 21.0">warning(StringOrReport[,Metadata])</name>
+ <name since="OTP 21.0">warning(Format,Args[,Metadata])</name>
+ <name since="OTP 21.0">warning(Fun,FunArgs[,Metadata])</name>
<fsummary>Logs the given message as level <c>warning</c>.</fsummary>
<desc>
<p>Equivalent to
@@ -389,9 +389,9 @@ logger:error("error happened because: ~p", [Reason]). % Without macro
</func>
<func>
- <name>notice(StringOrReport[,Metadata])</name>
- <name>notice(Format,Args[,Metadata])</name>
- <name>notice(Fun,FunArgs[,Metadata])</name>
+ <name since="OTP 21.0">notice(StringOrReport[,Metadata])</name>
+ <name since="OTP 21.0">notice(Format,Args[,Metadata])</name>
+ <name since="OTP 21.0">notice(Fun,FunArgs[,Metadata])</name>
<fsummary>Logs the given message as level <c>notice</c>.</fsummary>
<desc>
<p>Equivalent to
@@ -400,9 +400,9 @@ logger:error("error happened because: ~p", [Reason]). % Without macro
</func>
<func>
- <name>info(StringOrReport[,Metadata])</name>
- <name>info(Format,Args[,Metadata])</name>
- <name>info(Fun,FunArgs[,Metadata])</name>
+ <name since="OTP 21.0">info(StringOrReport[,Metadata])</name>
+ <name since="OTP 21.0">info(Format,Args[,Metadata])</name>
+ <name since="OTP 21.0">info(Fun,FunArgs[,Metadata])</name>
<fsummary>Logs the given message as level <c>info</c>.</fsummary>
<desc>
<p>Equivalent to
@@ -411,9 +411,9 @@ logger:error("error happened because: ~p", [Reason]). % Without macro
</func>
<func>
- <name>debug(StringOrReport[,Metadata])</name>
- <name>debug(Format,Args[,Metadata])</name>
- <name>debug(Fun,FunArgs[,Metadata])</name>
+ <name since="OTP 21.0">debug(StringOrReport[,Metadata])</name>
+ <name since="OTP 21.0">debug(Format,Args[,Metadata])</name>
+ <name since="OTP 21.0">debug(Fun,FunArgs[,Metadata])</name>
<fsummary>Logs the given message as level <c>debug</c>.</fsummary>
<desc>
<p>Equivalent to
@@ -422,12 +422,12 @@ logger:error("error happened because: ~p", [Reason]). % Without macro
</func>
<func>
- <name name="log" arity="2"/>
- <name name="log" arity="3" clause_i="1"/>
- <name name="log" arity="3" clause_i="2"/>
- <name name="log" arity="3" clause_i="3"/>
- <name name="log" arity="4" clause_i="1"/>
- <name name="log" arity="4" clause_i="2"/>
+ <name name="log" arity="2" since="OTP 21.0"/>
+ <name name="log" arity="3" clause_i="1" since="OTP 21.0"/>
+ <name name="log" arity="3" clause_i="2" since="OTP 21.0"/>
+ <name name="log" arity="3" clause_i="3" since="OTP 21.0"/>
+ <name name="log" arity="4" clause_i="1" since="OTP 21.0"/>
+ <name name="log" arity="4" clause_i="2" since="OTP 21.0"/>
<fsummary>Logs the given message.</fsummary>
<type variable="Level"/>
<type variable="StringOrReport" name_i="1"/>
@@ -448,7 +448,7 @@ logger:error("error happened because: ~p", [Reason]). % Without macro
</section>
<funcs>
<func>
- <name name="add_handler" arity="3"/>
+ <name name="add_handler" arity="3" since="OTP 21.0"/>
<fsummary>Add a handler with the given configuration.</fsummary>
<desc>
<p>Add a handler with the given configuration.</p>
@@ -459,7 +459,7 @@ logger:error("error happened because: ~p", [Reason]). % Without macro
</func>
<func>
- <name name="add_handler_filter" arity="3"/>
+ <name name="add_handler_filter" arity="3" since="OTP 21.0"/>
<fsummary>Add a filter to the specified handler.</fsummary>
<desc>
<p>Add a filter to the specified handler.</p>
@@ -500,7 +500,7 @@ logger:error("error happened because: ~p", [Reason]). % Without macro
</func>
<func>
- <name name="add_handlers" arity="1" clause_i="1"/>
+ <name name="add_handlers" arity="1" clause_i="1" since="OTP 21.0"/>
<fsummary>Set up log handlers from the application's
configuration parameters.</fsummary>
<desc>
@@ -510,7 +510,7 @@ logger:error("error happened because: ~p", [Reason]). % Without macro
</func>
<func>
- <name name="add_handlers" arity="1" clause_i="2"/>
+ <name name="add_handlers" arity="1" clause_i="2" since="OTP 21.0"/>
<fsummary>Setup logger handlers.</fsummary>
<type name="config_handler"/>
<desc>
@@ -553,7 +553,7 @@ start(_, []) ->
</func>
<func>
- <name name="add_primary_filter" arity="2"/>
+ <name name="add_primary_filter" arity="2" since="OTP 21.0"/>
<fsummary>Add a primary filter to Logger.</fsummary>
<desc>
<p>Add a primary filter to Logger.</p>
@@ -594,7 +594,7 @@ start(_, []) ->
</func>
<func>
- <name name="get_config" arity="0"/>
+ <name name="get_config" arity="0" since="OTP 21.0"/>
<fsummary>Look up the current Logger configuration</fsummary>
<desc>
<p>Look up all current Logger configuration, including primary
@@ -603,7 +603,7 @@ start(_, []) ->
</func>
<func>
- <name name="get_handler_config" arity="0"/>
+ <name name="get_handler_config" arity="0" since="OTP 21.0"/>
<fsummary>Look up the current configuration for all handlers.</fsummary>
<desc>
<p>Look up the current configuration for all handlers.</p>
@@ -611,7 +611,7 @@ start(_, []) ->
</func>
<func>
- <name name="get_handler_config" arity="1"/>
+ <name name="get_handler_config" arity="1" since="OTP 21.0"/>
<fsummary>Look up the current configuration for the given
handler.</fsummary>
<desc>
@@ -620,7 +620,7 @@ start(_, []) ->
</func>
<func>
- <name name="get_handler_ids" arity="0"/>
+ <name name="get_handler_ids" arity="0" since="OTP 21.0"/>
<fsummary>Look up the identities for all installed handlers.</fsummary>
<desc>
<p>Look up the identities for all installed handlers.</p>
@@ -628,7 +628,7 @@ start(_, []) ->
</func>
<func>
- <name name="get_primary_config" arity="0"/>
+ <name name="get_primary_config" arity="0" since="OTP 21.0"/>
<fsummary>Look up the current primary configuration for Logger.</fsummary>
<desc>
<p>Look up the current primary configuration for Logger.</p>
@@ -636,7 +636,7 @@ start(_, []) ->
</func>
<func>
- <name name="get_module_level" arity="0"/>
+ <name name="get_module_level" arity="0" since="OTP 21.0"/>
<fsummary>Look up all current module levels.</fsummary>
<desc>
<p>Look up all current module levels. Returns a list
@@ -648,7 +648,7 @@ start(_, []) ->
</func>
<func>
- <name name="get_module_level" arity="1"/>
+ <name name="get_module_level" arity="1" since="OTP 21.0"/>
<fsummary>Look up the current level for the given modules.</fsummary>
<desc>
<p>Look up the current level for the given modules. Returns a
@@ -660,7 +660,7 @@ start(_, []) ->
</func>
<func>
- <name name="get_process_metadata" arity="0"/>
+ <name name="get_process_metadata" arity="0" since="OTP 21.0"/>
<fsummary>Retrieve data set with set_process_metadata/1.</fsummary>
<desc>
<p>Retrieve data set
@@ -672,7 +672,7 @@ start(_, []) ->
</func>
<func>
- <name name="remove_handler" arity="1"/>
+ <name name="remove_handler" arity="1" since="OTP 21.0"/>
<fsummary>Remove the handler with the specified identity.</fsummary>
<desc>
<p>Remove the handler identified by <c><anno>HandlerId</anno></c>.</p>
@@ -680,7 +680,7 @@ start(_, []) ->
</func>
<func>
- <name name="remove_handler_filter" arity="2"/>
+ <name name="remove_handler_filter" arity="2" since="OTP 21.0"/>
<fsummary>Remove a filter from the specified handler.</fsummary>
<desc>
<p>Remove the filter identified
@@ -690,7 +690,7 @@ start(_, []) ->
</func>
<func>
- <name name="remove_primary_filter" arity="1"/>
+ <name name="remove_primary_filter" arity="1" since="OTP 21.0"/>
<fsummary>Remove a primary filter from Logger.</fsummary>
<desc>
<p>Remove the primary filter identified
@@ -699,7 +699,7 @@ start(_, []) ->
</func>
<func>
- <name name="set_application_level" arity="2"/>
+ <name name="set_application_level" arity="2" since="OTP 21.1"/>
<fsummary>Set the log level for all modules in the specified application.</fsummary>
<desc>
<p>Set the log level for all the modules of the specified application.</p>
@@ -710,7 +710,7 @@ start(_, []) ->
</func>
<func>
- <name name="set_handler_config" arity="2"/>
+ <name name="set_handler_config" arity="2" since="OTP 21.0"/>
<fsummary>Set configuration data for the specified handler.</fsummary>
<desc>
<p>Set configuration data for the specified handler. This
@@ -731,11 +731,11 @@ start(_, []) ->
</func>
<func>
- <name name="set_handler_config" arity="3" clause_i="1"/>
- <name name="set_handler_config" arity="3" clause_i="2"/>
- <name name="set_handler_config" arity="3" clause_i="3"/>
- <name name="set_handler_config" arity="3" clause_i="4"/>
- <name name="set_handler_config" arity="3" clause_i="5"/>
+ <name name="set_handler_config" arity="3" clause_i="1" since="OTP 21.0"/>
+ <name name="set_handler_config" arity="3" clause_i="2" since="OTP 21.0"/>
+ <name name="set_handler_config" arity="3" clause_i="3" since="OTP 21.0"/>
+ <name name="set_handler_config" arity="3" clause_i="4" since="OTP 21.0"/>
+ <name name="set_handler_config" arity="3" clause_i="5" since="OTP 21.0"/>
<fsummary>Add or update configuration data for the specified
handler.</fsummary>
<type variable="HandlerId"/>
@@ -767,7 +767,7 @@ start(_, []) ->
</func>
<func>
- <name name="set_primary_config" arity="1"/>
+ <name name="set_primary_config" arity="1" since="OTP 21.0"/>
<fsummary>Set primary configuration data for Logger.</fsummary>
<desc>
<p>Set primary configuration data for Logger. This
@@ -785,9 +785,9 @@ start(_, []) ->
</func>
<func>
- <name name="set_primary_config" arity="2" clause_i="1"/>
- <name name="set_primary_config" arity="2" clause_i="2"/>
- <name name="set_primary_config" arity="2" clause_i="3"/>
+ <name name="set_primary_config" arity="2" clause_i="1" since="OTP 21.0"/>
+ <name name="set_primary_config" arity="2" clause_i="2" since="OTP 21.0"/>
+ <name name="set_primary_config" arity="2" clause_i="3" since="OTP 21.0"/>
<fsummary>Add or update primary configuration data for Logger.</fsummary>
<type variable="Level" name_i="1"/>
<type variable="FilterDefault" name_i="2"/>
@@ -801,7 +801,7 @@ start(_, []) ->
</func>
<func>
- <name name="set_module_level" arity="2"/>
+ <name name="set_module_level" arity="2" since="OTP 21.0"/>
<fsummary>Set the log level for the specified modules.</fsummary>
<desc>
<p>Set the log level for the specified modules.</p>
@@ -841,7 +841,7 @@ start(_, []) ->
</func>
<func>
- <name name="set_process_metadata" arity="1"/>
+ <name name="set_process_metadata" arity="1" since="OTP 21.0"/>
<fsummary>Set metadata to use when logging from current process.</fsummary>
<desc>
<p>Set metadata which Logger shall automatically insert in
@@ -860,7 +860,7 @@ start(_, []) ->
</func>
<func>
- <name name="unset_application_level" arity="1"/>
+ <name name="unset_application_level" arity="1" since="OTP 21.1"/>
<fsummary>Unset the log level for all modules in the specified application.</fsummary>
<desc>
<p>Unset the log level for all the modules of the specified application.</p>
@@ -871,7 +871,7 @@ start(_, []) ->
</func>
<func>
- <name name="unset_module_level" arity="0"/>
+ <name name="unset_module_level" arity="0" since="OTP 21.0"/>
<fsummary>Remove module specific log settings for all modules.</fsummary>
<desc>
<p>Remove module specific log settings. After this, the
@@ -880,7 +880,7 @@ start(_, []) ->
</func>
<func>
- <name name="unset_module_level" arity="1"/>
+ <name name="unset_module_level" arity="1" since="OTP 21.0"/>
<fsummary>Remove module specific log settings for the given
modules.</fsummary>
<desc>
@@ -890,7 +890,7 @@ start(_, []) ->
</func>
<func>
- <name name="unset_process_metadata" arity="0"/>
+ <name name="unset_process_metadata" arity="0" since="OTP 21.0"/>
<fsummary>Delete data set with set_process_metadata/1.</fsummary>
<desc>
<p>Delete data set
@@ -902,7 +902,7 @@ start(_, []) ->
</func>
<func>
- <name name="update_formatter_config" arity="2"/>
+ <name name="update_formatter_config" arity="2" since="OTP 21.0"/>
<fsummary>Update the formatter configuration for the specified handler.</fsummary>
<desc>
<p>Update the formatter configuration for the specified handler.</p>
@@ -917,7 +917,7 @@ start(_, []) ->
</func>
<func>
- <name name="update_formatter_config" arity="3"/>
+ <name name="update_formatter_config" arity="3" since="OTP 21.0"/>
<fsummary>Update the formatter configuration for the specified handler.</fsummary>
<desc>
<p>Update the formatter configuration for the specified handler.</p>
@@ -928,7 +928,7 @@ start(_, []) ->
</func>
<func>
- <name name="update_handler_config" arity="2"/>
+ <name name="update_handler_config" arity="2" since="OTP 21.0"/>
<fsummary>Update configuration data for the specified handler.</fsummary>
<desc>
<p>Update configuration data for the specified handler. This function
@@ -944,11 +944,11 @@ logger:set_handler_config(HandlerId, maps:merge(Old, Config)).
</func>
<func>
- <name name="update_handler_config" arity="3" clause_i="1"/>
- <name name="update_handler_config" arity="3" clause_i="2"/>
- <name name="update_handler_config" arity="3" clause_i="3"/>
- <name name="update_handler_config" arity="3" clause_i="4"/>
- <name name="update_handler_config" arity="3" clause_i="5"/>
+ <name name="update_handler_config" arity="3" clause_i="1" since="OTP 21.2"/>
+ <name name="update_handler_config" arity="3" clause_i="2" since="OTP 21.2"/>
+ <name name="update_handler_config" arity="3" clause_i="3" since="OTP 21.2"/>
+ <name name="update_handler_config" arity="3" clause_i="4" since="OTP 21.2"/>
+ <name name="update_handler_config" arity="3" clause_i="5" since="OTP 21.2"/>
<fsummary>Add or update configuration data for the specified
handler.</fsummary>
<type variable="HandlerId"/>
@@ -980,7 +980,7 @@ logger:set_handler_config(HandlerId, maps:merge(Old, Config)).
</func>
<func>
- <name name="update_primary_config" arity="1"/>
+ <name name="update_primary_config" arity="1" since="OTP 21.0"/>
<fsummary>Update primary configuration data for Logger.</fsummary>
<desc>
<p>Update primary configuration data for Logger. This function
@@ -996,7 +996,7 @@ logger:set_primary_config(maps:merge(Old, Config)).
</func>
<func>
- <name name="update_process_metadata" arity="1"/>
+ <name name="update_process_metadata" arity="1" since="OTP 21.0"/>
<fsummary>Set or update metadata to use when logging from
current process.</fsummary>
<desc>
@@ -1021,7 +1021,7 @@ logger:set_process_metadata(maps:merge(logger:get_process_metadata(), Meta)).
</section>
<funcs>
<func>
- <name name="compare_levels" arity="2"/>
+ <name name="compare_levels" arity="2" since="OTP 21.0"/>
<fsummary>Compare the severity of two log levels.</fsummary>
<desc>
<p>Compare the severity of two log levels. Returns <c>gt</c>
@@ -1032,7 +1032,7 @@ logger:set_process_metadata(maps:merge(logger:get_process_metadata(), Meta)).
</func>
<func>
- <name name="format_report" arity="1"/>
+ <name name="format_report" arity="1" since="OTP 21.0"/>
<fsummary>Convert a log message on report form to {Format, Args}.</fsummary>
<desc>
<p>Convert a log message on report form to <c>{Format,
@@ -1062,7 +1062,7 @@ logger:set_process_metadata(maps:merge(logger:get_process_metadata(), Meta)).
<funcs>
<func>
- <name>HModule:adding_handler(Config1) -> {ok, Config2} | {error,
+ <name since="OTP 21.0">HModule:adding_handler(Config1) -> {ok, Config2} | {error,
Reason}</name>
<fsummary>An instance of this handler is about to be added.</fsummary>
<type>
@@ -1088,7 +1088,7 @@ logger:set_process_metadata(maps:merge(logger:get_process_metadata(), Meta)).
</func>
<func>
- <name>HModule:changing_config(SetOrUpdate, OldConfig, NewConfig) -> {ok, Config} | {error, Reason}</name>
+ <name since="OTP 21.2">HModule:changing_config(SetOrUpdate, OldConfig, NewConfig) -> {ok, Config} | {error, Reason}</name>
<fsummary>The configuration for this handler is about to change.</fsummary>
<type>
<v>SetOrUpdate = set | update</v>
@@ -1126,7 +1126,7 @@ logger:set_process_metadata(maps:merge(logger:get_process_metadata(), Meta)).
</func>
<func>
- <name>HModule:filter_config(Config) -> FilteredConfig</name>
+ <name since="OTP 21.2">HModule:filter_config(Config) -> FilteredConfig</name>
<fsummary>Remove internal data from configuration.</fsummary>
<type>
<v>Config = FilteredConfig =
@@ -1146,7 +1146,7 @@ logger:set_process_metadata(maps:merge(logger:get_process_metadata(), Meta)).
</func>
<func>
- <name>HModule:log(LogEvent, Config) -> void()</name>
+ <name since="OTP 21.0">HModule:log(LogEvent, Config) -> void()</name>
<fsummary>Log the given log event.</fsummary>
<type>
<v>LogEvent =
@@ -1169,7 +1169,7 @@ logger:set_process_metadata(maps:merge(logger:get_process_metadata(), Meta)).
</func>
<func>
- <name>HModule:removing_handler(Config) -> ok</name>
+ <name since="OTP 21.0">HModule:removing_handler(Config) -> ok</name>
<fsummary>The given handler is about to be removed.</fsummary>
<type>
<v>Config =
@@ -1197,7 +1197,7 @@ logger:set_process_metadata(maps:merge(logger:get_process_metadata(), Meta)).
<funcs>
<func>
- <name>FModule:check_config(FConfig) -> ok | {error, Reason}</name>
+ <name since="OTP 21.0">FModule:check_config(FConfig) -> ok | {error, Reason}</name>
<fsummary>Validate the given formatter configuration.</fsummary>
<type>
<v>FConfig =
@@ -1217,7 +1217,7 @@ logger:set_process_metadata(maps:merge(logger:get_process_metadata(), Meta)).
<item><seealso marker="logger#set_handler_config-2">
<c>logger:set_handler_config/2,3</c></seealso></item>
<item><seealso marker="logger#update_handler_config-2">
- <c>logger:updata_handler_config/2,3</c></seealso></item>
+ <c>logger:update_handler_config/2,3</c></seealso></item>
<item><seealso marker="logger#update_formatter_config-2">
<c>logger:update_formatter_config/2</c></seealso></item>
</list>
@@ -1228,7 +1228,7 @@ logger:set_process_metadata(maps:merge(logger:get_process_metadata(), Meta)).
</desc>
</func>
<func>
- <name>FModule:format(LogEvent, FConfig) -> FormattedLogEntry</name>
+ <name since="OTP 21.0">FModule:format(LogEvent, FConfig) -> FormattedLogEntry</name>
<fsummary>Format the given log event.</fsummary>
<type>
<v>LogEvent =
diff --git a/lib/kernel/doc/src/logger_disk_log_h.xml b/lib/kernel/doc/src/logger_disk_log_h.xml
index d9b941a0a9..5b2374690e 100644
--- a/lib/kernel/doc/src/logger_disk_log_h.xml
+++ b/lib/kernel/doc/src/logger_disk_log_h.xml
@@ -32,7 +32,7 @@
<rev>A</rev>
<file>logger_disk_log_h.xml</file>
</header>
- <module>logger_disk_log_h</module>
+ <module since="OTP 21.0">logger_disk_log_h</module>
<modulesummary>A disk_log based handler for Logger</modulesummary>
<description>
@@ -148,7 +148,7 @@ erl -kernel logger '[{handler,default,logger_disk_log_h,
<funcs>
<func>
- <name name="filesync" arity="1" clause_i="1"/>
+ <name name="filesync" arity="1" clause_i="1" since="OTP 21.0"/>
<fsummary>Writes buffered data to disk.</fsummary>
<desc>
<p>Write buffered data to disk.</p>
diff --git a/lib/kernel/doc/src/logger_filters.xml b/lib/kernel/doc/src/logger_filters.xml
index 90f1fcc270..0a02342864 100644
--- a/lib/kernel/doc/src/logger_filters.xml
+++ b/lib/kernel/doc/src/logger_filters.xml
@@ -32,7 +32,7 @@
<rev>A</rev>
<file>logger_filters.xml</file>
</header>
- <module>logger_filters</module>
+ <module since="OTP 21.0">logger_filters</module>
<modulesummary>Filters to use with Logger.</modulesummary>
<description>
@@ -51,7 +51,7 @@
<funcs>
<func>
- <name name="domain" arity="2"/>
+ <name name="domain" arity="2" since="OTP 21.0"/>
<fsummary>Filter log events based on the domain field in
metadata.</fsummary>
<desc>
@@ -152,7 +152,7 @@ ok</code>
</func>
<func>
- <name name="level" arity="2"/>
+ <name name="level" arity="2" since="OTP 21.0"/>
<fsummary>Filter log events based on the log level.</fsummary>
<desc>
<p>This filter provides a way of filtering log events based
@@ -212,7 +212,7 @@ ok</code>
</func>
<func>
- <name name="progress" arity="2"/>
+ <name name="progress" arity="2" since="OTP 21.0"/>
<fsummary>Filter progress reports from supervisor and application_controller.</fsummary>
<desc>
<p>This filter matches all progress reports
@@ -227,7 +227,7 @@ ok</code>
</func>
<func>
- <name name="remote_gl" arity="2"/>
+ <name name="remote_gl" arity="2" since="OTP 21.0"/>
<fsummary>Filter events with group leader on remote node.</fsummary>
<desc>
<p>This filter matches all events originating from a process
diff --git a/lib/kernel/doc/src/logger_formatter.xml b/lib/kernel/doc/src/logger_formatter.xml
index 24772fd6c4..6dc83d24e1 100644
--- a/lib/kernel/doc/src/logger_formatter.xml
+++ b/lib/kernel/doc/src/logger_formatter.xml
@@ -32,7 +32,7 @@
<rev>A</rev>
<file>logger_formatter.xml</file>
</header>
- <module>logger_formatter</module>
+ <module since="OTP 21.0">logger_formatter</module>
<modulesummary>Default formatter for Logger.</modulesummary>
<description>
@@ -289,7 +289,7 @@ exit_reason: "It crashed"</code>
<funcs>
<func>
- <name name="check_config" arity="1"/>
+ <name name="check_config" arity="1" since="OTP 21.0"/>
<fsummary>Validates the given formatter configuration.</fsummary>
<desc>
<p>The function is called by Logger when the formatter
@@ -303,14 +303,14 @@ exit_reason: "It crashed"</code>
<item><seealso marker="logger#set_handler_config-2">
<c>logger:set_handler_config/2,3</c></seealso></item>
<item><seealso marker="logger#update_handler_config-2">
- <c>logger:updata_handler_config/2</c></seealso></item>
+ <c>logger:update_handler_config/2</c></seealso></item>
<item><seealso marker="logger#update_formatter_config-2">
<c>logger:update_formatter_config/2</c></seealso></item>
</list>
</desc>
</func>
<func>
- <name name="format" arity="2"/>
+ <name name="format" arity="2" since="OTP 21.0"/>
<fsummary>Formats the given message.</fsummary>
<desc>
<p>This the formatter callback function to be called from
diff --git a/lib/kernel/doc/src/logger_std_h.xml b/lib/kernel/doc/src/logger_std_h.xml
index e156f5719b..fcd180abd6 100644
--- a/lib/kernel/doc/src/logger_std_h.xml
+++ b/lib/kernel/doc/src/logger_std_h.xml
@@ -32,7 +32,7 @@
<rev>A</rev>
<file>logger_std_h.xml</file>
</header>
- <module>logger_std_h</module>
+ <module since="OTP 21.0">logger_std_h</module>
<modulesummary>Standard handler for Logger.</modulesummary>
<description>
@@ -121,7 +121,7 @@ erl -kernel logger '[{handler,default,logger_std_h,
<funcs>
<func>
- <name name="filesync" arity="1" clause_i="1"/>
+ <name name="filesync" arity="1" clause_i="1" since="OTP 21.0"/>
<fsummary>Writes buffered data to disk.</fsummary>
<desc>
<p>Write buffered data to disk.</p>
diff --git a/lib/kernel/doc/src/net_adm.xml b/lib/kernel/doc/src/net_adm.xml
index 6957a3b5e4..c3e1619f1b 100644
--- a/lib/kernel/doc/src/net_adm.xml
+++ b/lib/kernel/doc/src/net_adm.xml
@@ -28,7 +28,7 @@
<date>1996-09-10</date>
<rev>A</rev>
</header>
- <module>net_adm</module>
+ <module since="">net_adm</module>
<modulesummary>Various Erlang net administration routines.</modulesummary>
<description>
<p>This module contains various network utility functions.</p>
@@ -36,7 +36,7 @@
<funcs>
<func>
- <name name="dns_hostname" arity="1"/>
+ <name name="dns_hostname" arity="1" since=""/>
<fsummary>Official name of a host.</fsummary>
<desc>
<p>Returns the official name of <c><anno>Host</anno></c>, or
@@ -46,7 +46,7 @@
</func>
<func>
- <name name="host_file" arity="0"/>
+ <name name="host_file" arity="0" since=""/>
<fsummary>Read file <c>.hosts.erlang</c>.</fsummary>
<desc>
<p>Reads file <c>.hosts.erlang</c>, see section
@@ -58,7 +58,7 @@
</func>
<func>
- <name name="localhost" arity="0"/>
+ <name name="localhost" arity="0" since=""/>
<fsummary>Name of the local host.</fsummary>
<desc>
<p>Returns the name of the local host. If Erlang was started
@@ -68,8 +68,8 @@
</func>
<func>
- <name name="names" arity="0"/>
- <name name="names" arity="1"/>
+ <name name="names" arity="0" since=""/>
+ <name name="names" arity="1" since=""/>
<fsummary>Names of Erlang nodes at a host.</fsummary>
<desc>
<p>Similar to <c>epmd -names</c>, see
@@ -86,7 +86,7 @@
</func>
<func>
- <name name="ping" arity="1"/>
+ <name name="ping" arity="1" since=""/>
<fsummary>Set up a connection to a node.</fsummary>
<desc>
<p>Sets up a connection to <c><anno>Node</anno></c>. Returns
@@ -95,8 +95,8 @@
</func>
<func>
- <name name="world" arity="0"/>
- <name name="world" arity="1"/>
+ <name name="world" arity="0" since=""/>
+ <name name="world" arity="1" since=""/>
<fsummary>Lookup and connect to all nodes at all hosts in
<c>.hosts.erlang</c>.</fsummary>
<type name="verbosity"/>
@@ -117,8 +117,8 @@
</func>
<func>
- <name name="world_list" arity="1"/>
- <name name="world_list" arity="2"/>
+ <name name="world_list" arity="1" since=""/>
+ <name name="world_list" arity="2" since=""/>
<fsummary>Lookup and connect to all nodes at specified hosts.</fsummary>
<type name="verbosity"/>
<desc>
diff --git a/lib/kernel/doc/src/net_kernel.xml b/lib/kernel/doc/src/net_kernel.xml
index bfbe7a6470..419d3cad84 100644
--- a/lib/kernel/doc/src/net_kernel.xml
+++ b/lib/kernel/doc/src/net_kernel.xml
@@ -28,7 +28,7 @@
<date>1996-09-10</date>
<rev>A</rev>
</header>
- <module>net_kernel</module>
+ <module since="">net_kernel</module>
<modulesummary>Erlang networking kernel.</modulesummary>
<description>
<p>The net kernel is a system process, registered as
@@ -81,7 +81,7 @@ $ <input>erl -sname foobar</input></pre>
<funcs>
<func>
- <name name="allow" arity="1"/>
+ <name name="allow" arity="1" since=""/>
<fsummary>Permit access to a specified set of nodes</fsummary>
<desc>
<p>Permits access to the specified set of nodes.</p>
@@ -98,7 +98,7 @@ $ <input>erl -sname foobar</input></pre>
</func>
<func>
- <name name="connect_node" arity="1"/>
+ <name name="connect_node" arity="1" since=""/>
<fsummary>Establish a connection to a node.</fsummary>
<desc>
<p>Establishes a connection to <c><anno>Node</anno></c>. Returns
@@ -110,7 +110,7 @@ $ <input>erl -sname foobar</input></pre>
</func>
<func>
- <name name="get_net_ticktime" arity="0"/>
+ <name name="get_net_ticktime" arity="0" since=""/>
<fsummary>Get <c>net_ticktime</c>.</fsummary>
<desc>
<p>Gets <c>net_ticktime</c> (see
@@ -131,7 +131,7 @@ $ <input>erl -sname foobar</input></pre>
</func>
<func>
- <name name="getopts" arity="2"/>
+ <name name="getopts" arity="2" since="OTP 19.1"/>
<fsummary>Get distribution socket options.</fsummary>
<desc>
<p>Get one or more options for the distribution socket
@@ -146,8 +146,8 @@ $ <input>erl -sname foobar</input></pre>
</func>
<func>
- <name name="monitor_nodes" arity="1"/>
- <name name="monitor_nodes" arity="2"/>
+ <name name="monitor_nodes" arity="1" since=""/>
+ <name name="monitor_nodes" arity="2" since=""/>
<fsummary>Subscribe to node status change messages.</fsummary>
<desc>
<p>The calling process subscribes or unsubscribes to node
@@ -267,8 +267,8 @@ $ <input>erl -sname foobar</input></pre>
</func>
<func>
- <name name="set_net_ticktime" arity="1"/>
- <name name="set_net_ticktime" arity="2"/>
+ <name name="set_net_ticktime" arity="1" since=""/>
+ <name name="set_net_ticktime" arity="2" since=""/>
<fsummary>Set <c>net_ticktime</c>.</fsummary>
<desc>
<p>Sets <c>net_ticktime</c> (see
@@ -324,7 +324,7 @@ $ <input>erl -sname foobar</input></pre>
</func>
<func>
- <name name="setopts" arity="2"/>
+ <name name="setopts" arity="2" since="OTP 19.1"/>
<fsummary>Set distribution socket options.</fsummary>
<desc>
<p>Set one or more options for distribution sockets.
@@ -345,9 +345,9 @@ $ <input>erl -sname foobar</input></pre>
</func>
<func>
- <name>start([Name]) -> {ok, pid()} | {error, Reason}</name>
- <name>start([Name, NameType]) -> {ok, pid()} | {error, Reason}</name>
- <name>start([Name, NameType, Ticktime]) -> {ok, pid()} | {error, Reason}</name>
+ <name since="">start([Name]) -> {ok, pid()} | {error, Reason}</name>
+ <name since="">start([Name, NameType]) -> {ok, pid()} | {error, Reason}</name>
+ <name since="">start([Name, NameType, Ticktime]) -> {ok, pid()} | {error, Reason}</name>
<fsummary>Turn an Erlang runtime system into a distributed node.</fsummary>
<type>
<v>Name = atom()</v>
@@ -364,7 +364,7 @@ $ <input>erl -sname foobar</input></pre>
</func>
<func>
- <name name="stop" arity="0"/>
+ <name name="stop" arity="0" since=""/>
<fsummary>Turn a node into a non-distributed Erlang runtime system.</fsummary>
<desc>
<p>Turns a distributed node into a non-distributed node. For
diff --git a/lib/kernel/doc/src/notes.xml b/lib/kernel/doc/src/notes.xml
index 8188ede6a2..021ecfa40d 100644
--- a/lib/kernel/doc/src/notes.xml
+++ b/lib/kernel/doc/src/notes.xml
@@ -31,6 +31,123 @@
</header>
<p>This document describes the changes made to the Kernel application.</p>
+<section><title>Kernel 6.2</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ A new function, <c>logger:update_handler_config/3</c> is
+ added, and the handler callback <c>changing_config</c>
+ now has a new argument, <c>SetOrUpdate</c>, which
+ indicates if the configuration change comes from
+ <c>set_handler_config/2,3</c> or
+ <c>update_handler_config/2,3</c>.</p>
+ <p>
+ This allows the handler to consistently merge the new
+ configuration with the old (if the change comes from
+ <c>update_handler_config/2,3</c>) or with the default (if
+ the change comes from <c>set_handler_config/2,3</c>).</p>
+ <p>
+ The built-in handlers <c>logger_std_h</c> and
+ <c>logger_disk_log_h</c> are updated accordingly. A bug
+ which could cause inconsistency between the handlers'
+ internal state and the stored configuration is also
+ corrected.</p>
+ <p>
+ *** POTENTIAL INCOMPATIBILITY ***</p>
+ <p>
+ Own Id: OTP-15364</p>
+ </item>
+ <item>
+ <p>
+ Fix fallback when custom erl_epmd client does not
+ implement address_please.</p>
+ <p>
+ Own Id: OTP-15388 Aux Id: PR-1983 </p>
+ </item>
+ <item>
+ <p>
+ The logger ets table did not have the
+ <c>read_concurrency</c> option. This is now added.</p>
+ <p>
+ Own Id: OTP-15453 Aux Id: ERL-782 </p>
+ </item>
+ <item>
+ <p>
+ During system start, logger has a simple handler which
+ prints to stdout. After the kernel supervision is
+ started, this handler is removed and replaced by the
+ default handler. Due to a bug, logger earlier issued a
+ debug printout saying it received an unexpected message,
+ which was the EXIT message from the simple handler's
+ process. This is now corrected. The simple handler's
+ process now unlinks from the logger process before
+ terminating.</p>
+ <p>
+ Own Id: OTP-15466 Aux Id: ERL-788 </p>
+ </item>
+ <item>
+ <p>
+ The logger handler <c>logger_std_h</c> would not
+ re-create it's log file if it was removed. Due to this it
+ could not be used with tools like 'logrotate'. This is
+ now corrected.</p>
+ <p>
+ Own Id: OTP-15469</p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ A function <c>inet:getifaddrs/1</c> that takes a list
+ with a namespace option has been added, for platforms
+ that support that feature, for example Linux (only?).</p>
+ <p>
+ Own Id: OTP-15121 Aux Id: ERIERL-189, PR-1974 </p>
+ </item>
+ <item>
+ <p>Added the <c>nopush</c> option for TCP sockets, which
+ corresponds to <c>TCP_NOPUSH</c> on *BSD and
+ <c>TCP_CORK</c> on Linux.</p>
+ <p>This is also used internally in <c>file:sendfile</c>
+ to reduce latency on subsequent send operations.</p>
+ <p>
+ Own Id: OTP-15357 Aux Id: ERL-698 </p>
+ </item>
+ <item>
+ <p>
+ Optimize handling of send_delay for tcp sockes to better
+ work with the new pollthread implementation introduced in
+ OTP-21.</p>
+ <p>
+ Own Id: OTP-15471 Aux Id: ERIERL-229 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Kernel 6.1.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fix bug causing net_kernel process crash on connection
+ attempt from node with name identical to local node.</p>
+ <p>
+ Own Id: OTP-15438 Aux Id: ERL-781 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Kernel 6.1</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/kernel/doc/src/os.xml b/lib/kernel/doc/src/os.xml
index c95e615c6b..0500e4cfb3 100644
--- a/lib/kernel/doc/src/os.xml
+++ b/lib/kernel/doc/src/os.xml
@@ -28,7 +28,7 @@
<date></date>
<rev></rev>
</header>
- <module>os</module>
+ <module since="">os</module>
<modulesummary>Operating system-specific functions.</modulesummary>
<description>
<p>The functions in this module are operating system-specific.
@@ -134,8 +134,8 @@
<funcs>
<func>
- <name name="cmd" arity="1"/>
- <name name="cmd" arity="2"/>
+ <name name="cmd" arity="1" since=""/>
+ <name name="cmd" arity="2" since="OTP 20.2.3"/>
<fsummary>Execute a command in a shell of the target OS.</fsummary>
<desc>
<p>Executes <c><anno>Command</anno></c> in a command shell of the
@@ -173,8 +173,8 @@ DirOut = os:cmd("dir"), % on Win32 platform</code>
</func>
<func>
- <name name="find_executable" arity="1"/>
- <name name="find_executable" arity="2"/>
+ <name name="find_executable" arity="1" since=""/>
+ <name name="find_executable" arity="2" since=""/>
<fsummary>Absolute filename of a program.</fsummary>
<desc>
<p>These two functions look up an executable program, with the
@@ -190,7 +190,7 @@ DirOut = os:cmd("dir"), % on Win32 platform</code>
</func>
<func>
- <name name="getenv" arity="0"/>
+ <name name="getenv" arity="0" since=""/>
<fsummary>List all environment variables.</fsummary>
<desc>
<p>Returns a list of all environment variables.
@@ -205,7 +205,7 @@ DirOut = os:cmd("dir"), % on Win32 platform</code>
</func>
<func>
- <name name="getenv" arity="1"/>
+ <name name="getenv" arity="1" since=""/>
<fsummary>Get the value of an environment variable.</fsummary>
<desc>
<p>Returns the <c><anno>Value</anno></c> of the environment variable
@@ -220,7 +220,7 @@ DirOut = os:cmd("dir"), % on Win32 platform</code>
</func>
<func>
- <name name="getenv" arity="2"/>
+ <name name="getenv" arity="2" since="OTP 18.0"/>
<fsummary>Get the value of an environment variable.</fsummary>
<desc>
<p>Returns the <c><anno>Value</anno></c> of the environment variable
@@ -235,7 +235,7 @@ DirOut = os:cmd("dir"), % on Win32 platform</code>
</func>
<func>
- <name name="getpid" arity="0"/>
+ <name name="getpid" arity="0" since=""/>
<fsummary>Return the process identifier of the emulator
process.</fsummary>
<desc>
@@ -251,7 +251,7 @@ DirOut = os:cmd("dir"), % on Win32 platform</code>
</func>
<func>
- <name name="putenv" arity="2"/>
+ <name name="putenv" arity="2" since=""/>
<fsummary>Set a new value for an environment variable.</fsummary>
<desc>
<p>Sets a new <c><anno>Value</anno></c> for environment variable
@@ -277,7 +277,7 @@ DirOut = os:cmd("dir"), % on Win32 platform</code>
</func>
<func>
- <name name="set_signal" arity="2"/>
+ <name name="set_signal" arity="2" since="OTP 20.0"/>
<fsummary>Enables or disables handling of OS signals.</fsummary>
<desc>
<p>Enables or disables OS signals.</p>
@@ -304,7 +304,7 @@ DirOut = os:cmd("dir"), % on Win32 platform</code>
</func>
<func>
- <name name="system_time" arity="0"/>
+ <name name="system_time" arity="0" since="OTP 18.0"/>
<fsummary>Current OS system time.</fsummary>
<desc>
<p>Returns the current
@@ -317,7 +317,7 @@ DirOut = os:cmd("dir"), % on Win32 platform</code>
</func>
<func>
- <name name="system_time" arity="1"/>
+ <name name="system_time" arity="1" since="OTP 18.0"/>
<fsummary>Current OS system time.</fsummary>
<desc>
<p>Returns the current
@@ -332,7 +332,7 @@ DirOut = os:cmd("dir"), % on Win32 platform</code>
</func>
<func>
- <name name="timestamp" arity="0"/>
+ <name name="timestamp" arity="0" since=""/>
<fsummary>Current OS system time on the <c>erlang:timestamp/0</c> format.</fsummary>
<type_desc variable="Timestamp">Timestamp = {MegaSecs, Secs, MicroSecs}</type_desc>
<desc>
@@ -373,7 +373,7 @@ calendar:now_to_universal_time(TS),
</func>
<func>
- <name name="perf_counter" arity="0"/>
+ <name name="perf_counter" arity="0" since="OTP 19.0"/>
<fsummary>Returns a performance counter</fsummary>
<desc>
<p>Returns the current performance counter value in <c>perf_counter</c>
@@ -383,7 +383,7 @@ calendar:now_to_universal_time(TS),
</desc>
</func>
<func>
- <name name="perf_counter" arity="1"/>
+ <name name="perf_counter" arity="1" since="OTP 19.0"/>
<fsummary>Returns a performance counter</fsummary>
<desc><p>Returns a performance counter that can be used as a very fast and
high resolution timestamp. This counter is read directly from the hardware or operating
@@ -397,7 +397,7 @@ calendar:now_to_universal_time(TS),
</desc>
</func>
<func>
- <name name="type" arity="0"/>
+ <name name="type" arity="0" since=""/>
<fsummary>Return the OS family and, in some cases, the OS name of the
current OS.</fsummary>
<desc>
@@ -417,7 +417,7 @@ calendar:now_to_universal_time(TS),
</func>
<func>
- <name name="unsetenv" arity="1"/>
+ <name name="unsetenv" arity="1" since="OTP R16B03"/>
<fsummary>Delete an environment variable.</fsummary>
<desc>
<p>Deletes the environment variable <c><anno>VarName</anno></c>.</p>
@@ -429,7 +429,7 @@ calendar:now_to_universal_time(TS),
</func>
<func>
- <name name="version" arity="0"/>
+ <name name="version" arity="0" since=""/>
<fsummary>Return the OS versions.</fsummary>
<desc>
<p>Returns the OS version.
diff --git a/lib/kernel/doc/src/pg2.xml b/lib/kernel/doc/src/pg2.xml
index 0631b317b4..058d711756 100644
--- a/lib/kernel/doc/src/pg2.xml
+++ b/lib/kernel/doc/src/pg2.xml
@@ -32,7 +32,7 @@
<rev>A2</rev>
<file>pg2.xml</file>
</header>
- <module>pg2</module>
+ <module since="">pg2</module>
<modulesummary>Distributed named process groups.</modulesummary>
<description>
<p>This module implements process groups. Each message can be sent
@@ -66,7 +66,7 @@
<funcs>
<func>
- <name name="create" arity="1"/>
+ <name name="create" arity="1" since=""/>
<fsummary>Create a new, empty process group.</fsummary>
<desc>
<p>Creates a new, empty process group. The group is globally
@@ -75,7 +75,7 @@
</func>
<func>
- <name name="delete" arity="1"/>
+ <name name="delete" arity="1" since=""/>
<fsummary>Delete a process group.</fsummary>
<desc>
<p>Deletes a process group.</p>
@@ -83,7 +83,7 @@
</func>
<func>
- <name name="get_closest_pid" arity="1"/>
+ <name name="get_closest_pid" arity="1" since=""/>
<fsummary>Common dispatch function.</fsummary>
<desc>
<p>A useful dispatch function that can be used from
@@ -93,7 +93,7 @@
</func>
<func>
- <name name="get_local_members" arity="1"/>
+ <name name="get_local_members" arity="1" since=""/>
<fsummary>Return all local processes in a group.</fsummary>
<desc>
<p>Returns all processes running on the local node in the
@@ -104,7 +104,7 @@
</func>
<func>
- <name name="get_members" arity="1"/>
+ <name name="get_members" arity="1" since=""/>
<fsummary>Return all processes in a group.</fsummary>
<desc>
<p>Returns all processes in the group <c>Name</c>. This
@@ -114,7 +114,7 @@
</func>
<func>
- <name name="join" arity="2"/>
+ <name name="join" arity="2" since=""/>
<fsummary>Join a process to a group.</fsummary>
<desc>
<p>Joins the process <c>Pid</c> to the group <c>Name</c>.
@@ -124,7 +124,7 @@
</func>
<func>
- <name name="leave" arity="2"/>
+ <name name="leave" arity="2" since=""/>
<fsummary>Make a process leave a group.</fsummary>
<desc>
<p>Makes the process <c>Pid</c> leave the group <c>Name</c>.
@@ -134,8 +134,8 @@
</func>
<func>
- <name name="start" arity="0"/>
- <name name="start_link" arity="0"/>
+ <name name="start" arity="0" since=""/>
+ <name name="start_link" arity="0" since=""/>
<fsummary>Start the <c>pg2</c> server.</fsummary>
<desc>
<p>Starts the <c>pg2</c> server. Normally, the server does not need
@@ -149,7 +149,7 @@
</func>
<func>
- <name name="which_groups" arity="0"/>
+ <name name="which_groups" arity="0" since=""/>
<fsummary>Return a list of all known groups.</fsummary>
<desc>
<p>Returns a list of all known groups.</p>
diff --git a/lib/kernel/doc/src/rpc.xml b/lib/kernel/doc/src/rpc.xml
index fab616e630..c55454506e 100644
--- a/lib/kernel/doc/src/rpc.xml
+++ b/lib/kernel/doc/src/rpc.xml
@@ -28,7 +28,7 @@
<date>1996-09-10</date>
<rev>A</rev>
</header>
- <module>rpc</module>
+ <module since="">rpc</module>
<modulesummary>Remote Procedure Call services.</modulesummary>
<description>
<p>This module contains services similar to Remote
@@ -51,7 +51,7 @@
<funcs>
<func>
- <name name="abcast" arity="2"/>
+ <name name="abcast" arity="2" since=""/>
<fsummary>Broadcast a message asynchronously to a registered process on
all nodes.</fsummary>
<desc>
@@ -61,7 +61,7 @@
</func>
<func>
- <name name="abcast" arity="3"/>
+ <name name="abcast" arity="3" since=""/>
<fsummary>Broadcast a message asynchronously to a registered process on
specific nodes.</fsummary>
<desc>
@@ -72,7 +72,7 @@
</func>
<func>
- <name name="async_call" arity="4"/>
+ <name name="async_call" arity="4" since=""/>
<fsummary>Evaluate a function call on a node, asynchronous
version.</fsummary>
<desc>
@@ -98,7 +98,7 @@
</func>
<func>
- <name name="block_call" arity="4"/>
+ <name name="block_call" arity="4" since=""/>
<fsummary>Evaluate a function call on a node in the RPC server's
context.</fsummary>
<desc>
@@ -115,7 +115,7 @@
</func>
<func>
- <name name="block_call" arity="5"/>
+ <name name="block_call" arity="5" since=""/>
<fsummary>Evaluate a function call on a node in the RPC server's
context.</fsummary>
<desc>
@@ -127,7 +127,7 @@
</func>
<func>
- <name name="call" arity="4"/>
+ <name name="call" arity="4" since=""/>
<fsummary>Evaluate a function call on a node.</fsummary>
<desc>
<p>Evaluates <c>apply(<anno>Module</anno>, <anno>Function</anno>,
@@ -138,7 +138,7 @@
</func>
<func>
- <name name="call" arity="5"/>
+ <name name="call" arity="5" since=""/>
<fsummary>Evaluate a function call on a node.</fsummary>
<desc>
<p>Evaluates <c>apply(<anno>Module</anno>, <anno>Function</anno>,
@@ -158,7 +158,7 @@
</func>
<func>
- <name name="cast" arity="4"/>
+ <name name="cast" arity="4" since=""/>
<fsummary>Run a function on a node ignoring the result.</fsummary>
<desc>
<p>Evaluates <c>apply(<anno>Module</anno>, <anno>Function</anno>,
@@ -171,7 +171,7 @@
</func>
<func>
- <name name="eval_everywhere" arity="3"/>
+ <name name="eval_everywhere" arity="3" since=""/>
<fsummary>Run a function on all nodes, ignoring the result.</fsummary>
<desc>
<p>Equivalent to <c>eval_everywhere([node()|nodes()],
@@ -181,7 +181,7 @@
</func>
<func>
- <name name="eval_everywhere" arity="4"/>
+ <name name="eval_everywhere" arity="4" since=""/>
<fsummary>Run a function on specific nodes, ignoring the
result.</fsummary>
<desc>
@@ -192,7 +192,7 @@
</func>
<func>
- <name name="multi_server_call" arity="2"/>
+ <name name="multi_server_call" arity="2" since=""/>
<fsummary>Interact with the servers on a number of nodes.</fsummary>
<desc>
<p>Equivalent to <c>multi_server_call([node()|nodes()],
@@ -201,7 +201,7 @@
</func>
<func>
- <name name="multi_server_call" arity="3"/>
+ <name name="multi_server_call" arity="3" since=""/>
<fsummary>Interact with the servers on a number of nodes.</fsummary>
<desc>
<p>Can be used when interacting with servers called
@@ -224,7 +224,7 @@
</func>
<func>
- <name name="multicall" arity="3"/>
+ <name name="multicall" arity="3" since=""/>
<fsummary>Evaluate a function call on a number of nodes.</fsummary>
<desc>
<p>Equivalent to <c>multicall([node()|nodes()], <anno>Module</anno>,
@@ -233,7 +233,7 @@
</func>
<func>
- <name name="multicall" arity="4" clause_i="1"/>
+ <name name="multicall" arity="4" clause_i="1" since=""/>
<fsummary>Evaluate a function call on a number of nodes.</fsummary>
<desc>
<p>Equivalent to <c>multicall(<anno>Nodes</anno>, <anno>Module</anno>,
@@ -242,7 +242,7 @@
</func>
<func>
- <name name="multicall" arity="4" clause_i="2"/>
+ <name name="multicall" arity="4" clause_i="2" since=""/>
<fsummary>Evaluate a function call on a number of nodes.</fsummary>
<desc>
<p>Equivalent to <c>multicall([node()|nodes()], <anno>Module</anno>,
@@ -252,7 +252,7 @@
</func>
<func>
- <name name="multicall" arity="5"/>
+ <name name="multicall" arity="5" since=""/>
<fsummary>Evaluate a function call on a number of nodes.</fsummary>
<desc>
<p>In contrast to an RPC, a multicall is an RPC that is sent
@@ -288,7 +288,7 @@
</func>
<func>
- <name name="nb_yield" arity="1"/>
+ <name name="nb_yield" arity="1" since=""/>
<fsummary>Deliver the result of evaluating a function call on a node
(non-blocking).</fsummary>
<desc>
@@ -297,7 +297,7 @@
</func>
<func>
- <name name="nb_yield" arity="2"/>
+ <name name="nb_yield" arity="2" since=""/>
<fsummary>Deliver the result of evaluating a function call on a node
(non-blocking).</fsummary>
<desc>
@@ -315,7 +315,7 @@
</func>
<func>
- <name name="parallel_eval" arity="1"/>
+ <name name="parallel_eval" arity="1" since=""/>
<fsummary>Evaluate many function calls on all nodes in
parallel.</fsummary>
<desc>
@@ -328,7 +328,7 @@
</func>
<func>
- <name name="pinfo" arity="1"/>
+ <name name="pinfo" arity="1" since=""/>
<fsummary>Information about a process.</fsummary>
<desc>
<p>Location transparent version of the BIF
@@ -337,8 +337,8 @@
</func>
<func>
- <name name="pinfo" arity="2" clause_i="1"/>
- <name name="pinfo" arity="2" clause_i="2"/>
+ <name name="pinfo" arity="2" clause_i="1" since=""/>
+ <name name="pinfo" arity="2" clause_i="2" since=""/>
<fsummary>Information about a process.</fsummary>
<desc>
<p>Location transparent version of the BIF
@@ -347,7 +347,7 @@
</func>
<func>
- <name name="pmap" arity="3"/>
+ <name name="pmap" arity="3" since=""/>
<fsummary>Parallel evaluation of mapping a function over a
list.</fsummary>
<desc>
@@ -360,7 +360,7 @@
</func>
<func>
- <name name="sbcast" arity="2"/>
+ <name name="sbcast" arity="2" since=""/>
<fsummary>Broadcast a message synchronously to a registered process on
all nodes.</fsummary>
<desc>
@@ -370,7 +370,7 @@
</func>
<func>
- <name name="sbcast" arity="3"/>
+ <name name="sbcast" arity="3" since=""/>
<fsummary>Broadcast a message synchronously to a registered process on
specific nodes.</fsummary>
<desc>
@@ -391,7 +391,7 @@
</func>
<func>
- <name name="server_call" arity="4"/>
+ <name name="server_call" arity="4" since=""/>
<fsummary>Interact with a server on a node.</fsummary>
<desc>
<p>Can be used when interacting with a server called
@@ -410,7 +410,7 @@
</func>
<func>
- <name name="yield" arity="1"/>
+ <name name="yield" arity="1" since=""/>
<fsummary>Deliver the result of evaluating a function call on a node
(blocking).</fsummary>
<desc>
diff --git a/lib/kernel/doc/src/seq_trace.xml b/lib/kernel/doc/src/seq_trace.xml
index 1a4a74419a..aa29223dd0 100644
--- a/lib/kernel/doc/src/seq_trace.xml
+++ b/lib/kernel/doc/src/seq_trace.xml
@@ -28,7 +28,7 @@
<date>1998-04-16</date>
<rev>A</rev>
</header>
- <module>seq_trace</module>
+ <module since="">seq_trace</module>
<modulesummary>Sequential tracing of messages.</modulesummary>
<description>
<p>Sequential tracing makes it possible to trace all messages
@@ -51,7 +51,7 @@
</datatypes>
<funcs>
<func>
- <name name="set_token" arity="1"/>
+ <name name="set_token" arity="1" since=""/>
<fsummary>Set the trace token</fsummary>
<desc>
<p>Sets the trace token for the calling process to <c><anno>Token</anno></c>.
@@ -71,7 +71,7 @@ seq_trace:set_token(OldToken), % activate the trace token again
</desc>
</func>
<func>
- <name name="set_token" arity="2"/>
+ <name name="set_token" arity="2" since=""/>
<fsummary>Set a component of the trace token</fsummary>
<type name="component"/>
<type name="flag"/>
@@ -158,7 +158,7 @@ seq_trace:set_token(OldToken), % activate the trace token again
</desc>
</func>
<func>
- <name name="get_token" arity="0"/>
+ <name name="get_token" arity="0" since=""/>
<fsummary>Return the value of the trace token</fsummary>
<desc>
<p>Returns the value of the trace token for the calling process.
@@ -169,7 +169,7 @@ seq_trace:set_token(OldToken), % activate the trace token again
</desc>
</func>
<func>
- <name name="get_token" arity="1"/>
+ <name name="get_token" arity="1" since=""/>
<fsummary>Return the value of a trace token component</fsummary>
<type name="component"/>
<type name="flag"/>
@@ -182,7 +182,7 @@ seq_trace:set_token(OldToken), % activate the trace token again
</desc>
</func>
<func>
- <name name="print" arity="1"/>
+ <name name="print" arity="1" since=""/>
<fsummary>Put the Erlang term <c>TraceInfo</c>into the sequential trace output</fsummary>
<desc>
<p>Puts the Erlang term <c><anno>TraceInfo</anno></c> into the sequential
@@ -192,7 +192,7 @@ seq_trace:set_token(OldToken), % activate the trace token again
</desc>
</func>
<func>
- <name name="print" arity="2"/>
+ <name name="print" arity="2" since=""/>
<fsummary>Put the Erlang term <c>TraceInfo</c>into the sequential trace output</fsummary>
<desc>
<p>Same as <c>print/1</c> with the additional condition that
@@ -201,7 +201,7 @@ seq_trace:set_token(OldToken), % activate the trace token again
</desc>
</func>
<func>
- <name name="reset_trace" arity="0"/>
+ <name name="reset_trace" arity="0" since=""/>
<fsummary>Stop all sequential tracing on the local node</fsummary>
<desc>
<p>Sets the trace token to empty for all processes on the
@@ -213,7 +213,7 @@ seq_trace:set_token(OldToken), % activate the trace token again
</desc>
</func>
<func>
- <name name="set_system_tracer" arity="1"/>
+ <name name="set_system_tracer" arity="1" since=""/>
<fsummary>Set the system tracer</fsummary>
<type name="tracer"/>
<desc>
@@ -227,7 +227,7 @@ seq_trace:set_token(OldToken), % activate the trace token again
</desc>
</func>
<func>
- <name name="get_system_tracer" arity="0"/>
+ <name name="get_system_tracer" arity="0" since=""/>
<fsummary>Return the pid() or port() of the current system tracer.</fsummary>
<type name="tracer"/>
<desc>
diff --git a/lib/kernel/doc/src/wrap_log_reader.xml b/lib/kernel/doc/src/wrap_log_reader.xml
index 7fb9c1c023..5f37e7ec5f 100644
--- a/lib/kernel/doc/src/wrap_log_reader.xml
+++ b/lib/kernel/doc/src/wrap_log_reader.xml
@@ -32,7 +32,7 @@
<rev>A</rev>
<file>wrap_log_reader.sgml</file>
</header>
- <module>wrap_log_reader</module>
+ <module since="">wrap_log_reader</module>
<modulesummary>A service to read internally formatted wrap disk logs.
</modulesummary>
<description>
@@ -65,8 +65,8 @@
<funcs>
<func>
- <name name="chunk" arity="1"/>
- <name name="chunk" arity="2"/>
+ <name name="chunk" arity="1" since=""/>
+ <name name="chunk" arity="2" since=""/>
<fsummary>Read a chunk of objects written to a wrap log.</fsummary>
<type name="chunk_ret"/>
<desc>
@@ -105,7 +105,7 @@
</func>
<func>
- <name name="close" arity="1"/>
+ <name name="close" arity="1" since=""/>
<fsummary>Close a log.</fsummary>
<desc>
<p>Closes a log file properly.</p>
@@ -113,8 +113,8 @@
</func>
<func>
- <name name="open" arity="1"/>
- <name name="open" arity="2"/>
+ <name name="open" arity="1" since=""/>
+ <name name="open" arity="2" since=""/>
<fsummary>Open a log file.</fsummary>
<type name="open_ret"/>
<desc>
diff --git a/lib/kernel/src/kernel.appup.src b/lib/kernel/src/kernel.appup.src
index 0c0435e051..ccf0a82ced 100644
--- a/lib/kernel/src/kernel.appup.src
+++ b/lib/kernel/src/kernel.appup.src
@@ -16,15 +16,42 @@
%% limitations under the License.
%%
%% %CopyrightEnd%
+%%
+%% We allow upgrade from, and downgrade to all previous
+%% versions from the following OTP releases:
+%% - OTP 20
+%% - OTP 21
+%%
+%% We also allow upgrade from, and downgrade to all
+%% versions that have branched off from the above
+%% stated previous versions.
+%%
{"%VSN%",
- %% Up from - max one major revision back
- [{<<"5\\.3(\\.[0-9]+)*">>,[restart_new_emulator]}, % OTP-20.0
- {<<"5\\.4(\\.[0-9]+)*">>,[restart_new_emulator]}, % OTP-20.1+
- {<<"6\\.0(\\.[0-9]+)*">>,[restart_new_emulator]}, % OTP-21.0
- {<<"6\\.1(\\.[0-9]+)*">>,[restart_new_emulator]}], % OTP-21.1
- %% Down to - max one major revision back
- [{<<"5\\.3(\\.[0-9]+)*">>,[restart_new_emulator]}, % OTP-20.0
- {<<"5\\.4(\\.[0-9]+)*">>,[restart_new_emulator]}, % OTP-20.1+
- {<<"6\\.0(\\.[0-9]+)*">>,[restart_new_emulator]}, % OTP-21.0
- {<<"6\\.1(\\.[0-9]+)*">>,[restart_new_emulator]}] % OTP-21.1
-}.
+ [{<<"^5\\.3$">>,[restart_new_emulator]},
+ {<<"^5\\.3\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]},
+ {<<"^5\\.3\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]},
+ {<<"^5\\.4$">>,[restart_new_emulator]},
+ {<<"^5\\.4\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]},
+ {<<"^5\\.4\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]},
+ {<<"^5\\.4\\.2(?:\\.[0-9]+)*$">>,[restart_new_emulator]},
+ {<<"^5\\.4\\.3(?:\\.[0-9]+)*$">>,[restart_new_emulator]},
+ {<<"^6\\.0$">>,[restart_new_emulator]},
+ {<<"^6\\.0\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]},
+ {<<"^6\\.0\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]},
+ {<<"^6\\.1$">>,[restart_new_emulator]},
+ {<<"^6\\.1\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]},
+ {<<"^6\\.1\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]}],
+ [{<<"^5\\.3$">>,[restart_new_emulator]},
+ {<<"^5\\.3\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]},
+ {<<"^5\\.3\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]},
+ {<<"^5\\.4$">>,[restart_new_emulator]},
+ {<<"^5\\.4\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]},
+ {<<"^5\\.4\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]},
+ {<<"^5\\.4\\.2(?:\\.[0-9]+)*$">>,[restart_new_emulator]},
+ {<<"^5\\.4\\.3(?:\\.[0-9]+)*$">>,[restart_new_emulator]},
+ {<<"^6\\.0$">>,[restart_new_emulator]},
+ {<<"^6\\.0\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]},
+ {<<"^6\\.0\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]},
+ {<<"^6\\.1$">>,[restart_new_emulator]},
+ {<<"^6\\.1\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]},
+ {<<"^6\\.1\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]}]}.
diff --git a/lib/kernel/src/logger_config.erl b/lib/kernel/src/logger_config.erl
index 6bfe658552..5e9faf332c 100644
--- a/lib/kernel/src/logger_config.erl
+++ b/lib/kernel/src/logger_config.erl
@@ -31,7 +31,9 @@
-include("logger_internal.hrl").
new(Name) ->
- _ = ets:new(Name,[set,protected,named_table,{write_concurrency,true}]),
+ _ = ets:new(Name,[set,protected,named_table,
+ {read_concurrency,true},
+ {write_concurrency,true}]),
ets:whereis(Name).
delete(Tid,Id) ->
diff --git a/lib/kernel/src/logger_disk_log_h.erl b/lib/kernel/src/logger_disk_log_h.erl
index 2a81458ec8..41e0d51a9d 100644
--- a/lib/kernel/src/logger_disk_log_h.erl
+++ b/lib/kernel/src/logger_disk_log_h.erl
@@ -19,59 +19,33 @@
%%
-module(logger_disk_log_h).
--behaviour(gen_server).
-
-include("logger.hrl").
-include("logger_internal.hrl").
-include("logger_h_common.hrl").
%%% API
--export([start_link/3, info/1, filesync/1, reset/1]).
+-export([info/1, filesync/1, reset/1]).
-%% gen_server callbacks
--export([init/1, handle_call/3, handle_cast/2, handle_info/2,
- terminate/2, code_change/3]).
+%% logger_h_common callbacks
+-export([init/2, check_config/4, reset_state/2,
+ filesync/3, write/4, handle_info/3, terminate/3]).
%% logger callbacks
-export([log/2, adding_handler/1, removing_handler/1, changing_config/3,
filter_config/1]).
-%% handler internal
--export([log_handler_info/4]).
-
%%%===================================================================
%%% API
%%%===================================================================
%%%-----------------------------------------------------------------
-%%% Start a disk_log handler process and link to caller.
-%%% This function is called by the kernel supervisor when this
-%%% handler process gets added (as a result of calling add/3).
--spec start_link(Name, Config, HandlerState) -> {ok,Pid} | {error,Reason} when
- Name :: atom(),
- Config :: logger:handler_config(),
- HandlerState :: map(),
- Pid :: pid(),
- Reason :: term().
-
-start_link(Name, Config, HandlerState) ->
- proc_lib:start_link(?MODULE,init,[[Name,Config,HandlerState]]).
-
-%%%-----------------------------------------------------------------
%%%
-spec filesync(Name) -> ok | {error,Reason} when
Name :: atom(),
Reason :: handler_busy | {badarg,term()}.
-filesync(Name) when is_atom(Name) ->
- try
- gen_server:call(?name_to_reg_name(?MODULE,Name),
- disk_log_sync, ?DEFAULT_CALL_TIMEOUT)
- catch
- _:{timeout,_} -> {error,handler_busy}
- end;
filesync(Name) ->
- {error,{badarg,{filesync,[Name]}}}.
+ logger_h_common:filesync(?MODULE,Name).
%%%-----------------------------------------------------------------
%%%
@@ -80,15 +54,8 @@ filesync(Name) ->
Info :: term(),
Reason :: handler_busy | {badarg,term()}.
-info(Name) when is_atom(Name) ->
- try
- gen_server:call(?name_to_reg_name(?MODULE,Name),
- info, ?DEFAULT_CALL_TIMEOUT)
- catch
- _:{timeout,_} -> {error,handler_busy}
- end;
info(Name) ->
- {error,{badarg,{info,[Name]}}}.
+ logger_h_common:info(?MODULE,Name).
%%%-----------------------------------------------------------------
%%%
@@ -96,16 +63,8 @@ info(Name) ->
Name :: atom(),
Reason :: handler_busy | {badarg,term()}.
-reset(Name) when is_atom(Name) ->
- try
- gen_server:call(?name_to_reg_name(?MODULE,Name),
- reset, ?DEFAULT_CALL_TIMEOUT)
- catch
- _:{timeout,_} -> {error,handler_busy}
- end;
reset(Name) ->
- {error,{badarg,{reset,[Name]}}}.
-
+ logger_h_common:reset(?MODULE,Name).
%%%===================================================================
%%% logger callbacks
@@ -113,30 +72,55 @@ reset(Name) ->
%%%-----------------------------------------------------------------
%%% Handler being added
-adding_handler(#{id:=Name}=Config) ->
- case check_config(adding, Config) of
- {ok, #{config:=HConfig}=Config1} ->
- %% create initial handler state by merging defaults with config
- HState = maps:merge(get_init_state(), HConfig),
- case logger_h_common:overload_levels_ok(HState) of
- true ->
- start(Name, Config1, HState);
- false ->
- #{sync_mode_qlen := SMQL,
- drop_mode_qlen := DMQL,
- flush_qlen := FQL} = HState,
- {error,{invalid_levels,{SMQL,DMQL,FQL}}}
- end;
+adding_handler(Config) ->
+ logger_h_common:adding_handler(Config).
+
+%%%-----------------------------------------------------------------
+%%% Updating handler config
+changing_config(SetOrUpdate, OldConfig, NewConfig) ->
+ logger_h_common:changing_config(SetOrUpdate, OldConfig, NewConfig).
+
+%%%-----------------------------------------------------------------
+%%% Handler being removed
+removing_handler(Config) ->
+ logger_h_common:removing_handler(Config).
+
+%%%-----------------------------------------------------------------
+%%% Log a string or report
+-spec log(LogEvent, Config) -> ok when
+ LogEvent :: logger:log_event(),
+ Config :: logger:handler_config().
+
+log(LogEvent, Config) ->
+ logger_h_common:log(LogEvent, Config).
+
+%%%-----------------------------------------------------------------
+%%% Remove internal fields from configuration
+filter_config(Config) ->
+ logger_h_common:filter_config(Config).
+
+%%%===================================================================
+%%% logger_h_common callbacks
+%%%===================================================================
+init(Name, #{file:=File,type:=Type,max_no_bytes:=MNB,max_no_files:=MNF}) ->
+ case open_disk_log(Name, File, Type, MNB, MNF) of
+ ok ->
+ {ok,#{log_opts => #{file => File,
+ type => Type,
+ max_no_bytes => MNB,
+ max_no_files => MNF},
+ prev_log_result => ok,
+ prev_sync_result => ok,
+ prev_disk_log_info => undefined}};
Error ->
Error
end.
-%%%-----------------------------------------------------------------
-%%% Updating handler config
-changing_config(SetOrUpdate,OldConfig=#{config:=OldHConfig},NewConfig) ->
+check_config(Name,set,undefined,HConfig0) ->
+ HConfig=merge_default_logopts(Name,maps:merge(get_default_config(),HConfig0)),
+ check_config(HConfig);
+check_config(_Name,SetOrUpdate,OldHConfig,NewHConfig0) ->
WriteOnce = maps:with([type,file,max_no_files,max_no_bytes],OldHConfig),
- ReadOnly = maps:with([handler_pid,mode_tab],OldHConfig),
- NewHConfig0 = maps:get(config, NewConfig, #{}),
Default =
case SetOrUpdate of
set ->
@@ -146,66 +130,25 @@ changing_config(SetOrUpdate,OldConfig=#{config:=OldHConfig},NewConfig) ->
OldHConfig
end,
- %% Allow (accidentially) included read-only fields - just overwrite them
- NewHConfig = maps:merge(maps:merge(Default,NewHConfig0),ReadOnly),
+ NewHConfig = maps:merge(Default,NewHConfig0),
- %% But fail if write-once fields are changed
+ %% Fail if write-once fields are changed
case maps:with([type,file,max_no_files,max_no_bytes],NewHConfig) of
WriteOnce ->
- changing_config1(maps:get(handler_pid,OldHConfig),
- OldConfig,
- NewConfig#{config=>NewHConfig});
+ check_config(NewHConfig);
Other ->
{Old,New} = logger_server:diff_maps(WriteOnce,Other),
- {error,{illegal_config_change,#{config=>Old},#{config=>New}}}
+ {error,{illegal_config_change,?MODULE,Old,New}}
end.
-changing_config1(HPid, OldConfig, NewConfig) ->
- case check_config(changing, NewConfig) of
- Result = {ok,NewConfig1} ->
- try gen_server:call(HPid, {change_config,OldConfig,NewConfig1},
- ?DEFAULT_CALL_TIMEOUT) of
- ok -> Result;
- Error -> Error
- catch
- _:{timeout,_} -> {error,handler_busy}
- end;
- Error ->
- Error
- end.
-
-check_config(adding, #{id:=Name}=Config) ->
- %% merge handler specific config data
- HConfig1 = maps:get(config, Config, #{}),
- HConfig2 = maps:merge(get_default_config(), HConfig1),
- HConfig3 = merge_default_logopts(Name, HConfig2),
- case check_h_config(maps:to_list(HConfig3)) of
- ok ->
- {ok,Config#{config=>HConfig3}};
- Error ->
- Error
- end;
-check_config(changing, Config) ->
- HConfig = maps:get(config, Config, #{}),
+check_config(HConfig) ->
case check_h_config(maps:to_list(HConfig)) of
- ok -> {ok,Config};
- Error -> Error
+ ok ->
+ {ok,HConfig};
+ {error,{Key,Value}} ->
+ {error,{invalid_config,?MODULE,#{Key=>Value}}}
end.
-merge_default_logopts(Name, HConfig) ->
- Type = maps:get(type, HConfig, wrap),
- {DefaultNoFiles,DefaultNoBytes} =
- case Type of
- halt -> {undefined,infinity};
- _wrap -> {10,1048576}
- end,
- {ok,Dir} = file:get_cwd(),
- Defaults = #{file => filename:join(Dir,Name),
- max_no_files => DefaultNoFiles,
- max_no_bytes => DefaultNoBytes,
- type => Type},
- maps:merge(Defaults, HConfig).
-
check_h_config([{file,File}|Config]) when is_list(File) ->
check_h_config(Config);
check_h_config([{max_no_files,undefined}|Config]) ->
@@ -218,454 +161,59 @@ check_h_config([{max_no_bytes,N}|Config]) when is_integer(N), N>0 ->
check_h_config(Config);
check_h_config([{type,Type}|Config]) when Type==wrap; Type==halt ->
check_h_config(Config);
-check_h_config([Other | Config]) ->
- case logger_h_common:check_common_config(Other) of
- valid ->
- check_h_config(Config);
- invalid ->
- {error,{invalid_config,?MODULE,Other}}
- end;
+check_h_config([Other | _]) ->
+ {error,Other};
check_h_config([]) ->
ok.
-%%%-----------------------------------------------------------------
-%%% Handler being removed
-removing_handler(#{id:=Name}) ->
- stop(Name).
-
-%%%-----------------------------------------------------------------
-%%% Log a string or report
--spec log(LogEvent, Config) -> ok when
- LogEvent :: logger:log_event(),
- Config :: logger:handler_config().
-
-log(LogEvent, Config = #{id := Name,
- config := #{handler_pid := HPid,
- mode_tab := ModeTab}}) ->
- %% if the handler has crashed, we must drop this event
- %% and hope the handler restarts so we can try again
- true = is_process_alive(HPid),
- Bin = logger_h_common:log_to_binary(LogEvent, Config),
- logger_h_common:call_cast_or_drop(Name, HPid, ModeTab, Bin).
+get_default_config() ->
+ #{}.
-%%%-----------------------------------------------------------------
-%%% Remove internal fields from configuration
-filter_config(#{config:=HConfig}=Config) ->
- Config#{config=>maps:without([handler_pid,mode_tab],HConfig)}.
+merge_default_logopts(Name, HConfig) ->
+ Type = maps:get(type, HConfig, wrap),
+ {DefaultNoFiles,DefaultNoBytes} =
+ case Type of
+ halt -> {undefined,infinity};
+ _wrap -> {10,1048576}
+ end,
+ {ok,Dir} = file:get_cwd(),
+ Defaults = #{file => filename:join(Dir,Name),
+ max_no_files => DefaultNoFiles,
+ max_no_bytes => DefaultNoBytes,
+ type => Type},
+ maps:merge(Defaults, HConfig).
-%%%===================================================================
-%%% gen_server callbacks
-%%%===================================================================
+filesync(Name,_Mode,State) ->
+ Result = ?disk_log_sync(Name),
+ maybe_notify_error(Name, filesync, Result, prev_sync_result, State).
-init([Name,
- Config = #{config := HConfig = #{file:=File,
- type:=Type,
- max_no_bytes:=MNB,
- max_no_files:=MNF}},
- State = #{dl_sync_int := DLSyncInt}]) ->
-
- RegName = ?name_to_reg_name(?MODULE,Name),
- register(RegName, self()),
- process_flag(trap_exit, true),
- process_flag(message_queue_data, off_heap),
-
- ?init_test_hooks(),
- ?start_observation(Name),
-
- LogOpts = #{file=>File, type=>Type, max_no_bytes=>MNB, max_no_files=>MNF},
- case open_disk_log(Name, File, Type, MNB, MNF) of
- ok ->
- try ets:new(Name, [public]) of
- ModeTab ->
- ?set_mode(ModeTab, async),
- T0 = ?timestamp(),
- State1 =
- ?merge_with_stats(State#{
- id => Name,
- mode_tab => ModeTab,
- mode => async,
- dl_sync => DLSyncInt,
- log_opts => LogOpts,
- last_qlen => 0,
- last_log_ts => T0,
- burst_win_ts => T0,
- burst_msg_count => 0,
- last_op => sync,
- prev_log_result => ok,
- prev_sync_result => ok,
- prev_disk_log_info => undefined}),
- Config1 =
- Config#{config => HConfig#{handler_pid => self(),
- mode_tab => ModeTab}},
- proc_lib:init_ack({ok,self(),Config1}),
- gen_server:cast(self(), repeated_disk_log_sync),
- case logger_h_common:unset_restart_flag(Name, ?MODULE) of
- true ->
- %% inform about restart
- gen_server:cast(self(), {log_handler_info,
- "Handler ~p restarted",
- [Name]});
- false ->
- %% initial start
- ok
- end,
- gen_server:enter_loop(?MODULE, [], State1)
- catch
- _:Error ->
- unregister(RegName),
- logger_h_common:error_notify({open_disk_log,Name,Error}),
- proc_lib:init_ack(Error)
- end;
- Error ->
- unregister(RegName),
- logger_h_common:error_notify({open_disk_log,Name,Error}),
- proc_lib:init_ack(Error)
- end.
+write(Name, Mode, Bin, State) ->
+ Result = ?disk_log_write(Name, Mode, Bin),
+ maybe_notify_error(Name, log, Result, prev_log_result, State).
-%% This is the synchronous log event.
-handle_call({log, Bin}, _From, State) ->
- {Result,State1} = do_log(Bin, call, State),
- %% Result == ok | dropped
- {reply, Result, State1};
-
-handle_call(disk_log_sync, _From, State = #{id := Name}) ->
- State1 = #{prev_sync_result := Result} = disk_log_sync(Name, State),
- {reply, Result, State1};
-
-handle_call({change_config,_OldConfig,NewConfig}, _From,
- State = #{filesync_repeat_interval := FSyncInt0}) ->
- HConfig = maps:get(config, NewConfig, #{}),
- State1 = #{sync_mode_qlen := SMQL,
- drop_mode_qlen := DMQL,
- flush_qlen := FQL} = maps:merge(State, HConfig),
- case logger_h_common:overload_levels_ok(State1) of
- true ->
- _ =
- case maps:get(filesync_repeat_interval, HConfig, undefined) of
- undefined ->
- ok;
- no_repeat ->
- _ = logger_h_common:cancel_timer(maps:get(rep_sync_tref,
- State,
- undefined));
- FSyncInt0 ->
- ok;
- _FSyncInt1 ->
- _ = logger_h_common:cancel_timer(maps:get(rep_sync_tref,
- State,
- undefined)),
- _ = gen_server:cast(self(), repeated_disk_log_sync)
- end,
- {reply, ok, State1};
- false ->
- {reply, {error,{invalid_levels,{SMQL,DMQL,FQL}}}, State}
- end;
-
-handle_call(info, _From, State) ->
- {reply, State, State};
-
-handle_call(reset, _From, State) ->
- State1 = ?merge_with_stats(State),
- {reply, ok, State1#{last_qlen => 0,
- last_log_ts => ?timestamp(),
- prev_log_result => ok,
- prev_sync_result => ok,
- prev_disk_log_info => undefined}};
-
-handle_call(stop, _From, State) ->
- {stop, {shutdown,stopped}, ok, State}.
-
-
-%% This is the asynchronous log event.
-handle_cast({log, Bin}, State) ->
- {_,State1} = do_log(Bin, cast, State),
- {noreply, State1};
-
-handle_cast({log_handler_info, Format, Args}, State = #{id:=Name}) ->
- log_handler_info(Name, Format, Args, State),
- {noreply, State};
-
-%% If FILESYNC_REPEAT_INTERVAL is set to a millisec value, this
-%% clause gets called repeatedly by the handler. In order to
-%% guarantee that a filesync *always* happens after the last log
-%% event, the repeat operation must be active!
-handle_cast(repeated_disk_log_sync,
- State = #{id := Name,
- filesync_repeat_interval := FSyncInt,
- last_op := LastOp}) ->
- State1 =
- if is_integer(FSyncInt) ->
- %% only do filesync if something has been
- %% written since last time we checked
- NewState = if LastOp == sync ->
- State;
- true ->
- disk_log_sync(Name, State)
- end,
- {ok,TRef} =
- timer:apply_after(FSyncInt, gen_server,cast,
- [self(),repeated_disk_log_sync]),
- NewState#{rep_sync_tref => TRef, last_op => sync};
- true ->
- State
- end,
- {noreply,State1}.
+reset_state(_Name, State) ->
+ State#{prev_log_result => ok,
+ prev_sync_result => ok,
+ prev_disk_log_info => undefined}.
%% The disk log owner must handle status messages from disk_log.
-handle_info({disk_log, _Node, _Log, {wrap,_NoLostItems}}, State) ->
- {noreply, State};
-handle_info({disk_log, _Node, Log, Info = {truncated,_NoLostItems}},
- State = #{id := Name, prev_disk_log_info := PrevInfo}) ->
- error_notify_new(Info, PrevInfo, {disk_log,Name,Log,Info}),
- {noreply, State#{prev_disk_log_info => Info}};
-handle_info({disk_log, _Node, Log, Info = {blocked_log,_Items}},
- State = #{id := Name, prev_disk_log_info := PrevInfo}) ->
- error_notify_new(Info, PrevInfo, {disk_log,Name,Log,Info}),
- {noreply, State#{prev_disk_log_info => Info}};
-handle_info({disk_log, _Node, Log, full},
- State = #{id := Name, prev_disk_log_info := PrevInfo}) ->
- error_notify_new(full, PrevInfo, {disk_log,Name,Log,full}),
- {noreply, State#{prev_disk_log_info => full}};
-handle_info({disk_log, _Node, Log, Info = {error_status,_Status}},
- State = #{id := Name, prev_disk_log_info := PrevInfo}) ->
- error_notify_new(Info, PrevInfo, {disk_log,Name,Log,Info}),
- {noreply, State#{prev_disk_log_info => Info}};
-
-handle_info({'EXIT',_Pid,_Why}, State = #{id := _Name}) ->
- {noreply, State};
-
-handle_info(_, State) ->
- {noreply, State}.
-
-terminate(Reason, State = #{id := Name}) ->
- _ = logger_h_common:cancel_timer(maps:get(rep_sync_tref, State,
- undefined)),
+handle_info(Name, {disk_log, _Node, Log, Info={truncated,_NoLostItems}}, State) ->
+ maybe_notify_status(Name, Log, Info, prev_disk_log_info, State);
+handle_info(Name, {disk_log, _Node, Log, Info = {blocked_log,_Items}}, State) ->
+ maybe_notify_status(Name, Log, Info, prev_disk_log_info, State);
+handle_info(Name, {disk_log, _Node, Log, Info = full}, State) ->
+ maybe_notify_status(Name, Log, Info, prev_disk_log_info, State);
+handle_info(Name, {disk_log, _Node, Log, Info = {error_status,_Status}}, State) ->
+ maybe_notify_status(Name, Log, Info, prev_disk_log_info, State);
+handle_info(_, _, State) ->
+ State.
+
+terminate(Name, _Reason, _State) ->
_ = close_disk_log(Name, normal),
- ok = logger_h_common:stop_or_restart(Name, Reason, State),
- unregister(?name_to_reg_name(?MODULE, Name)),
ok.
-code_change(_OldVsn, State, _Extra) ->
- {ok, State}.
-
%%%-----------------------------------------------------------------
%%% Internal functions
-
-%%%-----------------------------------------------------------------
-%%%
-get_default_config() ->
- #{sync_mode_qlen => ?SYNC_MODE_QLEN,
- drop_mode_qlen => ?DROP_MODE_QLEN,
- flush_qlen => ?FLUSH_QLEN,
- burst_limit_enable => ?BURST_LIMIT_ENABLE,
- burst_limit_max_count => ?BURST_LIMIT_MAX_COUNT,
- burst_limit_window_time => ?BURST_LIMIT_WINDOW_TIME,
- overload_kill_enable => ?OVERLOAD_KILL_ENABLE,
- overload_kill_qlen => ?OVERLOAD_KILL_QLEN,
- overload_kill_mem_size => ?OVERLOAD_KILL_MEM_SIZE,
- overload_kill_restart_after => ?OVERLOAD_KILL_RESTART_AFTER,
- filesync_repeat_interval => ?FILESYNC_REPEAT_INTERVAL}.
-
-get_init_state() ->
- #{dl_sync_int => ?CONTROLLER_SYNC_INTERVAL,
- filesync_ok_qlen => ?FILESYNC_OK_QLEN}.
-
-%%%-----------------------------------------------------------------
-%%% Add a disk_log handler to the logger.
-%%% This starts a dedicated handler process which should always
-%%% exist if the handler is registered with logger (and should not
-%%% exist if the handler is not registered).
-%%%
-%%% Config is the logger:handler_config() map. Handler specific parameters
-%%% should be provided with a sub map associated with a key named
-%%% 'config', e.g:
-%%%
-%%% Config = #{config => #{sync_mode_qlen => 50}
-%%%
-%%% The 'config' sub map will also contain parameters for configuring
-%%% the disk_log:
-%%%
-%%% Config = #{config => #{file => file:filename(),
-%%% max_no_bytes => integer(),
-%%% max_no_files => integer(),
-%%% type => wrap | halt}}.
-%%%
-%%% If type == halt, then max_no_files is ignored.
-%%%
-%%% The disk_log handler process is linked to logger_sup, which is
-%%% part of the kernel application's supervision tree.
-start(Name, Config, HandlerState) ->
- LoggerDLH =
- #{id => Name,
- start => {?MODULE, start_link, [Name,Config,HandlerState]},
- restart => temporary,
- shutdown => 2000,
- type => worker,
- modules => [?MODULE]},
- case supervisor:start_child(logger_sup, LoggerDLH) of
- {ok,Pid,Config1} ->
- ok = logger_handler_watcher:register_handler(Name,Pid),
- {ok,Config1};
- Error ->
- Error
- end.
-
-%%%-----------------------------------------------------------------
-%%% Stop and remove the handler.
-stop(Name) ->
- case whereis(?name_to_reg_name(?MODULE,Name)) of
- undefined ->
- ok;
- Pid ->
- %% We don't want to do supervisor:terminate_child here
- %% since we need to distinguish this explicit stop from a
- %% system termination in order to avoid circular attempts
- %% at removing the handler (implying deadlocks and
- %% timeouts).
- %% And we don't need to do supervisor:delete_child, since
- %% the restart type is temporary, which means that the
- %% child specification is automatically removed from the
- %% supervisor when the process dies.
- _ = gen_server:call(Pid, stop),
- ok
- end.
-
-%%%-----------------------------------------------------------------
-%%% Logging and overload control.
--define(update_dl_sync(C, Interval),
- if C == 0 -> Interval;
- true -> C-1 end).
-
-%% check for overload between every event (and set Mode to async,
-%% sync or drop accordingly), but never flush the whole mailbox
-%% before LogWindowSize events have been handled
-do_log(Bin, CallOrCast, State = #{id:=Name, mode := Mode0}) ->
- T1 = ?timestamp(),
-
- %% check if the handler is getting overloaded, or if it's
- %% recovering from overload (the check must be done for each
- %% event to react quickly to large bursts of events and
- %% to ensure that the handler can never end up in drop mode
- %% with an empty mailbox, which would stop operation)
- {Mode1,QLen,Mem,State1} = logger_h_common:check_load(State),
-
- if (Mode1 == drop) andalso (Mode0 =/= drop) ->
- log_handler_info(Name, "Handler ~p switched to drop mode",
- [Name], State);
- (Mode0 == drop) andalso ((Mode1 == async) orelse (Mode1 == sync)) ->
- log_handler_info(Name, "Handler ~p switched to ~w mode",
- [Name,Mode1], State);
- true ->
- ok
- end,
-
- %% kill the handler if it can't keep up with the load
- logger_h_common:kill_if_choked(Name, QLen, Mem, ?MODULE, State),
-
- if Mode1 == flush ->
- flush(Name, QLen, T1, State1);
- true ->
- write(Name, Mode1, T1, Bin, CallOrCast, State1)
- end.
-
-%% this function is called by do_log/3 after an overload check
-%% has been performed, where QLen > FlushQLen
-flush(Name, _QLen0, T1, State=#{last_log_ts := _T0, mode_tab := ModeTab}) ->
- %% flush messages in the mailbox (a limited number in
- %% order to not cause long delays)
- NewFlushed = logger_h_common:flush_log_events(?FLUSH_MAX_N),
-
- %% write info in log about flushed messages
- log_handler_info(Name, "Handler ~p flushed ~w log events",
- [Name,NewFlushed], State),
-
- %% because of the receive loop when flushing messages, the
- %% handler will be scheduled out often and the mailbox could
- %% grow very large, so we'd better check the queue again here
- {_,_QLen1} = process_info(self(), message_queue_len),
- ?observe(Name,{max_qlen,_QLen1}),
-
- %% Add 1 for the current log event
- ?observe(Name,{flushed,NewFlushed+1}),
-
- State1 = ?update_max_time(?diff_time(T1,_T0),State),
- {dropped,?update_other(flushed,FLUSHED,NewFlushed,
- State1#{mode => ?set_mode(ModeTab,async),
- last_qlen => 0,
- last_log_ts => T1})}.
-
-%% this function is called to write to disk_log
-write(Name, Mode, T1, Bin, _CallOrCast,
- State = #{mode_tab := ModeTab,
- dl_sync := DLSync,
- dl_sync_int := DLSyncInt,
- last_qlen := LastQLen,
- last_log_ts := T0}) ->
- %% check if we need to limit the number of writes
- %% during a burst of log events
- {DoWrite,BurstWinT,BurstMsgCount} = logger_h_common:limit_burst(State),
-
- %% only send a synhrounous event to the disk_log process
- %% every DLSyncInt time, to give the handler time between
- %% writes so it can keep up with incoming messages
- {Status,LastQLen1,State1} =
- if DoWrite, DLSync == 0 ->
- ?observe(Name,{_CallOrCast,1}),
- NewState = disk_log_write(Name, Bin, State),
- {ok, element(2,process_info(self(),message_queue_len)),
- NewState};
- DoWrite ->
- ?observe(Name,{_CallOrCast,1}),
- NewState = disk_log_write(Name, Bin, State),
- {ok, LastQLen, NewState};
- not DoWrite ->
- ?observe(Name,{flushed,1}),
- {dropped, LastQLen, State}
- end,
-
- %% Check if the time since the previous log event is long enough -
- %% and the queue length small enough - to assume the mailbox has
- %% been emptied, and if so, do filesync operation and reset mode to
- %% async. Note that this is the best we can do to detect an idle
- %% handler without setting a timer after each log call/cast. If the
- %% time between two consecutive log events is fast and no new
- %% event comes in after the last one, idle state won't be detected!
- Time = ?diff_time(T1,T0),
- {Mode1,BurstMsgCount1,State2} =
- if (LastQLen1 < ?FILESYNC_OK_QLEN) andalso
- (Time > ?IDLE_DETECT_TIME_USEC) ->
- {?change_mode(ModeTab,Mode,async), 0, disk_log_sync(Name,State1)};
- true ->
- {Mode, BurstMsgCount,State1}
- end,
-
- State3 =
- ?update_calls_or_casts(_CallOrCast,1,State2),
- State4 =
- ?update_max_time(Time,
- State3#{mode => Mode1,
- last_qlen := LastQLen1,
- last_log_ts => T1,
- burst_win_ts => BurstWinT,
- burst_msg_count => BurstMsgCount1,
- dl_sync => ?update_dl_sync(DLSync,DLSyncInt)}),
- {Status,State4}.
-
-
-log_handler_info(Name, Format, Args, State) ->
- Config =
- case logger:get_handler_config(Name) of
- {ok,Conf} -> Conf;
- _ -> #{formatter=>{?DEFAULT_FORMATTER,?DEFAULT_FORMAT_CONFIG}}
- end,
- Meta = #{time=>erlang:system_time(microsecond)},
- Bin = logger_h_common:log_to_binary(#{level => notice,
- msg => {Format,Args},
- meta => Meta}, Config),
- _ = disk_log_write(Name, Bin, State),
- ok.
-
-
open_disk_log(Name, File, Type, MaxNoBytes, MaxNoFiles) ->
case filelib:ensure_dir(File) of
ok ->
@@ -698,43 +246,26 @@ close_disk_log(Name, _) ->
_ = disk_log:lclose(Name),
ok.
-disk_log_write(Name, Bin, State) ->
- case ?disk_log_blog(Name, Bin) of
- ok ->
- State#{prev_log_result => ok, last_op => write};
- LogError ->
- _ = case maps:get(prev_log_result, State) of
- LogError ->
- %% don't report same error twice
- ok;
- _ ->
- LogOpts = maps:get(log_opts, State),
- logger_h_common:error_notify({Name,log,
- LogOpts,
- LogError})
- end,
- State#{prev_log_result => LogError}
- end.
-
-disk_log_sync(Name, State) ->
- case ?disk_log_sync(Name) of
- ok ->
- State#{prev_sync_result => ok, last_op => sync};
- SyncError ->
- _ = case maps:get(prev_sync_result, State) of
- SyncError ->
- %% don't report same error twice
- ok;
- _ ->
- LogOpts = maps:get(log_opts, State),
- logger_h_common:error_notify({Name,filesync,
- LogOpts,
- SyncError})
- end,
- State#{prev_sync_result => SyncError}
- end.
+disk_log_write(Name, sync, Bin) ->
+ disk_log:blog(Name, Bin);
+disk_log_write(Name, async, Bin) ->
+ disk_log:balog(Name, Bin).
+
+%%%-----------------------------------------------------------------
+%%% Print error messages, but don't repeat the same message
+maybe_notify_error(Name, Op, Result, Key, #{log_opts:=LogOpts}=State) ->
+ {Result,error_notify_new({Name, Op, LogOpts, Result}, Result, Key, State)}.
-error_notify_new(Info,Info, _Term) ->
+maybe_notify_status(Name, Log, Info, Key, State) ->
+ error_notify_new({disk_log, Name, Log, Info}, Info, Key, State).
+
+error_notify_new(Term, What, Key, State) ->
+ error_notify_new(What, maps:get(Key,State), Term),
+ State#{Key => What}.
+
+error_notify_new(ok,_Prev,_Term) ->
+ ok;
+error_notify_new(Same,Same,_Term) ->
ok;
-error_notify_new(_Info0,_Info1, Term) ->
+error_notify_new(_New,_Prev,Term) ->
logger_h_common:error_notify(Term).
diff --git a/lib/kernel/src/logger_h_common.erl b/lib/kernel/src/logger_h_common.erl
index 94c640cb92..74a2d158fc 100644
--- a/lib/kernel/src/logger_h_common.erl
+++ b/lib/kernel/src/logger_h_common.erl
@@ -18,26 +18,469 @@
%% %CopyrightEnd%
%%
-module(logger_h_common).
+-behaviour(gen_server).
-include("logger_h_common.hrl").
-include("logger_internal.hrl").
--export([log_to_binary/2,
- check_common_config/1,
- call_cast_or_drop/4,
- check_load/1,
- limit_burst/1,
- kill_if_choked/5,
- flush_log_events/0,
- flush_log_events/1,
- handler_exit/2,
- set_restart_flag/2,
- unset_restart_flag/2,
- cancel_timer/1,
- stop_or_restart/3,
- overload_levels_ok/1,
- error_notify/1,
- info_notify/1]).
+%% API
+-export([start_link/1, info/2, filesync/2, reset/2]).
+
+%% gen_server and proc_lib callbacks
+-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
+ terminate/2, code_change/3]).
+
+%% logger callbacks
+-export([log/2, adding_handler/1, removing_handler/1, changing_config/3,
+ filter_config/1]).
+
+%% Library functions for handlers
+-export([error_notify/1]).
+
+%%%-----------------------------------------------------------------
+-define(CONFIG_KEYS,[sync_mode_qlen,
+ drop_mode_qlen,
+ flush_qlen,
+ burst_limit_enable,
+ burst_limit_max_count,
+ burst_limit_window_time,
+ overload_kill_enable,
+ overload_kill_qlen,
+ overload_kill_mem_size,
+ overload_kill_restart_after,
+ filesync_repeat_interval]).
+-define(READ_ONLY_KEYS,[handler_pid,mode_tab]).
+
+%%%-----------------------------------------------------------------
+%%% API
+
+%% This function is called by the logger_sup supervisor
+start_link(Args) ->
+ proc_lib:start_link(?MODULE,init,[Args]).
+
+filesync(Module, Name) ->
+ call(Module, Name, filesync).
+
+info(Module, Name) ->
+ call(Module, Name, info).
+
+reset(Module, Name) ->
+ call(Module, Name, reset).
+
+%%%-----------------------------------------------------------------
+%%% Handler being added
+adding_handler(#{id:=Name,module:=Module}=Config) ->
+ HConfig0 = maps:get(config, Config, #{}),
+ HandlerConfig0 = maps:without(?CONFIG_KEYS,HConfig0),
+ case Module:check_config(Name,set,undefined,HandlerConfig0) of
+ {ok,HandlerConfig} ->
+ ModifiedCommon = maps:with(?CONFIG_KEYS,HandlerConfig),
+ CommonConfig0 = maps:with(?CONFIG_KEYS,HConfig0),
+ CommonConfig = maps:merge(
+ maps:merge(get_default_config(), CommonConfig0),
+ ModifiedCommon),
+ case check_config(CommonConfig) of
+ ok ->
+ HConfig = maps:merge(CommonConfig,HandlerConfig),
+ start(Config#{config => HConfig});
+ {error,Faulty} ->
+ {error,{invalid_config,Module,Faulty}}
+ end;
+ Error ->
+ Error
+ end.
+
+%%%-----------------------------------------------------------------
+%%% Handler being removed
+removing_handler(#{id:=Name, module:=Module}) ->
+ case whereis(?name_to_reg_name(Module,Name)) of
+ undefined ->
+ ok;
+ Pid ->
+ %% We don't want to do supervisor:terminate_child here
+ %% since we need to distinguish this explicit stop from a
+ %% system termination in order to avoid circular attempts
+ %% at removing the handler (implying deadlocks and
+ %% timeouts).
+ %% And we don't need to do supervisor:delete_child, since
+ %% the restart type is temporary, which means that the
+ %% child specification is automatically removed from the
+ %% supervisor when the process dies.
+ _ = gen_server:call(Pid, stop),
+ ok
+ end.
+
+%%%-----------------------------------------------------------------
+%%% Updating handler config
+changing_config(SetOrUpdate,
+ #{id:=Name,config:=OldHConfig,module:=Module},
+ NewConfig0) ->
+ NewHConfig0 = maps:get(config, NewConfig0, #{}),
+ OldHandlerConfig = maps:without(?CONFIG_KEYS++?READ_ONLY_KEYS,OldHConfig),
+ NewHandlerConfig0 = maps:without(?CONFIG_KEYS++?READ_ONLY_KEYS,NewHConfig0),
+ case Module:check_config(Name, SetOrUpdate,
+ OldHandlerConfig,NewHandlerConfig0) of
+ {ok, NewHandlerConfig} ->
+ ModifiedCommon = maps:with(?CONFIG_KEYS,NewHandlerConfig),
+ NewCommonConfig0 = maps:with(?CONFIG_KEYS,NewHConfig0),
+ CommonDefault =
+ case SetOrUpdate of
+ set ->
+ get_default_config();
+ update ->
+ maps:with(?CONFIG_KEYS,OldHConfig)
+ end,
+ NewCommonConfig = maps:merge(
+ maps:merge(CommonDefault,NewCommonConfig0),
+ ModifiedCommon),
+ case check_config(NewCommonConfig) of
+ ok ->
+ ReadOnly = maps:with(?READ_ONLY_KEYS,OldHConfig),
+ NewHConfig = maps:merge(
+ maps:merge(NewCommonConfig,NewHandlerConfig),
+ ReadOnly),
+ NewConfig = NewConfig0#{config=>NewHConfig},
+ HPid = maps:get(handler_pid,OldHConfig),
+ case call(HPid, {change_config,NewConfig}) of
+ ok -> {ok,NewConfig};
+ Error -> Error
+ end;
+ {error,Faulty} ->
+ {error,{invalid_config,Module,Faulty}}
+ end;
+ Error ->
+ Error
+ end.
+
+%%%-----------------------------------------------------------------
+%%% Log a string or report
+-spec log(LogEvent, Config) -> ok when
+ LogEvent :: logger:log_event(),
+ Config :: logger:handler_config().
+
+log(LogEvent, Config = #{id := Name,
+ config := #{handler_pid := HPid,
+ mode_tab := ModeTab}}) ->
+ %% if the handler has crashed, we must drop this event
+ %% and hope the handler restarts so we can try again
+ true = is_process_alive(HPid),
+ Bin = log_to_binary(LogEvent, Config),
+ call_cast_or_drop(Name, HPid, ModeTab, Bin).
+
+%%%-----------------------------------------------------------------
+%%% Remove internal fields from configuration
+filter_config(#{config:=HConfig}=Config) ->
+ Config#{config=>maps:without(?READ_ONLY_KEYS,HConfig)}.
+
+%%%-----------------------------------------------------------------
+%%% Start the handler process
+%%%
+%%% The process must always exist if the handler is registered with
+%%% logger (and must not exist if the handler is not registered).
+%%%
+%%% The handler process is linked to logger_sup, which is part of the
+%%% kernel application's supervision tree.
+start(#{id := Name} = Config0) ->
+ ChildSpec =
+ #{id => Name,
+ start => {?MODULE, start_link, [Config0]},
+ restart => temporary,
+ shutdown => 2000,
+ type => worker,
+ modules => [?MODULE]},
+ case supervisor:start_child(logger_sup, ChildSpec) of
+ {ok,Pid,Config} ->
+ ok = logger_handler_watcher:register_handler(Name,Pid),
+ {ok,Config};
+ Error ->
+ Error
+ end.
+
+%%%===================================================================
+%%% gen_server callbacks
+%%%===================================================================
+
+init(#{id := Name, module := Module,
+ formatter := Formatter, config := HConfig0} = Config0) ->
+ RegName = ?name_to_reg_name(Module,Name),
+ register(RegName, self()),
+ process_flag(trap_exit, true),
+ process_flag(message_queue_data, off_heap),
+
+ ?init_test_hooks(),
+ ?start_observation(Name),
+
+ case Module:init(Name, HConfig0) of
+ {ok,HState} ->
+ try ets:new(Name, [public]) of
+ ModeTab ->
+ ?set_mode(ModeTab, async),
+ T0 = ?timestamp(),
+ HConfig = HConfig0#{handler_pid => self(),
+ mode_tab => ModeTab},
+ Config = Config0#{config => HConfig},
+ proc_lib:init_ack({ok,self(),Config}),
+ %% Storing common config in state to avoid copying
+ %% (sending) the config data for each log message
+ CommonConfig = maps:with(?CONFIG_KEYS,HConfig),
+ State =
+ ?merge_with_stats(
+ CommonConfig#{id => Name,
+ module => Module,
+ mode_tab => ModeTab,
+ mode => async,
+ ctrl_sync_count =>
+ ?CONTROLLER_SYNC_INTERVAL,
+ last_qlen => 0,
+ last_log_ts => T0,
+ last_op => sync,
+ burst_win_ts => T0,
+ burst_msg_count => 0,
+ formatter => Formatter,
+ handler_state => HState}),
+ State1 = set_repeated_filesync(State),
+ unset_restart_flag(State1),
+ gen_server:enter_loop(?MODULE, [], State1)
+ catch
+ _:Error ->
+ unregister(RegName),
+ error_notify({init_handler,Name,Error}),
+ proc_lib:init_ack(Error)
+ end;
+ Error ->
+ unregister(RegName),
+ error_notify({init_handler,Name,Error}),
+ proc_lib:init_ack(Error)
+ end.
+
+%% This is the synchronous log event.
+handle_call({log, Bin}, _From, State) ->
+ {Result,State1} = do_log(Bin, call, State),
+ %% Result == ok | dropped
+ {reply,Result, State1};
+
+handle_call(filesync, _From, State = #{id := Name,
+ module := Module,
+ handler_state := HandlerState}) ->
+ {Result,HandlerState1} = Module:filesync(Name,sync,HandlerState),
+ {reply, Result, State#{handler_state=>HandlerState1, last_op=>sync}};
+
+handle_call({change_config, #{formatter:=Formatter, config:=NewHConfig}}, _From,
+ State = #{filesync_repeat_interval := FSyncInt0}) ->
+ %% In the future, if handler_state must be updated due to config
+ %% change, then we need to add a callback to Module here.
+ CommonConfig = maps:with(?CONFIG_KEYS,NewHConfig),
+ State1 = maps:merge(State, CommonConfig),
+ State2 =
+ case maps:get(filesync_repeat_interval, NewHConfig) of
+ FSyncInt0 ->
+ State1;
+ _FSyncInt1 ->
+ set_repeated_filesync(cancel_repeated_filesync(State1))
+ end,
+ {reply, ok, State2#{formatter:=Formatter}};
+
+handle_call(info, _From, State) ->
+ {reply, State, State};
+
+handle_call(reset, _From,
+ #{id:=Name,module:=Module,handler_state:=HandlerState}=State) ->
+ State1 = ?merge_with_stats(State),
+ {reply, ok, State1#{last_qlen => 0,
+ last_log_ts => ?timestamp(),
+ handler_state => Module:reset_state(Name,HandlerState)}};
+
+handle_call(stop, _From, State) ->
+ {stop, {shutdown,stopped}, ok, State}.
+
+%% This is the asynchronous log event.
+handle_cast({log, Bin}, State) ->
+ {_,State1} = do_log(Bin, cast, State),
+ {noreply, State1};
+
+%% If FILESYNC_REPEAT_INTERVAL is set to a millisec value, this
+%% clause gets called repeatedly by the handler. In order to
+%% guarantee that a filesync *always* happens after the last log
+%% event, the repeat operation must be active!
+handle_cast(repeated_filesync,State = #{filesync_repeat_interval := no_repeat}) ->
+ %% This clause handles a race condition which may occur when
+ %% config changes filesync_repeat_interval from an integer value
+ %% to no_repeat.
+ {noreply,State};
+handle_cast(repeated_filesync,
+ State = #{id := Name,
+ module := Module,
+ handler_state := HandlerState,
+ last_op := LastOp}) ->
+ State1 =
+ if LastOp == sync ->
+ State;
+ true ->
+ {_,HS} = Module:filesync(Name, async, HandlerState),
+ State#{handler_state => HS, last_op => sync}
+ end,
+ {noreply,set_repeated_filesync(State1)}.
+
+handle_info(Info, #{id := Name, module := Module,
+ handler_state := HandlerState} = State) ->
+ {noreply,State#{handler_state => Module:handle_info(Name,Info,HandlerState)}}.
+
+terminate(Reason, State = #{id := Name,
+ module := Module,
+ handler_state := HandlerState}) ->
+ _ = cancel_repeated_filesync(State),
+ _ = Module:terminate(Name, Reason, HandlerState),
+ ok = stop_or_restart(Name, Reason, State),
+ unregister(?name_to_reg_name(Module, Name)),
+ ok.
+
+code_change(_OldVsn, State, _Extra) ->
+ {ok, State}.
+
+
+%%%-----------------------------------------------------------------
+%%% Internal functions
+call(Module, Name, Op) when is_atom(Name) ->
+ call(?name_to_reg_name(Module,Name), Op);
+call(_, Name, Op) ->
+ {error,{badarg,{Op,[Name]}}}.
+
+call(Server, Msg) ->
+ try
+ gen_server:call(Server, Msg, ?DEFAULT_CALL_TIMEOUT)
+ catch
+ _:{timeout,_} -> {error,handler_busy}
+ end.
+
+%% check for overload between every event (and set Mode to async,
+%% sync or drop accordingly), but never flush the whole mailbox
+%% before LogWindowSize events have been handled
+do_log(Bin, CallOrCast, State = #{id:=Name, mode:=Mode0}) ->
+ T1 = ?timestamp(),
+
+ %% check if the handler is getting overloaded, or if it's
+ %% recovering from overload (the check must be done for each
+ %% event to react quickly to large bursts of events and
+ %% to ensure that the handler can never end up in drop mode
+ %% with an empty mailbox, which would stop operation)
+ {Mode1,QLen,Mem,State1} = check_load(State),
+
+ if (Mode1 == drop) andalso (Mode0 =/= drop) ->
+ log_handler_info(Name, "Handler ~p switched to drop mode",
+ [Name], State);
+ (Mode0 == drop) andalso ((Mode1 == async) orelse (Mode1 == sync)) ->
+ log_handler_info(Name, "Handler ~p switched to ~w mode",
+ [Name,Mode1], State);
+ true ->
+ ok
+ end,
+
+ %% kill the handler if it can't keep up with the load
+ kill_if_choked(Name, QLen, Mem, State),
+
+ if Mode1 == flush ->
+ flush(Name, QLen, T1, State1);
+ true ->
+ write(Name, Mode1, T1, Bin, CallOrCast, State1)
+ end.
+
+%% this clause is called by do_log/3 after an overload check
+%% has been performed, where QLen > FlushQLen
+flush(Name, _QLen0, T1, State=#{last_log_ts := _T0, mode_tab := ModeTab}) ->
+ %% flush messages in the mailbox (a limited number in
+ %% order to not cause long delays)
+ NewFlushed = flush_log_events(?FLUSH_MAX_N),
+
+ %% write info in log about flushed messages
+ log_handler_info(Name, "Handler ~p flushed ~w log events",
+ [Name,NewFlushed], State),
+
+ %% because of the receive loop when flushing messages, the
+ %% handler will be scheduled out often and the mailbox could
+ %% grow very large, so we'd better check the queue again here
+ {_,_QLen1} = process_info(self(), message_queue_len),
+ ?observe(Name,{max_qlen,_QLen1}),
+
+ %% Add 1 for the current log event
+ ?observe(Name,{flushed,NewFlushed+1}),
+
+ State1 = ?update_max_time(?diff_time(T1,_T0),State),
+ State2 = ?update_max_qlen(_QLen1,State1),
+ {dropped,?update_other(flushed,FLUSHED,NewFlushed,
+ State2#{mode => ?set_mode(ModeTab,async),
+ last_qlen => 0,
+ last_log_ts => T1})}.
+
+%% this clause is called to write to file
+write(Name, Mode, T1, Bin, _CallOrCast,
+ State = #{module := Module,
+ handler_state := HandlerState,
+ mode_tab := ModeTab,
+ ctrl_sync_count := CtrlSync,
+ last_qlen := LastQLen,
+ last_log_ts := T0}) ->
+ %% check if we need to limit the number of writes
+ %% during a burst of log events
+ {DoWrite,State1} = limit_burst(State),
+
+ %% only log synhrounously every ?CONTROLLER_SYNC_INTERVAL time, to
+ %% give the handler time between writes so it can keep up with
+ %% incoming messages
+ {Result,LastQLen1,HandlerState1} =
+ if DoWrite, CtrlSync == 0 ->
+ ?observe(Name,{_CallOrCast,1}),
+ {_,HS1} = Module:write(Name, sync, Bin, HandlerState),
+ {ok,element(2, process_info(self(), message_queue_len)),HS1};
+ DoWrite ->
+ ?observe(Name,{_CallOrCast,1}),
+ {_,HS1} = Module:write(Name, async, Bin, HandlerState),
+ {ok,LastQLen,HS1};
+ not DoWrite ->
+ ?observe(Name,{flushed,1}),
+ {dropped,LastQLen,HandlerState}
+ end,
+
+ %% Check if the time since the previous log event is long enough -
+ %% and the queue length small enough - to assume the mailbox has
+ %% been emptied, and if so, do filesync operation and reset mode to
+ %% async. Note that this is the best we can do to detect an idle
+ %% handler without setting a timer after each log call/cast. If the
+ %% time between two consecutive log events is fast and no new
+ %% event comes in after the last one, idle state won't be detected!
+ Time = ?diff_time(T1,T0),
+ State2 =
+ if (LastQLen1 < ?FILESYNC_OK_QLEN) andalso
+ (Time > ?IDLE_DETECT_TIME_USEC) ->
+ {_,HS2} = Module:filesync(Name,async,HandlerState),
+ State1#{mode => ?change_mode(ModeTab, Mode, async),
+ burst_msg_count => 0,
+ handler_state => HS2};
+ true ->
+ State1#{mode => Mode, handler_state => HandlerState1}
+ end,
+ State3 = ?update_calls_or_casts(_CallOrCast,1,State2),
+ State4 = ?update_max_qlen(LastQLen1,State3),
+ State5 =
+ ?update_max_time(Time,
+ State4#{last_qlen := LastQLen1,
+ last_log_ts => T1,
+ last_op => write,
+ ctrl_sync_count =>
+ if CtrlSync==0 -> ?CONTROLLER_SYNC_INTERVAL;
+ true -> CtrlSync-1
+ end}),
+ {Result,State5}.
+
+log_handler_info(Name, Format, Args, #{module:=Module,
+ formatter:=Formatter,
+ handler_state:=HandlerState}) ->
+ Config = #{formatter=>Formatter},
+ Meta = #{time=>erlang:system_time(microsecond)},
+ Bin = log_to_binary(#{level => notice,
+ msg => {Format,Args},
+ meta => Meta}, Config),
+ _ = Module:write(Name, async, Bin, HandlerState),
+ ok.
%%%-----------------------------------------------------------------
%%% Convert log data on any form to binary
@@ -94,46 +537,65 @@ string_to_binary(String) ->
throw(Error)
end.
-
%%%-----------------------------------------------------------------
%%% Check that the configuration term is valid
-check_common_config({mode_tab,_Tid}) ->
- valid;
-check_common_config({handler_pid,Pid}) when is_pid(Pid) ->
- valid;
-
-check_common_config({sync_mode_qlen,N}) when is_integer(N) ->
- valid;
-check_common_config({drop_mode_qlen,N}) when is_integer(N) ->
- valid;
-check_common_config({flush_qlen,N}) when is_integer(N) ->
- valid;
-
-check_common_config({burst_limit_enable,Bool}) when Bool == true;
- Bool == false ->
- valid;
-check_common_config({burst_limit_max_count,N}) when is_integer(N) ->
- valid;
-check_common_config({burst_limit_window_time,N}) when is_integer(N) ->
- valid;
-
-check_common_config({overload_kill_enable,Bool}) when Bool == true;
- Bool == false ->
- valid;
-check_common_config({overload_kill_qlen,N}) when is_integer(N) ->
- valid;
-check_common_config({overload_kill_mem_size,N}) when is_integer(N) ->
- valid;
-check_common_config({overload_kill_restart_after,NorA}) when is_integer(NorA);
- NorA == infinity ->
- valid;
-
-check_common_config({filesync_repeat_interval,NorA}) when is_integer(NorA);
- NorA == no_repeat ->
- valid;
-check_common_config(_) ->
- invalid.
+check_config(Config) when is_map(Config) ->
+ case check_common_config(maps:to_list(Config)) of
+ ok ->
+ case overload_levels_ok(Config) of
+ true ->
+ ok;
+ false ->
+ Faulty = maps:with([sync_mode_qlen,
+ drop_mode_qlen,
+ flush_qlen],Config),
+ {error,{invalid_levels,Faulty}}
+ end;
+ Error ->
+ Error
+ end.
+
+check_common_config([{sync_mode_qlen,N}|Config]) when is_integer(N) ->
+ check_common_config(Config);
+check_common_config([{drop_mode_qlen,N}|Config]) when is_integer(N) ->
+ check_common_config(Config);
+check_common_config([{flush_qlen,N}|Config]) when is_integer(N) ->
+ check_common_config(Config);
+check_common_config([{burst_limit_enable,Bool}|Config]) when is_boolean(Bool) ->
+ check_common_config(Config);
+check_common_config([{burst_limit_max_count,N}|Config]) when is_integer(N) ->
+ check_common_config(Config);
+check_common_config([{burst_limit_window_time,N}|Config]) when is_integer(N) ->
+ check_common_config(Config);
+check_common_config([{overload_kill_enable,Bool}|Config]) when is_boolean(Bool) ->
+ check_common_config(Config);
+check_common_config([{overload_kill_qlen,N}|Config]) when is_integer(N) ->
+ check_common_config(Config);
+check_common_config([{overload_kill_mem_size,N}|Config]) when is_integer(N) ->
+ check_common_config(Config);
+check_common_config([{overload_kill_restart_after,NorA}|Config])
+ when is_integer(NorA); NorA == infinity ->
+ check_common_config(Config);
+check_common_config([{filesync_repeat_interval,NorA}|Config])
+ when is_integer(NorA); NorA == no_repeat ->
+ check_common_config(Config);
+check_common_config([{Key,Value}|_]) ->
+ {error,#{Key=>Value}};
+check_common_config([]) ->
+ ok.
+get_default_config() ->
+ #{sync_mode_qlen => ?SYNC_MODE_QLEN,
+ drop_mode_qlen => ?DROP_MODE_QLEN,
+ flush_qlen => ?FLUSH_QLEN,
+ burst_limit_enable => ?BURST_LIMIT_ENABLE,
+ burst_limit_max_count => ?BURST_LIMIT_MAX_COUNT,
+ burst_limit_window_time => ?BURST_LIMIT_WINDOW_TIME,
+ overload_kill_enable => ?OVERLOAD_KILL_ENABLE,
+ overload_kill_qlen => ?OVERLOAD_KILL_QLEN,
+ overload_kill_mem_size => ?OVERLOAD_KILL_MEM_SIZE,
+ overload_kill_restart_after => ?OVERLOAD_KILL_RESTART_AFTER,
+ filesync_repeat_interval => ?FILESYNC_REPEAT_INTERVAL}.
%%%-----------------------------------------------------------------
%%% Overload Protection
@@ -146,15 +608,13 @@ call_cast_or_drop(_Name, HandlerPid, ModeTab, Bin) ->
async ->
gen_server:cast(HandlerPid, {log,Bin});
sync ->
- try gen_server:call(HandlerPid, {log,Bin}, ?DEFAULT_CALL_TIMEOUT) of
- %% if return value from call == dropped, the
- %% message has been flushed by handler and should
- %% therefore not be counted as dropped in stats
- ok -> ok;
- dropped -> ok
- catch
- _:{timeout,_} ->
- ?observe(_Name,{dropped,1})
+ case call(HandlerPid, {log,Bin}) of
+ ok ->
+ ok;
+ _Other ->
+ %% dropped or {error,handler_busy}
+ ?observe(_Name,{dropped,1}),
+ ok
end;
drop ->
?observe(_Name,{dropped,1})
@@ -165,10 +625,8 @@ call_cast_or_drop(_Name, HandlerPid, ModeTab, Bin) ->
end,
ok.
-handler_exit(_Name, Reason) ->
- exit(Reason).
-
-set_restart_flag(Name, Module) ->
+set_restart_flag(#{id := Name, module := Module} = State) ->
+ log_handler_info(Name, "Handler ~p overloaded and stopping", [Name], State),
Flag = list_to_atom(lists:concat([Module,"_",Name,"_restarting"])),
spawn(fun() ->
register(Flag, self()),
@@ -176,14 +634,14 @@ set_restart_flag(Name, Module) ->
end),
ok.
-unset_restart_flag(Name, Module) ->
+unset_restart_flag(#{id := Name, module := Module} = State) ->
Flag = list_to_atom(lists:concat([Module,"_",Name,"_restarting"])),
case whereis(Flag) of
undefined ->
- false;
+ ok;
Pid ->
exit(Pid, kill),
- true
+ log_handler_info(Name, "Handler ~p restarted", [Name], State)
end.
check_load(State = #{id:=_Name, mode_tab := ModeTab, mode := Mode,
@@ -221,46 +679,41 @@ check_load(State = #{id:=_Name, mode_tab := ModeTab, mode := Mode,
?update_other(flushes,FLUSHES,_NewFlushes,
State1#{last_qlen => QLen})}.
-limit_burst(#{burst_limit_enable := false}) ->
- {true,0,0};
+limit_burst(#{burst_limit_enable := false}=State) ->
+ {true,State};
limit_burst(#{burst_win_ts := BurstWinT0,
burst_msg_count := BurstMsgCount,
burst_limit_window_time := BurstLimitWinTime,
- burst_limit_max_count := BurstLimitMaxCnt}) ->
+ burst_limit_max_count := BurstLimitMaxCnt} = State) ->
if (BurstMsgCount >= BurstLimitMaxCnt) ->
%% the limit for allowed messages has been reached
BurstWinT1 = ?timestamp(),
case ?diff_time(BurstWinT1,BurstWinT0) of
BurstCheckTime when BurstCheckTime < (BurstLimitWinTime*1000) ->
%% we're still within the burst time frame
- {false,BurstWinT0,BurstMsgCount};
+ {false,?update_other(burst_drops,BURSTS,1,State)};
_BurstCheckTime ->
%% burst time frame passed, reset counters
- {true,BurstWinT1,0}
+ {true,State#{burst_win_ts => BurstWinT1,
+ burst_msg_count => 0}}
end;
true ->
%% the limit for allowed messages not yet reached
- {true,BurstWinT0,BurstMsgCount+1}
+ {true,State#{burst_win_ts => BurstWinT0,
+ burst_msg_count => BurstMsgCount+1}}
end.
-kill_if_choked(Name, QLen, Mem, HandlerMod,
- State = #{overload_kill_enable := KillIfOL,
- overload_kill_qlen := OLKillQLen,
- overload_kill_mem_size := OLKillMem}) ->
+kill_if_choked(Name, QLen, Mem, State = #{overload_kill_enable := KillIfOL,
+ overload_kill_qlen := OLKillQLen,
+ overload_kill_mem_size := OLKillMem}) ->
if KillIfOL andalso
((QLen > OLKillQLen) orelse (Mem > OLKillMem)) ->
- HandlerMod:log_handler_info(Name,
- "Handler ~p overloaded and stopping",
- [Name], State),
- set_restart_flag(Name, HandlerMod),
- handler_exit(Name, {shutdown,{overloaded,Name,QLen,Mem}});
+ set_restart_flag(State),
+ exit({shutdown,{overloaded,Name,QLen,Mem}});
true ->
ok
end.
-flush_log_events() ->
- flush_log_events(-1).
-
flush_log_events(Limit) ->
process_flag(priority, high),
Flushed = flush_log_events(0, Limit),
@@ -283,16 +736,29 @@ flush_log_events(N, Limit) ->
0 -> N
end.
-cancel_timer(TRef) when is_atom(TRef) -> ok;
-cancel_timer(TRef) -> timer:cancel(TRef).
+set_repeated_filesync(#{filesync_repeat_interval:=FSyncInt} = State)
+ when is_integer(FSyncInt) ->
+ {ok,TRef} = timer:apply_after(FSyncInt, gen_server, cast,
+ [self(),repeated_filesync]),
+ State#{rep_sync_tref=>TRef};
+set_repeated_filesync(State) ->
+ State.
+cancel_repeated_filesync(State) ->
+ case maps:take(rep_sync_tref,State) of
+ {TRef,State1} ->
+ _ = timer:cancel(TRef),
+ State1;
+ error ->
+ State
+ end.
stop_or_restart(Name, {shutdown,Reason={overloaded,_Name,_QLen,_Mem}},
#{overload_kill_restart_after := RestartAfter}) ->
%% If we're terminating because of an overload situation (see
- %% logger_h_common:kill_if_choked/4), we need to remove the handler
- %% and set a restart timer. A separate process must perform this
- %% in order to avoid deadlock.
+ %% kill_if_choked/4), we need to remove the handler and set a
+ %% restart timer. A separate process must perform this in order to
+ %% avoid deadlock.
HandlerPid = self(),
ConfigResult = logger:get_handler_config(Name),
RemoveAndRestart =
@@ -334,6 +800,3 @@ overload_levels_ok(HandlerConfig) ->
error_notify(Term) ->
?internal_log(error, Term).
-
-info_notify(Term) ->
- ?internal_log(info, Term).
diff --git a/lib/kernel/src/logger_h_common.hrl b/lib/kernel/src/logger_h_common.hrl
index e0a7b6e3ca..261b0a6246 100644
--- a/lib/kernel/src/logger_h_common.hrl
+++ b/lib/kernel/src/logger_h_common.hrl
@@ -137,7 +137,7 @@
ets:insert(?TEST_HOOKS_TAB, {internal_log,{logger,internal_log}}),
ets:insert(?TEST_HOOKS_TAB, {file_write,ok}),
ets:insert(?TEST_HOOKS_TAB, {file_datasync,ok}),
- ets:insert(?TEST_HOOKS_TAB, {disk_log_blog,ok}),
+ ets:insert(?TEST_HOOKS_TAB, {disk_log_write,ok}),
ets:insert(?TEST_HOOKS_TAB, {disk_log_sync,ok})).
-define(set_internal_log(MOD_FUNC),
@@ -150,7 +150,7 @@
ets:insert(?TEST_HOOKS_TAB, {internal_log,{logger,internal_log}}),
ets:insert(?TEST_HOOKS_TAB, {file_write,ok}),
ets:insert(?TEST_HOOKS_TAB, {file_datasync,ok}),
- ets:insert(?TEST_HOOKS_TAB, {disk_log_blog,ok}),
+ ets:insert(?TEST_HOOKS_TAB, {disk_log_write,ok}),
ets:insert(?TEST_HOOKS_TAB, {disk_log_sync,ok})).
-define(internal_log(TYPE, TERM),
@@ -171,11 +171,11 @@
[{_,ERROR}] -> ERROR
catch _:_ -> file:datasync(DEVICE) end).
- -define(disk_log_blog(LOG, DATA),
- try ets:lookup(?TEST_HOOKS_TAB, disk_log_blog) of
- [{_,ok}] -> disk_log:blog(LOG, DATA);
+ -define(disk_log_write(LOG, MODE, DATA),
+ try ets:lookup(?TEST_HOOKS_TAB, disk_log_write) of
+ [{_,ok}] -> disk_log_write(LOG, MODE, DATA);
[{_,ERROR}] -> ERROR
- catch _:_ -> disk_log:blog(LOG, DATA) end).
+ catch _:_ -> disk_log_write(LOG, MODE, DATA) end).
-define(disk_log_sync(LOG),
try ets:lookup(?TEST_HOOKS_TAB, disk_log_sync) of
@@ -194,7 +194,7 @@
-define(internal_log(TYPE, TERM), logger:internal_log(TYPE, TERM)).
-define(file_write(DEVICE, DATA), file:write(DEVICE, DATA)).
-define(file_datasync(DEVICE), file:datasync(DEVICE)).
- -define(disk_log_blog(LOG, DATA), disk_log:blog(LOG, DATA)).
+ -define(disk_log_write(LOG, MODE, DATA), disk_log_write(LOG, MODE, DATA)).
-define(disk_log_sync(LOG), disk_log:sync(LOG)).
-define(DEFAULT_CALL_TIMEOUT, 10000).
-endif.
@@ -210,7 +210,7 @@
-ifdef(SAVE_STATS).
-define(merge_with_stats(STATE),
STATE#{flushes => 0, flushed => 0, drops => 0,
- casts => 0, calls => 0,
+ burst_drops => 0, casts => 0, calls => 0,
max_qlen => 0, max_time => 0}).
-define(update_max_qlen(QLEN, STATE),
diff --git a/lib/kernel/src/logger_simple_h.erl b/lib/kernel/src/logger_simple_h.erl
index 8b51dd8569..fe181722f3 100644
--- a/lib/kernel/src/logger_simple_h.erl
+++ b/lib/kernel/src/logger_simple_h.erl
@@ -50,7 +50,6 @@ removing_handler(#{id:=simple}) ->
ok;
Pid ->
Ref = erlang:monitor(process,Pid),
- unlink(Pid),
Pid ! stop,
receive {'DOWN',Ref,process,Pid,_} ->
ok
@@ -99,7 +98,11 @@ loop(Buffer) ->
replay_buffer(Buffer);
_ ->
ok
- end;
+ end,
+ %% Before stopping, we unlink the logger process to avoid
+ %% an unexpected EXIT message
+ unlink(whereis(logger)),
+ ok;
{log,#{msg:=_,meta:=#{time:=_}}=Log} ->
do_log(Log),
loop(update_buffer(Buffer,Log));
diff --git a/lib/kernel/src/logger_std_h.erl b/lib/kernel/src/logger_std_h.erl
index 42e0f5caf4..63d1dbaba2 100644
--- a/lib/kernel/src/logger_std_h.erl
+++ b/lib/kernel/src/logger_std_h.erl
@@ -19,8 +19,6 @@
%%
-module(logger_std_h).
--behaviour(gen_server).
-
-include("logger.hrl").
-include("logger_internal.hrl").
-include("logger_h_common.hrl").
@@ -28,52 +26,28 @@
-include_lib("kernel/include/file.hrl").
%% API
--export([start_link/3, info/1, filesync/1, reset/1]).
+-export([info/1, filesync/1, reset/1]).
-%% gen_server and proc_lib callbacks
--export([init/1, handle_call/3, handle_cast/2, handle_info/2,
- terminate/2, code_change/3]).
+%% logger_h_common callbacks
+-export([init/2, check_config/4, reset_state/2,
+ filesync/3, write/4, handle_info/3, terminate/3]).
%% logger callbacks
-export([log/2, adding_handler/1, removing_handler/1, changing_config/3,
filter_config/1]).
-%% handler internal
--export([log_handler_info/4]).
-
%%%===================================================================
%%% API
%%%===================================================================
%%%-----------------------------------------------------------------
-%%% Start a standard handler process and link to caller.
-%%% This function is called by the kernel supervisor when this
-%%% handler process gets added
--spec start_link(Name, Config, HandlerState) -> {ok,Pid} | {error,Reason} when
- Name :: atom(),
- Config :: logger:handler_config(),
- HandlerState :: map(),
- Pid :: pid(),
- Reason :: term().
-
-start_link(Name, Config, HandlerState) ->
- proc_lib:start_link(?MODULE,init,[[Name,Config,HandlerState]]).
-
-%%%-----------------------------------------------------------------
%%%
-spec filesync(Name) -> ok | {error,Reason} when
Name :: atom(),
Reason :: handler_busy | {badarg,term()}.
-filesync(Name) when is_atom(Name) ->
- try
- gen_server:call(?name_to_reg_name(?MODULE,Name),
- filesync, ?DEFAULT_CALL_TIMEOUT)
- catch
- _:{timeout,_} -> {error,handler_busy}
- end;
filesync(Name) ->
- {error,{badarg,{filesync,[Name]}}}.
+ logger_h_common:filesync(?MODULE,Name).
%%%-----------------------------------------------------------------
%%%
@@ -82,15 +56,8 @@ filesync(Name) ->
Info :: term(),
Reason :: handler_busy | {badarg,term()}.
-info(Name) when is_atom(Name) ->
- try
- gen_server:call(?name_to_reg_name(?MODULE,Name),
- info, ?DEFAULT_CALL_TIMEOUT)
- catch
- _:{timeout,_} -> {error,handler_busy}
- end;
info(Name) ->
- {error,{badarg,{info,[Name]}}}.
+ logger_h_common:info(?MODULE,Name).
%%%-----------------------------------------------------------------
%%%
@@ -98,47 +65,75 @@ info(Name) ->
Name :: atom(),
Reason :: handler_busy | {badarg,term()}.
-reset(Name) when is_atom(Name) ->
- try
- gen_server:call(?name_to_reg_name(?MODULE,Name),
- reset, ?DEFAULT_CALL_TIMEOUT)
- catch
- _:{timeout,_} -> {error,handler_busy}
- end;
reset(Name) ->
- {error,{badarg,{reset,[Name]}}}.
-
+ logger_h_common:reset(?MODULE,Name).
%%%===================================================================
-%%% logger callbacks
+%%% logger callbacks - just forward to logger_h_common
%%%===================================================================
%%%-----------------------------------------------------------------
%%% Handler being added
-adding_handler(#{id:=Name}=Config) ->
- case check_config(adding, Config) of
- {ok, #{config:=HConfig}=Config1} ->
- %% create initial handler state by merging defaults with config
- HState = maps:merge(get_init_state(), HConfig),
- case logger_h_common:overload_levels_ok(HState) of
- true ->
- start(Name, Config1, HState);
- false ->
- #{sync_mode_qlen := SMQL,
- drop_mode_qlen := DMQL,
- flush_qlen := FQL} = HState,
- {error,{invalid_levels,{SMQL,DMQL,FQL}}}
- end;
+-spec adding_handler(Config) -> {ok,Config} | {error,Reason} when
+ Config :: logger:handler_config(),
+ Reason :: term().
+
+adding_handler(Config) ->
+ logger_h_common:adding_handler(Config).
+
+%%%-----------------------------------------------------------------
+%%% Updating handler config
+-spec changing_config(SetOrUpdate, OldConfig, NewConfig) ->
+ {ok,Config} | {error,Reason} when
+ SetOrUpdate :: set | update,
+ OldConfig :: logger:handler_config(),
+ NewConfig :: logger:handler_config(),
+ Config :: logger:handler_config(),
+ Reason :: term().
+
+changing_config(SetOrUpdate, OldConfig, NewConfig) ->
+ logger_h_common:changing_config(SetOrUpdate, OldConfig, NewConfig).
+
+%%%-----------------------------------------------------------------
+%%% Handler being removed
+-spec removing_handler(Config) -> ok when
+ Config :: logger:handler_config().
+
+removing_handler(Config) ->
+ logger_h_common:removing_handler(Config).
+
+%%%-----------------------------------------------------------------
+%%% Log a string or report
+-spec log(LogEvent, Config) -> ok when
+ LogEvent :: logger:log_event(),
+ Config :: logger:handler_config().
+
+log(LogEvent, Config) ->
+ logger_h_common:log(LogEvent, Config).
+
+%%%-----------------------------------------------------------------
+%%% Remove internal fields from configuration
+-spec filter_config(Config) -> Config when
+ Config :: logger:handler_config().
+
+filter_config(Config) ->
+ logger_h_common:filter_config(Config).
+
+%%%===================================================================
+%%% logger_h_common callbacks
+%%%===================================================================
+init(Name, #{type := Type}) ->
+ case open_log_file(Name, Type) of
+ {ok,FileCtrlPid} ->
+ {ok,#{type=>Type,file_ctrl_pid=>FileCtrlPid}};
Error ->
Error
end.
-%%%-----------------------------------------------------------------
-%%% Updating handler config
-changing_config(SetOrUpdate,OldConfig=#{config:=OldHConfig},NewConfig) ->
+check_config(_Name,set,undefined,NewHConfig) ->
+ check_config(maps:merge(get_default_config(),NewHConfig));
+check_config(_Name,SetOrUpdate,OldHConfig,NewHConfig0) ->
WriteOnce = maps:with([type],OldHConfig),
- ReadOnly = maps:with([handler_pid,mode_tab],OldHConfig),
- NewHConfig0 = maps:get(config, NewConfig, #{}),
Default =
case SetOrUpdate of
set ->
@@ -148,48 +143,24 @@ changing_config(SetOrUpdate,OldConfig=#{config:=OldHConfig},NewConfig) ->
OldHConfig
end,
- %% Allow (accidentially) included read-only fields - just overwrite them
- NewHConfig = maps:merge(maps:merge(Default, NewHConfig0),ReadOnly),
+ NewHConfig = maps:merge(Default, NewHConfig0),
- %% But fail if write-once fields are changed
+ %% Fail if write-once fields are changed
case maps:with([type],NewHConfig) of
WriteOnce ->
- changing_config1(maps:get(handler_pid,OldHConfig),
- OldConfig,
- NewConfig#{config=>NewHConfig});
+ check_config(NewHConfig);
Other ->
- {error,{illegal_config_change,#{config=>WriteOnce},#{config=>Other}}}
+ {error,{illegal_config_change,?MODULE,WriteOnce,Other}}
end.
-changing_config1(HPid, OldConfig, NewConfig) ->
- case check_config(changing, NewConfig) of
- Result = {ok,NewConfig1} ->
- try gen_server:call(HPid, {change_config,OldConfig,NewConfig1},
- ?DEFAULT_CALL_TIMEOUT) of
- ok -> Result;
- HError -> HError
- catch
- _:{timeout,_} -> {error,handler_busy}
- end;
- Error ->
- Error
- end.
-
-check_config(adding, Config) ->
- %% Merge in defaults on handler level
- HConfig0 = maps:get(config, Config, #{}),
- HConfig = maps:merge(get_default_config(),HConfig0),
+check_config(#{type:=Type}=HConfig) ->
case check_h_config(maps:to_list(HConfig)) of
+ ok when is_atom(Type) ->
+ {ok,HConfig#{filesync_repeat_interval=>no_repeat}};
ok ->
- {ok,Config#{config=>HConfig}};
- Error ->
- Error
- end;
-check_config(changing, Config) ->
- HConfig = maps:get(config, Config, #{}),
- case check_h_config(maps:to_list(HConfig)) of
- ok -> {ok,Config};
- Error -> Error
+ {ok,HConfig};
+ {error,{Key,Value}} ->
+ {error,{invalid_config,?MODULE,#{Key=>Value}}}
end.
check_h_config([{type,Type} | Config]) when Type == standard_io;
@@ -200,219 +171,40 @@ check_h_config([{type,{file,File}} | Config]) when is_list(File) ->
check_h_config([{type,{file,File,Modes}} | Config]) when is_list(File),
is_list(Modes) ->
check_h_config(Config);
-check_h_config([Other | Config]) ->
- case logger_h_common:check_common_config(Other) of
- valid ->
- check_h_config(Config);
- invalid ->
- {error,{invalid_config,?MODULE,Other}}
- end;
+check_h_config([Other | _]) ->
+ {error,Other};
check_h_config([]) ->
ok.
-
-%%%-----------------------------------------------------------------
-%%% Handler being removed
-removing_handler(#{id:=Name}) ->
- stop(Name).
-
-%%%-----------------------------------------------------------------
-%%% Log a string or report
--spec log(LogEvent, Config) -> ok when
- LogEvent :: logger:log_event(),
- Config :: logger:handler_config().
-
-log(LogEvent, Config = #{id := Name,
- config := #{handler_pid := HPid,
- mode_tab := ModeTab}}) ->
- %% if the handler has crashed, we must drop this event
- %% and hope the handler restarts so we can try again
- true = is_process_alive(HPid),
- Bin = logger_h_common:log_to_binary(LogEvent, Config),
- logger_h_common:call_cast_or_drop(Name, HPid, ModeTab, Bin).
-
-%%%-----------------------------------------------------------------
-%%% Remove internal fields from configuration
-filter_config(#{config:=HConfig}=Config) ->
- Config#{config=>maps:without([handler_pid,mode_tab],HConfig)}.
-
-%%%===================================================================
-%%% gen_server callbacks
-%%%===================================================================
-
-init([Name, Config = #{config := HConfig},
- State0 = #{type := Type, file_ctrl_sync_int := FileCtrlSyncInt}]) ->
- RegName = ?name_to_reg_name(?MODULE,Name),
- register(RegName, self()),
- process_flag(trap_exit, true),
- process_flag(message_queue_data, off_heap),
-
- ?init_test_hooks(),
- ?start_observation(Name),
-
- case do_init(Name, Type) of
- {ok,InitState} ->
- try ets:new(Name, [public]) of
- ModeTab ->
- ?set_mode(ModeTab, async),
- State = maps:merge(State0, InitState),
- T0 = ?timestamp(),
- State1 =
- ?merge_with_stats(State#{
- mode_tab => ModeTab,
- mode => async,
- file_ctrl_sync => FileCtrlSyncInt,
- last_qlen => 0,
- last_log_ts => T0,
- last_op => sync,
- burst_win_ts => T0,
- burst_msg_count => 0}),
- Config1 =
- Config#{config => HConfig#{handler_pid => self(),
- mode_tab => ModeTab}},
- proc_lib:init_ack({ok,self(),Config1}),
- gen_server:cast(self(), repeated_filesync),
- gen_server:enter_loop(?MODULE, [], State1)
- catch
- _:Error ->
- unregister(RegName),
- logger_h_common:error_notify({init_handler,Name,Error}),
- proc_lib:init_ack(Error)
- end;
- Error ->
- unregister(RegName),
- logger_h_common:error_notify({init_handler,Name,Error}),
- proc_lib:init_ack(Error)
- end.
-
-do_init(Name, Type) ->
- case open_log_file(Name, Type) of
- {ok,FileCtrlPid} ->
- case logger_h_common:unset_restart_flag(Name, ?MODULE) of
- true ->
- %% inform about restart
- gen_server:cast(self(), {log_handler_info,
- "Handler ~p restarted",
- [Name]});
- false ->
- %% initial start
- ok
- end,
- {ok,#{id=>Name,type=>Type,file_ctrl_pid=>FileCtrlPid}};
- Error ->
- Error
- end.
-
-%% This is the synchronous log event.
-handle_call({log, Bin}, _From, State) ->
- {Result,State1} = do_log(Bin, call, State),
- %% Result == ok | dropped
- {reply,Result, State1};
-
-handle_call(filesync, _From, State = #{type := Type,
- file_ctrl_pid := FileCtrlPid}) ->
- if is_atom(Type) ->
- {reply, ok, State};
- true ->
- {reply, file_ctrl_filesync_sync(FileCtrlPid), State#{last_op=>sync}}
- end;
-
-handle_call({change_config,_OldConfig,NewConfig}, _From,
- State = #{filesync_repeat_interval := FSyncInt0}) ->
- HConfig = maps:get(config, NewConfig, #{}),
- State1 = maps:merge(State, HConfig),
- case logger_h_common:overload_levels_ok(State1) of
- true ->
- _ =
- case maps:get(filesync_repeat_interval, HConfig, undefined) of
- undefined ->
- ok;
- no_repeat ->
- _ = logger_h_common:cancel_timer(maps:get(rep_sync_tref,
- State,
- undefined));
- FSyncInt0 ->
- ok;
- _FSyncInt1 ->
- _ = logger_h_common:cancel_timer(maps:get(rep_sync_tref,
- State,
- undefined)),
- gen_server:cast(self(), repeated_filesync)
- end,
- {reply, ok, State1};
- false ->
- #{sync_mode_qlen := SMQL,
- drop_mode_qlen := DMQL,
- flush_qlen := FQL} = State1,
- {reply, {error,{invalid_levels,{SMQL,DMQL,FQL}}}, State}
- end;
-
-handle_call(info, _From, State) ->
- {reply, State, State};
-
-handle_call(reset, _From, State) ->
- State1 = ?merge_with_stats(State),
- {reply, ok, State1#{last_qlen => 0,
- last_log_ts => ?timestamp()}};
-
-handle_call(stop, _From, State) ->
- {stop, {shutdown,stopped}, ok, State}.
-
-%% This is the asynchronous log event.
-handle_cast({log, Bin}, State) ->
- {_,State1} = do_log(Bin, cast, State),
- {noreply, State1};
-
-handle_cast({log_handler_info, Format, Args}, State = #{id:=Name}) ->
- log_handler_info(Name, Format, Args, State),
- {noreply, State};
-
-%% If FILESYNC_REPEAT_INTERVAL is set to a millisec value, this
-%% clause gets called repeatedly by the handler. In order to
-%% guarantee that a filesync *always* happens after the last log
-%% event, the repeat operation must be active!
-handle_cast(repeated_filesync,
- State = #{type := Type,
- file_ctrl_pid := FileCtrlPid,
- filesync_repeat_interval := FSyncInt,
- last_op := LastOp}) ->
- State1 =
- if not is_atom(Type), is_integer(FSyncInt) ->
- %% only do filesync if something has been
- %% written since last time we checked
- if LastOp == sync ->
- ok;
- true ->
- file_ctrl_filesync_async(FileCtrlPid)
- end,
- {ok,TRef} =
- timer:apply_after(FSyncInt, gen_server,cast,
- [self(),repeated_filesync]),
- State#{rep_sync_tref => TRef, last_op => sync};
- true ->
- State
- end,
- {noreply,State1}.
-
-handle_info({'EXIT',Pid,Why}, State = #{id := Name, type := FileInfo}) ->
- case maps:get(file_ctrl_pid, State, undefined) of
- Pid ->
- %% file error, terminate handler
- logger_h_common:handler_exit(Name,
- {error,{write_failed,FileInfo,Why}});
- _Other ->
- %% ignore EXIT
- ok
- end,
- {noreply, State};
-
-handle_info(_Info, State) ->
- {noreply, State}.
-
-terminate(Reason, State = #{id:=Name, file_ctrl_pid:=FWPid,
- type:=_FileInfo}) ->
- _ = logger_h_common:cancel_timer(maps:get(rep_sync_tref, State,
- undefined)),
+get_default_config() ->
+ #{type => standard_io}.
+
+filesync(_Name, _Mode, #{type := Type}=State) when is_atom(Type) ->
+ {ok,State};
+filesync(_Name, async, #{file_ctrl_pid := FileCtrlPid} = State) ->
+ ok = file_ctrl_filesync_async(FileCtrlPid),
+ {ok,State};
+filesync(_Name, sync, #{file_ctrl_pid := FileCtrlPid} = State) ->
+ Result = file_ctrl_filesync_sync(FileCtrlPid),
+ {Result,State}.
+
+write(_Name, async, Bin, #{file_ctrl_pid:=FileCtrlPid} = State) ->
+ ok = file_write_async(FileCtrlPid, Bin),
+ {ok,State};
+write(_Name, sync, Bin, #{file_ctrl_pid:=FileCtrlPid} = State) ->
+ Result = file_write_sync(FileCtrlPid, Bin),
+ {Result,State}.
+
+reset_state(_Name, State) ->
+ State.
+
+handle_info(_Name, {'EXIT',Pid,Why}, #{type := FileInfo, file_ctrl_pid := Pid}) ->
+ %% file_ctrl_pid died, file error, terminate handler
+ exit({error,{write_failed,FileInfo,Why}});
+handle_info(_, _, State) ->
+ State.
+
+terminate(_Name, _Reason, #{file_ctrl_pid:=FWPid}) ->
case is_process_alive(FWPid) of
true ->
unlink(FWPid),
@@ -423,17 +215,12 @@ terminate(Reason, State = #{id:=Name, file_ctrl_pid:=FWPid,
ok
after
?DEFAULT_CALL_TIMEOUT ->
- exit(FWPid, kill)
+ exit(FWPid, kill),
+ ok
end;
false ->
ok
- end,
- ok = logger_h_common:stop_or_restart(Name, Reason, State),
- unregister(?name_to_reg_name(?MODULE, Name)),
- ok.
-
-code_change(_OldVsn, State, _Extra) ->
- {ok, State}.
+ end.
%%%===================================================================
%%% Internal functions
@@ -441,203 +228,6 @@ code_change(_OldVsn, State, _Extra) ->
%%%-----------------------------------------------------------------
%%%
-get_default_config() ->
- #{type => standard_io,
- sync_mode_qlen => ?SYNC_MODE_QLEN,
- drop_mode_qlen => ?DROP_MODE_QLEN,
- flush_qlen => ?FLUSH_QLEN,
- burst_limit_enable => ?BURST_LIMIT_ENABLE,
- burst_limit_max_count => ?BURST_LIMIT_MAX_COUNT,
- burst_limit_window_time => ?BURST_LIMIT_WINDOW_TIME,
- overload_kill_enable => ?OVERLOAD_KILL_ENABLE,
- overload_kill_qlen => ?OVERLOAD_KILL_QLEN,
- overload_kill_mem_size => ?OVERLOAD_KILL_MEM_SIZE,
- overload_kill_restart_after => ?OVERLOAD_KILL_RESTART_AFTER,
- filesync_repeat_interval => ?FILESYNC_REPEAT_INTERVAL}.
-
-get_init_state() ->
- #{file_ctrl_sync_int => ?CONTROLLER_SYNC_INTERVAL,
- filesync_ok_qlen => ?FILESYNC_OK_QLEN}.
-
-%%%-----------------------------------------------------------------
-%%% Add a standard handler to the logger.
-%%% This starts a dedicated handler process which should always
-%%% exist if the handler is registered with logger (and should not
-%%% exist if the handler is not registered).
-%%%
-%%% Handler specific config should be provided with a sub map associated
-%%% with a key named 'config', e.g:
-%%%
-%%% Config = #{config => #{sync_mode_qlen => 50}
-%%%
-%%% The standard handler process is linked to logger_sup, which is
-%%% part of the kernel application's supervision tree.
-start(Name, Config, HandlerState) ->
- LoggerStdH =
- #{id => Name,
- start => {?MODULE, start_link, [Name,Config,HandlerState]},
- restart => temporary,
- shutdown => 2000,
- type => worker,
- modules => [?MODULE]},
- case supervisor:start_child(logger_sup, LoggerStdH) of
- {ok,Pid,Config1} ->
- ok = logger_handler_watcher:register_handler(Name,Pid),
- {ok,Config1};
- Error ->
- Error
- end.
-
-%%%-----------------------------------------------------------------
-%%% Stop and remove the handler.
-stop(Name) ->
- case whereis(?name_to_reg_name(?MODULE,Name)) of
- undefined ->
- ok;
- Pid ->
- %% We don't want to do supervisor:terminate_child here
- %% since we need to distinguish this explicit stop from a
- %% system termination in order to avoid circular attempts
- %% at removing the handler (implying deadlocks and
- %% timeouts).
- %% And we don't need to do supervisor:delete_child, since
- %% the restart type is temporary, which means that the
- %% child specification is automatically removed from the
- %% supervisor when the process dies.
- _ = gen_server:call(Pid, stop),
- ok
- end.
-
-%%%-----------------------------------------------------------------
-%%% Logging and overload control.
--define(update_file_ctrl_sync(C, Interval),
- if C == 0 -> Interval;
- true -> C-1 end).
-
-%% check for overload between every event (and set Mode to async,
-%% sync or drop accordingly), but never flush the whole mailbox
-%% before LogWindowSize events have been handled
-do_log(Bin, CallOrCast, State = #{id:=Name, mode:=Mode0}) ->
- T1 = ?timestamp(),
-
- %% check if the handler is getting overloaded, or if it's
- %% recovering from overload (the check must be done for each
- %% event to react quickly to large bursts of events and
- %% to ensure that the handler can never end up in drop mode
- %% with an empty mailbox, which would stop operation)
- {Mode1,QLen,Mem,State1} = logger_h_common:check_load(State),
-
- if (Mode1 == drop) andalso (Mode0 =/= drop) ->
- log_handler_info(Name, "Handler ~p switched to drop mode",
- [Name], State);
- (Mode0 == drop) andalso ((Mode1 == async) orelse (Mode1 == sync)) ->
- log_handler_info(Name, "Handler ~p switched to ~w mode",
- [Name,Mode1], State);
- true ->
- ok
- end,
-
- %% kill the handler if it can't keep up with the load
- logger_h_common:kill_if_choked(Name, QLen, Mem, ?MODULE, State),
-
- if Mode1 == flush ->
- flush(Name, QLen, T1, State1);
- true ->
- write(Name, Mode1, T1, Bin, CallOrCast, State1)
- end.
-
-%% this clause is called by do_log/3 after an overload check
-%% has been performed, where QLen > FlushQLen
-flush(Name, _QLen0, T1, State=#{last_log_ts := _T0, mode_tab := ModeTab}) ->
- %% flush messages in the mailbox (a limited number in
- %% order to not cause long delays)
- NewFlushed = logger_h_common:flush_log_events(?FLUSH_MAX_N),
-
- %% write info in log about flushed messages
- log_handler_info(Name, "Handler ~p flushed ~w log events",
- [Name,NewFlushed], State),
-
- %% because of the receive loop when flushing messages, the
- %% handler will be scheduled out often and the mailbox could
- %% grow very large, so we'd better check the queue again here
- {_,_QLen1} = process_info(self(), message_queue_len),
- ?observe(Name,{max_qlen,_QLen1}),
-
- %% Add 1 for the current log event
- ?observe(Name,{flushed,NewFlushed+1}),
-
- State1 = ?update_max_time(?diff_time(T1,_T0),State),
- {dropped,?update_other(flushed,FLUSHED,NewFlushed,
- State1#{mode => ?set_mode(ModeTab,async),
- last_qlen => 0,
- last_log_ts => T1})}.
-
-%% this clause is called to write to file
-write(_Name, Mode, T1, Bin, _CallOrCast,
- State = #{mode_tab := ModeTab,
- file_ctrl_pid := FileCtrlPid,
- file_ctrl_sync := FileCtrlSync,
- last_qlen := LastQLen,
- last_log_ts := T0,
- file_ctrl_sync_int := FileCtrlSyncInt}) ->
- %% check if we need to limit the number of writes
- %% during a burst of log events
- {DoWrite,BurstWinT,BurstMsgCount} = logger_h_common:limit_burst(State),
-
- %% only send a synhrounous event to the file controller process
- %% every FileCtrlSyncInt time, to give the handler time between
- %% file writes so it can keep up with incoming messages
- {Result,LastQLen1} =
- if DoWrite, FileCtrlSync == 0 ->
- ?observe(_Name,{_CallOrCast,1}),
- file_write_sync(FileCtrlPid, Bin, false),
- {ok,element(2, process_info(self(), message_queue_len))};
- DoWrite ->
- ?observe(_Name,{_CallOrCast,1}),
- file_write_async(FileCtrlPid, Bin),
- {ok,LastQLen};
- not DoWrite ->
- ?observe(_Name,{flushed,1}),
- {dropped,LastQLen}
- end,
-
- %% Check if the time since the previous log event is long enough -
- %% and the queue length small enough - to assume the mailbox has
- %% been emptied, and if so, do filesync operation and reset mode to
- %% async. Note that this is the best we can do to detect an idle
- %% handler without setting a timer after each log call/cast. If the
- %% time between two consecutive log events is fast and no new
- %% event comes in after the last one, idle state won't be detected!
- Time = ?diff_time(T1,T0),
- {Mode1,BurstMsgCount1} =
- if (LastQLen1 < ?FILESYNC_OK_QLEN) andalso
- (Time > ?IDLE_DETECT_TIME_USEC) ->
- %% do filesync if necessary
- case maps:get(type, State) of
- Std when is_atom(Std) ->
- ok;
- _File ->
- file_ctrl_filesync_async(FileCtrlPid)
- end,
- {?change_mode(ModeTab, Mode, async),0};
- true ->
- {Mode,BurstMsgCount}
- end,
- State1 =
- ?update_calls_or_casts(_CallOrCast,1,State),
- State2 =
- ?update_max_time(Time,
- State1#{mode => Mode1,
- last_qlen := LastQLen1,
- last_log_ts => T1,
- last_op => write,
- burst_win_ts => BurstWinT,
- burst_msg_count => BurstMsgCount1,
- file_ctrl_sync =>
- ?update_file_ctrl_sync(FileCtrlSync,
- FileCtrlSyncInt)}),
- {Result,State2}.
-
open_log_file(HandlerName, FileInfo) ->
case file_ctrl_start(HandlerName, FileInfo) of
OK = {ok,_FileCtrlPid} -> OK;
@@ -669,19 +259,6 @@ close_log_file(Fd) ->
_ = file:close(Fd).
-log_handler_info(Name, Format, Args, #{file_ctrl_pid := FileCtrlPid}) ->
- Config =
- case logger:get_handler_config(Name) of
- {ok,Conf} -> Conf;
- _ -> #{formatter=>{?DEFAULT_FORMATTER,?DEFAULT_FORMAT_CONFIG}}
- end,
- Meta = #{time=>erlang:system_time(microsecond)},
- Bin = logger_h_common:log_to_binary(#{level => notice,
- msg => {Format,Args},
- meta => Meta}, Config),
- _ = file_write_async(FileCtrlPid, Bin),
- ok.
-
%%%-----------------------------------------------------------------
%%% File control process
@@ -708,24 +285,19 @@ file_write_async(Pid, Bin) ->
Pid ! {log,Bin},
ok.
-file_write_sync(Pid, Bin, FileSync) ->
- case file_ctrl_call(Pid, {log,self(),Bin,FileSync}) of
- {error,Reason} ->
- {error,{write_failed,Bin,Reason}};
- Result ->
- Result
- end.
+file_write_sync(Pid, Bin) ->
+ file_ctrl_call(Pid, {log,Bin}).
file_ctrl_filesync_async(Pid) ->
Pid ! filesync,
ok.
file_ctrl_filesync_sync(Pid) ->
- file_ctrl_call(Pid, {filesync,self()}).
+ file_ctrl_call(Pid, filesync).
file_ctrl_call(Pid, Msg) ->
MRef = monitor(process, Pid),
- Pid ! {Msg,MRef},
+ Pid ! {Msg,{self(),MRef}},
receive
{MRef,Result} ->
demonitor(MRef, [flush]),
@@ -743,74 +315,43 @@ file_ctrl_init(HandlerName, FileInfo, Starter) when is_tuple(FileInfo) ->
case do_open_log_file(FileInfo) of
{ok,Fd} ->
Starter ! {self(),ok},
- file_ctrl_loop(Fd, file, FileName, false, ok, ok, HandlerName);
+ file_ctrl_loop(Fd, FileName, false, ok, ok, HandlerName);
{error,Reason} ->
Starter ! {self(),{error,{open_failed,FileName,Reason}}}
end;
file_ctrl_init(HandlerName, StdDev, Starter) ->
Starter ! {self(),ok},
- file_ctrl_loop(StdDev, standard_io, StdDev, false, ok, ok, HandlerName).
+ file_ctrl_loop(StdDev, StdDev, false, ok, ok, HandlerName).
-file_ctrl_loop(Fd, Type, DevName, Synced,
+file_ctrl_loop(Fd, DevName, Synced,
PrevWriteResult, PrevSyncResult, HandlerName) ->
receive
%% asynchronous event
{log,Bin} ->
- Result = if Type == file ->
- write_to_dev(Fd, Bin, DevName,
- PrevWriteResult, HandlerName);
- true ->
- io:put_chars(Fd, Bin)
- end,
- file_ctrl_loop(Fd, Type, DevName, false,
+ Fd1 = ensure(Fd, DevName),
+ Result = write_to_dev(Fd1, Bin, DevName, PrevWriteResult, HandlerName),
+ file_ctrl_loop(Fd1, DevName, false,
Result, PrevSyncResult, HandlerName);
%% synchronous event
- {{log,From,Bin,FileSync},MRef} ->
- if Type == file ->
- %% check that file hasn't been deleted
- CheckFile =
- fun() -> {ok,_} = file:read_file_info(DevName) end,
- spawn_link(CheckFile),
- WResult = write_to_dev(Fd, Bin, DevName,
- PrevWriteResult, HandlerName),
- {Synced1,SResult} =
- if not FileSync ->
- {false,PrevSyncResult};
- true ->
- case sync_dev(Fd, DevName,
- PrevSyncResult, HandlerName) of
- ok -> {true,ok};
- Error -> {false,Error}
- end
- end,
- From ! {MRef,ok},
- file_ctrl_loop(Fd, Type, DevName, Synced1,
- WResult, SResult, HandlerName);
- true ->
- _ = io:put_chars(Fd, Bin),
- From ! {MRef,ok},
- file_ctrl_loop(Fd, Type, DevName, false,
- ok, PrevSyncResult, HandlerName)
- end;
+ {{log,Bin},{From,MRef}} ->
+ Fd1 = ensure(Fd, DevName),
+ Result = write_to_dev(Fd1, Bin, DevName, PrevWriteResult, HandlerName),
+ From ! {MRef,ok},
+ file_ctrl_loop(Fd1, DevName, false,
+ Result, PrevSyncResult, HandlerName);
- filesync when not Synced ->
- Result = sync_dev(Fd, DevName, PrevSyncResult, HandlerName),
- file_ctrl_loop(Fd, Type, DevName, true,
+ filesync ->
+ Fd1 = ensure(Fd, DevName),
+ Result = sync_dev(Fd1, DevName, Synced, PrevSyncResult, HandlerName),
+ file_ctrl_loop(Fd1, DevName, true,
PrevWriteResult, Result, HandlerName);
- filesync ->
- file_ctrl_loop(Fd, Type, DevName, true,
- PrevWriteResult, PrevSyncResult, HandlerName);
-
- {{filesync,From},MRef} ->
- Result = if not Synced ->
- sync_dev(Fd, DevName, PrevSyncResult, HandlerName);
- true ->
- ok
- end,
+ {filesync,{From,MRef}} ->
+ Fd1 = ensure(Fd, DevName),
+ Result = sync_dev(Fd1, DevName, Synced, PrevSyncResult, HandlerName),
From ! {MRef,ok},
- file_ctrl_loop(Fd, Type, DevName, true,
+ file_ctrl_loop(Fd1, DevName, true,
PrevWriteResult, Result, HandlerName);
stop ->
@@ -818,26 +359,44 @@ file_ctrl_loop(Fd, Type, DevName, Synced,
stopped
end.
-write_to_dev(Fd, Bin, FileName, PrevWriteResult, HandlerName) ->
- case ?file_write(Fd, Bin) of
- ok ->
- ok;
- PrevWriteResult ->
- %% don't report same error twice
- PrevWriteResult;
- Error ->
- logger_h_common:error_notify({HandlerName,write,FileName,Error}),
- Error
+%% In order to play well with tools like logrotate, we need to be able
+%% to re-create the file if it has disappeared (e.g. if rotated by
+%% logrotate)
+ensure(Fd,DevName) when is_atom(DevName) ->
+ Fd;
+ensure(Fd,FileName) ->
+ case file:read_file_info(FileName) of
+ {ok,_} ->
+ Fd;
+ _ ->
+ _ = file:close(Fd),
+ _ = file:close(Fd), % delayed_write cause close not to close
+ case do_open_log_file({file,FileName}) of
+ {ok,Fd1} ->
+ Fd1;
+ Error ->
+ exit({could_not_reopen_file,Error})
+ end
end.
-sync_dev(Fd, DevName, PrevSyncResult, HandlerName) ->
- case ?file_datasync(Fd) of
- ok ->
- ok;
- PrevSyncResult ->
- %% don't report same error twice
- PrevSyncResult;
- Error ->
- logger_h_common:error_notify({HandlerName,filesync,DevName,Error}),
- Error
- end.
+write_to_dev(DevName, Bin, _DevName, _PrevWriteResult, _HandlerName)
+ when is_atom(DevName) ->
+ io:put_chars(DevName, Bin);
+write_to_dev(Fd, Bin, FileName, PrevWriteResult, HandlerName) ->
+ Result = ?file_write(Fd, Bin),
+ maybe_notify_error(write,Result,PrevWriteResult,FileName,HandlerName).
+
+sync_dev(_Fd, _FileName, true, PrevSyncResult, _HandlerName) ->
+ PrevSyncResult;
+sync_dev(Fd, FileName, false, PrevSyncResult, HandlerName) ->
+ Result = ?file_datasync(Fd),
+ maybe_notify_error(filesync,Result,PrevSyncResult,FileName,HandlerName).
+
+maybe_notify_error(_Op, ok, _PrevResult, _FileName, _HandlerName) ->
+ ok;
+maybe_notify_error(_Op, PrevResult, PrevResult, _FileName, _HandlerName) ->
+ %% don't report same error twice
+ PrevResult;
+maybe_notify_error(Op, Error, _PrevResult, FileName, HandlerName) ->
+ logger_h_common:error_notify({HandlerName,Op,FileName,Error}),
+ Error.
diff --git a/lib/kernel/src/seq_trace.erl b/lib/kernel/src/seq_trace.erl
index 14fe21e9de..4f9d7b3e5c 100644
--- a/lib/kernel/src/seq_trace.erl
+++ b/lib/kernel/src/seq_trace.erl
@@ -98,7 +98,7 @@ print(Label, Term) ->
-spec reset_trace() -> 'true'.
reset_trace() ->
- erlang:system_flag(1, 0).
+ erlang:system_flag(reset_seq_trace, true).
%% reset_trace(Pid) -> % this might be a useful function too
diff --git a/lib/kernel/test/gen_tcp_misc_SUITE.erl b/lib/kernel/test/gen_tcp_misc_SUITE.erl
index 04c0c48e3a..244bd7e2a0 100644
--- a/lib/kernel/test/gen_tcp_misc_SUITE.erl
+++ b/lib/kernel/test/gen_tcp_misc_SUITE.erl
@@ -1969,20 +1969,20 @@ recvtclass(_Config) ->
{skip,{ipv6_not_supported,IFs}}
end.
-%% These version numbers are the highest noted in daily tests
-%% where the test fails for a plausible reason, so
-%% skip on that platform.
+%% These version numbers are above the highest noted
+%% in daily tests where the test fails for a plausible reason,
+%% so skip on platforms of lower version, i.e they are future
+%% versions where it is possible that it might not fail.
%%
-%% On newer versions it might be fixed, but we'll see about that
-%% when machines with newer versions gets installed...
-%% If the test still fails for a plausible reason these
+%% When machines with newer versions gets installed,
+%% if the test still fails for a plausible reason these
%% version numbers simply should be increased.
%% Or maybe we should change to only test on known good
%% platforms - change {unix,_} to false?
%% pktoptions is not supported for IPv4
recvtos_ok({unix,openbsd}, OSVer) -> not semver_lt(OSVer, {6,4,0});
-recvtos_ok({unix,darwin}, OSVer) -> not semver_lt(OSVer, {17,6,0});
+recvtos_ok({unix,darwin}, OSVer) -> not semver_lt(OSVer, {19,0,0});
%% Using the option returns einval, so it is not implemented.
recvtos_ok({unix,freebsd}, OSVer) -> not semver_lt(OSVer, {11,2,0});
recvtos_ok({unix,sunos}, OSVer) -> not semver_lt(OSVer, {5,12,0});
@@ -1994,18 +1994,19 @@ recvtos_ok(_, _) -> false.
%% pktoptions is not supported for IPv4
recvttl_ok({unix,openbsd}, OSVer) -> not semver_lt(OSVer, {6,4,0});
-recvttl_ok({unix,darwin}, OSVer) -> not semver_lt(OSVer, {17,6,0});
+recvttl_ok({unix,darwin}, OSVer) -> not semver_lt(OSVer, {19,0,0});
%% Using the option returns einval, so it is not implemented.
recvttl_ok({unix,freebsd}, OSVer) -> not semver_lt(OSVer, {11,2,0});
recvttl_ok({unix,sunos}, OSVer) -> not semver_lt(OSVer, {5,12,0});
+%% Does not return any value - not implemented for pktoptions
+recvttl_ok({unix,linux}, OSVer) -> not semver_lt(OSVer, {2,7,0});
%%
-recvttl_ok({unix,linux}, _) -> true;
recvttl_ok({unix,_}, _) -> true;
recvttl_ok(_, _) -> false.
%% pktoptions is not supported for IPv6
recvtclass_ok({unix,openbsd}, OSVer) -> not semver_lt(OSVer, {6,4,0});
-recvtclass_ok({unix,darwin}, OSVer) -> not semver_lt(OSVer, {17,6,0});
+recvtclass_ok({unix,darwin}, OSVer) -> not semver_lt(OSVer, {19,0,0});
recvtclass_ok({unix,sunos}, OSVer) -> not semver_lt(OSVer, {5,12,0});
%% Using the option returns einval, so it is not implemented.
recvtclass_ok({unix,freebsd}, OSVer) -> not semver_lt(OSVer, {11,2,0});
diff --git a/lib/kernel/test/init_SUITE.erl b/lib/kernel/test/init_SUITE.erl
index 7828cc4716..a0154b2694 100644
--- a/lib/kernel/test/init_SUITE.erl
+++ b/lib/kernel/test/init_SUITE.erl
@@ -295,7 +295,7 @@ is_real_system(KernelVsn, StdlibVsn) ->
%% before restart.
%% ------------------------------------------------
many_restarts() ->
- [{timetrap,{minutes,8}}].
+ [{timetrap,{minutes,16}}].
many_restarts(Config) when is_list(Config) ->
{ok, Node} = loose_node:start(init_test, "", ?DEFAULT_TIMEOUT_SEC),
@@ -315,7 +315,7 @@ loop_restart(N,Node,EHPid) ->
loose_node:stop(Node),
ct:fail(not_stopping)
end,
- ok = wait_for(30, Node, EHPid),
+ ok = wait_for(60, Node, EHPid),
loop_restart(N-1,Node,rpc:call(Node,erlang,whereis,[logger])).
wait_for(0,Node,_) ->
@@ -367,7 +367,8 @@ restart(Config) when is_list(Config) ->
SysProcs0 = rpc:call(Node, ?MODULE, find_system_processes, []),
io:format("SysProcs0=~p~n", [SysProcs0]),
[InitPid, PurgerPid, LitCollectorPid,
- DirtySigNPid, DirtySigHPid, DirtySigMPid] = SysProcs0,
+ DirtySigNPid, DirtySigHPid, DirtySigMPid,
+ PrimFilePid] = SysProcs0,
InitPid = rpc:call(Node, erlang, whereis, [init]),
PurgerPid = rpc:call(Node, erlang, whereis, [erts_code_purger]),
Procs = rpc:call(Node, erlang, processes, []),
@@ -385,7 +386,8 @@ restart(Config) when is_list(Config) ->
SysProcs1 = rpc:call(Node, ?MODULE, find_system_processes, []),
io:format("SysProcs1=~p~n", [SysProcs1]),
[InitPid1, PurgerPid1, LitCollectorPid1,
- DirtySigNPid1, DirtySigHPid1, DirtySigMPid1] = SysProcs1,
+ DirtySigNPid1, DirtySigHPid1, DirtySigMPid1,
+ PrimFilePid1] = SysProcs1,
%% Still the same init process!
InitPid1 = rpc:call(Node, erlang, whereis, [init]),
@@ -411,6 +413,10 @@ restart(Config) when is_list(Config) ->
DirtySigMP = pid_to_list(DirtySigMPid),
DirtySigMP = pid_to_list(DirtySigMPid1),
+ %% and same prim_file helper process!
+ PrimFileP = pid_to_list(PrimFilePid),
+ PrimFileP = pid_to_list(PrimFilePid1),
+
NewProcs0 = rpc:call(Node, erlang, processes, []),
NewProcs = NewProcs0 -- SysProcs1,
case check_processes(NewProcs, MaxPid) of
@@ -437,7 +443,8 @@ restart(Config) when is_list(Config) ->
literal_collector,
dirty_sig_handler_normal,
dirty_sig_handler_high,
- dirty_sig_handler_max}).
+ dirty_sig_handler_max,
+ prim_file}).
find_system_processes() ->
find_system_procs(processes(), #sys_procs{}).
@@ -448,7 +455,8 @@ find_system_procs([], SysProcs) ->
SysProcs#sys_procs.literal_collector,
SysProcs#sys_procs.dirty_sig_handler_normal,
SysProcs#sys_procs.dirty_sig_handler_high,
- SysProcs#sys_procs.dirty_sig_handler_max];
+ SysProcs#sys_procs.dirty_sig_handler_max,
+ SysProcs#sys_procs.prim_file];
find_system_procs([P|Ps], SysProcs) ->
case process_info(P, [initial_call, priority]) of
[{initial_call,{erl_init,start,2}},_] ->
@@ -472,6 +480,9 @@ find_system_procs([P|Ps], SysProcs) ->
{priority,max}] ->
undefined = SysProcs#sys_procs.dirty_sig_handler_max,
find_system_procs(Ps, SysProcs#sys_procs{dirty_sig_handler_max = P});
+ [{initial_call,{prim_file,start,0}},_] ->
+ undefined = SysProcs#sys_procs.prim_file,
+ find_system_procs(Ps, SysProcs#sys_procs{prim_file = P});
_ ->
find_system_procs(Ps, SysProcs)
end.
diff --git a/lib/kernel/test/logger_disk_log_h_SUITE.erl b/lib/kernel/test/logger_disk_log_h_SUITE.erl
index 905c2c52c5..87b8250781 100644
--- a/lib/kernel/test/logger_disk_log_h_SUITE.erl
+++ b/lib/kernel/test/logger_disk_log_h_SUITE.erl
@@ -332,16 +332,18 @@ errors(Config) ->
%%! Check how bad log_opts are handled!
{error,{illegal_config_change,
- #{config:=#{type:=wrap}},
- #{config:=#{type:=halt}}}} =
+ logger_disk_log_h,
+ #{type:=wrap},
+ #{type:=halt}}} =
logger:update_handler_config(Name1,
config,
#{type=>halt,
file=>LogFile1}),
{error,{illegal_config_change,
- #{config:=#{file:=LogFile1}},
- #{config:=#{file:="newfilename"}}}} =
+ logger_disk_log_h,
+ #{file:=LogFile1},
+ #{file:="newfilename"}}} =
logger:update_handler_config(Name1,
config,
#{file=>"newfilename"}),
@@ -411,20 +413,25 @@ formatter_fail(cleanup,_Config) ->
ok.
config_fail(_Config) ->
- {error,{handler_not_added,{invalid_config,logger_disk_log_h,{bad,bad}}}} =
+ {error,{handler_not_added,{invalid_config,logger_disk_log_h,#{bad:=bad}}}} =
logger:add_handler(?MODULE,logger_disk_log_h,
#{config => #{bad => bad},
filter_default=>log,
formatter=>{?MODULE,self()}}),
- {error,{handler_not_added,{invalid_levels,{_,1,_}}}} =
+ {error,{handler_not_added,{invalid_config,logger_disk_log_h,
+ {invalid_levels,#{drop_mode_qlen:=1}}}}} =
logger:add_handler(?MODULE,logger_disk_log_h,
#{config => #{drop_mode_qlen=>1}}),
- {error,{handler_not_added,{invalid_levels,{43,42,_}}}} =
+ {error,{handler_not_added,{invalid_config,logger_disk_log_h,
+ {invalid_levels,#{sync_mode_qlen:=43,
+ drop_mode_qlen:=42}}}}} =
logger:add_handler(?MODULE,logger_disk_log_h,
#{config => #{sync_mode_qlen=>43,
drop_mode_qlen=>42}}),
- {error,{handler_not_added,{invalid_levels,{_,43,42}}}} =
+ {error,{handler_not_added,{invalid_config,logger_disk_log_h,
+ {invalid_levels,#{drop_mode_qlen:=43,
+ flush_qlen:=42}}}}} =
logger:add_handler(?MODULE,logger_disk_log_h,
#{config => #{drop_mode_qlen=>43,
flush_qlen=>42}}),
@@ -433,20 +440,17 @@ config_fail(_Config) ->
#{filter_default=>log,
formatter=>{?MODULE,self()}}),
%% can't change the disk log options for a log already in use
- {error,{illegal_config_change,_,_}} =
+ {error,{illegal_config_change,logger_disk_log_h,_,_}} =
logger:update_handler_config(?MODULE,config,
#{max_no_files=>2}),
- %% can't change name of an existing handler
- {error,{illegal_config_change,_,_}} =
- logger:update_handler_config(?MODULE,id,bad),
%% incorrect values of OP params
{ok,#{config := HConfig}} = logger:get_handler_config(?MODULE),
- {error,{invalid_levels,_}} =
+ {error,{invalid_config,logger_disk_log_h,{invalid_levels,_}}} =
logger:update_handler_config(?MODULE,config,
HConfig#{sync_mode_qlen=>100,
flush_qlen=>99}),
%% invalid name of config parameter
- {error,{invalid_config,logger_disk_log_h,{filesync_rep_int,2000}}} =
+ {error,{invalid_config,logger_disk_log_h,#{filesync_rep_int:=2000}}} =
logger:update_handler_config(?MODULE, config,
HConfig#{filesync_rep_int => 2000}),
ok.
@@ -487,10 +491,11 @@ reconfig(Config) ->
overload_kill_mem_size := ?OVERLOAD_KILL_MEM_SIZE,
overload_kill_restart_after := ?OVERLOAD_KILL_RESTART_AFTER,
filesync_repeat_interval := ?FILESYNC_REPEAT_INTERVAL,
- log_opts := #{type := ?DISK_LOG_TYPE,
- max_no_files := ?DISK_LOG_MAX_NO_FILES,
- max_no_bytes := ?DISK_LOG_MAX_NO_BYTES,
- file := DiskLogFile}} =
+ handler_state :=
+ #{log_opts := #{type := ?DISK_LOG_TYPE,
+ max_no_files := ?DISK_LOG_MAX_NO_FILES,
+ max_no_bytes := ?DISK_LOG_MAX_NO_BYTES,
+ file := DiskLogFile}}} =
logger_disk_log_h:info(?MODULE),
{ok,#{config :=
#{sync_mode_qlen := ?SYNC_MODE_QLEN,
@@ -572,10 +577,11 @@ reconfig(Config) ->
max_no_files => 1,
max_no_bytes => 1024,
file => File}}),
- #{log_opts := #{type := halt,
- max_no_files := 1,
- max_no_bytes := 1024,
- file := File}} =
+ #{handler_state :=
+ #{log_opts := #{type := halt,
+ max_no_files := 1,
+ max_no_bytes := 1024,
+ file := File}}} =
logger_disk_log_h:info(?MODULE),
{ok,#{config :=
#{type := halt,
@@ -596,13 +602,13 @@ reconfig(Config) ->
%% You are not allowed to actively set the write once fields
%% (type, max_no_files, max_no_bytes, file) in runtime.
- {error, {illegal_config_change,_,_}} =
+ {error, {illegal_config_change,_,_,_}} =
logger:set_handler_config(?MODULE,config,#{type=>wrap}),
- {error, {illegal_config_change,_,_}} =
+ {error, {illegal_config_change,_,_,_}} =
logger:set_handler_config(?MODULE,config,#{max_no_files=>2}),
- {error, {illegal_config_change,_,_}} =
+ {error, {illegal_config_change,_,_,_}} =
logger:set_handler_config(?MODULE,config,#{max_no_bytes=>2048}),
- {error, {illegal_config_change,_,_}} =
+ {error, {illegal_config_change,_,_,_}} =
logger:set_handler_config(?MODULE,config,#{file=>"otherfile.log"}),
{ok,C7} = logger:get_handler_config(?MODULE),
ct:log("C7: ~p",[C7]),
@@ -630,16 +636,16 @@ sync(Config) ->
filters=>?DEFAULT_HANDLER_FILTERS([?MODULE]),
formatter=>{?MODULE,nl}}),
- start_tracer([{disk_log,blog,2},
- {logger_disk_log_h,disk_log_sync,2}],
- [{disk_log,blog,<<"first\n">>},
- {logger_disk_log_h,disk_log_sync}]),
+ start_tracer([{logger_disk_log_h,disk_log_write,3},
+ {disk_log,sync,1}],
+ [{logger_disk_log_h,disk_log_write,<<"first\n">>},
+ {disk_log,sync}]),
logger:notice("first", ?domain),
%% wait for automatic disk_log_sync
check_tracer(?FILESYNC_REPEAT_INTERVAL*2),
- %% check that if there's no repeated disk_log_sync active,
+ %% check that if there's no repeated filesync active,
%% a disk_log_sync is still performed when handler goes idle
{ok,#{config := HConfig}} = logger:get_handler_config(?MODULE),
HConfig1 = HConfig#{filesync_repeat_interval => no_repeat},
@@ -652,12 +658,12 @@ sync(Config) ->
%% triggered by the idle timeout between "fourth" and "fifth".
timer:sleep(?IDLE_DETECT_TIME_MSEC*2),
- start_tracer([{disk_log,blog,2},
- {logger_disk_log_h,disk_log_sync,2}],
- [{disk_log,blog,<<"second\n">>},
- {logger_disk_log_h,disk_log_sync},
- {disk_log,blog,<<"third\n">>},
- {logger_disk_log_h,disk_log_sync}]),
+ start_tracer([{logger_disk_log_h,disk_log_write,3},
+ {disk_log,sync,1}],
+ [{logger_disk_log_h,disk_log_write,<<"second\n">>},
+ {disk_log,sync},
+ {logger_disk_log_h,disk_log_write,<<"third\n">>},
+ {disk_log,sync}]),
logger:notice("second", ?domain),
timer:sleep(?IDLE_DETECT_TIME_MSEC*2),
@@ -667,13 +673,13 @@ sync(Config) ->
try_read_file(Log, {ok,<<"first\nsecond\nthird\n">>}, 1000),
- %% switch repeated disk_log_sync on and verify that the looping works
+ %% switch repeated filesync on and verify that the looping works
SyncInt = 1000,
WaitT = 4500,
- OneSync = {logger_disk_log_h,handle_cast,repeated_disk_log_sync},
- %% receive 1 initial repeated_disk_log_sync, then 1 per sec
- start_tracer([{logger_disk_log_h,handle_cast,2}],
- [OneSync || _ <- lists:seq(1, 1 + trunc(WaitT/SyncInt))]),
+ OneSync = {logger_h_common,handle_cast,repeated_filesync},
+ %% receive 1 repeated_filesync per sec
+ start_tracer([{logger_h_common,handle_cast,2}],
+ [OneSync || _ <- lists:seq(1, trunc(WaitT/SyncInt))]),
HConfig2 = HConfig#{filesync_repeat_interval => SyncInt},
ok = logger:update_handler_config(?MODULE, config, HConfig2),
@@ -716,7 +722,7 @@ disk_log_wrap(Config) ->
end,
{ok,_} = dbg:tracer(process, {TraceFun, Tester}),
{ok,_} = dbg:p(whereis(h_proc_name()), [c]),
- {ok,_} = dbg:tp(logger_disk_log_h, handle_info, 2, []),
+ {ok,_} = dbg:tp(logger_disk_log_h, handle_info, 3, []),
Text = [34 + rand:uniform(126-34) || _ <- lists:seq(1,MaxBytes)],
ct:pal("String = ~p (~w)", [Text, erts_debug:size(Text)]),
@@ -734,7 +740,7 @@ disk_log_wrap(Config) ->
timer:sleep(1000),
dbg:stop_clear(),
Received = lists:flatmap(fun({trace,_M,handle_info,
- [{disk_log,_Node,_Name,What},_]}) ->
+ [_,{disk_log,_Node,_Name,What},_]}) ->
[{trace,What}];
({log,_}) ->
[]
@@ -770,7 +776,7 @@ disk_log_full(Config) ->
end,
{ok,_} = dbg:tracer(process, {TraceFun, Tester}),
{ok,_} = dbg:p(whereis(h_proc_name()), [c]),
- {ok,_} = dbg:tp(logger_disk_log_h, handle_info, 2, []),
+ {ok,_} = dbg:tp(logger_disk_log_h, handle_info, 3, []),
NoOfChars = 5,
Text = [34 + rand:uniform(126-34) || _ <- lists:seq(1,NoOfChars)],
@@ -780,14 +786,18 @@ disk_log_full(Config) ->
timer:sleep(2000),
dbg:stop_clear(),
Received = lists:flatmap(fun({trace,_M,handle_info,
- [{disk_log,_Node,_Name,What},_]}) ->
+ [_,{disk_log,_Node,_Name,What},_]}) ->
[{trace,What}];
({log,_}) ->
[]
end, test_server:messages_get()),
ct:pal("Trace =~n~p", [Received]),
- [{trace,full},
- {trace,{error_status,{error,{full,_}}}}] = Received,
+
+ %% The tail here could be an error_status notification, if the
+ %% last write was synchronous, but in most cases it will not be
+ [{trace,full}|_] = Received,
+ %% [{trace,full},
+ %% {trace,{error_status,{error,{full,_}}}}] = Received,
ok.
disk_log_full(cleanup, _Config) ->
dbg:stop_clear(),
@@ -819,14 +829,14 @@ disk_log_events(Config) ->
end,
{ok,_} = dbg:tracer(process, {TraceFun, Tester}),
{ok,_} = dbg:p(whereis(h_proc_name()), [c]),
- {ok,_} = dbg:tp(logger_disk_log_h, handle_info, 2, []),
+ {ok,_} = dbg:tp(logger_disk_log_h, handle_info, 3, []),
[whereis(h_proc_name()) ! E || E <- Events],
%% wait for trace messages
timer:sleep(2000),
dbg:stop_clear(),
Received = lists:map(fun({trace,_M,handle_info,
- [Got,_]}) -> Got
+ [_,Got,_]}) -> Got
end, test_server:messages_get()),
ct:pal("Trace =~n~p", [Received]),
NoOfEvents = length(Events),
@@ -849,13 +859,15 @@ write_failure(Config) ->
false = (undefined == rpc:call(Node, ets, whereis, [?TEST_HOOKS_TAB])),
rpc:call(Node, ets, insert, [?TEST_HOOKS_TAB,{tester,self()}]),
rpc:call(Node, ?MODULE, set_internal_log, [?MODULE,internal_log]),
- rpc:call(Node, ?MODULE, set_result, [disk_log_blog,ok]),
+ rpc:call(Node, ?MODULE, set_result, [disk_log_write,ok]),
HState = rpc:call(Node, logger_disk_log_h, info, [?STANDARD_HANDLER]),
- ct:pal("LogOpts = ~p", [LogOpts = maps:get(log_opts, HState)]),
+ ct:pal("LogOpts = ~p", [LogOpts = maps:get(log_opts,
+ maps:get(handler_state,HState))]),
+ %% ?check and ?check_no_log in this test only check for internal log events
ok = log_on_remote_node(Node, "Logged1"),
rpc:call(Node, logger_disk_log_h, filesync, [?STANDARD_HANDLER]),
- ?check_no_log,
+ ?check_no_log, % no internal log when write ok
SyncRepInt = case (fun() -> is_atom(?FILESYNC_REPEAT_INTERVAL) end)() of
true -> 5500;
@@ -864,24 +876,26 @@ write_failure(Config) ->
try_read_file(Log, {ok,<<"Logged1\n">>}, SyncRepInt),
- rpc:call(Node, ?MODULE, set_result, [disk_log_blog,{error,no_such_log}]),
+ rpc:call(Node, ?MODULE, set_result, [disk_log_write,{error,no_such_log}]),
ok = log_on_remote_node(Node, "Cause simple error printout"),
+ %% this should have caused an internal log
?check({error,{?STANDARD_HANDLER,log,LogOpts,{error,no_such_log}}}),
-
+
ok = log_on_remote_node(Node, "No second error printout"),
- ?check_no_log,
+ ?check_no_log, % but don't log same error twice
- rpc:call(Node, ?MODULE, set_result, [disk_log_blog,
+ rpc:call(Node, ?MODULE, set_result, [disk_log_write,
{error,{full,?STANDARD_HANDLER}}]),
ok = log_on_remote_node(Node, "Cause simple error printout"),
+ %% this was a different error, so it should be logged
?check({error,{?STANDARD_HANDLER,log,LogOpts,
{error,{full,?STANDARD_HANDLER}}}}),
- rpc:call(Node, ?MODULE, set_result, [disk_log_blog,ok]),
+ rpc:call(Node, ?MODULE, set_result, [disk_log_write,ok]),
ok = log_on_remote_node(Node, "Logged2"),
rpc:call(Node, logger_disk_log_h, filesync, [?STANDARD_HANDLER]),
- ?check_no_log,
+ ?check_no_log, % no internal log when write ok
try_read_file(Log, {ok,<<"Logged1\nLogged2\n">>}, SyncRepInt),
ok.
write_failure(cleanup, _Config) ->
@@ -901,7 +915,7 @@ sync_failure(Config) ->
rpc:call(Node, ?MODULE, set_internal_log, [?MODULE,internal_log]),
rpc:call(Node, ?MODULE, set_result, [disk_log_sync,ok]),
HState = rpc:call(Node, logger_disk_log_h, info, [?STANDARD_HANDLER]),
- LogOpts = maps:get(log_opts, HState),
+ LogOpts = maps:get(log_opts, maps:get(handler_state,HState)),
SyncInt = 500,
ok = rpc:call(Node, logger, update_handler_config,
@@ -1606,10 +1620,10 @@ tpl([{M,F,A}|Trace]) ->
tpl([]) ->
ok.
-tracer({trace,_,call,{logger_disk_log_h,handle_cast,[Op|_]},Caller},
+tracer({trace,_,call,{logger_h_common,handle_cast,[Op|_]},Caller},
{Pid,[{Mod,Func,Op}|Expected]}) ->
maybe_tracer_done(Pid,Expected,{Mod,Func,Op},Caller);
-tracer({trace,_,call,{Mod=disk_log,Func=blog,[_,Data]},Caller}, {Pid,[{Mod,Func,Data}|Expected]}) ->
+tracer({trace,_,call,{Mod=logger_disk_log_h,Func=disk_log_write,[_,_,Data]},Caller}, {Pid,[{Mod,Func,Data}|Expected]}) ->
maybe_tracer_done(Pid,Expected,{Mod,Func,Data},Caller);
tracer({trace,_,call,{Mod,Func,_},Caller}, {Pid,[{Mod,Func}|Expected]}) ->
maybe_tracer_done(Pid,Expected,{Mod,Func},Caller);
diff --git a/lib/kernel/test/logger_std_h_SUITE.erl b/lib/kernel/test/logger_std_h_SUITE.erl
index b6a09f4980..eb17a6d857 100644
--- a/lib/kernel/test/logger_std_h_SUITE.erl
+++ b/lib/kernel/test/logger_std_h_SUITE.erl
@@ -136,11 +136,12 @@ all() ->
mem_kill_new,
mem_kill_std,
restart_after,
- handler_requests_under_load
+ handler_requests_under_load,
+ recreate_deleted_log
].
add_remove_instance_tty(_Config) ->
- {error,{handler_not_added,{invalid_config,logger_std_h,{type,tty}}}} =
+ {error,{handler_not_added,{invalid_config,logger_std_h,#{type:=tty}}}} =
logger:add_handler(?MODULE,logger_std_h,
#{config => #{type => tty},
filter_default=>log,
@@ -234,7 +235,7 @@ errors(Config) ->
{error,
{handler_not_added,
- {invalid_config,logger_std_h,{type,faulty_type}}}} =
+ {invalid_config,logger_std_h,#{type:=faulty_type}}}} =
logger:add_handler(?MODULE,logger_std_h,
#{config => #{type => faulty_type}}),
@@ -308,25 +309,30 @@ formatter_fail(cleanup,_Config) ->
logger:remove_handler(?MODULE).
config_fail(_Config) ->
- {error,{handler_not_added,{invalid_config,logger_std_h,{bad,bad}}}} =
+ {error,{handler_not_added,{invalid_config,logger_std_h,#{bad:=bad}}}} =
logger:add_handler(?MODULE,logger_std_h,
#{config => #{bad => bad},
filter_default=>log,
formatter=>{?MODULE,self()}}),
{error,{handler_not_added,{invalid_config,logger_std_h,
- {restart_type,bad}}}} =
+ #{restart_type:=bad}}}} =
logger:add_handler(?MODULE,logger_std_h,
#{config => #{restart_type => bad},
filter_default=>log,
formatter=>{?MODULE,self()}}),
- {error,{handler_not_added,{invalid_levels,{_,1,_}}}} =
+ {error,{handler_not_added,{invalid_config,logger_std_h,
+ {invalid_levels,#{drop_mode_qlen:=1}}}}} =
logger:add_handler(?MODULE,logger_std_h,
#{config => #{drop_mode_qlen=>1}}),
- {error,{handler_not_added,{invalid_levels,{43,42,_}}}} =
+ {error,{handler_not_added,{invalid_config,logger_std_h,
+ {invalid_levels,#{sync_mode_qlen:=43,
+ drop_mode_qlen:=42}}}}} =
logger:add_handler(?MODULE,logger_std_h,
#{config => #{sync_mode_qlen=>43,
drop_mode_qlen=>42}}),
- {error,{handler_not_added,{invalid_levels,{_,43,42}}}} =
+ {error,{handler_not_added,{invalid_config,logger_std_h,
+ {invalid_levels,#{drop_mode_qlen:=43,
+ flush_qlen:=42}}}}} =
logger:add_handler(?MODULE,logger_std_h,
#{config => #{drop_mode_qlen=>43,
flush_qlen=>42}}),
@@ -334,15 +340,15 @@ config_fail(_Config) ->
ok = logger:add_handler(?MODULE,logger_std_h,
#{filter_default=>log,
formatter=>{?MODULE,self()}}),
- {error,{illegal_config_change,#{config:=#{type:=_}},#{config:=#{type:=_}}}} =
+ {error,{illegal_config_change,logger_std_h,#{type:=_},#{type:=_}}} =
logger:set_handler_config(?MODULE,config,
#{type=>{file,"file"}}),
- {error,{invalid_levels,_}} =
+ {error,{invalid_config,logger_std_h,{invalid_levels,_}}} =
logger:set_handler_config(?MODULE,config,
#{sync_mode_qlen=>100,
flush_qlen=>99}),
- {error,{invalid_config,logger_std_h,{filesync_rep_int,2000}}} =
+ {error,{invalid_config,logger_std_h,#{filesync_rep_int:=2000}}} =
logger:set_handler_config(?MODULE, config,
#{filesync_rep_int => 2000}),
@@ -468,8 +474,8 @@ reconfig(Config) ->
filters=>?DEFAULT_HANDLER_FILTERS([?MODULE]),
formatter=>{?MODULE,self()}}),
#{id := ?MODULE,
- type := standard_io,
- file_ctrl_pid := FileCtrlPid,
+ handler_state := #{type := standard_io,
+ file_ctrl_pid := FileCtrlPid},
sync_mode_qlen := ?SYNC_MODE_QLEN,
drop_mode_qlen := ?DROP_MODE_QLEN,
flush_qlen := ?FLUSH_QLEN,
@@ -480,7 +486,7 @@ reconfig(Config) ->
overload_kill_qlen := ?OVERLOAD_KILL_QLEN,
overload_kill_mem_size := ?OVERLOAD_KILL_MEM_SIZE,
overload_kill_restart_after := ?OVERLOAD_KILL_RESTART_AFTER,
- filesync_repeat_interval := ?FILESYNC_REPEAT_INTERVAL} = DefaultInfo =
+ filesync_repeat_interval := no_repeat} = DefaultInfo =
logger_std_h:info(?MODULE),
{ok,
@@ -496,7 +502,7 @@ reconfig(Config) ->
overload_kill_qlen := ?OVERLOAD_KILL_QLEN,
overload_kill_mem_size := ?OVERLOAD_KILL_MEM_SIZE,
overload_kill_restart_after := ?OVERLOAD_KILL_RESTART_AFTER,
- filesync_repeat_interval := ?FILESYNC_REPEAT_INTERVAL} =
+ filesync_repeat_interval := no_repeat} =
DefaultHConf}}
= logger:get_handler_config(?MODULE),
@@ -511,10 +517,10 @@ reconfig(Config) ->
overload_kill_qlen => 100000,
overload_kill_mem_size => 10000000,
overload_kill_restart_after => infinity,
- filesync_repeat_interval => no_repeat}),
+ filesync_repeat_interval => 5000}),
#{id := ?MODULE,
- type := standard_io,
- file_ctrl_pid := FileCtrlPid,
+ handler_state := #{type := standard_io,
+ file_ctrl_pid := FileCtrlPid},
sync_mode_qlen := 1,
drop_mode_qlen := 2,
flush_qlen := 3,
@@ -584,7 +590,7 @@ reconfig(Config) ->
%% You are not allowed to actively set 'type' in runtime, since
%% this is a write once field.
- {error, {illegal_config_change,_,_}} =
+ {error, {illegal_config_change,logger_std_h,_,_}} =
logger:set_handler_config(?MODULE,config,#{type=>standard_io}),
{ok,#{config:=C6}} = logger:get_handler_config(?MODULE),
ct:log("C6: ~p",[C6]),
@@ -620,7 +626,7 @@ file_opts(Config) ->
filters=>?DEFAULT_HANDLER_FILTERS([?MODULE]),
formatter=>{?MODULE,self()}}),
- #{type := OkType} = logger_std_h:info(?MODULE),
+ #{handler_state := #{type := OkType}} = logger_std_h:info(?MODULE),
logger:notice(M1=?msg,?domain),
?check(M1),
B1 = ?bin(M1),
@@ -643,10 +649,8 @@ sync(Config) ->
%% check repeated filesync happens
start_tracer([{logger_std_h, write_to_dev, 5},
- {logger_std_h, sync_dev, 4},
{file, datasync, 1}],
[{logger_std_h, write_to_dev, <<"first\n">>},
- {logger_std_h, sync_dev},
{file,datasync}]),
logger:notice("first", ?domain),
@@ -655,10 +659,8 @@ sync(Config) ->
%% check that explicit filesync is only done once
start_tracer([{logger_std_h, write_to_dev, 5},
- {logger_std_h, sync_dev, 4},
{file, datasync, 1}],
[{logger_std_h, write_to_dev, <<"second\n">>},
- {logger_std_h, sync_dev},
{file,datasync},
{no_more,500}
]),
@@ -679,13 +681,10 @@ sync(Config) ->
%% triggered by the idle timeout between "thrid" and "fourth".
timer:sleep(?IDLE_DETECT_TIME_MSEC*2),
start_tracer([{logger_std_h, write_to_dev, 5},
- {logger_std_h, sync_dev, 4},
{file, datasync, 1}],
[{logger_std_h, write_to_dev, <<"third\n">>},
- {logger_std_h, sync_dev},
{file,datasync},
{logger_std_h, write_to_dev, <<"fourth\n">>},
- {logger_std_h, sync_dev},
{file,datasync}]),
logger:notice("third", ?domain),
%% wait for automatic filesync
@@ -697,10 +696,10 @@ sync(Config) ->
%% switch repeated filesync on and verify that the looping works
SyncInt = 1000,
WaitT = 4500,
- OneSync = {logger_std_h,handle_cast,repeated_filesync},
- %% receive 1 initial repeated_filesync, then 1 per sec
- start_tracer([{logger_std_h,handle_cast,2}],
- [OneSync || _ <- lists:seq(1, 1 + trunc(WaitT/SyncInt))]),
+ OneSync = {logger_h_common,handle_cast,repeated_filesync},
+ %% receive 1 repeated_filesync per sec
+ start_tracer([{logger_h_common,handle_cast,2}],
+ [OneSync || _ <- lists:seq(1, trunc(WaitT/SyncInt))]),
ok = logger:update_handler_config(?MODULE, config,
#{filesync_repeat_interval => SyncInt}),
@@ -1257,6 +1256,22 @@ handler_requests_under_load(Config) ->
handler_requests_under_load(cleanup, _Config) ->
ok = stop_handler(?MODULE).
+recreate_deleted_log(Config) ->
+ {Log,_HConfig,_StdHConfig} =
+ start_handler(?MODULE, ?FUNCTION_NAME, Config),
+ logger:notice("first",?domain),
+ logger_std_h:filesync(?MODULE),
+ ok = file:rename(Log,Log++".old"),
+ logger:notice("second",?domain),
+ logger_std_h:filesync(?MODULE),
+ {ok,<<"first\n">>} = file:read_file(Log++".old"),
+ {ok,<<"second\n">>} = file:read_file(Log),
+ ok.
+recreate_deleted_log(cleanup, _Config) ->
+ ok = stop_handler(?MODULE).
+
+%%%-----------------------------------------------------------------
+%%%
send_requests(HName, TO, Reqs = [{Req,Res}|Rs]) ->
receive
{From,finish} ->
@@ -1278,8 +1293,8 @@ send_requests(HName, TO, Reqs = [{Req,Res}|Rs]) ->
%%%-----------------------------------------------------------------
%%%
-start_handler(Name, TTY, Config) when TTY == standard_io;
- TTY == standard_error->
+start_handler(Name, TTY, _Config) when TTY == standard_io;
+ TTY == standard_error->
ok = logger:add_handler(Name,
logger_std_h,
#{config => #{type => TTY},
@@ -1533,7 +1548,7 @@ start_op_trace() ->
{ok,_} = dbg:p(self(), [c]),
MS1 = dbg:fun2ms(fun([_]) -> return_trace() end),
- {ok,_} = dbg:tp(logger_h_common, check_load, 1, MS1),
+ {ok,_} = dbg:tpl(logger_h_common, check_load, 1, MS1),
{ok,_} = dbg:tpl(logger_h_common, flush_log_requests, 2, []),
@@ -1607,7 +1622,9 @@ analyse(Msgs) ->
start_tracer(Trace,Expected) ->
Pid = self(),
- FileCtrlPid = maps:get(file_ctrl_pid, logger_std_h:info(?MODULE)),
+ FileCtrlPid = maps:get(file_ctrl_pid,
+ maps:get(handler_state,
+ logger_std_h:info(?MODULE))),
dbg:tracer(process,{fun tracer/2,{Pid,Expected}}),
dbg:p(whereis(h_proc_name()),[c]),
dbg:p(FileCtrlPid,[c]),
@@ -1628,7 +1645,7 @@ tpl([{M,F,A}|Trace]) ->
tpl([]) ->
ok.
-tracer({trace,_,call,{logger_std_h,handle_cast,[Op|_]}},
+tracer({trace,_,call,{logger_h_common,handle_cast,[Op|_]}},
{Pid,[{Mod,Func,Op}|Expected]}) ->
maybe_tracer_done(Pid,Expected,{Mod,Func,Op});
tracer({trace,_,call,{Mod=logger_std_h,Func=write_to_dev,[_,Data,_,_,_]}},
diff --git a/lib/kernel/test/sendfile_SUITE.erl b/lib/kernel/test/sendfile_SUITE.erl
index 0c0b1cbcb6..ad060aa05c 100644
--- a/lib/kernel/test/sendfile_SUITE.erl
+++ b/lib/kernel/test/sendfile_SUITE.erl
@@ -341,7 +341,21 @@ t_sendfile_closeduring(Config) ->
-1
end,
- ok = sendfile_send({127,0,0,1}, Send, 0).
+ ok = sendfile_send({127,0,0,1}, Send, 0, [{active,false}]),
+ [] = flush(),
+ ok = sendfile_send({127,0,0,1}, Send, 0, [{active,true}]),
+ [] = flush(),
+ ok.
+
+flush() ->
+ lists:reverse(flush([])).
+
+flush(Acc) ->
+ receive M ->
+ flush([M | Acc])
+ after 0 ->
+ Acc
+ end.
t_sendfile_crashduring(Config) ->
Filename = proplists:get_value(big_file, Config),
@@ -409,12 +423,16 @@ sendfile_send(Send) ->
sendfile_send(Host, Send) ->
sendfile_send(Host, Send, []).
sendfile_send(Host, Send, Orig) ->
+ sendfile_send(Host, Send, Orig, [{active,false}]).
+
+sendfile_send(Host, Send, Orig, SockOpts) ->
+
SFServer = spawn_link(?MODULE, sendfile_server, [self(), Orig]),
receive
{server, Port} ->
- {ok, Sock} = gen_tcp:connect(Host, Port,
- [binary,{packet,0},
- {active,false}]),
+ Opts = [binary,{packet,0}|SockOpts],
+ io:format("connect with opts = ~p\n", [Opts]),
+ {ok, Sock} = gen_tcp:connect(Host, Port, Opts),
Data = case proplists:get_value(arity,erlang:fun_info(Send)) of
1 ->
Send(Sock);
diff --git a/lib/kernel/test/seq_trace_SUITE.erl b/lib/kernel/test/seq_trace_SUITE.erl
index 3bbf62e832..663f910751 100644
--- a/lib/kernel/test/seq_trace_SUITE.erl
+++ b/lib/kernel/test/seq_trace_SUITE.erl
@@ -28,7 +28,8 @@
-export([token_set_get/1, tracer_set_get/1, print/1,
send/1, distributed_send/1, recv/1, distributed_recv/1,
trace_exit/1, distributed_exit/1, call/1, port/1,
- match_set_seq_token/1, gc_seq_token/1, label_capability_mismatch/1]).
+ match_set_seq_token/1, gc_seq_token/1, label_capability_mismatch/1,
+ send_literal/1]).
%% internal exports
-export([simple_tracer/2, one_time_receiver/0, one_time_receiver/1,
@@ -47,7 +48,7 @@ suite() ->
{timetrap,{minutes,1}}].
all() ->
- [token_set_get, tracer_set_get, print, send,
+ [token_set_get, tracer_set_get, print, send, send_literal,
distributed_send, recv, distributed_recv, trace_exit,
distributed_exit, call, port, match_set_seq_token,
gc_seq_token, label_capability_mismatch].
@@ -161,23 +162,51 @@ do_print(TsType) ->
{0,{print,_,_,[],print3}, Ts1}] = stop_tracer(2),
check_ts(TsType, Ts0),
check_ts(TsType, Ts1).
-
+
send(Config) when is_list(Config) ->
lists:foreach(fun do_send/1, ?TIMESTAMP_MODES).
do_send(TsType) ->
+ do_send(TsType, send).
+
+do_send(TsType, Msg) ->
seq_trace:reset_trace(),
start_tracer(),
Receiver = spawn(?MODULE,one_time_receiver,[]),
Label = make_ref(),
seq_trace:set_token(label,Label),
set_token_flags([send, TsType]),
- Receiver ! send,
+ Receiver ! Msg,
Self = self(),
seq_trace:reset_trace(),
- [{Label,{send,_,Self,Receiver,send}, Ts}] = stop_tracer(1),
+ [{Label,{send,_,Self,Receiver,Msg}, Ts}] = stop_tracer(1),
check_ts(TsType, Ts).
+%% This testcase tests that we do not segfault when we have a
+%% literal as the message and the message is copied onto the
+%% heap during a GC.
+send_literal(Config) when is_list(Config) ->
+ lists:foreach(fun do_send_literal/1,
+ [atom, make_ref(), ets:new(hej,[]), 1 bsl 64,
+ "gurka", {tuple,test,with,#{}}, #{}]).
+
+do_send_literal(Msg) ->
+ N = 10000,
+ seq_trace:reset_trace(),
+ start_tracer(),
+ Label = make_ref(),
+ seq_trace:set_token(label,Label),
+ set_token_flags([send, 'receive', no_timestamp]),
+ Receiver = spawn_link(fun() -> receive ok -> ok end end),
+ [Receiver ! Msg || _ <- lists:seq(1, N)],
+ erlang:garbage_collect(Receiver),
+ [Receiver ! Msg || _ <- lists:seq(1, N)],
+ erlang:garbage_collect(Receiver),
+ Self = self(),
+ seq_trace:reset_trace(),
+ [{Label,{send,_,Self,Receiver,Msg}, Ts} | _] = stop_tracer(N),
+ check_ts(no_timestamp, Ts).
+
distributed_send(Config) when is_list(Config) ->
lists:foreach(fun do_distributed_send/1, ?TIMESTAMP_MODES).
diff --git a/lib/kernel/vsn.mk b/lib/kernel/vsn.mk
index df95174c9f..4b43c6ae9d 100644
--- a/lib/kernel/vsn.mk
+++ b/lib/kernel/vsn.mk
@@ -1 +1 @@
-KERNEL_VSN = 6.1
+KERNEL_VSN = 6.2