aboutsummaryrefslogtreecommitdiffstats
path: root/lib/kernel/doc/src/logger_chapter.xml
diff options
context:
space:
mode:
Diffstat (limited to 'lib/kernel/doc/src/logger_chapter.xml')
-rw-r--r--lib/kernel/doc/src/logger_chapter.xml1018
1 files changed, 640 insertions, 378 deletions
diff --git a/lib/kernel/doc/src/logger_chapter.xml b/lib/kernel/doc/src/logger_chapter.xml
index 4232429589..a3eec7bd4b 100644
--- a/lib/kernel/doc/src/logger_chapter.xml
+++ b/lib/kernel/doc/src/logger_chapter.xml
@@ -30,219 +30,403 @@
<file>logger_chapter.xml</file>
</header>
+ <p>Erlang/OTP 21.0 provides a new standard API for logging
+ through <c>Logger</c>, which is part of the Kernel
+ application. Logger consists of the API for issuing log events,
+ and a customizable backend where log handlers, filters and
+ formatters can be plugged in.</p>
+ <p>By default, the Kernel application installs one log handler at
+ system start. This handler is named <c>default</c>. It receives
+ and processes standard log events produced by the Erlang runtime
+ system, standard behaviours and different Erlang/OTP
+ applications. The log events are by default written to the
+ terminal.</p>
+ <p>You can also configure the system so that the default handler
+ prints log events to a single file, or to a set of wrap logs
+ via <seealso marker="disk_log"><c>disk_log</c></seealso>.</p>
+ <p>By confiugration, you can aslo modify or disable the default
+ handler, replace it by a custom handler, and install additional
+ handlers.</p>
+
<section>
<title>Overview</title>
- <p>Erlang/OTP provides a standard API for logging. The backend of
- this API can be used as is, or it can be customized to suite
- specific needs.</p>
- <p>It consists of two parts - the <em>logger</em> part and the
- <em>handler</em> part. The logger will forward log events to one
- or more handler(s).</p>
+ <p>A <em>log event</em> consists of a <em>log level</em>, the
+ <em>message</em> to be logged, and <em>metadata</em>.</p>
+ <p>The Logger backend forwards log events from the API, first
+ through a set of <em>global filters</em>, then through a set
+ of <em>handler filters</em> for each log handler.</p>
+ <p>Each filter set consists of a <em>log level check</em>,
+ followed by zero or more <em>filter functions</em>.</p>
+ <p>The following figure show a conseptual overview of Logger. The
+ figure shows two log handlers, but any number of handlers can be
+ installed.</p>
<image file="logger_arch.png">
- <icaption>Conceptual overview</icaption>
+ <icaption>Conceptual Overview</icaption>
</image>
- <p><em>Filters</em> can be added to the logger and to each
- handler. The filters decide if an event is to be forwarded or
- not, and they can also modify all parts of the log event.</p>
-
- <p>A <em>formatter</em> can be set for each handler. The formatter
- does the final formatting of the log event, including the log
- message itself, and possibly a timestamp, header and other
- metadata.</p>
-
- <p>In accordance with the Syslog protocol, RFC-5424, eight
- severity levels can be specified:</p>
-
- <table align="left">
- <row>
- <cell><strong>Level</strong></cell>
- <cell align="center"><strong>Integer</strong></cell>
- <cell><strong>Description</strong></cell>
- </row>
- <row>
- <cell>emergency</cell>
- <cell align="center">0</cell>
- <cell>system is unusable</cell>
- </row>
- <row>
- <cell>alert</cell>
- <cell align="center">1</cell>
- <cell>action must be taken immediately</cell>
- </row>
- <row>
- <cell>critical</cell>
- <cell align="center">2</cell>
- <cell>critical contidions</cell>
- </row>
- <row>
- <cell>error</cell>
- <cell align="center">3</cell>
- <cell>error conditions</cell>
- </row>
- <row>
- <cell>warning</cell>
- <cell align="center">4</cell>
- <cell>warning conditions</cell>
- </row>
- <row>
- <cell>notice</cell>
- <cell align="center">5</cell>
- <cell>normal but significant conditions</cell>
- </row>
- <row>
- <cell>info</cell>
- <cell align="center">6</cell>
- <cell>informational messages</cell>
- </row>
- <row>
- <cell>debug</cell>
- <cell align="center">7</cell>
- <cell>debug-level messages</cell>
- </row>
- <tcaption>Severity levels</tcaption>
- </table>
-
- <p>A log event is allowed by Logger if the integer value of
- its <c>Level</c> is less than or equal to the currently
- configured log level. The log level can be configured globally,
- or to allow more verbose logging from a specific part of the
- system, per module.</p>
-
+ <p>Log levels are expressed as atoms. Internally in Logger, the
+ atoms are mapped to integer values, and a log event passes the
+ log level check if the integer value of its log level is less
+ than or equal to the currently configured log level. That is,
+ the check pases if the event is equally or more severe than the
+ configured level. See section <seealso marker="#log_level">Log
+ Level</seealso> for a listing and description of all log
+ levels.</p>
+ <p>The global log level can be overridden by a log level
+ configured per module. This is to, for instance, allow more
+ verbose logging from a specific part of the system.</p>
+ <p>Filter functions can be used for more sophisticated filtering
+ than the log level check provides. A filter function can stop or
+ pass a log event, based on any of the event's contents. It can
+ also modify all parts of the log event. See see
+ section <seealso marker="#filters">Filters</seealso> for more
+ details.</p>
+ <p>If a log event passes through all global filters and all
+ handler filters for a specific handler, Logger forwards the event
+ to the handler callback. The handler formats and prints the
+ event to its destination. See
+ section <seealso marker="#handlers">Handlers</seealso> for
+ more details.</p>
+ <p>Everything up to and including the call to the handler
+ callbacks is executed on the client process, that is, the
+ process where the log event was issued. It is up to the handler
+ implementation if other processes are involved or not.</p>
+ <p>The handlers are called in sequence, and the order is not
+ defined.</p>
+ </section>
+ <section>
+ <title>Logger API</title>
+ <p>The API for logging consists of a set
+ of <seealso marker="logger#macros">macros</seealso>, and a set
+ of functions on the form <c>logger:Level/1,2,3</c>, which are
+ all shortcuts
+ for <seealso marker="logger#log-2">
+ <c>logger:log(Level,Arg1[,Arg2[,Arg3]])</c></seealso>.</p>
+ <p>The difference between using the macros and the exported
+ functions is that macros add location (originator) information
+ to the metadata, and performs lazy evaluation by wrapping the
+ logger call in a case statement, so it is only evaluated if the
+ log level of the event passes the global log level check.</p>
<section>
- <title>Customizable parts</title>
-
+ <marker id="log_level"/>
+ <title>Log Level</title>
+ <p>The log level indicates the severity of a event. In
+ accordance with the Syslog protocol, RFC-5424, eight log
+ levels can be specified. The following table lists all
+ possible log levels by name (atom), integer value, and
+ description:</p>
+
+ <table align="left">
+ <row>
+ <cell><strong>Level</strong></cell>
+ <cell align="center"><strong>Integer</strong></cell>
+ <cell><strong>Description</strong></cell>
+ </row>
+ <row>
+ <cell>emergency</cell>
+ <cell align="center">0</cell>
+ <cell>system is unusable</cell>
+ </row>
+ <row>
+ <cell>alert</cell>
+ <cell align="center">1</cell>
+ <cell>action must be taken immediately</cell>
+ </row>
+ <row>
+ <cell>critical</cell>
+ <cell align="center">2</cell>
+ <cell>critical contidions</cell>
+ </row>
+ <row>
+ <cell>error</cell>
+ <cell align="center">3</cell>
+ <cell>error conditions</cell>
+ </row>
+ <row>
+ <cell>warning</cell>
+ <cell align="center">4</cell>
+ <cell>warning conditions</cell>
+ </row>
+ <row>
+ <cell>notice</cell>
+ <cell align="center">5</cell>
+ <cell>normal but significant conditions</cell>
+ </row>
+ <row>
+ <cell>info</cell>
+ <cell align="center">6</cell>
+ <cell>informational messages</cell>
+ </row>
+ <row>
+ <cell>debug</cell>
+ <cell align="center">7</cell>
+ <cell>debug-level messages</cell>
+ </row>
+ <tcaption>Log Levels</tcaption>
+ </table>
+ <p>Notice that the integer value is only used internally in
+ Logger. In the API, you must always use the atom. To compare
+ the severity of two log levels,
+ use <seealso marker="logger#compare_levels-2">
+ <c>logger:compare_levels/2</c></seealso>.</p>
+ </section>
+ <section>
+ <marker id="log_message"/>
+ <title>Log Message</title>
+ <p>The log message contains the information to be logged. The
+ message can consist of a format string and arguments (given as
+ two separate parameters in the Logger API), a string or a
+ report. The latter, which is either a map or a key-value list,
+ can be accompanied by a report callback specified in the log
+ event's <seealso marker="#metadata">metadata</seealso>. The
+ report callback is a convenience function that
+ the <seealso marker="#formatters">formatter</seealso> can use
+ to convert the report to a format string and arguments. The
+ formatter can also use its own conversion function, if no
+ callback is provided, or if a customized formatting is
+ desired.</p>
+ <p>Example, format string and arguments:</p>
+ <code>logger:error("The file does not exist: ~ts",[Filename])</code>
+ <p>Example, string:</p>
+ <code>logger:notice("Something strange happened!")</code>
+ <p>Example, report, and metadata with report callback:</p>
+ <code>
+logger:debug(#{got => connection_request, id => Id, state => State},
+ #{report_cb => fun(R) -> {"~p",[R]} end})</code>
+ <p>The log message can also be provided through a fun for lazy
+ evaluation. The fun is only evaluated if the global log level
+ check passes, and is therefore recommended if it is expensive
+ to generate the message. The lazy fun must return a string, a
+ report, or a tuple with format string and arguments.</p>
+ </section>
+ <section>
+ <title>Metadata</title>
+ <p>Metadata contains additional data associated with a log
+ message. Logger inserts some metadata fields by default, and
+ the client can add custom metadata in two different ways:</p>
<taglist>
- <tag><marker id="Handler"/>Handler</tag>
+ <tag>Set process metadata</tag>
<item>
- <p>A handler is defined as a module exporting the following
- function:</p>
-
- <code>log(Log, Config) -> ok</code>
-
- <p>A handler is called by the logger backend after filtering on
- logger level and on handler level for the handler which is
- about to be called. The function call is done on the client
- process, and it is up to the handler implementation if other
- processes are to be involved or not.</p>
-
- <p>Multiple instances of the same handler can be
- added. Configuration is per instance.</p>
-
+ <p>Process metadata is set and updated
+ with <seealso marker="logger#set_process_metadata-1">
+ <c>logger:set_process_metadata/1</c></seealso>
+ and <seealso marker="logger#update_process_metadata-1">
+ <c>logger:update_process metadata/1</c></seealso>,
+ respectively. This metadata applies to the process on
+ which these calls are made, and Logger adds the metadata
+ to all log events issued on that process.</p>
</item>
-
- <tag><marker id="Filter"/>Filter</tag>
- <item>
- <p>Filters can be set on the logger or on a handler. Logger
- filters are applied first, and if passed, the handler filters
- for each handler are applied. The handler callback is only
- called if all handler filters for the handler in question also
- pass.</p>
-
- <p>A filter is specified as:</p>
-
- <code>{fun((Log,Extra) -> Log | stop | ignore), Extra}</code>
-
- <p>The configuration parameter <c>filter_default</c>
- specifies the behavior if all filters return <c>ignore</c>.
- <c>filter_default</c> is by default set to <c>log</c>.</p>
-
- <p>The <c>Extra</c> parameter may contain any data that the
- filter needs.</p>
- </item>
-
- <tag><marker id="Formatter"/>Formatter</tag>
+ <tag>Add metadata to a specifc log event</tag>
<item>
- <p>A formatter is defined as a module exporting the following
- function:</p>
-
- <code>format(Log,Extra) -> unicode:chardata()</code>
-
- <p>The formatter callback is called by each handler, and the
- returned string can be printed to the handler's destination
- (stdout, file, ...).</p>
+ <p>Metadata associated with one specifc log event is given
+ as the last parameter to the log macro or Logger API
+ function when the event is issued. For example:</p>
+ <code>?LOG_ERROR("Connection closed",#{context => server})</code>
</item>
-
</taglist>
+ <p>See the description of
+ the <seealso marker="logger#type-metadata">
+ <c>logger:metadata()</c></seealso> type for information
+ about which default keys Logger inserts, and how the different
+ metadata maps are merged.</p>
</section>
+ </section>
+ <section>
+ <marker id="filter"/>
+ <title>Filters</title>
+ <p>Filters can be global, or attached to a specific
+ handler. Logger calls the global filters first, and if they all
+ pass, it calls the handler filters for each handler. Logger
+ calls the handler callback only if all filters attached to the
+ handler in question also pass.</p>
+ <p>A filter is defined as:</p>
+ <pre>{FilterFun, Extra}</pre>
+ <p>where <c>FilterFun</c> is a function of arity 2,
+ and <c>Extra</c> is any term. When applying the filter, Logger
+ calls the function with the log event as the first argument,
+ and the value of <c>Extra</c> as the second
+ argument. See <seealso marker="logger#type-filter">
+ <c>logger:filter()</c></seealso> for type definitions.</p>
+ <p>The filter function can return <c>stop</c>, <c>ignore</c> or
+ the (possibly modified) log event.</p>
+ <p>If <c>stop</c> is returned, the log event is immediately
+ discarded. If the filter is global, no handler filters or
+ callbacks are called. If it is a handler filter, the
+ corresponding handler callback is not called, but the log event
+ is forwarded to filters attached to the next handler, if
+ any.</p>
+ <p>If the log event is returned, the next filter function is
+ called with the returned value as the first argument. That is,
+ if a filter function modifies the log event, the next filter
+ function receives the modified event. The value returned from
+ the last filter function is the value that the handler callback
+ receives.</p>
+ <p>If the filter function returns <c>ignore</c>, it means that it
+ did not recognize the log event, and thus leaves to other
+ filters to decide the event's destiny.</p>
+ <p>The configuration
+ option <seealso marker="#filter_default"><c>filter_default</c></seealso>
+ specifies the behaviour if all filter functions
+ return <c>ignore</c>, or if no filters
+ exist. <c>filter_default</c> is by default set to <c>log</c>,
+ meaning that if all existing filters ignore a log event, Logger
+ forwards the event to the handler
+ callback. If <c>filter_default</c> is set to <c>stop</c>, Logger
+ discards such events.</p>
+ <p>Global filters are added
+ with <seealso marker="logger#add_logger_filter-2">
+ <c>logger:add_logger_filter/2</c></seealso>
+ and removed
+ with <seealso marker="logger#remove_logger_filter-1">
+ <c>logger:remove_logger_filter/1</c></seealso>. They can also
+ be added at system start via the Kernel configuration
+ parameter <seealso marker="#logger"><c>logger</c></seealso>.</p>
+ <p>Handler filters are added
+ with <seealso marker="logger#add_handler_filter-3">
+ <c>logger:add_handler_filter/3</c></seealso>
+ and removed
+ with <seealso marker="logger#remove_handler_filter-2">
+ <c>logger:remove_handler_filter/2</c></seealso>. They can also
+ be specified directly in the configuration when adding a handler
+ with <seealso marker="logger#add_handler/3">
+ <c>logger:add_handler/3</c></seealso>
+ or via the Kernel configuration
+ parameter <seealso marker="#logger"><c>logger</c></seealso>.</p>
+
+ <p>To see which filters are currently installed in the system,
+ use <seealso marker="logger#i-0"><c>logger:i/0</c></seealso>,
+ or <seealso marker="logger#get_logger_config-0">
+ <c>logger:get_logger_config/0</c></seealso>
+ and <seealso marker="logger#get_handler_config-1">
+ <c>logger:get_handler_config/1</c></seealso>. Filters are
+ listed in the order they are applied, that is, the first
+ filter in the list is applied first, and so on.</p>
+
+ <p>For convenience, the following built-in filters exist:</p>
- <section>
- <title>Built-in handlers</title>
-
- <taglist>
- <tag><c>logger_std_h</c></tag>
+ <taglist>
+ <tag><seealso marker="logger_filters#domain-2">
+ <c>logger_filters:domain/2</c></seealso></tag>
<item>
- <p>This is the default handler used by OTP. Multiple instances
- can be started, and each instance will write log events to a
- given destination, console or file. Filters can be used for
- selecting which event to send to which handler instance.</p>
+ <p>Provides a way of filtering log events based on a
+ <c>domain</c> field in <c>Metadata</c>.</p>
</item>
-
- <tag><c>logger_disk_log_h</c></tag>
+ <tag><seealso marker="logger_filters#level-2">
+ <c>logger_filters:level/2</c></seealso></tag>
<item>
- <p>This handler behaves much like logger_std_h, except it uses
- <seealso marker="disk_log"><c>disk_log</c></seealso> as its
- destination.</p>
+ <p>Provides a way of filtering log events based on the log
+ level.</p>
</item>
-
- <tag><marker id="ErrorLoggerManager"/><c>error_logger</c></tag>
+ <tag><seealso marker="logger_filters#progress-2">
+ <c>logger_filters:progress/2</c></seealso></tag>
<item>
- <p>This handler is to be used for backwards compatibility
- only. It is not started by default, but will be automatically
- started the first time an event handler is added
- with <seealso marker="error_logger#add_report_handler-1">
- <c>error_logger:add_report_handler/1,2</c></seealso>.</p>
-
- <p>No built-in event handlers exist.</p>
+ <p>Stops or allows progress reports from <c>supervisor</c>
+ and <c>application_controller</c>.</p>
</item>
- </taglist>
- </section>
-
- <section>
- <title>Built-in filters</title>
-
- <taglist>
- <tag><c>logger_filters:domain/2</c></tag>
+ <tag><seealso marker="logger_filters#remote_gl-2">
+ <c>logger_filters:remote_gl/2</c></seealso></tag>
<item>
- <p>This filter provides a way of filtering log events based on a
- <c>domain</c> field <c>Metadata</c>. See
- <seealso marker="logger_filters#domain-2">
- <c>logger_filters:domain/2</c></seealso></p>
+ <p>Stops or allows log events originating from a process
+ that has its group leader on a remote node.</p>
</item>
+ </taglist>
+ </section>
- <tag><c>logger_filters:level/2</c></tag>
- <item>
- <p>This filter provides a way of filtering log events based
- on the log level. See <seealso marker="logger_filters#level-2">
- <c>logger_filters:level/2</c></seealso></p>
- </item>
+ <section>
+ <marker id="handlers"/>
+ <title>Handlers</title>
+ <p>A handler is defined as a module exporting at least the
+ following function:</p>
+
+ <pre><seealso marker="logger#HModule:log-2">log(LogEvent, Config) -> void()</seealso></pre>
+
+ <p>This function is called when a log event has passed through all
+ global filters, and all handler filters attached to the handler
+ in question. The function call is executed on the client
+ process, and it is up to the handler implementation if other
+ processes are involved or not.</p>
+
+ <p>Logger allows adding multiple instances of a handler
+ callback. That is, if a callback module implementation allows
+ it, you can add multiple handler instances using the same
+ callback module. The different instances are identified by
+ unique handler identities.</p>
+
+ <p>In addition to the mandatory callback function <c>log/2</c>, a
+ handler module can export the optional callback
+ functions <c>adding_handler/1</c>, <c>changing_config/2</c>
+ and <c>removing_handler/1</c>. See
+ section <seealso marker="logger#handler_callback_functions">Handler
+ Callback Functions</seealso> in the logger(3) manual for more
+ information about these function.</p>
+
+ <p>The following built-in handlers exist:</p>
- <tag><c>logger_filters:progress/2</c></tag>
- <item>
- <p>This filter matches all progress reports
- from <c>supervisor</c> and <c>application_controller</c>.
- See <seealso marker="logger_filters#progress/2">
- <c>logger_filters:progress/2</c></seealso></p>
- </item>
+ <taglist>
+ <tag><c>logger_std_h</c></tag>
+ <item>
+ <p>This is the default handler used by OTP. Multiple instances
+ can be started, and each instance will write log events to a
+ given destination, terminal or file.</p>
+ </item>
- <tag><c>logger_filters:remote_gl/2</c></tag>
- <item>
- <p>This filter matches all events originating from a process
- that has its group leader on a remote node.
- See <seealso marker="logger_filters#remote_gl/2">
- <c>logger_filters:remote_gl/2</c></seealso></p>
- </item>
- </taglist>
- </section>
+ <tag><c>logger_disk_log_h</c></tag>
+ <item>
+ <p>This handler behaves much like <c>logger_std_h</c>, except it uses
+ <seealso marker="disk_log"><c>disk_log</c></seealso> as its
+ destination.</p>
+ </item>
- <section>
- <title>Default formatter</title>
+ <tag><marker id="ErrorLoggerManager"/><c>error_logger</c></tag>
+ <item>
+ <p>This handler is provided for backwards compatibility
+ only. It is not started by default, but will be
+ automatically started the first time an <c>error_logger</c>
+ event handler is added
+ with <seealso marker="error_logger#add_report_handler-1">
+ <c>error_logger:add_report_handler/1,2</c></seealso>.</p>
+
+ <p>The old <c>error_logger</c> event handlers in STDLIB and
+ SASL still exist, but they are not added by Erlang/OTP 21.0
+ or later.</p>
+ </item>
+ </taglist>
+ </section>
- <p>The default formatter is <c>logger_formatter</c>.
- See <seealso marker="logger_formatter#format-2">
- <c>logger_formatter:format/2</c></seealso>.</p>
- </section>
+ <section>
+ <marker id="formatters"/>
+ <title>Formatters</title>
+ <p>A formatter can be used by the handler implementation to do the
+ final formatting of a log event, before printing to the
+ handler's destination. The handler callback receives the
+ formatter information as part of the handler configuration,
+ which is passed as the second argument
+ to <seealso marker="logger#HModule:log-2">
+ <c>HModule:log/2</c></seealso>.</p>
+ <p>The formatter information consits of a formatter
+ module, <c>FModule</c> and its
+ configuration, <c>FConfig</c>. <c>FModule</c> must export the
+ following function, which can be called by the handler:</p>
+ <pre><seealso marker="logger#FModule:format-2">format(LogEvent,FConfig)
+ -> FormattedLogEntry</seealso></pre>
+ <p>The formatter information for a handler is set as a part of its
+ configuration when the handler is added. It can also be changed
+ during runtime
+ with <seealso marker="logger#set_handler_config-3">
+ <c>logger:set_handler_config(HandlerId,formatter,{FModule,FConfig})</c>
+ </seealso>, which overwrites the current formatter information,
+ or with <seealso marker="logger#update_formatter_config-2">
+ <c>logger:update_formatter_config/2,3</c></seealso>, which
+ only modifies the formatter configuration.</p>
+ <p>If the formatter module exports the optional callback
+ function <seealso marker="logger#FModule:check_config-1">
+ <c>check_config(FConfig)</c></seealso>, Logger calls this
+ function when the formatter information is set or modified, to
+ verify the validity of the formatter configuration.</p>
+ <p>If no formatter information is specified for a handler, Logger
+ uses <seealso marker="logger_formatter">
+ <c>logger_formatter(3)</c></seealso> as default.</p>
</section>
<section>
@@ -250,52 +434,58 @@
<p>Logger can be configured either when the system starts through
<seealso marker="config">configuration parameters</seealso>,
- or at run-time by using the <seealso marker="logger">logger</seealso>
+ or at run-time by using the <seealso marker="logger">logger(3)</seealso>
API. The recommended approach is to do the initial configuration in
the <c>sys.config</c> file and then use the API when some configuration
- has to be changed at run-time, such as the logging level.</p>
+ has to be changed at runtime, such as the log level.</p>
<section>
- <title>Application configuration parameters</title>
+ <title>Kernel Configuration Parameters</title>
<p>Logger is best configured by using the configuration parameters
- of kernel. There are three possible configuration parameters:
+ of Kernel. There are four possible configuration parameters:
<seealso marker="#logger"><c>logger</c></seealso>,
<seealso marker="kernel_app#logger_level"><c>logger_level</c></seealso>,
<seealso marker="kernel_app#logger_sasl_compatible"><c>logger_sasl_compatible</c></seealso> and
- <seealso marker="kernel_app#logger_log_progress"><c>logger_log_progress</c></seealso>.
- logger_level, logger_sasl_compatible and logger_log_progress are described in the
+ <seealso marker="kernel_app#logger_progress_reports"><c>logger_progress_reports</c></seealso>.
+ <c>logger_level</c>, <c>logger_sasl_compatible</c> and <c>logger_progress_reports</c> are described in the
<seealso marker="kernel_app#configuration">Kernel Configuration</seealso>,
while <c>logger</c> is described below.</p>
- <section>
+
<marker id="logger"/>
- <title>logger</title>
- <p>The <c>logger</c> application configuration parameter is used to configure
- three different logger aspects; handlers, logger filters and module levels.
+ <p><em>logger</em></p>
+ <p>The application configuration parameter <c>logger</c> is used to configure
+ three different Logger aspects; handlers, logger filters and module levels.
The configuration is a list containing tagged tuples that look like this:</p>
<taglist>
<tag><c>DisableHandler = {handler,default,undefined}</c></tag>
- <item>Disable the default handler. This will allow another application
+ <item>
+ <p>Disable the default handler. This allows another application
to add its own default handler. See <seealso marker="logger#add_handlers/1">
- <c>logger:add_handlers/1</c></seealso> for more details.</item>
+ <c>logger:add_handlers/1</c></seealso> for more details.</p>
+ <p>Only one entry of this option is allowed.</p></item>
<tag><c>AddHandler = {handler,HandlerId,Module,HandlerConfig}</c></tag>
- <item>Add a handler as if <seealso marker="logger:add_handler/3">
- <c>logger:add_handler(HandlerId,Module,HandlerConfig)</c></seealso> had been
- called.</item>
- <tag><c>Filters = {filters, FilterDefault, [Filter]}</c><br/>
+ <item>
+ <p>Add a handler as if <seealso marker="logger:add_handler/3">
+ <c>logger:add_handler(HandlerId,Module,HandlerConfig)</c></seealso> is
+ called.</p>
+ <p>It is allowed to have multiple entries of this option.</p></item>
+ <tag><c>Filters = {filters, default, [Filter]}</c><br/>
<c>FilterDefault = log | stop</c><br/>
<c>Filter = {FilterId, {FilterFun, FilterConfig}}</c></tag>
- <item>Add the specified <seealso marker="logger#add_logger_filter/2">
- logger filters</seealso>. Only one entry is allowed of this option.</item>
- <tag><c>ModuleLevel</c></tag>
- <item><c>{module_level, Level, [Module]}</c>,
- this option configures the <seealso marker="logger#set_module_level/2">
- module log level</seealso> to be used. It is possible to have multiple
- <c>module_level</c> entries.</item>
+ <item>
+ <p>Add the specified <seealso marker="logger#add_logger_filter/2">
+ logger filters</seealso>.</p>
+ <p>Only one entry of this option is allowed.</p></item>
+ <tag><c>ModuleLevel = {module_level, Level, [Module]}</c></tag>
+ <item>
+ <p>This option configures <seealso marker="logger#set_module_level/2">
+ module log level</seealso>.</p>
+ <p>It is allowed to have multiple entries of this option.</p></item>
</taglist>
<p>Examples:</p>
<list>
<item>
- <p>Output logs into a the file &quot;logs/erlang.log&quot;</p>
+ <p>Output logs into the file &quot;logs/erlang.log&quot;</p>
<code>
[{kernel,
[{logger,
@@ -338,153 +528,175 @@
</code>
</item>
</list>
- </section>
</section>
<section>
- <title>Logger configuration</title>
+ <title>Global Logger Configuration</title>
<taglist>
- <tag><c>level</c></tag>
+ <tag><c>level = </c><seealso marker="logger#type-level">
+ <c>logger:level()</c></seealso></tag>
<item>
- <p>Specifies the severity level to log.</p>
+ <p>Specifies the global log level to log.</p>
+ <p>See section <seealso marker="#log_level">Log
+ Level</seealso> for a listing and description of
+ possible log levels.</p>
+ <p>The initial value of this option is set by the Kernel
+ configuration
+ parameter <seealso marker="kernel_app#logger_level">
+ <c>logger_level</c></seealso>. It can be changed during
+ runtime
+ with <seealso marker="logger#set_logger_config-2">
+ <c>logger:set_logger_config(level,NewLevel)</c></seealso>.</p>
</item>
- <tag><c>filters</c></tag>
+ <tag><c>filters = [{</c><seealso marker="logger#type-filter_id">
+ <c>logger:filter_id()</c></seealso><c>,</c>
+ <seealso marker="logger#type-filter">
+ <c>logger:filter()</c></seealso><c>}]</c></tag>
<item>
- <p>Logger filters are added or removed with
+ <p>Global filters are added and removed with
<seealso marker="logger#add_logger_filter-2">
<c>logger:add_logger_filter/2</c></seealso> and
<seealso marker="logger#remove_logger_filter-1">
<c>logger:remove_logger_filter/1</c></seealso>,
respectively.</p>
- <p>See <seealso marker="#Filter">Filter</seealso> for more
- information.</p>
- <p>By default, no filters exist.</p>
+ <p>See section <seealso marker="#filters">Filters</seealso>
+ for more information.</p>
+ <p>Default is <c>[]</c>, that is, no filters exist.</p>
</item>
- <tag><c>filter_default = log | stop</c></tag>
+ <tag><marker id="filter_default"/><c>filter_default = log | stop</c></tag>
<item>
<p>Specifies what to do with an event if all filters
- return <c>ignore</c>.</p>
+ return <c>ignore</c>, or if no filters exist.</p>
+ <p>See section <seealso marker="#filters">Filters</seealso>
+ for more information about how this option is used.</p>
<p>Default is <c>log</c>.</p>
</item>
- <tag><c>handlers</c></tag>
- <item>
- <p>Handlers are added or removed with
- <seealso marker="logger#add_handler-3">
- <c>logger:add_handler/3</c></seealso> and
- <seealso marker="logger#remove_handler-1">
- <c>logger:remove_handler/1</c></seealso>,
- respectively.</p>
- <p>See <seealso marker="#Handler">Handler</seealso> for more
- information.</p>
- </item>
</taglist>
</section>
<section>
<marker id="handler_configuration"/>
- <title>Handler configuration</title>
+ <title>Handler Configuration</title>
<taglist>
- <tag><c>level</c></tag>
+ <tag><c>level = </c><seealso marker="logger#type-level">
+ <c>logger:level()</c></seealso></tag>
<item>
- <p>Specifies the severity level to log.</p>
+ <p>Specifies the log level which the handler logs.</p>
+ <p>See section <seealso marker="#log_level">Log
+ Level</seealso> for a listing and description of
+ possible log levels.</p>
+ <p>The log level can be specified when adding the handler,
+ or changed during runtime with, for
+ instance, <seealso marker="logger#set_handler_config/3">
+ <c>logger:set_handler_config/3</c></seealso>.</p>
+ <p>Default is <c>info</c>.</p>
</item>
- <tag><c>filters</c></tag>
+ <tag><c>filters = [{</c><seealso marker="logger#type-filter_id">
+ <c>logger:filter_id()</c></seealso><c>,</c>
+ <seealso marker="logger#type-filter">
+ <c>logger:filter()</c></seealso><c>}]</c></tag>
<item>
<p>Handler filters can be specified when adding the handler,
- or added or removed later with
+ or added or removed during runtime with
<seealso marker="logger#add_handler_filter-3">
<c>logger:add_handler_filter/3</c></seealso> and
<seealso marker="logger#remove_handler_filter-2">
<c>logger:remove_handler_filter/2</c></seealso>,
respectively.</p>
- <p>See <seealso marker="#Filter">Filter</seealso> for more
+ <p>See <seealso marker="#filters">Filters</seealso> for more
information.</p>
- <p>By default, no filters exist.</p>
+ <p>Default is <c>[]</c>, that is, no filters exist.</p>
</item>
- <tag><c>filter_default = log | stop</c></tag>
+ <tag><marker id="filter_default"/><c>filter_default = log | stop</c></tag>
<item>
<p>Specifies what to do with an event if all filters
- return <c>ignore</c>.</p>
+ return <c>ignore</c>, or if no filters exist.</p>
+ <p>See section <seealso marker="#filters">Filters</seealso>
+ for more information about how this option is used.</p>
<p>Default is <c>log</c>.</p>
</item>
- <tag><c>formatter = {Module::module(),Extra::term()}</c></tag>
+ <tag><c>formatter = {module(),</c><seealso marker="logger#type-formatter_config">
+ <c>logger:formatter_config()</c></seealso><c>}</c></tag>
<item>
- <p>See <seealso marker="#Formatter">Formatter</seealso> for more
+ <p>The formatter which the handler can use for converting
+ the log event term to a printable string.</p>
+ <p>See <seealso marker="#formatters">Formatters</seealso> for more
information.</p>
- <p>The default module is <seealso marker="logger_formatter">
- <c>logger_formatter</c></seealso>, and <c>Extra</c> is
- it's configuration map.</p>
+ <p>Default
+ is <c>{logger_formatter,DefaultFormatterConfig}</c>, see
+ the <seealso marker="logger_formatter">
+ <c>logger_formatter(3)</c></seealso>
+ manual for information about this formatter and its
+ default configuration.</p>
</item>
- <tag>HandlerConfig, <c>term() = term()</c></tag>
+ <tag><c>HandlerConfig, atom() = term()</c></tag>
<item>
- Any keys not listed above are considered to be handler specific
- configuration. The configuration of the Kernel handlers can be found in
- <seealso marker="logger_std_h"><c>logger_std_h</c></seealso> and
- <seealso marker="logger_disk_log_h"><c>logger_disk_log_h</c></seealso>.
+ <p>Any keys not listed above are considered to be handler
+ specific configuration. The configuration of the Kernel
+ handlers can be found in
+ the <seealso marker="logger_std_h"><c>logger_std_h(3)</c></seealso>
+ and
+ <seealso marker="logger_disk_log_h"><c>logger_disk_log_h(3)</c>
+ </seealso> manual pages.</p>
</item>
</taglist>
- <p>Note that <c>level</c> and <c>filters</c> are obeyed by
+ <p>Notice that <c>level</c> and <c>filters</c> are obeyed by
Logger itself before forwarding the log events to each
- handler, while <c>formatter</c> is left to the handler
- implementation. All Logger's built-in handlers will call the
- given formatter before printing.</p>
+ handler, while <c>formatter</c> and all handle specific
+ options are left to the handler implementation.</p>
+ <p>All Logger's built-in handlers will call the given formatter
+ before printing.</p>
</section>
</section>
<section>
<marker id="compatibility"/>
- <title>Backwards compatibility with error_logger</title>
- <p>Logger provides backwards compatibility with the old
+ <title>Backwards Compatibility with error_logger</title>
+ <p>Logger provides backwards compatibility with
<c>error_logger</c> in the following ways:</p>
<taglist>
- <tag>Legacy event handlers</tag>
- <item>
- <p>To use event handlers written for <c>error_logger</c>, just
- add your event handler with</p>
- <code>
-error_logger:add_report_handler/1,2.
- </code>
- <p>This will automatically start the <c>error_logger</c>
- event manager, and add <c>error_logger</c> as a
- handler to <c>logger</c>, with configuration</p>
-<code>
-#{level=>info,
- filter_default=>log,
- filters=>[]}.
-</code>
- <p>Note that this handler will ignore events that do not
- originate from the old <c>error_logger</c> API, or from
- within OTP. This means that if your code uses the logger API
- for logging, then your log events will be discarded by this
- handler.</p>
- <p>Also note that <c>error_logger</c> is not overload
- protected.</p>
- </item>
- <tag>Logger API</tag>
+ <tag>API for Logging</tag>
<item>
- <p>The old <c>error_logger</c> API still exists, but should
- only be used by legacy code. It will be removed in a later
+ <p>The <c>error_logger</c> API still exists, but should only
+ be used by legacy code. It will be removed in a later
release.</p>
+ <p>Calls
+ to <seealso marker="error_logger#error_report-1">
+ <c>error_logger:error_report/1,2</c></seealso>,
+ <seealso marker="error_logger#error_msg-1">
+ <c>error_logger:error_msg/1,2</c></seealso>, and
+ corresponding functions for warning and info messages, are
+ all forwarded to Logger as calls
+ to <seealso marker="logger#log-3">
+ <c>logger:log(Level,Report,Metadata)</c></seealso>.</p>
+ <p><c>Level = error | warning | info</c> and is taken
+ from the function name. <c>Report</c> contains the actual
+ log message, and <c>Metadata</c> contains additional
+ information which can be used for creating backwards
+ compatible events for legacy <c>error_logger</c> event
+ handlers, see
+ section <seealso marker="#legacy_event_handlers">Legacy
+ Event Handlers</seealso>.</p>
</item>
- <tag>Output format</tag>
+ <tag>Output Format</tag>
<item>
<p>To get log events on the same format as produced
by <c>error_logger_tty_h</c> and <c>error_logger_file_h</c>,
use the default formatter, <c>logger_formatter</c>, with
- configuration parameter <c>legacy_header=>true</c>. This is
+ configuration parameter <c>legacy_header => true</c>. This is
also the default.</p>
</item>
- <tag>Default format of log events from OTP</tag>
+ <tag>Default Format of Log Events from OTP</tag>
<item>
<p>By default, all log events originating from within OTP,
except the former so called "SASL reports", look the same as
before.</p>
</item>
- <tag>SASL reports</tag>
+ <tag><marker id="sasl_reports"/>SASL Reports</tag>
<item>
<p>By SASL reports we mean supervisor reports, crash reports
and progress reports.</p>
@@ -494,96 +706,134 @@ error_logger:add_report_handler/1,2.
named <c>sasl_report_tty_h</c>
and <c>sasl_report_file_h</c>.</p>
<p>The destination of these log events were configured by
- environment variables for the SASL application.</p>
+ <seealso marker="sasl:sasl_app#deprecated_error_logger_config">SASL
+ configuration parameters</seealso>.</p>
<p>Due to the specific event handlers, the output format
slightly differed from other log events.</p>
- <p>As of OTP-21, the concept of SASL reports is removed,
- meaning that the default behavior is as follows:</p>
+ <p>As of Erlang/OTP 21.0, the concept of SASL reports is
+ removed, meaning that the default behaviour is as
+ follows:</p>
<list>
- <item>Supervisor reports, crash reports and progress reports
+ <item>Supervisor reports, crash reports, and progress reports
are no longer connected to the SASL application.</item>
<item>Supervisor reports and crash reports are logged by
default.</item>
<item>Progress reports are not logged by default, but can be
- enabled with the kernel environment
- variable <c>logger_log_progress</c>.</item>
+ enabled with the Kernel configuration
+ parameter <seealso marker="kernel_app#logger_progress_reports">
+ <c>logger_progress_reports</c></seealso>.</item>
<item>The output format is the same for all log
events.</item>
</list>
- <p>If the old behavior is preferred, the kernel environment
- variable <c>logger_sasl_compatible</c> can be set
- to <c>true</c>. The old SASL environment variables can then
- be used as before, and the SASL reports will only be printed
- if the SASL application is running - through a second log
- handler named <c>sasl_h</c>.</p>
+ <p>If the old behaviour is preferred, the Kernel configuation
+ parameter <seealso marker="kernel_app:logger_sasl_compatible">
+ <c>logger_sasl_compatible</c></seealso> can be set
+ to <c>true</c>. The
+ <seealso marker="sasl:sasl_app#deprecated_error_logger_config">SASL
+ configuration parameters</seealso> can then be used as
+ before, and the SASL reports will only be printed if the
+ SASL application is running, through a second log handler
+ named <c>sasl</c>.</p>
<p>All SASL reports have a metadata
- field <c>domain=>[beam,erlang,otp,sasl]</c>, which can be
+ field <c>domain => [beam,erlang,otp,sasl]</c>, which can be
used, for example, by filters to stop or allow the
- events.</p>
+ log events.</p>
+ <p>See the <seealso marker="sasl:error_logging">SASL User's
+ Guide</seealso> for more information about the old SASL
+ error logging functionality.</p>
+ </item>
+ <tag><marker id="legacy_event_handlers"/>Legacy Event Handlers</tag>
+ <item>
+ <p>To use event handlers written for <c>error_logger</c>, just
+ add your event handler with</p>
+ <code>
+error_logger:add_report_handler/1,2.
+ </code>
+ <p>This will automatically start the <c>error_logger</c>
+ event manager, and add <c>error_logger</c> as a
+ handler to <c>logger</c>, with configuration</p>
+<code>
+#{level => info,
+ filter_default => log,
+ filters => []}.
+</code>
+ <p>Notice that this handler will ignore events that do not
+ originate from the <c>error_logger</c> API, or from within
+ OTP. This means that if your code uses the Logger API for
+ logging, then your log events will be discarded by this
+ handler.</p>
+ <p>Also notice that <c>error_logger</c> is not overload
+ protected.</p>
</item>
</taglist>
</section>
<section>
- <title>Error handling</title>
+ <title>Error Handling</title>
<p>Log data is expected to be either a format string and
- arguments, a string (unicode:chardata), or a report (map or
+ arguments, a string
+ (<seealso marker="stdlib:unicode#type-chardata">
+ <c>unicode:chardata()</c></seealso>), or a report (map or
key-value list) which can be converted to a format string and
- arguments by the handler. A default report callback should be
- included in the log event's metadata, which can be used for
- converting the report to a format string and arguments. The
- handler might also do a custom conversion if the default format
- is not desired.</p>
- <p><c>logger</c> does, to a certain extent, check its input data
+ arguments by the handler. If a report is given, a default report
+ callback can be included in the log event's metadata. The
+ handler can use this callback for converting the report to a
+ format string and arguments. If the format obtained by the
+ provided callback is not desired, or if there is no provided
+ callback, the handler must do a custom conversion.</p>
+ <p>Logger does, to a certain extent, check its input data
before forwarding a log event to the handlers, but it does not
evaluate conversion funs or check the validity of format strings
and arguments. This means that any filter or handler must be
careful when formatting the data of a log event, making sure
that it does not crash due to bad input data or faulty
callbacks.</p>
- <p>If a filter or handler still crashes, logger will remove the
- filter or handler in question from the configuration, and then
- print a short error message on the console. A debug event
- containing the crash reason and other details is also issued,
- and can be seen if a handler is installed which logs on debug
- level.</p>
+ <p>If a filter or handler still crashes, Logger will remove the
+ filter or handler in question from the configuration, and print
+ a short error message to the terminal. A debug event containing
+ the crash reason and other details is also issued, and can be
+ seen if a handler logging debug events is installed.</p>
</section>
<section>
<title>Example: add a handler to log debug events to file</title>
- <p>When starting an erlang node, the default behavior is that all
+ <p>When starting an Erlang node, the default behaviour is that all
log events with level info and above are logged to the
- console. In order to also log debug events, you can either
+ terminal. In order to also log debug events, you can either
change the global log level to <c>debug</c> or add a separate
handler to take care of this. In this example we will add a new
handler which prints the debug events to a separate file.</p>
- <p>First, we add an instance of logger_std_h with
+ <p>First, we add an instance of <c>logger_std_h</c> with
type <c>{file,File}</c>, and we set the handler's level
to <c>debug</c>:</p>
<pre>
-1> <input>Config = #{level=>debug,logger_std_h=>#{type=>{file,"./debug.log"}}}.</input>
+1> <input>Config = #{level => debug, logger_std_h => #{type => {file,"./debug.log"}}}.</input>
#{logger_std_h => #{type => {file,"./debug.log"}},
level => debug}
2> <input>logger:add_handler(debug_handler,logger_std_h,Config).</input>
ok</pre>
<p>By default, the handler receives all events
- (<c>filter_defalt=log</c>), so we need to add a filter to stop
- all non-debug events:</p>
+ (<c>filter_default=log</c>, see
+ section <seealso marker="#filters">Filters</seealso> for more
+ details), so we need to add a filter to stop all non-debug
+ events. The built-in
+ filter <seealso marker="logger_filters#level-2">
+ <c>logger_filters:level/2</c></seealso>
+ is used for this:</p>
<pre>
-3> <input>Fun = fun(#{level:=debug}=Log,_) -> Log; (_,_) -> stop end.</input>
-#Fun&lt;erl_eval.12.98642416>
-4> <input>logger:add_handler_filter(debug_handler,allow_debug,{Fun,[]}).</input>
+3> <input>logger:add_handler_filter(debug_handler,stop_non_debug,
+ {fun logger_filters:level/2,{stop,neq,debug}}).</input>
ok</pre>
- <p>And finally, we need to make sure that the logger itself allows
+ <p>And finally, we need to make sure that Logger itself allows
debug events. This can either be done by setting the global
- logger level:</p>
+ log level:</p>
<pre>
-5> <input>logger:set_logger_config(level,debug).</input>
+4> <input>logger:set_logger_config(level,debug).</input>
ok</pre>
<p>Or by allowing debug events from one or a few modules only:</p>
<pre>
-6> <input>logger:set_module_level(mymodule,debug).</input>
+5> <input>logger:set_module_level(mymodule,debug).</input>
ok</pre>
</section>
@@ -592,107 +842,112 @@ ok</pre>
<title>Example: implement a handler</title>
<p>The only requirement that a handler MUST fulfill is to export
the following function:</p>
- <code>log(logger:log(),logger:config()) ->ok</code>
- <p>It may also implement the following callbacks:</p>
+ <code>log(logger:log_event(),logger:config()) -> ok</code>
+ <p>It can optionally also implement the following callbacks:</p>
<code>
-adding_handler(logger:handler_id(),logger:config()) -> {ok,logger:config()} | {error,term()}
-removing_handler(logger:handler_id(),logger:config()) -> ok
-changing_config(logger:handler_id(),logger:config(),logger:config()) -> {ok,logger:config()} | {error,term()}
+adding_handler(logger:config()) -> {ok,logger:config()} | {error,term()}
+removing_handler(logger:config()) -> ok
+changing_config(logger:config(),logger:config()) -> {ok,logger:config()} | {error,term()}
</code>
- <p>When logger:add_handler(Id,Module,Config) is called, logger
- will first call Module:adding_handler(Id,Config), and if it
- returns {ok,NewConfig} the NewConfig is written to the
- configuration database. After this, the handler may receive log
- events as calls to Module:log/2.</p>
+ <p>When <c>logger:add_handler(Id,Module,Config)</c> is called,
+ Logger first calls <c>HModule:adding_handler(Config)</c>. If
+ this function returns <c>{ok,NewConfig}</c>, Logger
+ writes <c>NewConfig</c> to the configuration database, and
+ the <c>logger:add_handler/3</c> call returns. After this, the
+ handler is installed and must be ready to receive log events as
+ calls to <c>HModule:log/2</c>.</p>
<p>A handler can be removed by calling
- logger:remove_handler(Id). logger will call
- Module:removing_handler(Id,Config), and then remove the handler's
- configuration from the configuration database.</p>
- <p>When logger:set_handler_config is called, logger calls
- Module:changing_config(Id,OldConfig,NewConfig). If this function
- returns ok, the NewConfig is written to the configuration
- database.</p>
-
- <p>A simple handler which prints to the console could be
- implemented as follows:</p>
+ <c>logger:remove_handler(Id)</c>. Logger calls
+ <c>HModule:removing_handler(Config)</c>, and removes the
+ handler's configuration from the configuration database.</p>
+ <p>When <c>logger:set_handler_config/2,3</c>
+ or <c>logger:update_handler_config/2</c> is called, Logger
+ calls <c>HModule:changing_config(OldConfig,NewConfig)</c>. If
+ this function returns <c>{ok,NewConfig}</c>, Logger
+ writes <c>NewConfig</c> to the configuration database.</p>
+
+ <p>A simple handler that prints to the terminal can be implemented
+ as follows:</p>
<code>
-module(myhandler).
-export([log/2]).
-log(Log,#{formatter:={FModule,FConfig}) ->
- io:put_chars(FModule:format(Log,FConfig)).
+log(LogEvent,#{formatter:={FModule,FConfig}) ->
+ io:put_chars(FModule:format(LogEvent,FConfig)).
</code>
<p>A simple handler which prints to file could be implemented like
this:</p>
<code>
-module(myhandler).
--export([adding_handler/2, removing_handler/2, log/2]).
+-export([adding_handler/1, removing_handler/1, log/2]).
-export([init/1, handle_call/3, handle_cast/2, terminate/2]).
-adding_handler(Id,Config) ->
+adding_handler(Config) ->
{ok,Fd} = file:open(File,[append,{encoding,utf8}]),
- {ok,Config#{myhandler_fd=>Fd}}.
+ {ok,Config#{myhandler_fd => Fd}}.
-removing_handler(Id,#{myhandler_fd:=Fd}) ->
+removing_handler(#{myhandler_fd:=Fd}) ->
_ = file:close(Fd),
ok.
-log(Log,#{myhandler_fd:=Fd,formatter:={FModule,FConfig}}) ->
- io:put_chars(Fd,FModule:format(Log,FConfig)).
+log(LogEvent,#{myhandler_fd:=Fd,formatter:={FModule,FConfig}}) ->
+ io:put_chars(Fd,FModule:format(LogEvent,FConfig)).
</code>
<note><p>The above handlers do not have any overload
protection, and all log events are printed directly from the
client process.</p></note>
- <p>For examples of overload protection, please refer to the
- implementation
- of <seealso marker="logger_std_h"><c>logger_std_h</c></seealso>
- and <seealso marker="logger_disk_log_h"><c>logger_disk_log_h</c>
+ <p>For information and examples of overload protection, please
+ refer to
+ section <seealso marker="#overload_protection">Protecting the
+ Handler from Overload</seealso>, and the implementation
+ of <seealso marker="logger_std_h"><c>logger_std_h(3)</c></seealso>
+ and <seealso marker="logger_disk_log_h"><c>logger_disk_log_h(3)</c>
</seealso>.</p>
<p>Below is a simpler example of a handler which logs through one
single process.</p>
<code>
-module(myhandler).
--export([adding_handler/2, removing_handler/2, log/2]).
+-export([adding_handler/1, removing_handler/1, log/2]).
-export([init/1, handle_call/3, handle_cast/2, terminate/2]).
-adding_handler(Id,Config) ->
+adding_handler(Config) ->
{ok,Pid} = gen_server:start(?MODULE,Config),
- {ok,Config#{myhandler_pid=>Pid}}.
+ {ok,Config#{myhandler_pid => Pid}}.
-removing_handler(Id,#{myhandler_pid:=Pid}) ->
+removing_handler(#{myhandler_pid:=Pid}) ->
gen_server:stop(Pid).
-log(Log,#{myhandler_pid:=Pid} = Config) ->
- gen_server:cast(Pid,{log,Log,Config}).
+log(LogEvent,#{myhandler_pid:=Pid} = Config) ->
+ gen_server:cast(Pid,{log,LogEvent,Config}).
init(#{myhandler_file:=File}) ->
{ok,Fd} = file:open(File,[append,{encoding,utf8}]),
- {ok,#{file=>File,fd=>Fd}}.
+ {ok,#{file => File, fd => Fd}}.
handle_call(_,_,State) ->
{reply,{error,bad_request},State}.
-handle_cast({log,Log,Config},#{fd:=Fd} = State) ->
- do_log(Fd,Log,Config),
+handle_cast({log,LogEvent,Config},#{fd:=Fd} = State) ->
+ do_log(Fd,LogEvent,Config),
{noreply,State}.
terminate(Reason,#{fd:=Fd}) ->
_ = file:close(Fd),
ok.
-do_log(Fd,Log,#{formatter:={FModule,FConfig}}) ->
- String = FModule:format(Log,FConfig),
+do_log(Fd,LogEvent,#{formatter:={FModule,FConfig}}) ->
+ String = FModule:format(LogEvent,FConfig),
io:put_chars(Fd,String).
</code>
</section>
<section>
<marker id="overload_protection"/>
- <title>Protecting the handler from overload</title>
+ <title>Protecting the Handler from Overload</title>
<p>In order for the built-in handlers to survive, and stay responsive,
during periods of high load (i.e. when huge numbers of incoming
log requests must be handled), a mechanism for overload protection
@@ -703,7 +958,7 @@ do_log(Fd,Log,#{formatter:={FModule,FConfig}}) ->
as follows:</p>
<section>
- <title>Message queue length</title>
+ <title>Message Queue Length</title>
<p>The handler process keeps track of the length of its message
queue and reacts in different ways depending on the current status.
The purpose is to keep the handler in, or (as quickly as possible),
@@ -720,7 +975,7 @@ do_log(Fd,Log,#{formatter:={FModule,FConfig}}) ->
and as long as the length of the message queue is lower, all log
requests are handled asynchronously. This simply means that the
process sending the log request (by calling a log function in the
- logger API) does not wait for a response from the handler but
+ Logger API) does not wait for a response from the handler but
continues executing immediately after the request (i.e. it will not
be affected by the time it takes the handler to print to the log
device). If the message queue grows larger than this value, however,
@@ -798,14 +1053,14 @@ logger:add_handler(my_standard_h, logger_std_h,
</section>
<section>
- <title>Controlling bursts of log requests</title>
+ <title>Controlling Bursts of Log Requests</title>
<p>A potential problem with large bursts of log requests, is that log files
may get full or wrapped too quickly (in the latter case overwriting
previously logged data that could be of great importance). For this reason,
both built-in handlers offer the possibility to set a maximum level of how
many requests to process with a certain time frame. With this burst control
feature enabled, the handler will take care of bursts of log requests
- without choking log files, or the console, with massive amounts of
+ without choking log files, or the terminal, with massive amounts of
printouts. These are the configuration parameters:</p>
<taglist>
@@ -839,7 +1094,7 @@ logger:add_handler(my_disk_log_h, logger_disk_log_h,
</section>
<section>
- <title>Terminating a large handler</title>
+ <title>Terminating a Large Handler</title>
<p>A handler process may grow large even if it can manage peaks of high load
without crashing. The overload protection mechanism includes user configurable
levels for a maximum allowed message queue length and maximum allowed memory
@@ -876,7 +1131,14 @@ logger:add_handler(my_disk_log_h, logger_disk_log_h,
<section>
<title>See Also</title>
- <p><seealso marker="error_logger"><c>error_logger(3)</c></seealso>,
- <seealso marker="sasl:sasl_app"><c>SASL(6)</c></seealso></p>
+ <p>
+ <seealso marker="disk_log"><c>disk_log(3)</c></seealso>,
+ <seealso marker="error_logger"><c>error_logger(3)</c></seealso>,
+ <seealso marker="logger"><c>logger(3)</c></seealso>,
+ <seealso marker="logger_disk_log_h"><c>logger_disk_log_h(3)</c></seealso>,
+ <seealso marker="logger_filters"><c>logger_filters(3)</c></seealso>,
+ <seealso marker="logger_formatter"><c>logger_formatter(3)</c></seealso>,
+ <seealso marker="logger_std_h"><c>logger_std_h(3)</c></seealso>,
+ <seealso marker="sasl:sasl_app"><c>sasl(6)</c></seealso></p>
</section>
</chapter>