File 6865-kernel-Add-logger_handler-callbacks.patch of Package erlang

From 2afd6748f16ad226d0ae12b54e57e0147dafdbdd Mon Sep 17 00:00:00 2001
From: Lukas Larsson <lukas@erlang.org>
Date: Wed, 4 Oct 2023 13:59:22 +0200
Subject: [PATCH 05/10] kernel: Add logger_handler callbacks

We move the handler callbacks to a separate module so
that the documentation can live there and so that we
can use -behavior(logger_handler) which makes more sense
than -behaviour(logger).
---
 lib/kernel/doc/src/Makefile               |   1 +
 lib/kernel/doc/src/logger.xml             | 185 ++----------------
 lib/kernel/doc/src/logger_chapter.xml     |  16 +-
 lib/kernel/doc/src/logger_handler.xml     | 224 ++++++++++++++++++++++
 lib/kernel/doc/src/ref_man.xml            |   1 +
 lib/kernel/doc/src/specs.xml              |   1 +
 lib/kernel/src/Makefile                   |   8 +-
 lib/kernel/src/error_logger.erl           |   8 +-
 lib/kernel/src/kernel.app.src             |   1 +
 lib/kernel/src/logger.erl                 |  93 ++++-----
 lib/kernel/src/logger_disk_log_h.erl      |   4 +-
 lib/kernel/src/logger_h_common.erl        |   4 +-
 lib/kernel/src/logger_handler.erl         |  61 ++++++
 lib/kernel/src/logger_handler_watcher.erl |   2 +-
 lib/kernel/src/logger_simple_h.erl        |   2 +
 lib/kernel/src/logger_std_h.erl           |  16 +-
 16 files changed, 369 insertions(+), 258 deletions(-)
 create mode 100644 lib/kernel/doc/src/logger_handler.xml
 create mode 100644 lib/kernel/src/logger_handler.erl

diff --git a/lib/kernel/doc/src/Makefile b/lib/kernel/doc/src/Makefile
index a9fd26904a..143a841f3b 100644
--- a/lib/kernel/doc/src/Makefile
+++ b/lib/kernel/doc/src/Makefile
@@ -59,6 +59,7 @@ XML_REF3_FILES = application.xml \
         logger_disk_log_h.xml \
         logger_filters.xml \
         logger_formatter.xml \
+        logger_handler.xml \
 	net.xml \
 	net_adm.xml \
 	net_kernel.xml \
diff --git a/lib/kernel/doc/src/logger.xml b/lib/kernel/doc/src/logger.xml
index 0c2a963e6e..ceafb8e0df 100644
--- a/lib/kernel/doc/src/logger.xml
+++ b/lib/kernel/doc/src/logger.xml
@@ -134,40 +134,21 @@ logger:error("error happened because: ~p", [Reason]). % Without macro
     <datatype>
       <name name="handler_config"/>
       <desc>
-	<p>Handler configuration data for Logger. The following
-	  default values apply:</p>
-	<list>
-	  <item><c>level => all</c></item>
-	  <item><c>filter_default => log</c></item>
-	  <item><c>filters => []</c></item>
-	  <item><c>formatter => {logger_formatter, DefaultFormatterConfig</c>}</item>
-	</list>
-	<p>In addition to these, the following fields are
-	  automatically inserted by Logger, values taken from the
-	  two first parameters
-	  to <seemfa marker="#add_handler/3"><c>add_handler/3</c></seemfa>:</p>
-	<list>
-	  <item><c>id => HandlerId</c></item>
-	  <item><c>module => Module</c></item>
-	</list>
-	<p>These are read-only and cannot be changed in runtime.</p>
-	<p>Handler specific configuration data is inserted by the
-	  handler callback itself, in a sub structure associated with
-	  the field named <c>config</c>. See
-	  the <seeerl marker="logger_std_h"><c>logger_std_h(3)</c></seeerl>
-	  and <seeerl marker="logger_disk_log_h"><c>logger_disk_log_h(3)</c></seeerl>
-	  manual pages for information about the specific configuration
-	  for these handlers.</p>
-	<p>See the <seetype marker="logger_formatter#config">
-	    <c>logger_formatter(3)</c></seetype> manual page for
-	  information about the default configuration for this
-	  formatter.</p>
+	  <p>Handler configuration data for Logger.</p>
+          <note>
+              <p>DEPRECATED: Use <seetype marker="logger_handler#config"><c>logger_handler:config()</c></seetype> instead.
+              </p>
+          </note>
       </desc>
     </datatype>
     <datatype>
       <name name="handler_id"/>
       <desc>
-	<p>A unique identifier for a handler instance.</p>
+	  <p>A unique identifier for a handler instance.</p>
+          <note>
+              <p>DEPRECATED: Use <seetype marker="logger_handler#id"><c>logger_handler:id()</c></seetype> instead.
+              </p>
+          </note>
       </desc>
     </datatype>
     <datatype>
@@ -837,8 +818,8 @@ start(_, []) ->
 	  the rest, use <seemfa marker="#update_handler_config/3">
 	    <c>update_handler_config/3</c></seemfa>.</p>
 	<p>See the definition of
-	  the <seetype marker="#handler_config">
-	    <c>handler_config()</c></seetype> type for more
+	  the <seetype marker="logger_handler#config">
+	    <c>logger_handler:config()</c></seetype> type for more
 	  information about the different parameters.</p>
       </desc>
     </func>
@@ -1073,8 +1054,8 @@ logger:set_handler_config(HandlerId, maps:merge(Old, Config)).
 	  use <seemfa marker="#set_handler_config/3">
 	    <c>set_handler_config/3</c></seemfa>.</p>
 	<p>See the definition of
-	  the <seetype marker="#handler_config">
-	    <c>handler_config()</c></seetype> type for more
+	  the <seetype marker="logger_handler#config">
+	    <c>logger_handler:config()</c></seetype> type for more
 	  information about the different parameters.</p>
       </desc>
     </func>
@@ -1134,7 +1115,6 @@ logger:set_proxy_config(maps:merge(Old, Config)).
     </func>
   </funcs>
 
- 
   <funcs>
     <fsdescription>
       <marker id="misc_API"/>
@@ -1203,142 +1183,6 @@ logger:set_proxy_config(maps:merge(Old, Config)).
 
   </funcs>
 
- 
-
-  <funcs>
-    <fsdescription>
-      <marker id="handler_callback_functions"/>
-      <title>Handler Callback Functions</title>
-      <p>The following functions are to be exported from a handler
-        callback module.</p>
-    </fsdescription>
-    <func>
-      <name since="OTP 21.0">Module:adding_handler(Config1) -> {ok, Config2} | {error,
-	Reason}</name>
-      <fsummary>An instance of this handler is about to be added.</fsummary>
-      <type>
-	<v>Config1 = Config2 =
-	  <seetype marker="#handler_config">handler_config()</seetype></v>
-	<v>Reason = term()</v>
-      </type>
-      <desc>
-	<p>This callback function is optional.</p>
-	<p>The function is called on a temporary process when a new
-	  handler is about to be added. The purpose is to verify the
-	  configuration and initiate all resources needed by the
-	  handler.</p>
-	<p>The handler identity is associated with the <c>id</c> key
-	  in <c>Config1</c>.</p>
-	<p>If everything succeeds, the callback function can add
-	  possible default values or internal state values to the
-	  configuration, and return the adjusted map
-	  in <c>{ok,Config2}</c>.</p>
-	<p>If the configuration is faulty, or if the initiation fails,
-	  the callback function must return <c>{error,Reason}</c>.</p>
-      </desc>
-    </func>
-
-    <func>
-      <name since="OTP 21.2">Module: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>
-	<v>OldConfig = NewConfig = Config =
-	  <seetype marker="#handler_config">handler_config()</seetype></v>
-	<v>Reason = term()</v>
-      </type>
-      <desc>
-	<p>This callback function is optional.</p>
-	<p>The function is called on a temporary process when the
-	  configuration for a handler is about to change. The purpose
-	  is to verify and act on the new configuration.</p>
-	<p><c>OldConfig</c> is the existing configuration
-	  and <c>NewConfig</c> is the new configuration.</p>
-	<p>The handler identity is associated with the <c>id</c> key
-	  in <c>OldConfig</c>.</p>
-	<p><c>SetOrUpdate</c> has the value <c>set</c> if the
-	  configuration change originates from a call to
-	  <seemfa marker="#set_handler_config/2">
-	    <c>set_handler_config/2,3</c></seemfa>, and <c>update</c>
-	  if it originates from <seemfa marker="#update_handler_config/2">
-	    <c>update_handler_config/2,3</c></seemfa>. The handler can
-	  use this parameter to decide how to update the value of
-	  the <c>config</c> field, that is, the handler specific
-	  configuration data. Typically, if <c>SetOrUpdate</c>
-	  equals <c>set</c>, values that are not specified must be
-	  given their default values. If <c>SetOrUpdate</c>
-	  equals <c>update</c>, the values found in <c>OldConfig</c>
-	  must be used instead.</p>
-	<p>If everything succeeds, the callback function must return a
-	  possibly adjusted configuration in <c>{ok,Config}</c>.</p>
-	<p>If the configuration is faulty, the callback function must
-	  return <c>{error,Reason}</c>.</p>
-      </desc>
-    </func>
-
-    <func>
-      <name since="OTP 21.2">Module:filter_config(Config) -> FilteredConfig</name>
-      <fsummary>Remove internal data from configuration.</fsummary>
-      <type>
-	<v>Config = FilteredConfig =
-	  <seetype marker="#handler_config">handler_config()</seetype></v>
-      </type>
-      <desc>
-	<p>This callback function is optional.</p>
-	<p>The function is called when one of the Logger API functions
-	  for fetching the handler configuration is called, for
-	  example
-	  <seemfa marker="#get_handler_config/1">
-	    <c>logger:get_handler_config/1</c></seemfa>.</p>
-	<p>It allows the handler to remove internal data fields from
-	  its configuration data before it is returned to the
-	  caller.</p>
-      </desc>
-    </func>
-
-    <func>
-      <name since="OTP 21.0">Module:log(LogEvent, Config) -> void()</name>
-      <fsummary>Log the given log event.</fsummary>
-      <type>
-	<v>LogEvent =
-	  <seetype marker="#log_event">log_event()</seetype></v>
-	<v>Config =
-	  <seetype marker="#handler_config">handler_config()</seetype></v>
-      </type>
-      <desc>
-	<p>This callback function is mandatory.</p>
-	<p>The function is called when all primary filters and all
-	  handler filters for the handler in question have passed for
-	  the given log event. It is called on the client process, that
-	  is, the process that issued the log event.</p>
-	<p>The handler identity is associated with the <c>id</c> key
-	  in <c>Config</c>.</p>
-	<p>The handler must log the event.</p>
-	<p>The return value from this function is ignored by
-	  Logger.</p>
-      </desc>
-    </func>
-
-    <func>
-      <name since="OTP 21.0">Module:removing_handler(Config) -> ok</name>
-      <fsummary>The given handler is about to be removed.</fsummary>
-      <type>
-	<v>Config =
-	  <seetype marker="#handler_config">handler_config()</seetype></v>
-      </type>
-      <desc>
-	<p>This callback function is optional.</p>
-	<p>The function is called on a temporary process when a
-	  handler is about to be removed. The purpose is to release
-	  all resources used by the handler.</p>
-	<p>The handler identity is associated with the <c>id</c> key
-	  in <c>Config</c>.</p>
-	<p>The return value is ignored by Logger.</p>
-      </desc>
-    </func>
-
-  </funcs>
-
   <section>
     <title>See Also</title>
     <p>
@@ -1347,6 +1191,7 @@ logger:set_proxy_config(maps:merge(Old, Config)).
       <seeerl marker="stdlib:io"><c>io(3)</c></seeerl>,
       <seeerl marker="logger_disk_log_h"><c>logger_disk_log_h(3)</c></seeerl>,
       <seeerl marker="logger_filters"><c>logger_filters(3)</c></seeerl>,
+      <seeerl marker="logger_handler"><c>logger_handler(3)</c></seeerl>,
       <seeerl marker="logger_formatter"><c>logger_formatter(3)</c></seeerl>,
       <seeerl marker="logger_std_h"><c>logger_std_h(3)</c></seeerl>,
       <seeerl marker="stdlib:unicode"><c>unicode(3)</c></seeerl>
diff --git a/lib/kernel/doc/src/logger_chapter.xml b/lib/kernel/doc/src/logger_chapter.xml
index d35cef3465..302666cc3e 100644
--- a/lib/kernel/doc/src/logger_chapter.xml
+++ b/lib/kernel/doc/src/logger_chapter.xml
@@ -390,7 +390,7 @@ logger:debug(#{got => connection_request, id => Id, state => State},
     <p>A handler is defined as a module exporting at least the
       following callback function:</p>
 
-    <pre><seemfa marker="logger#Module:log/2">log(LogEvent, Config) -> void()</seemfa></pre>
+    <pre><seemfa marker="logger_handler#Module:log/2">log(LogEvent, Config) -> void()</seemfa></pre>
 
     <p>This function is called when a log event has passed through all
       primary filters, and all handler filters attached to the handler
@@ -408,9 +408,8 @@ logger:debug(#{got => connection_request, id => Id, state => State},
       handler module can export the optional callback
       functions <c>adding_handler/1</c>, <c>changing_config/3</c>,
       <c>filter_config/1</c>, and <c>removing_handler/1</c>. See
-      section <seeerl marker="logger#handler_callback_functions">Handler
-      Callback Functions</seeerl> in the logger(3) manual page for
-      more information about these function.</p>
+      <seeerl marker="logger_handler">logger_handler(3)</seeerl>
+      for more information about these function.</p>
 
     <p>The following built-in handlers exist:</p>
 
@@ -453,7 +452,7 @@ logger:debug(#{got => connection_request, id => Id, state => State},
       handler's destination. The handler callback receives the
       formatter information as part of the handler configuration,
       which is passed as the second argument
-      to <seemfa marker="logger#Module:log/2">
+      to <seemfa marker="logger_handler#Module:log/2">
 	<c>HModule:log/2</c></seemfa>.</p>
     <p>The formatter information consist of a formatter
       module, <c>FModule</c> and its
@@ -594,8 +593,8 @@ logger:debug(#{got => connection_request, id => Id, state => State},
       </list>
       <p>The configuration for a handler is a map with the following keys:</p>
       <taglist>
-	<tag><c>id = </c><seetype marker="logger#handler_id">
-	    <c>logger:handler_id()</c></seetype></tag>
+	<tag><c>id = </c><seetype marker="logger_handler#id">
+	    <c>logger_handler:id()</c></seetype></tag>
 	<item>
 	  <p>Automatically inserted by Logger. The value is the same
 	    as the <c>HandlerId</c> specified when adding the handler,
@@ -1062,8 +1061,7 @@ ok</pre>
 
   <section>
     <title>Example: Implement a handler</title>
-    <p>Section <seeerl marker="logger#handler_callback_functions">Handler
-	Callback Functions</seeerl> in the logger(3) manual page
+    <p><seeerl marker="logger_handler">logger_handler(3)</seeerl>
 	describes the callback functions that can be implemented for a
 	Logger handler.</p>
     <p>A handler callback module must export:</p>
diff --git a/lib/kernel/doc/src/logger_handler.xml b/lib/kernel/doc/src/logger_handler.xml
new file mode 100644
index 0000000000..204a2a2244
--- /dev/null
+++ b/lib/kernel/doc/src/logger_handler.xml
@@ -0,0 +1,224 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!DOCTYPE erlref SYSTEM "erlref.dtd">
+
+<erlref>
+  <header>
+    <copyright>
+      <year>2023</year><year>2023</year>
+      <holder>Ericsson AB. All Rights Reserved.</holder>
+    </copyright>
+    <legalnotice>
+      Licensed under the Apache License, Version 2.0 (the "License");
+      you may not use this file except in compliance with the License.
+      You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+      Unless required by applicable law or agreed to in writing, software
+      distributed under the License is distributed on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+      See the License for the specific language governing permissions and
+      limitations under the License.
+
+    </legalnotice>
+
+    <title>logger_handler</title>
+    <prepared></prepared>
+    <responsible></responsible>
+    <docno></docno>
+    <approved></approved>
+    <checked></checked>
+    <date></date>
+    <rev>A</rev>
+    <file>logger_handler.xml</file>
+  </header>
+  <module since="OTP @OTP-XYZ@">logger_handler</module>
+  <modulesummary>logger_handler behavior module.</modulesummary>
+
+  <description>
+      <p>The behaviour module for logger handlers. A logger handler
+        is a callback module that is called when a log event has passed
+        all filters and is ready to be logged somewhere. For more information
+        see <seeguide marker="logger_chapter#handlers">Handlers</seeguide> in
+        the Users Guide.</p>
+  </description>
+
+  <datatypes>
+    <datatype>
+      <name name="config"/>
+      <desc>
+	<p>Handler configuration data for Logger. The following
+	  default values apply:</p>
+	<list>
+	  <item><c>level => all</c></item>
+	  <item><c>filter_default => log</c></item>
+	  <item><c>filters => []</c></item>
+	  <item><c>formatter => {logger_formatter, DefaultFormatterConfig</c>}</item>
+	</list>
+	<p>In addition to these, the following fields are
+	  automatically inserted by Logger, values taken from the
+	  two first parameters
+	  to <seemfa marker="logger#add_handler/3"><c>logger:add_handler/3</c></seemfa>:</p>
+	<list>
+	  <item><c>id => HandlerId</c></item>
+	  <item><c>module => Module</c></item>
+	</list>
+	<p>These are read-only and cannot be changed in runtime.</p>
+	<p>Handler specific configuration data is inserted by the
+	  handler callback itself, in a sub structure associated with
+	  the field named <c>config</c>. See
+	  the <seeerl marker="logger_std_h"><c>logger_std_h(3)</c></seeerl>
+	  and <seeerl marker="logger_disk_log_h"><c>logger_disk_log_h(3)</c></seeerl>
+	  manual pages for information about the specific configuration
+	  for these handlers.</p>
+	<p>See the <seetype marker="logger_formatter#config">
+	    <c>logger_formatter(3)</c></seetype> manual page for
+	  information about the default configuration for this
+	  formatter.</p>
+      </desc>
+    </datatype>
+    <datatype>
+      <name name="id"/>
+      <desc>
+	<p>A unique identifier for a handler instance.</p>
+      </desc>
+    </datatype>
+  </datatypes>
+
+  <funcs>
+    <func>
+      <name since="OTP 21.0">Module:adding_handler(Config1) -> {ok, Config2} | {error,
+	Reason}</name>
+      <fsummary>An instance of this handler is about to be added.</fsummary>
+      <type>
+	<v>Config1 = Config2 =
+	  <seetype marker="#config">config()</seetype></v>
+	<v>Reason = term()</v>
+      </type>
+      <desc>
+	<p>This callback function is optional.</p>
+	<p>The function is called on a temporary process when a new
+	  handler is about to be added. The purpose is to verify the
+	  configuration and initiate all resources needed by the
+	  handler.</p>
+	<p>The handler identity is associated with the <c>id</c> key
+	  in <c>Config1</c>.</p>
+	<p>If everything succeeds, the callback function can add
+	  possible default values or internal state values to the
+	  configuration, and return the adjusted map
+	  in <c>{ok,Config2}</c>.</p>
+	<p>If the configuration is faulty, or if the initiation fails,
+	  the callback function must return <c>{error,Reason}</c>.</p>
+      </desc>
+    </func>
+
+    <func>
+      <name since="OTP 21.2">Module: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>
+	<v>OldConfig = NewConfig = Config =
+	  <seetype marker="#config">config()</seetype></v>
+	<v>Reason = term()</v>
+      </type>
+      <desc>
+	<p>This callback function is optional.</p>
+	<p>The function is called on a temporary process when the
+	  configuration for a handler is about to change. The purpose
+	  is to verify and act on the new configuration.</p>
+	<p><c>OldConfig</c> is the existing configuration
+	  and <c>NewConfig</c> is the new configuration.</p>
+	<p>The handler identity is associated with the <c>id</c> key
+	  in <c>OldConfig</c>.</p>
+	<p><c>SetOrUpdate</c> has the value <c>set</c> if the
+	  configuration change originates from a call to
+	  <seemfa marker="logger#set_handler_config/2">
+	    <c>logger:set_handler_config/2,3</c></seemfa>, and <c>update</c>
+	  if it originates from <seemfa marker="logger#update_handler_config/2">
+	    <c>logger:update_handler_config/2,3</c></seemfa>. The handler can
+	  use this parameter to decide how to update the value of
+	  the <c>config</c> field, that is, the handler specific
+	  configuration data. Typically, if <c>SetOrUpdate</c>
+	  equals <c>set</c>, values that are not specified must be
+	  given their default values. If <c>SetOrUpdate</c>
+	  equals <c>update</c>, the values found in <c>OldConfig</c>
+	  must be used instead.</p>
+	<p>If everything succeeds, the callback function must return a
+	  possibly adjusted configuration in <c>{ok,Config}</c>.</p>
+	<p>If the configuration is faulty, the callback function must
+	  return <c>{error,Reason}</c>.</p>
+      </desc>
+    </func>
+
+    <func>
+      <name since="OTP 21.2">Module:filter_config(Config) -> FilteredConfig</name>
+      <fsummary>Remove internal data from configuration.</fsummary>
+      <type>
+	<v>Config = FilteredConfig =
+	  <seetype marker="#config">config()</seetype></v>
+      </type>
+      <desc>
+	<p>This callback function is optional.</p>
+	<p>The function is called when one of the Logger API functions
+	  for fetching the handler configuration is called, for
+	  example
+	  <seemfa marker="logger#get_handler_config/1">
+	    <c>logger:get_handler_config/1</c></seemfa>.</p>
+	<p>It allows the handler to remove internal data fields from
+	  its configuration data before it is returned to the
+	  caller.</p>
+      </desc>
+    </func>
+
+    <func>
+      <name since="OTP 21.0">Module:log(LogEvent, Config) -> void()</name>
+      <fsummary>Log the given log event.</fsummary>
+      <type>
+	<v>LogEvent =
+	  <seetype marker="logger#log_event">logger:log_event()</seetype></v>
+	<v>Config =
+	  <seetype marker="#config">config()</seetype></v>
+      </type>
+      <desc>
+	<p>This callback function is mandatory.</p>
+	<p>The function is called when all primary filters and all
+	  handler filters for the handler in question have passed for
+	  the given log event. It is called on the client process, that
+	  is, the process that issued the log event.</p>
+	<p>The handler identity is associated with the <c>id</c> key
+	  in <c>Config</c>.</p>
+	<p>The handler must log the event.</p>
+	<p>The return value from this function is ignored by
+	  Logger.</p>
+      </desc>
+    </func>
+
+    <func>
+      <name since="OTP 21.0">Module:removing_handler(Config) -> ok</name>
+      <fsummary>The given handler is about to be removed.</fsummary>
+      <type>
+	<v>Config =
+	  <seetype marker="#config">config()</seetype></v>
+      </type>
+      <desc>
+	<p>This callback function is optional.</p>
+	<p>The function is called on a temporary process when a
+	  handler is about to be removed. The purpose is to release
+	  all resources used by the handler.</p>
+	<p>The handler identity is associated with the <c>id</c> key
+	  in <c>Config</c>.</p>
+	<p>The return value is ignored by Logger.</p>
+      </desc>
+    </func>
+
+  </funcs>
+
+  <section>
+    <title>See Also</title>
+    <p>
+      <seeerl marker="logger_filters"><c>logger_filters(3)</c></seeerl>,
+      <seeerl marker="logger_formatter"><c>logger_formatter(3)</c></seeerl>,
+      <seeerl marker="logger"><c>logger(3)</c></seeerl>
+    </p>
+  </section>
+</erlref>
diff --git a/lib/kernel/doc/src/ref_man.xml b/lib/kernel/doc/src/ref_man.xml
index 39973158d6..05c022e4ea 100644
--- a/lib/kernel/doc/src/ref_man.xml
+++ b/lib/kernel/doc/src/ref_man.xml
@@ -59,6 +59,7 @@
   <xi:include href="logger.xml"/>
   <xi:include href="logger_filters.xml"/>
   <xi:include href="logger_formatter.xml"/>
+  <xi:include href="logger_handler.xml"/>
   <xi:include href="logger_std_h.xml"/>
   <xi:include href="logger_disk_log_h.xml"/>
   <xi:include href="net.xml"/>
diff --git a/lib/kernel/doc/src/specs.xml b/lib/kernel/doc/src/specs.xml
index fd3877d9a8..ec7f0af552 100644
--- a/lib/kernel/doc/src/specs.xml
+++ b/lib/kernel/doc/src/specs.xml
@@ -25,6 +25,7 @@
   <xi:include href="../specs/specs_logger.xml"/>
   <xi:include href="../specs/specs_logger_filters.xml"/>
   <xi:include href="../specs/specs_logger_formatter.xml"/>
+  <xi:include href="../specs/specs_logger_handler.xml"/>
   <xi:include href="../specs/specs_logger_std_h.xml"/>
   <xi:include href="../specs/specs_logger_disk_log_h.xml"/>
   <xi:include href="../specs/specs_net.xml"/>
diff --git a/lib/kernel/src/Makefile b/lib/kernel/src/Makefile
index 929f1d2c4e..8ac4768674 100644
--- a/lib/kernel/src/Makefile
+++ b/lib/kernel/src/Makefile
@@ -119,6 +119,7 @@ MODULES = \
         logger \
         logger_backend \
         logger_config \
+	logger_handler \
 	logger_handler_watcher \
 	logger_std_h \
 	logger_disk_log_h \
@@ -185,6 +186,7 @@ APPUP_TARGET= $(EBIN)/$(APPUP_FILE)
 
 ERL_COMPILE_FLAGS += -Werror
 ERL_COMPILE_FLAGS += -I../include
+ERL_COMPILE_FLAGS += -pa ../ebin
 
 
 # ----------------------------------------------------
@@ -283,14 +285,14 @@ $(EBIN)/local_tcp.beam: inet_int.hrl
 $(EBIN)/logger.beam: logger_internal.hrl ../include/logger.hrl
 $(EBIN)/logger_backend.beam: logger_internal.hrl ../include/logger.hrl
 $(EBIN)/logger_config.beam: logger_internal.hrl ../include/logger.hrl
-$(EBIN)/logger_disk_log_h.beam: logger_h_common.hrl logger_internal.hrl ../include/logger.hrl ../include/file.hrl
+$(EBIN)/logger_disk_log_h.beam: $(EBIN)/logger_handler.beam logger_h_common.hrl logger_internal.hrl ../include/logger.hrl ../include/file.hrl
 $(EBIN)/logger_filters.beam: logger_internal.hrl ../include/logger.hrl
 $(EBIN)/logger_formatter.beam: logger_internal.hrl ../include/logger.hrl
 $(EBIN)/logger_olp.beam: logger_olp.hrl logger_internal.hrl
 $(EBIN)/logger_proxy.beam: logger_internal.hrl
 $(EBIN)/logger_server.beam: logger_internal.hrl ../include/logger.hrl
-$(EBIN)/logger_simple_h.beam: logger_internal.hrl ../include/logger.hrl
-$(EBIN)/logger_std_h.beam: logger_h_common.hrl logger_internal.hrl ../include/logger.hrl ../include/file.hrl
+$(EBIN)/logger_simple_h.beam: $(EBIN)/logger_handler.beam logger_internal.hrl ../include/logger.hrl
+$(EBIN)/logger_std_h.beam: $(EBIN)/logger_handler.beam logger_h_common.hrl logger_internal.hrl ../include/logger.hrl ../include/file.hrl
 $(EBIN)/logger_h_common.beam: logger_h_common.hrl logger_internal.hrl ../include/logger.hrl
 $(EBIN)/net_kernel.beam: ../include/net_address.hrl
 $(EBIN)/os.beam: ../include/file.hrl
diff --git a/lib/kernel/src/error_logger.erl b/lib/kernel/src/error_logger.erl
index 829f28f00d..c243fa9fd3 100644
--- a/lib/kernel/src/error_logger.erl
+++ b/lib/kernel/src/error_logger.erl
@@ -106,8 +106,8 @@ stop() ->
 
 %%%-----------------------------------------------------------------
 %%% Callbacks for logger
--spec adding_handler(logger:handler_config()) ->
-                            {ok,logger:handler_config()} | {error,term()}.
+-spec adding_handler(logger_handler:config()) ->
+                            {ok,logger_handler:config()} | {error,term()}.
 adding_handler(#{id:=?MODULE}=Config) ->
     case start() of
         ok ->
@@ -116,12 +116,12 @@ adding_handler(#{id:=?MODULE}=Config) ->
             Error
     end.
 
--spec removing_handler(logger:handler_config()) -> ok.
+-spec removing_handler(logger_handler:config()) -> ok.
 removing_handler(#{id:=?MODULE}) ->
     stop(),
     ok.
 
--spec log(logger:log_event(),logger:handler_config()) -> ok.
+-spec log(logger:log_event(),logger_handler:config()) -> ok.
 log(#{level:=Level,msg:=Msg,meta:=Meta},_Config) ->
     do_log(Level,Msg,Meta).
 
diff --git a/lib/kernel/src/kernel.app.src b/lib/kernel/src/kernel.app.src
index 4ae0fb6bb5..a06840ac1c 100644
--- a/lib/kernel/src/kernel.app.src
+++ b/lib/kernel/src/kernel.app.src
@@ -72,6 +72,7 @@
              logger_filters,
              logger_formatter,
              logger_h_common,
+             logger_handler,
              logger_handler_watcher,
              logger_olp,
              logger_proxy,
diff --git a/lib/kernel/src/logger.erl b/lib/kernel/src/logger.erl
index 83f7aeba2a..14f47ddf9b 100644
--- a/lib/kernel/src/logger.erl
+++ b/lib/kernel/src/logger.erl
@@ -103,7 +103,6 @@
 -type location() :: #{mfa  := {module(),atom(),non_neg_integer()},
                       file := file:filename(),
                       line := non_neg_integer()}.
--type handler_id() :: atom().
 -type filter_id() :: atom().
 -type filter() :: {fun((log_event(),filter_arg()) ->
                               filter_return()),filter_arg()}.
@@ -113,17 +112,10 @@
                             metadata => metadata(),
                             filter_default => log | stop,
                             filters => [{filter_id(),filter()}]}.
--type handler_config() :: #{id => handler_id(),
-                            config => term(),
-                            level => level() | all | none,
-                            module => module(),
-                            filter_default => log | stop,
-                            filters => [{filter_id(),filter()}],
-                            formatter => {module(),formatter_config()}}.
 -type timestamp() :: integer().
 -type formatter_config() :: #{atom() => term()}.
 
--type config_handler() :: {handler, handler_id(), module(), handler_config()}.
+-type config_handler() :: {handler, logger_handler:id(), module(), logger_handler:config()}.
 
 -type config_logger() :: [{handler,default,undefined} |
                           config_handler() |
@@ -142,6 +134,10 @@
                         overload_kill_restart_after =>
                             non_neg_integer() | infinity}.
 
+%% Kept for backwards compatibility
+-type handler_id() :: logger_handler:id().
+-type handler_config() :: logger_handler:config().
+
 -export_type([log_event/0,
               level/0,
               report/0,
@@ -161,31 +157,6 @@
               olp_config/0,
               timestamp/0]).
 
-%%%-----------------------------------------------------------------
-%%% Callbacks
--callback adding_handler(Config1) -> {ok, Config2} | {error, Reason} when
-      Config1 :: handler_config(),
-      Config2 :: handler_config(),
-      Reason :: term().
-
--callback changing_config(SetOrUpdate, OldConfig, NewConfig) ->
-    {ok, Config} | {error, Reason} when
-      SetOrUpdate :: set | update,
-      OldConfig :: handler_config(),
-      NewConfig :: handler_config(),
-      Config :: handler_config(),
-      Reason :: term().
-
--callback filter_config(Config) -> FilteredConfig when
-      Config :: handler_config(),
-      FilteredConfig :: handler_config().
-
--callback log(LogEvent, Config) -> term() when
-      LogEvent :: log_event(), Config :: handler_config().
-
--callback removing_handler(Config) -> ok when
-      Config :: handler_config().
-
 %%%-----------------------------------------------------------------
 %%% API
 emergency(X) ->
@@ -399,7 +370,7 @@ add_primary_filter(FilterId,Filter) ->
     logger_server:add_filter(primary,{FilterId,Filter}).
 
 -spec add_handler_filter(HandlerId,FilterId,Filter) -> ok | {error,term()} when
-      HandlerId :: handler_id(),
+      HandlerId :: logger_handler:id(),
       FilterId :: filter_id(),
       Filter :: filter().
 add_handler_filter(HandlerId,FilterId,Filter) ->
@@ -412,20 +383,20 @@ remove_primary_filter(FilterId) ->
     logger_server:remove_filter(primary,FilterId).
 
 -spec remove_handler_filter(HandlerId,FilterId) -> ok | {error,term()} when
-      HandlerId :: handler_id(),
+      HandlerId :: logger_handler:id(),
       FilterId :: filter_id().
 remove_handler_filter(HandlerId,FilterId) ->
     logger_server:remove_filter(HandlerId,FilterId).
 
 -spec add_handler(HandlerId,Module,Config) -> ok | {error,term()} when
-      HandlerId :: handler_id(),
+      HandlerId :: logger_handler:id(),
       Module :: module(),
-      Config :: handler_config().
+      Config :: logger_handler:config().
 add_handler(HandlerId,Module,Config) ->
     logger_server:add_handler(HandlerId,Module,Config).
 
 -spec remove_handler(HandlerId) -> ok | {error,term()} when
-      HandlerId :: handler_id().
+      HandlerId :: logger_handler:id().
 remove_handler(HandlerId) ->
     logger_server:remove_handler(HandlerId).
 
@@ -447,31 +418,31 @@ set_primary_config(Config) ->
 
 
 -spec set_handler_config(HandlerId,level,Level) -> Return when
-      HandlerId :: handler_id(),
+      HandlerId :: logger_handler:id(),
       Level :: level() | all | none,
       Return :: ok | {error,term()};
                         (HandlerId,filter_default,FilterDefault) -> Return when
-      HandlerId :: handler_id(),
+      HandlerId :: logger_handler:id(),
       FilterDefault :: log | stop,
       Return :: ok | {error,term()};
                         (HandlerId,filters,Filters) -> Return when
-      HandlerId :: handler_id(),
+      HandlerId :: logger_handler:id(),
       Filters :: [{filter_id(),filter()}],
       Return :: ok | {error,term()};
                         (HandlerId,formatter,Formatter) -> Return when
-      HandlerId :: handler_id(),
+      HandlerId :: logger_handler:id(),
       Formatter :: {module(), formatter_config()},
       Return :: ok | {error,term()};
                         (HandlerId,config,Config) -> Return when
-      HandlerId :: handler_id(),
+      HandlerId :: logger_handler:id(),
       Config :: term(),
       Return :: ok | {error,term()}.
 set_handler_config(HandlerId,Key,Value) ->
     logger_server:set_config(HandlerId,Key,Value).
 
 -spec set_handler_config(HandlerId,Config) -> ok | {error,term()} when
-      HandlerId :: handler_id(),
-      Config :: handler_config().
+      HandlerId :: logger_handler:id(),
+      Config :: logger_handler:config().
 set_handler_config(HandlerId,Config) ->
     logger_server:set_config(HandlerId,Config).
 
@@ -486,31 +457,31 @@ update_primary_config(Config) ->
     logger_server:update_config(primary,Config).
 
 -spec update_handler_config(HandlerId,level,Level) -> Return when
-      HandlerId :: handler_id(),
+      HandlerId :: logger_handler:id(),
       Level :: level() | all | none,
       Return :: ok | {error,term()};
                         (HandlerId,filter_default,FilterDefault) -> Return when
-      HandlerId :: handler_id(),
+      HandlerId :: logger_handler:id(),
       FilterDefault :: log | stop,
       Return :: ok | {error,term()};
                         (HandlerId,filters,Filters) -> Return when
-      HandlerId :: handler_id(),
+      HandlerId :: logger_handler:id(),
       Filters :: [{filter_id(),filter()}],
       Return :: ok | {error,term()};
                         (HandlerId,formatter,Formatter) -> Return when
-      HandlerId :: handler_id(),
+      HandlerId :: logger_handler:id(),
       Formatter :: {module(), formatter_config()},
       Return :: ok | {error,term()};
                         (HandlerId,config,Config) -> Return when
-      HandlerId :: handler_id(),
+      HandlerId :: logger_handler:id(),
       Config :: term(),
       Return :: ok | {error,term()}.
 update_handler_config(HandlerId,Key,Value) ->
     logger_server:update_config(HandlerId,Key,Value).
 
 -spec update_handler_config(HandlerId,Config) -> ok | {error,term()} when
-      HandlerId :: handler_id(),
-      Config :: handler_config().
+      HandlerId :: logger_handler:id(),
+      Config :: logger_handler:config().
 update_handler_config(HandlerId,Config) ->
     logger_server:update_config(HandlerId,Config).
 
@@ -526,8 +497,8 @@ get_primary_config() ->
     maps:remove(handlers,Config).
 
 -spec get_handler_config(HandlerId) -> {ok,Config} | {error,term()} when
-      HandlerId :: handler_id(),
-      Config :: handler_config().
+      HandlerId :: logger_handler:id(),
+      Config :: logger_handler:config().
 get_handler_config(HandlerId) ->
     case logger_config:get(?LOGGER_TABLE,HandlerId) of
         {ok,#{module:=Module}=Config} ->
@@ -539,7 +510,7 @@ get_handler_config(HandlerId) ->
     end.
 
 -spec get_handler_config() -> [Config] when
-      Config :: handler_config().
+      Config :: logger_handler:config().
 get_handler_config() ->
     [begin
          {ok,Config} = get_handler_config(HandlerId),
@@ -547,7 +518,7 @@ get_handler_config() ->
      end || HandlerId <- get_handler_ids()].
 
 -spec get_handler_ids() -> [HandlerId] when
-      HandlerId :: handler_id().
+      HandlerId :: logger_handler:id().
 get_handler_ids() ->
     {ok,#{handlers:=HandlerIds}} = logger_config:get(?LOGGER_TABLE,primary),
     HandlerIds.
@@ -560,14 +531,14 @@ get_proxy_config() ->
 
 -spec update_formatter_config(HandlerId,FormatterConfig) ->
                                      ok | {error,term()} when
-      HandlerId :: handler_id(),
+      HandlerId :: logger_handler:id(),
       FormatterConfig :: formatter_config().
 update_formatter_config(HandlerId,FormatterConfig) ->
     logger_server:update_formatter_config(HandlerId,FormatterConfig).
 
 -spec update_formatter_config(HandlerId,Key,Value) ->
                                      ok | {error,term()} when
-      HandlerId :: handler_id(),
+      HandlerId :: logger_handler:id(),
       Key :: atom(),
       Value :: term().
 update_formatter_config(HandlerId,Key,Value) ->
@@ -677,7 +648,7 @@ unset_process_metadata() ->
     ok.
 
 -spec get_config() -> #{primary=>primary_config(),
-                        handlers=>[handler_config()],
+                        handlers=>[logger_handler:config()],
                         proxy=>olp_config(),
                         module_levels=>[{module(),level() | all | none}]}.
 get_config() ->
@@ -699,7 +670,7 @@ i() ->
     i_modules(Modules,M).
 
 -spec i(What) -> ok when
-      What :: primary | handlers | proxy | modules | handler_id().
+      What :: primary | handlers | proxy | modules | logger_handler:id().
 i(primary) ->
     i_primary(get_primary_config(),modifier());
 i(handlers) ->
diff --git a/lib/kernel/src/logger_disk_log_h.erl b/lib/kernel/src/logger_disk_log_h.erl
index 2f386acbf3..ca209ace8e 100644
--- a/lib/kernel/src/logger_disk_log_h.erl
+++ b/lib/kernel/src/logger_disk_log_h.erl
@@ -26,6 +26,8 @@
 %%% API
 -export([filesync/1]).
 
+-behaviour(logger_handler).
+
 %% logger_h_common callbacks
 -export([init/2, check_config/4, reset_state/2,
          filesync/3, write/4, handle_info/3, terminate/3]).
@@ -70,7 +72,7 @@ removing_handler(Config) ->
 %%% Log a string or report
 -spec log(LogEvent,Config) -> ok when
       LogEvent :: logger:log_event(),
-      Config :: logger:handler_config().
+      Config :: logger_handler:config().
 
 log(LogEvent,Config) ->
     logger_h_common:log(LogEvent,Config).
diff --git a/lib/kernel/src/logger_h_common.erl b/lib/kernel/src/logger_h_common.erl
index 3c99d49f3d..99c258c40f 100644
--- a/lib/kernel/src/logger_h_common.erl
+++ b/lib/kernel/src/logger_h_common.erl
@@ -168,7 +168,7 @@ changing_config(SetOrUpdate,
 %%% Log a string or report
 -spec log(LogEvent, Config) -> ok when
       LogEvent :: logger:log_event(),
-      Config :: logger:handler_config().
+      Config :: logger_handler:config().
 
 log(LogEvent, Config = #{config := #{olp:=Olp}}) ->
     %% if the handler has crashed, we must drop this event
@@ -379,7 +379,7 @@ log_handler_info(Name, Format, Args, #{module:=Module,
 %%% Convert log data on any form to binary
 -spec log_to_binary(LogEvent,Config) -> LogString when
       LogEvent :: logger:log_event(),
-      Config :: logger:handler_config(),
+      Config :: logger_handler:config(),
       LogString :: binary().
 log_to_binary(#{msg:={report,_},meta:=#{report_cb:=_}}=Log,Config) ->
     do_log_to_binary(Log,Config);
diff --git a/lib/kernel/src/logger_handler.erl b/lib/kernel/src/logger_handler.erl
new file mode 100644
index 0000000000..f8aef0fe6e
--- /dev/null
+++ b/lib/kernel/src/logger_handler.erl
@@ -0,0 +1,61 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2023-2023. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%%     http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(logger_handler).
+
+%%%
+%%% Types
+-type config() :: #{id => id(),
+                    config => term(),
+                    level => logger:level() | all | none,
+                    module => module(),
+                    filter_default => log | stop,
+                    filters => [{logger:filter_id(),logger:filter()}],
+                    formatter => {module(),logger:formatter_config()}}.
+-type id() :: atom().
+
+-export_type([config/0, id/0]).
+
+%%%-----------------------------------------------------------------
+%%% Callbacks
+-callback adding_handler(Config1) -> {ok, Config2} | {error, Reason} when
+      Config1 :: config(),
+      Config2 :: config(),
+      Reason :: term().
+
+-callback changing_config(SetOrUpdate, OldConfig, NewConfig) ->
+    {ok, Config} | {error, Reason} when
+      SetOrUpdate :: set | update,
+      OldConfig :: config(),
+      NewConfig :: config(),
+      Config :: config(),
+      Reason :: term().
+
+-callback filter_config(Config) -> FilteredConfig when
+      Config :: config(),
+      FilteredConfig :: config().
+
+-callback log(LogEvent, Config) -> term() when
+      LogEvent :: logger:log_event(), Config :: config().
+
+-callback removing_handler(Config) -> ok when
+      Config :: config().
+
+-optional_callbacks([adding_handler/1, changing_config/3,
+                     filter_config/1, removing_handler/1]).
diff --git a/lib/kernel/src/logger_handler_watcher.erl b/lib/kernel/src/logger_handler_watcher.erl
index 6f622b169c..1e4cd4ce48 100644
--- a/lib/kernel/src/logger_handler_watcher.erl
+++ b/lib/kernel/src/logger_handler_watcher.erl
@@ -43,7 +43,7 @@
 start_link() ->
     gen_server:start_link({local, ?SERVER}, ?MODULE, [], []).
 
--spec register_handler(Id::logger:handler_id(),Pid::pid()) -> ok.
+-spec register_handler(Id :: logger_handler:id(), Pid :: pid()) -> ok.
 register_handler(Id,Pid) ->
     gen_server:call(?SERVER,{register,Id,Pid}).
 
diff --git a/lib/kernel/src/logger_simple_h.erl b/lib/kernel/src/logger_simple_h.erl
index d35c533b6d..cd677e505b 100644
--- a/lib/kernel/src/logger_simple_h.erl
+++ b/lib/kernel/src/logger_simple_h.erl
@@ -21,6 +21,8 @@
 
 -export([adding_handler/1, removing_handler/1, log/2]).
 
+-behaviour(logger_handler).
+
 %% This module implements a simple handler for logger. It is the
 %% default used during system start.
 
diff --git a/lib/kernel/src/logger_std_h.erl b/lib/kernel/src/logger_std_h.erl
index 1b2fabad72..d90f9b2acb 100644
--- a/lib/kernel/src/logger_std_h.erl
+++ b/lib/kernel/src/logger_std_h.erl
@@ -28,6 +28,8 @@
 %% API
 -export([filesync/1]).
 
+-behaviour(logger_handler).
+
 %% logger_h_common callbacks
 -export([init/2, check_config/4, config_changed/3, reset_state/2,
          filesync/3, write/4, handle_info/3, terminate/3]).
@@ -58,7 +60,7 @@ filesync(Name) ->
 %%%-----------------------------------------------------------------
 %%% Handler being added
 -spec adding_handler(Config) -> {ok,Config} | {error,Reason} when
-      Config :: logger:handler_config(),
+      Config :: logger_handler:config(),
       Reason :: term().
 
 adding_handler(Config) ->
@@ -69,9 +71,9 @@ adding_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(),
+      OldConfig :: logger_handler:config(),
+      NewConfig :: logger_handler:config(),
+      Config :: logger_handler:config(),
       Reason :: term().
 
 changing_config(SetOrUpdate, OldConfig, NewConfig) ->
@@ -80,7 +82,7 @@ changing_config(SetOrUpdate, OldConfig, NewConfig) ->
 %%%-----------------------------------------------------------------
 %%% Handler being removed
 -spec removing_handler(Config) -> ok when
-      Config :: logger:handler_config().
+      Config :: logger_handler:config().
 
 removing_handler(Config) ->
     logger_h_common:removing_handler(Config).
@@ -89,7 +91,7 @@ removing_handler(Config) ->
 %%% Log a string or report
 -spec log(LogEvent, Config) -> ok when
       LogEvent :: logger:log_event(),
-      Config :: logger:handler_config().
+      Config :: logger_handler:config().
 
 log(LogEvent, Config) ->
     logger_h_common:log(LogEvent, Config).
@@ -97,7 +99,7 @@ log(LogEvent, Config) ->
 %%%-----------------------------------------------------------------
 %%% Remove internal fields from configuration
 -spec filter_config(Config) -> Config when
-      Config :: logger:handler_config().
+      Config :: logger_handler:config().
 
 filter_config(Config) ->
     logger_h_common:filter_config(Config).
-- 
2.35.3

openSUSE Build Service is sponsored by