From b9d2cb688e562d200663bdbedfa65adc5a29aeae Mon Sep 17 00:00:00 2001
From: Siri Hansen When set to When set to If If a scheduler fails to bind, this is often silently
ignored, as it is not always possible to verify valid
logical processor identifiers. If an error is reported,
- it is reported to Enables or disables printout of standard events to a file. This is done by adding or deleting the standard event handler
- for output to file. Thus, calling this function overrides
- the value of the Kernel Enabling file logging can be used together with calling
- This is done by adding or deleting
+ the Notice that this function does not manipulate the Logger
+ configuration directly, meaning that if the default Logger
+ handler is already logging to a file, this function can
+ potentially cause logging to a second file. This function is useful as a shortcut during development
+ and testing, but must not be used in a production
+ system. See
+ section Enables ( This is done by adding or deleting the standard event handler
- for output to the terminal. Thus, calling this function overrides
- the value of the Kernel This is done by manipulating the Logger configuration. The
+ function is useful as a shortcut during development and
+ testing, but must not be used in a production system. See
+ section Two standard logger handlers are defined in
the Kernel application. These are described in the
Specifies how
For more details and examples, see the
Specifies the configuration
+ for
The
This parameter specifies which log levels to log. The - specified level, and all levels that are more severe, will - be logged.
-The default value is
To change the global log level at run-time, use
-
Specifies the primary log level for Logger. Log events with
+ the same, or a more severe level, pass through the primary
+ log level check. See
+ section
To change the primary log level at runtime, use
+
Defaults to
If this parameter is set to true, then the
The default value is
See chapter
This configuration option only effects the
If
If
The default value is
This configuration option only effects the
Specifies if Logger behaves backwards compatible with the + SASL error logging functionality from releases prior to + Erlang/OTP 21.0.
+If this parameter is set to
See section
+
See section
Defaults to
If this parameter is set to
If set, no
-
If set, no log events are issued when erroneous lines are + found and skipped in the various Inet configuration files.
-erl -kernel logger '[{handler,default,logger_std_h,#{logger_std_h=>#{type=>{file,"/tmp/erlang.log"}}}}]'
+erl -kernel logger '[{handler,default,logger_std_h,#{config=>#{type=>{file,"/tmp/erlang.log"}}}}]'
- This module is the main API for logging in Erlang/OTP. It
- contains functions that allow applications to use a single log
- API and the system to manage those log events independently. Use
- the
-?LOG_ERROR("error happened because: ~p",[Reason]). %% With macro
-logger:error("error happened because: ~p",[Reason]). %% Without macro
-
- This log event is then sent to the configured log handlers which
- by default means that it is be printed to the console. If you want
- your systems logs to be printed to a file instead of the console you
- must configure the default handler to do so. The simplest way is
- to include the following in your
This module implements the main API for logging in
+ Erlang/OTP. To create a log event, use the
+
+?LOG_ERROR("error happened because: ~p", [Reason]). % With macro
+logger:error("error happened because: ~p", [Reason]). % Without macro
+
+ To configure the Logger backend,
+ use
By default, the Kernel application installs one log handler at
+ system start. This handler is named
If you want your systems logs to be printed to a file instead,
+ you must configure the default handler to do so. The simplest
+ way is to include the following in
+ your
[{kernel,
[{logger,
- [{handler,default,logger_std_h,
- #{logger_std_h=>#{type=>{file,"path/to/file.log"}}}}]}]}].
+ [{handler, default, logger_std_h,
+ #{config => #{type => {file, "path/to/file.log"}}}}]}]}].
For more information about:
The severity level for the message to be logged.
+Primary configuration data for Logger. The following + default values apply:
+Handler configuration data for Logger. The following + default values apply:
+In addition to these, the following fields are
+ automatically inserted by Logger, values taken from the
+ two first parameters
+ to
Handler specific configuration data is inserted by the
+ handler callback itself, in a sub structure associated with
+ the field named
See the
A filter which can be installed as a handler filter, or as + a primary filter in Logger.
The second argument to the filter fun.
+A unique identifier for a filter.
+The return value from the filter fun.
+Configuration data for the
+ formatter. See
A unique identifier for a handler instance.
+The severity level for the message to be logged.
+When a log macro is used, Logger also inserts location information:
Configuration data for the logger part of Logger, or for a handler.
-The following default values apply:
-See the
A unique identifier for a handler instance.
-A unique identifier for a filter.
-A filter which can be installed for the logger part of - Logger, or for a handler.
-The second argument to the filter fun.
+The return value from the filter fun.
+Configuration data for the
- formatter. See
Equivalent to @@ -366,136 +402,21 @@ logger:error("error happened because: ~p",[Reason]). %% Without macro
Log the given message.
Look up the current configuration for the logger part of - Logger.
-Look up the current configuration for the given handler.
-Same as
Display or return all current Logger configurations.
-Return the pretty printed current Logger configuration - as iodata.
-Return the current Logger configuration as a term. The
- format of this term may change between releases. For a
- stable format use
The same as calling
Pretty print all the current Logger configuration to - standard out. Example:
- logger:i(print).
-Current logger configuration:
- Level: info
- Filter Default: log
- Filters:
- Handlers:
- Id: default
- Module: logger_std_h
- Level: info
- Formatter:
- Module: logger_formatter
- Config: #{legacy_header => true,single_line => false,
- template => [{logger_formatter,header},"\n",msg,"\n"]}
- Filter Default: stop
- Filters:
- Id: stop_progress
- Fun: fun logger_filters:progress/2
- Config: stop
- Id: remote_gl
- Fun: fun logger_filters:remote_gl/2
- Config: stop
- Id: domain
- Fun: fun logger_filters:domain/2
- Config: {log,super,[beam,erlang,otp,sasl]}
- Id: no_domain
- Fun: fun logger_filters:domain/2
- Config: {log,undefined,[]}
- Handler Config:
- logger_std_h: #{type => standard_io}
- Level set per module:
- Module: my_module
- Level: debug]]>
- Add a filter to the logger part of Logger.
-The filter fun is called with the log event as the first
- parameter, and the specified
The return value of the fun specifies if a log event is to - be discarded or forwarded to the handlers:
-The filter passed. The next logger filter, if - any, is applied. If no more logger filters exist, the - log event is forwarded to the handler part of Logger, - where handler filters are applied.
-The filter did not pass, and the log event is - immediately discarded.
-The filter has no knowledge of the log event. The next
- logger filter, if any, is applied. If no more logger
- filters exist, the value of the
See section
Some built-in filters exist. These are defined
- in
Add a handler with the given configuration.
+Remove the filter identified
- by
Remove the filter identified
- by
Add a handler with the given configuration.
-Remove the handler identified by
Set the log level for the
- specified
The log level for a module overrides the global log level - of Logger for log events originating from the module in - question. Notice, however, that it does not override the - level configuration for any handler.
-For example: Assume that the global log level for Logger
- is
With this configuration, no debug messages will be logged, - since they are all stopped by the global log level.
-If the level for
Debug events from other modules are still not logged.
-To change the global log level for Logger, use
-
To change the log level for a handler, use
-
The originating module for a log event is only detected
- if
Remove a module specific log setting. After this, the - global log level is used for the specified module.
-Reads the application configuration parameter
Set configuration data for the logger part of Logger. This - overwrites the current logger configuration.
-To modify the existing configuration,
- use
If a key is removed compared to the current configuration, - the default value is used.
+Add a primary filter to Logger.
+The filter fun is called with the log event as the first
+ parameter, and the specified
The return value of the fun specifies if a log event is to + be discarded or forwarded to the handlers:
+The filter passed. The next primary filter, if + any, is applied. If no more primary filters exist, the + log event is forwarded to the handler part of Logger, + where handler filters are applied.
+The filter did not pass, and the log event is + immediately discarded.
+The filter has no knowledge of the log event. The next
+ primary filter, if any, is applied. If no more primary
+ filters exist, the value of the
+ primary
See section
Some built-in filters exist. These are defined
+ in
Add or update configuration data for the logger part of
- Logger. If the given
Look up all current Logger configuration, including primary + and handler configuration, and module level settings.
Update configuration data for the logger part of - Logger. This function behaves as if it was implemented as - follows:
-
-{ok,Old} = logger:get_logger_config(),
-logger:set_logger_config(maps:merge(Old,Config)).
-
- To overwrite the existing configuration without any merge,
- use
Look up the current configuration for all handlers.
+Look up the current configuration for the given handler.
+Look up the identities for all installed handlers.
+Look up the current primary configuration for Logger.
+Look up all current module levels. Returns a list
+ containing one
Look up the current level for the given modules. Returns a
+ list containing one
Retrieve data set
+ with
Remove the handler identified by
Remove the filter identified
+ by
Remove the primary filter identified
+ by
Update configuration data for the specified handler. This function - behaves as if it was implemented as follows:
-
-{ok,{_,Old}} = logger:get_handler_config(HandlerId),
-logger:set_handler_config(HandlerId,maps:merge(Old,Config)).
-
- To overwrite the existing configuration without any merge,
- use Set primary configuration data for Logger. This
+ overwrites the current configuration. To modify the existing configuration,
+ use If a key is removed compared to the current configuration,
+ the default value is used.
Add or update primary configuration data for Logger. If the
+ given
Set the log level for the + specified modules.
+The log level for a module overrides the primary log level + of Logger for log events originating from the module in + question. Notice, however, that it does not override the + level configuration for any handler.
+For example: Assume that the primary log level for Logger
+ is
With this configuration, no debug messages will be logged, + since they are all stopped by the primary log level.
+If the level for
Debug events from other modules are still not logged.
+To change the primary log level for Logger, use
+
To change the log level for a handler, use
+
The originating module for a log event is only detected
+ if the key
Set metadata which Logger shall automatically insert in + all log events produced on the current process.
+Location data produced by the log macros, and/or metadata + given as argument to the log call (API function or macro), + are merged with the process metadata. If the same keys + occur, values from the metadata argument to the log call + overwrite values from the process metadata, which in turn + overwrite values from the location data.
+Subsequent calls to this function overwrites previous data
+ set. To update existing data instead of overwriting it,
+ see
Remove module specific log settings. After this, the + primary log level is used for all modules.
+Remove module specific log settings. After this, the + primary log level is used for the specified modules.
+Delete data set
+ with
The new configuration is merged with the existing formatter configuration.
To overwrite the existing configuration without any merge,
- use
+@@ -797,39 +834,41 @@ logger:set_handler_config(HandlerId,maps:merge(Old,Config)).set_handler_config(HandlerId, formatter, + {FormatterModule, FormatterConfig}) .
Update the formatter configuration for the specified handler.
-This is equivalent
- to
This is equivalent to
++update_formatter_config( HandlerId , #{Key =>Value })
Compare the severity of two log levels. Returns
Update configuration data for the specified handler. This function + behaves as if it was implemented as follows:
+
+{ok, {_, Old}} = logger:get_handler_config(HandlerId),
+logger:set_handler_config(HandlerId, maps:merge(Old, Config)).
+
+ To overwrite the existing configuration without any merge,
+ use
Set metadata which Logger shall automatically insert in - all log events produced on the current process.
-Location data produced by the log macros, and/or metadata - given as argument to the log call (API function or macro), - are merged with the process metadata. If the same keys - occur, values from the metadata argument to the log call - overwrite values from the process metadata, which in turn - overwrite values from the location data.
-Subsequent calls to this function overwrites previous data
- set. To update existing data instead of overwriting it,
- see
Update primary configuration data for Logger. This function + behaves as if it was implemented as follows:
+
+Old = logger:get_primary_config(),
+logger:set_primary_config(maps:merge(Old, Config)).
+
+ To overwrite the existing configuration without any merge,
+ use
If process metadata exists for the current process, this function behaves as if it was implemented as follows:
-logger:set_process_metadata(maps:merge(logger:get_process_metadata(),Meta)).
+logger:set_process_metadata(maps:merge(logger:get_process_metadata(), Meta)).
If no process metadata exists, the function behaves as
Retrieve data set
- with
Delete data set
- with
Compare the severity of two log levels. Returns
Convert a log message on report form to
This is the default report callback used +
Convert a log message on report form to
The function produces lines of
If the
If
This callback function is mandatory.
-The function is called when all global filters and all +
The function is called when all primary filters and all handler filters for the handler in question have passed for the given log event.
The handler identity is associated with the This callback function is optional. This callback function is optional. The function is called by a Logger when formatter
configuration is set or modified. The formatter must
validate the given configuration and return
The following Logger API functions can trigger this callback:
+See
+
Erlang/OTP 21.0 provides a new standard API for logging +
Erlang/OTP 21.0 provides a standard API for logging
through
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
By confiugration, you can aslo modify or disable the default +
By configuration, you can also modify or disable the default handler, replace it by a custom handler, and install additional handlers.
@@ -53,11 +53,12 @@A log event consists of a log level, the message to be logged, and metadata.
The Logger backend forwards log events from the API, first - through a set of global filters, then through a set - of handler filters for each log handler.
+ through a set of primary filters, then through a set of + secondary filters attached to each log handler. The secondary + filters are in the following named handler filters.Each filter set consists of a log level check, followed by zero or more filter functions.
-The following figure show a conseptual overview of Logger. The +
The following figure shows a conceptual overview of Logger. The figure shows two log handlers, but any number of handlers can be installed.
@@ -69,11 +70,11 @@ 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 + the check passes if the event is equally or more severe than the configured level. See sectionThe global log level can be overridden by a log level +
The primary 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.
Filter functions can be used for more sophisticated filtering
@@ -82,7 +83,7 @@
also modify all parts of the log event. See see
section
If a log event passes through all global filters and all +
If a log event passes through all primary 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 @@ -107,7 +108,7 @@ 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.
+ log level of the event passes the primary log level check.The log message can also be provided through a fun for lazy - evaluation. The fun is only evaluated if the global log level + evaluation. The fun is only evaluated if the primary 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.
@@ -217,9 +218,9 @@ logger:debug(#{got => connection_request, id => Id, state => State}, which these calls are made, and Logger adds the metadata to all log events issued on that process. -Metadata associated with one specifc log event is given +
Metadata associated with one specific log event is given as the last parameter to the log macro or Logger API function when the event is issued. For example:
?LOG_ERROR("Connection closed",#{context => server})
@@ -235,8 +236,8 @@ logger:debug(#{got => connection_request, id => Id, state => State},
Filters can be global, or attached to a specific - handler. Logger calls the global filters first, and if they all +
Filters can be primary, or attached to a specific + handler. Logger calls the primary 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.
@@ -251,7 +252,7 @@ logger:debug(#{got => connection_request, id => Id, state => State},The filter function can return
If
If the filter function returns
The configuration
- option
The configuration option
Global filters are added
- with
Primary filters are added
+ with
Handler filters are added
with
To see which filters are currently installed in the system,
- use
log(LogEvent, Config) -> void()
This function is called when a log event has passed through all - global filters, and all handler filters attached to the handler + primary 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.
@@ -358,8 +358,8 @@ logger:debug(#{got => connection_request, id => Id, state => State}, functionsThe following built-in handlers exist:
@@ -404,7 +404,7 @@ logger:debug(#{got => connection_request, id => Id, state => State}, which is passed as the second argument toThe formatter information consits of a formatter +
The formatter information consist of a formatter
module,
If no formatter information is specified for a handler, Logger
- uses
Logger can be configured either when the system starts through
-
At system start, Logger is configured through Kernel
+ configuration parameters. The parameters that apply to Logger
+ are described in
+ section
During runtime, Logger configuration is changed via API
+ functions. See
+ section
Logger is best configured by using the configuration parameters
- of Kernel. There are four possible configuration parameters:
-
logger
-The application configuration parameter
Disable the default handler. This allows another application
- to add its own default handler. See
Only one entry of this option is allowed.
Add a handler as if
It is allowed to have multiple entries of this option.
Add the specified
Only one entry of this option is allowed.
This option configures
It is allowed to have multiple entries of this option.
Examples:
-Output logs into the file "logs/erlang.log"
-
-[{kernel,
- [{logger,
- [{handler, default, logger_std_h,
- #{ logger_std_h => #{ type => {file,"log/erlang.log"}}}}]}]}].
-
- Output logs in single line format
-
-[{kernel,
- [{logger,
- [{handler, default, logger_std_h,
- #{ formatter => { logger_formatter,#{ single_line => true}}}}]}]}].
-
- Add the pid to each log event
-
-[{kernel,
- [{logger,
- [{handler, default, logger_std_h,
- #{ formatter => { logger_formatter,
- #{ template => [time," ",pid," ",msg,"\n"]}}
- }}]}]}].
-
- Use a different file for debug logging
-
-[{kernel,
- [{logger,
- [{handler, default, logger_std_h,
- #{ level => error,
- logger_std_h => #{ type => {file, "log/erlang.log"}}}},
- {handler, info, logger_std_h,
- #{ level => debug,
- logger_std_h => #{ type => {file, "log/debug.log"}}}}
- ]}]}].
-
- Logger API functions that apply to the primary Logger + configuration are:
+The primary Logger configuration is a map with the following + keys:
Specifies the global log level to log.
+Specifies the primary log level, that is, log event that + are equally or more severe than this level, are forwarded + to the primary filters. Less severe log events are + immediately discarded.
See section
The initial value of this option is set by the Kernel
- configuration
- parameter
Defaults to
Global filters are added and removed with
-
Specifies the primary filters.
+The initial value of this option is set by the Kernel
+ configuration
+ parameter
See section
Default is
Defaults to
Specifies what to do with an event if all filters +
Specifies what happens to a log event if all filters
return
See section
Default is
Defaults to
Logger API functions that apply to handler configuration + are:
+The configuration for a handler is a map with the following keys:
Automatically inserted by Logger. The value is the same
+ as the
Automatically inserted by Logger. The value is the same
+ as the
Specifies the log level which the handler logs.
+Specifies the log level for the handler, that is, log + events that are equally or more severe than this level, + are forwarded to the handler filters for this + handler.
See section
The log level can be specified when adding the handler, - or changed during runtime with, for +
The log level is specified when adding the handler, or
+ changed during runtime with, for
instance,
Default is
Defaults to
Handler filters can be specified when adding the handler, +
Specifies the handler filters.
+Handler filters are specified when adding the handler,
or added or removed during runtime with
See
Default is
Defaults to
Specifies what to do with an event if all filters +
Specifies what happens to a log event if all filters
return
See section
Default is
Defaults to
The formatter which the handler can use for converting - the log event term to a printable string.
-See
Default
- is
Specifies a formatter that the handler can use for + converting the log event term to a printable string.
+The formatter information is specified when adding the
+ handler. The formatter configuration can be changed during
+ runtime
+ with
See
+ section
Defaults
+ to
Any keys not listed above are considered to be handler
- specific configuration. The configuration of the Kernel
- handlers can be found in
+ Handler specific configuration, that is, configuration
+ data related to a specific handler implementation. The configuration for the built-in handlers is described
+ in
the
Notice that
All Logger's built-in handlers will call the given formatter - before printing.
+The following Kernel configuration parameters apply to + Logger:
+Specifies the configuration
+ for
With this parameter, you can modify or disable the default + handler, add custom handlers and primary logger filters, and + set log levels per module.
+Disables the default handler. This allows another + application to add its own default handler.
+Only one entry of this type is allowed.
+If
++ logger:set_handler_config(default, Module, HandlerConfig) +
For all other values of
++ logger:add_handler(HandlerId, Module, HandlerConfig) +
Multiple entries of this type are allowed.
Adds the specified primary filters.
+Equivalent to calling
+++ logger:add_primary_filter(FilterId, {FilterFun, FilterConfig}) +
for each
Only one entry of this type is allowed.
+Sets module log level for the given modules. Equivalent + to calling
+++ logger:set_module_level(Module, Level)
for each
Multiple entries of this type are allowed.
+See
+ section
Specifies the primary log level. See
+ the
Specifies Logger's compatibility
+ with
The value of the Kernel configuration parameter
Each of the following examples shows a simple system + configuration file that configures Logger according to the + description.
+Modify the default handler to print to a file instead of
+
+[{kernel,
+ [{logger,
+ [{handler, default, logger_std_h, % {handler, HandlerId, Module,
+ #{config => #{type => {file,"log/erlang.log"}}}} % Config}
+ ]}]}].
+
+ Modify the default handler to print each log event as a + single line:
+
+[{kernel,
+ [{logger,
+ [{handler, default, logger_std_h,
+ #{formatter => {logger_formatter, #{single_line => true}}}}
+ ]}]}].
+
+ Modify the default handler to print the pid of the logging + process for each log event:
+
+[{kernel,
+ [{logger,
+ [{handler, default, logger_std_h,
+ #{formatter => {logger_formatter,
+ #{template => [time," ",pid," ",msg,"\n"]}}}}
+ ]}]}].
+
+ Modify the default handler to only print errors and more + severe log events to "log/erlang.log", and add another handler + to print all log events to "log/debug.log".
+
+[{kernel,
+ [{logger,
+ [{handler, default, logger_std_h,
+ #{level => error,
+ config => #{type => {file, "log/erlang.log"}}}},
+ {handler, info, logger_std_h,
+ #{level => debug,
+ config => #{type => {file, "log/debug.log"}}}}
+ ]}]}].
+
To get log events on the same format as produced
by
By SASL reports we mean supervisor reports, crash reports and progress reports.
-In earlier releases, these reports were only logged when
- the SASL application was running, and they were printed
- trough specific event handlers
- named
Prior to Erlang/OTP 21.0, these reports were only logged
+ when the SASL application was running, and they were printed
+ trough SASL's own event handlers
The destination of these log events were configured by +
The destination of these log events was configured by
Due to the specific event handlers, the output format
@@ -716,17 +859,20 @@ logger:debug(#{got => connection_request, id => Id, state => State},
-
If the old behaviour is preferred, the Kernel configuation
- parameter If the old behaviour is preferred, the Kernel configuration
+ parameter All SASL reports have a metadata
- field See the All SASL reports have a metadata field See section
error_logger:add_report_handler/1,2.
- This will automatically start the
This automatically starts the error logger event manager,
+ and adds
#{level => info,
filter_default => log,
filters => []}.
- Notice that this handler will ignore events that do not
- originate from the
Also notice that
This handler ignores events that do not originate from
+ the
The handler is not overload protected.
+Log data is expected to be either a format string and
- arguments, a string
- (
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.
+Logger does, to a certain extent, check its input data before + forwarding a log event to filters and handlers. It does, + however, not evaluate report callbacks, or check the validity of + format strings and arguments. This means that all filters and + handlers 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.
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.
+ the crash reason and other details is also issued. +See section
When starting an Erlang node, the default behaviour is that all
- log events with level info and above are logged to the
- terminal. In order to also log debug events, you can either
- change the global log level to
First, we add an instance of
-1> Config = #{level => debug, logger_std_h => #{type => {file,"./debug.log"}}}. -#{logger_std_h => #{type => {file,"./debug.log"}}, - level => debug} -2> logger:add_handler(debug_handler,logger_std_h,Config). +1> logger:set_primary_config(level, debug). ok-
By default, the handler receives all events
- (
or set the level for one or a few modules only:
-3> logger:add_handler_filter(debug_handler,stop_non_debug, - {fun logger_filters:level/2,{stop,neq,debug}}). +2> logger:set_module_level(mymodule, debug). ok-
And finally, we need to make sure that Logger itself allows - debug events. This can either be done by setting the global - log level:
+This allows debug events to pass through to the default handler, + and be printed to the terminal as well. If there are many debug + events, it can be useful to print these to a file instead.
+First, set the log level of the default handler to
-4> logger:set_logger_config(level,debug). +3> logger:set_handler_config(default, level, info). ok-
Or by allowing debug events from one or a few modules only:
+Then, add a new handler which prints to file. You can use the
+ handler
+ module
+4> Config = #{config => #{type => {file,"./debug.log"}}}. +#{config => #{type => {file,"./debug.log"}}} +5> logger:add_handler(debugger, logger_std_h, Config). +ok+
Since
-5> logger:set_module_level(mymodule,debug). +6> logger:add_handler_filter(debugger, stop_non_debug, + {fun logger_filters:level/2, {stop, neq, debug}}). ok+
See section
The only requirement that a handler MUST fulfill is to export - the following function:
-log(logger:log_event(),logger:config()) -> ok
- It can optionally also implement the following callbacks:
-
-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()}
-
- When
Section
A handler callback module must export:
+It can optionally also export some, or all, of the following:
+When a handler is added, by for example a call
+ to
A handler can be removed by calling
-
When
When
A simple handler that prints to the terminal can be implemented as follows:
@@ -872,11 +1026,11 @@ changing_config(logger:config(),logger:config()) -> {ok,logger:config()} | {erro -module(myhandler). -export([log/2]). -log(LogEvent,#{formatter:={FModule,FConfig}) -> - io:put_chars(FModule:format(LogEvent,FConfig)). +log(LogEvent, #{formatter := {FModule, FConfig}) -> + io:put_chars(FModule:format(LogEvent, FConfig)). -A simple handler which prints to file could be implemented like +
A simple handler which prints to file can be implemented like this:
-module(myhandler).
@@ -884,28 +1038,29 @@ log(LogEvent,#{formatter:={FModule,FConfig}) ->
-export([init/1, handle_call/3, handle_cast/2, terminate/2]).
adding_handler(Config) ->
- {ok,Fd} = file:open(File,[append,{encoding,utf8}]),
- {ok,Config#{myhandler_fd => Fd}}.
+ {ok, Fd} = file:open(File, [append, {encoding, utf8}]),
+ {ok, Config#{myhandler_fd => Fd}}.
-removing_handler(#{myhandler_fd:=Fd}) ->
+removing_handler(#{myhandler_fd := Fd}) ->
_ = file:close(Fd),
ok.
-log(LogEvent,#{myhandler_fd:=Fd,formatter:={FModule,FConfig}}) ->
- io:put_chars(Fd,FModule:format(LogEvent,FConfig)).
+log(LogEvent,#{myhandler_fd := Fd, formatter := {FModule, FConfig}}) ->
+ io:put_chars(Fd, FModule:format(LogEvent, FConfig)).
- The above handlers do not have any overload - protection, and all log events are printed directly from the - client process.
For information and examples of overload protection, please
- refer to
- section
The above handlers do not have any overload + protection, and all log events are printed directly from the + client process.
+For information and examples of overload protection, please
+ refer to
+ section
Below is a simpler example of a handler which logs through one single process.
@@ -915,33 +1070,33 @@ log(LogEvent,#{myhandler_fd:=Fd,formatter:={FModule,FConfig}}) -> -export([init/1, handle_call/3, handle_cast/2, terminate/2]). adding_handler(Config) -> - {ok,Pid} = gen_server:start(?MODULE,Config), - {ok,Config#{myhandler_pid => Pid}}. + {ok, Pid} = gen_server:start(?MODULE, Config), + {ok, Config#{myhandler_pid => Pid}}. -removing_handler(#{myhandler_pid:=Pid}) -> +removing_handler(#{myhandler_pid := Pid}) -> gen_server:stop(Pid). -log(LogEvent,#{myhandler_pid:=Pid} = Config) -> - gen_server:cast(Pid,{log,LogEvent,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}}. +init(#{myhandler_file := File}) -> + {ok, Fd} = file:open(File, [append, {encoding, utf8}]), + {ok, #{file => File, fd => Fd}}. -handle_call(_,_,State) -> - {reply,{error,bad_request},State}. +handle_call(_, _, State) -> + {reply, {error, bad_request}, State}. -handle_cast({log,LogEvent,Config},#{fd:=Fd} = State) -> - do_log(Fd,LogEvent,Config), - {noreply,State}. +handle_cast({log, LogEvent, Config}, #{fd := Fd} = State) -> + do_log(Fd, LogEvent, Config), + {noreply, State}. -terminate(Reason,#{fd:=Fd}) -> +terminate(Reason, #{fd := Fd}) -> _ = file:close(Fd), ok. -do_log(Fd,LogEvent,#{formatter:={FModule,FConfig}}) -> - String = FModule:format(LogEvent,FConfig), - io:put_chars(Fd,String). +do_log(Fd, LogEvent, #{formatter := {FModule, FConfig}}) -> + String = FModule:format(LogEvent, FConfig), + io:put_chars(Fd, String).A configuration example:
logger:add_handler(my_standard_h, logger_std_h,
- #{logger_std_h =>
- #{type => {file,"./system_info.log"},
- toggle_sync_qlen => 100,
- drop_new_reqs_qlen => 1000,
- flush_reqs_qlen => 2000}}).
+ #{config =>
+ #{type => {file,"./system_info.log"},
+ toggle_sync_qlen => 100,
+ drop_new_reqs_qlen => 1000,
+ flush_reqs_qlen => 2000}}).
logger:add_handler(my_disk_log_h, logger_disk_log_h,
#{disk_log_opts =>
- #{file => "./my_disk_log"},
- logger_disk_log_h =>
- #{burst_limit_size => 10,
- burst_window_time => 500}}).
+ #{file => "./my_disk_log"},
+ config =>
+ #{burst_limit_size => 10,
+ burst_window_time => 500}}).
The default standard handler,
The handler has an overload protection mechanism that will keep the handler process and the Kernel application alive during a high load of log @@ -60,7 +60,7 @@ , as well as handler specific parameters.
The settings for the disk_log log file should be specified with the
key
Parameters in the
Specific configuration for the handler (represented as a sub map)
- is specified with the key
There are a number of other configuration parameters available, that are @@ -117,7 +117,7 @@ logger:add_handler(my_disk_log_h, logger_disk_log_h, type => wrap, max_no_files => 4, max_no_bytes => 10000}, - logger_disk_log_h => + config => #{filesync_repeat_interval => 1000}}).
In order to use the disk_log handler instead of the default standard @@ -125,14 +125,14 @@ logger:add_handler(my_disk_log_h, logger_disk_log_h, use disk_log. Example:
erl -kernel logger '[{handler,default,logger_disk_log_h,
- #{ disk_log_opts => #{ file => "./system_disk_log"}}}]'
+ #{disk_log_opts => #{file => "./system_disk_log"}}}]'
Write buffered data to disk.
@@ -143,9 +143,9 @@ erl -kernel logger '[{handler,default,logger_disk_log_h,All functions exported from this module can be used as logger +
All functions exported from this module can be used as primary
or handler
- filters. See
Filters are removed with
Filters are removed with
A domain field must be a list of atoms, creating smaller
and more specialized domains as the list grows longer. The
- biggest domain is
For example, consider the following domains:
-D1 = [beam,erlang,otp] -D2 = [beam,erlang,otp,sasl]+D1 = [otp] +D2 = [otp, sasl] -
The above domains are used for logs originating from Erlang/OTP. D1 specifies that the log event comes from @@ -86,50 +86,50 @@ D2 = [beam,erlang,otp,sasl]
The
The filter compares the value of the
The filter compares the value of the
The filter matches if
and
The filter matches if
and
The filter matches if
and
The filter matches if
and
The filter matches if there is no domain field in
- metadata. In this case
and there is no domain field in metadata. In this
+ case
If the filter matches and
If the filter matches and
If the filter does not match, it returns
Log events that do not contain any domain field, match only
- when
Example: stop all events with
- domain
Example: stop all events with domain
-logger:set_handler_config(h1,filter_default,log). % this is the default
-Filter = {fun logger_filters:domain/2,{stop,sub,[beam,erlang,otp,sasl]}}.
-logger:add_handler_filter(h1,no_sasl,Filter).
+logger:set_handler_config(h1, filter_default, log). % this is the default
+Filter = {fun logger_filters:domain/2, {stop, sub, [otp, sasl]}}.
+logger:add_handler_filter(h1, no_sasl, Filter).
ok
This filter provides a way of filtering log events based
on the log level. It matches log events by comparing the
- log level with a predefined
The
The filter compares the value of the event's log level
(
If the filter matches and
and the compare function returns
and the compare function returns
and the compare function returns
and the compare function returns
and the compare function returns
and the compare function returns
If the filter matches and
If the filter does not match, it returns
Example: only allow debug level log events
-logger:set_handler_config(h1,filter_default,stop).
-Filter = {fun logger_filters:level/2,{log,eq,debug}}.
-logger:add_handler_filter(h1,debug_only,Filter).
+logger:set_handler_config(h1, filter_default, stop).
+Filter = {fun logger_filters:level/2, {log, eq, debug}}.
+logger:add_handler_filter(h1, debug_only, Filter).
ok
This filter matches all progress reports
from
If
If
The filter returns
This filter matches all events originating from a process that has its group leader on a remote node.
-If
If
The filter returns
+
Each log handler has a configured formatter specified as a +
Each Logger handler has a configured formatter specified as a
module and a configuration term. The purpose of the formatter is
to translate the log events to a final printable string
(
A positive integer representing the value of the option
with the same name to be used when calling
@@ -65,14 +69,8 @@
for each log event. Notice that this is a soft limit. For a
hard truncation limit, see option
Defaults to
A positive integer representing the maximum depth to
which terms shall be printed by this formatter. Format
@@ -83,26 +81,23 @@
Defaults to
If set to
Defaults to
A positive integer representing the absolute maximum size a
string returned from this formatter can have. If the
@@ -110,12 +105,12 @@
by
Defaults to
A report callback is used by the formatter to transform
log messages on report form to a format string and
arguments. The report callback can be specified in the
- metadata for the log event. If no report callback exist
+ metadata for the log event. If no report callback exists
in metadata, If set to Defaults to The template describes how the formatted string is
composed by combining different data values from the log
@@ -183,32 +180,43 @@
The template is a list of atoms, tuples and strings. The +
The template is a list of atoms, atom lists, tuples and strings. The
atoms
-#{key1=>#{key2=>my_value,
- ...}
+
+#{key1 => #{key2 => my_value,
+ ...}
...}
- Strings in the template are printed literally.
- The default template differs depending on the values
- of legacy_header
- and single_line :
+ Tuples in the template express if-exist tests for metadata
+ keys. For example, the following tuple says that
+ if key1 exists in the metadata map,
+ print "key1=Value" , where Value is the value
+ that key1 is associated with in the metadata map. If
+ key1 does not exist, print nothing.
+
+{key1, ["key1=",key1], []}
+ Strings in the template are printed literally.
The default value for the template configuration
parameter depends on the value of the single_line
and legacy_header configuration parameters as
@@ -216,13 +224,13 @@
The log event used in the examples is:
-?LOG_ERROR("name: ~p~nexit_reason: ~p",[my_name,"It crashed"])
+?LOG_ERROR("name: ~p~nexit_reason: ~p", [my_name, "It crashed"])
Default
- template:
Example log entry:
@@ -231,15 +239,16 @@ name: my_name
exit_reason: "It crashed"
Notice that all eight levels can occur in the heading,
- not only
Default
- template:
Notice that the template is here the same as
for
Default template:
Default template:
This callback function is called by Logger when the - formatter configuration for a handler is set or modified. It +
The function is called by Logger when the formatter
+ configuration for a handler is set or modified. It
returns
The following Logger API functions can trigger this callback:
+
+
There are a number of other configuration parameters available, that are @@ -99,26 +99,26 @@ logger:add_handler(my_standard_h, logger_std_h, #{level => info, filter_default => log, - logger_std_h => - #{type => {file,"./system_info.log"}, - filesync_repeat_interval => 1000}}). + config => + #{type => {file,"./system_info.log"}, + filesync_repeat_interval => 1000}}).
In order to configure the default handler (that starts initially with
the Kernel application) to log to file instead of
erl -kernel logger '[{handler,default,logger_std_h,
- #{ logger_std_h => #{ type => {file,"./log.log"}}}}]'
+ #{config => #{type => {file,"./log.log"}}}}]'
An example of how to replace the standard handler with a disk_log handler
- at startup can be found in the manual of
+ at start up can be found in the manual of
Write buffered data to disk.
@@ -129,8 +129,9 @@ erl -kernel logger '[{handler,default,logger_std_h,The System Architecture Support Libraries SASL application - provides support for alarm handling, release handling, and - related functions.
+The SASL error logging concept desribed in this section is - deprecated since OTP-21, when the +
The SASL error logging concept described in this section is
+ deprecated since Erlang/OTP 21.0, when the
new
The new default behaviour is that the SASL application no
@@ -45,9 +45,10 @@
which is setup by
Kernel.
The old SASL error logging behaviour can be re-enabled by setting the
Kernel configuration
parameter When the SASL application is started, it adds a logger handler
+ When the SASL application is started, it adds a Logger handler
that formats and writes these reports, as specified in
the
If the old error logger event handlers are still desired, they
must be added by
calling
A similar behaviour, but still using the new logger API, can be
obtained by setting the Kernel application environment
- variable
The
The
The standard behaviours (
Prior to Erlang/OTP 21.0, supervisor, crash, and progress
reports were only logged when the SASL application was
running. This behaviour can, for backwards compatibility, be
enabled by setting the Kernel configuration
- parameter
-% erl -kernel logger_progress_reports log -Erlang/OTP 21 [erts-10.0] [source-76388a1] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:1] [hipe] +% erl -kernel logger_level info +Erlang/OTP 21 [erts-10.0] [source-13c50db] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:1] [hipe] -=PROGRESS REPORT==== 18-May-2018::21:33:41.705292 === +=PROGRESS REPORT==== 8-Jun-2018::16:54:19.916404 === application: kernel started_at: nonode@nohost -=PROGRESS REPORT==== 18-May-2018::21:33:41.708900 === +=PROGRESS REPORT==== 8-Jun-2018::16:54:19.922908 === application: stdlib started_at: nonode@nohost -=PROGRESS REPORT==== 18-May-2018::21:33:41.726003 === +=PROGRESS REPORT==== 8-Jun-2018::16:54:19.925755 === supervisor: {local,kernel_safe_sup} - started: [{pid,<0.75.0>}, + started: [{pid,<0.74.0>}, {id,disk_log_sup}, {mfargs,{disk_log_sup,start_link,[]}}, {restart_type,permanent}, {shutdown,1000}, {child_type,supervisor}] -=PROGRESS REPORT==== 18-May-2018::21:33:41.726348 === +=PROGRESS REPORT==== 8-Jun-2018::16:54:19.926056 === supervisor: {local,kernel_safe_sup} - started: [{pid,<0.76.0>}, + started: [{pid,<0.75.0>}, {id,disk_log_server}, {mfargs,{disk_log_server,start_link,[]}}, {restart_type,permanent}, {shutdown,2000}, {child_type,worker}] -Eshell V9.3.1 (abort with ^G) +Eshell V10.0 (abort with ^G) 1>