summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLukas Larsson <lukas@erlang.org>2021-09-30 11:49:30 +0200
committerGitHub <noreply@github.com>2021-09-30 11:49:30 +0200
commit0efa5ed6563614b2e68be9790c7b6bb3205658de (patch)
tree6173e3c81c9cdf9fe2931e0bff7672d308c283c7
parent1f26b218ea612627a3ae10af06680627fff20cfc (diff)
parentf7916862465ad18eb1b71a17a714449a20f29733 (diff)
downloaderlang-0efa5ed6563614b2e68be9790c7b6bb3205658de.tar.gz
Merge pull request #5186 from hauleth/feat/allow-reconfiguration-of-logger/OTP-17375
Allow reconfiguration of logger
-rw-r--r--lib/kernel/doc/src/logger.xml12
-rw-r--r--lib/kernel/src/logger.erl30
-rw-r--r--lib/kernel/test/logger_SUITE.erl59
3 files changed, 62 insertions, 39 deletions
diff --git a/lib/kernel/doc/src/logger.xml b/lib/kernel/doc/src/logger.xml
index 1c17004aa0..68d1984c7f 100644
--- a/lib/kernel/doc/src/logger.xml
+++ b/lib/kernel/doc/src/logger.xml
@@ -1189,6 +1189,18 @@ logger:set_proxy_config(maps:merge(Old, Config)).
</desc>
</func>
+ <func>
+ <name name="reconfigure" arity="0" since="OTP @OTP-17375@"/>
+ <fsummary>Reconfigure Logger.</fsummary>
+ <desc>
+ <p>Reconfigure Logger using updated <c>kernel</c> configuration
+ that was set after <c>kernel</c> application was loaded.</p>
+ <p>Beware, that this is meant to be run only by the build tools,
+ not manually during application lifetime, as this may cause
+ missing log entries.</p>
+ </desc>
+ </func>
+
</funcs>
diff --git a/lib/kernel/src/logger.erl b/lib/kernel/src/logger.erl
index ea75c8d720..9107bf0e61 100644
--- a/lib/kernel/src/logger.erl
+++ b/lib/kernel/src/logger.erl
@@ -51,9 +51,9 @@
get_primary_config/0, get_handler_config/1,
get_handler_config/0, get_handler_ids/0, get_config/0,
get_proxy_config/0,
- add_handlers/1]).
+ add_handlers/1,
+ reconfigure/0]).
-%% Private configuration
-export([internal_init_logger/0]).
%% Misc
@@ -794,6 +794,31 @@ print_module_levels(Modules,M) ->
[print_module_levels(Module,M) || Module <- Modules],
ok.
+-spec reconfigure() -> ok | {error,term()}.
+%% This function is meant to be used by the build tools like Rebar3 or Mix
+%% to ensure that the logger configuration is reset to the expected state
+%% before running main application.
+reconfigure() ->
+ try
+ [case logger:remove_handler(Id) of
+ ok -> ok;
+ {error, Reason} -> throw({remove, Id, Reason})
+ end || #{id := Id} <- logger:get_handler_config()],
+ ok=logger:add_handler(simple,logger_simple_h,
+ #{filter_default=>stop,
+ filters=>?DEFAULT_HANDLER_FILTERS}),
+ logger:unset_module_level(),
+ internal_init_logger()
+ of
+ ok ->
+ logger:add_handlers(kernel);
+ Error ->
+ Error
+ catch
+ throw:Reason ->
+ {error, Reason}
+ end.
+
-spec internal_init_logger() -> ok | {error,term()}.
%% This function is responsible for config of the logger
%% This is done before add_handlers because we want the
@@ -807,6 +832,7 @@ internal_init_logger() ->
ok = logger:set_primary_config(metadata, get_primary_metadata()),
ok = logger:set_primary_config(filter_default,
get_primary_filter_default(Env)),
+ ok = logger:set_primary_config(filters, []),
[case logger:add_primary_filter(Id, Filter) of
ok -> ok;
diff --git a/lib/kernel/test/logger_SUITE.erl b/lib/kernel/test/logger_SUITE.erl
index 82533ab572..5545759b5d 100644
--- a/lib/kernel/test/logger_SUITE.erl
+++ b/lib/kernel/test/logger_SUITE.erl
@@ -24,6 +24,7 @@
-include_lib("common_test/include/ct.hrl").
-include_lib("kernel/include/logger.hrl").
-include_lib("kernel/src/logger_internal.hrl").
+-include_lib("stdlib/include/assert.hrl").
-define(str,"Log from "++atom_to_list(?FUNCTION_NAME)++
":"++integer_to_list(?LINE)).
@@ -1009,15 +1010,14 @@ app_config(Config) ->
%% start, it is not possible to see code coverage in that test.
kernel_config(Config) ->
%% Start a node with simple handler only, then simulate kernel
- %% start by calling internally exported
- %% internal_init_logger(). This is to test all variants of kernel
- %% config, including bad config, and see the code coverage.
+ %% start by calling logger:reconfigure(). This is to test all
+ %% variants of kernel config, including bad config, and see
+ %% the code coverage.
{ok,#{handlers:=[#{id:=simple,filters:=DF}]}=LC,Node} =
logger_test_lib:setup(Config,[{error_logger,false}]),
%% Same once more, to get coverage
ok = rpc:call(Node,logger,internal_init_logger,[]),
- ok = rpc:call(Node,logger,add_handlers,[kernel]),
LC = rpc:call(Node,logger,get_config,[]),
%% This shall mean the same as above, but using 'logger' parameter
@@ -1025,15 +1025,13 @@ kernel_config(Config) ->
ok = rpc:call(Node,application,unset_env,[kernel,error_logger]),
ok = rpc:call(Node,application,set_env,
[kernel,logger,[{handler,default,undefined}]]),
- ok = rpc:call(Node,logger,internal_init_logger,[]),
- ok = rpc:call(Node,logger,add_handlers,[kernel]),
- LC = rpc:call(Node,logger,get_config,[]),
+ ok = rpc:call(Node,logger,reconfigure,[]),
+ ?assertEqual(LC, rpc:call(Node,logger,get_config,[])),
%% Silent
ok = rpc:call(Node,application,unset_env,[kernel,logger]),
ok = rpc:call(Node,application,set_env,[kernel,error_logger,silent]),
- ok = rpc:call(Node,logger,internal_init_logger,[]),
- ok = rpc:call(Node,logger,add_handlers,[kernel]),
+ ok = rpc:call(Node,logger,reconfigure,[]),
#{primary:=#{filter_default:=log,filters:=[]},
handlers:=[],
module_levels:=[]} = rpc:call(Node,logger,get_config,[]),
@@ -1041,30 +1039,25 @@ kernel_config(Config) ->
%% Default
ok = rpc:call(Node,application,unset_env,[kernel,error_logger]),
ok = rpc:call(Node,application,unset_env,[kernel,logger]),
- ok = rpc:call(Node,logger,internal_init_logger,[]),
- ok = rpc:call(Node,logger,add_handlers,[kernel]),
+ ok = rpc:call(Node,logger,reconfigure,[]),
#{primary:=#{filter_default:=log,filters:=[]},
handlers:=[#{id:=default,filters:=DF,config:=#{type:=standard_io}}],
module_levels:=[]} = rpc:call(Node,logger,get_config,[]),
%% error_logger=tty (same as default)
- ok = rpc:call(Node,logger,remove_handler,[default]),% so it can be added again
ok = rpc:call(Node,application,set_env,[kernel,error_logger,tty]),
ok = rpc:call(Node,application,unset_env,[kernel,logger]),
- ok = rpc:call(Node,logger,internal_init_logger,[]),
- ok = rpc:call(Node,logger,add_handlers,[kernel]),
+ ok = rpc:call(Node,logger,reconfigure,[]),
#{primary:=#{filter_default:=log,filters:=[]},
handlers:=[#{id:=default,filters:=DF,config:=#{type:=standard_io}}],
module_levels:=[]} = rpc:call(Node,logger,get_config,[]),
%% error_logger={file,File}
- ok = rpc:call(Node,logger,remove_handler,[default]),% so it can be added again
F = filename:join(?config(priv_dir,Config),
atom_to_list(?FUNCTION_NAME)++".log"),
ok = rpc:call(Node,application,set_env,[kernel,error_logger,{file,F}]),
ok = rpc:call(Node,application,unset_env,[kernel,logger]),
- ok = rpc:call(Node,logger,internal_init_logger,[]),
- ok = rpc:call(Node,logger,add_handlers,[kernel]),
+ ok = rpc:call(Node,logger,reconfigure,[]),
#{primary:=#{filter_default:=log,filters:=[]},
handlers:=[#{id:=default,filters:=DF,
config:=#{type:=file,file:=F,modes:=Modes}}],
@@ -1073,55 +1066,47 @@ kernel_config(Config) ->
%% Same, but using 'logger' parameter instead of 'error_logger'
- ok = rpc:call(Node,logger,remove_handler,[default]),% so it can be added again
ok = rpc:call(Node,application,unset_env,[kernel,error_logger]),
ok = rpc:call(Node,application,set_env,[kernel,logger,
[{handler,default,logger_std_h,
#{config=>#{type=>{file,F}}}}]]),
- ok = rpc:call(Node,logger,internal_init_logger,[]),
- ok = rpc:call(Node,logger,add_handlers,[kernel]),
+ ok = rpc:call(Node,logger,reconfigure,[]),
#{primary:=#{filter_default:=log,filters:=[]},
handlers:=[#{id:=default,filters:=DF,
config:=#{type:=file,file:=F,modes:=Modes}}],
module_levels:=[]} = rpc:call(Node,logger,get_config,[]),
%% Same, but with type={file,File,Modes}
- ok = rpc:call(Node,logger,remove_handler,[default]),% so it can be added again
ok = rpc:call(Node,application,unset_env,[kernel,error_logger]),
M = [raw,write],
ok = rpc:call(Node,application,set_env,[kernel,logger,
[{handler,default,logger_std_h,
#{config=>#{type=>{file,F,M}}}}]]),
- ok = rpc:call(Node,logger,internal_init_logger,[]),
- ok = rpc:call(Node,logger,add_handlers,[kernel]),
+ ok = rpc:call(Node,logger,reconfigure,[]),
#{primary:=#{filter_default:=log,filters:=[]},
handlers:=[#{id:=default,filters:=DF,
config:=#{type:=file,file:=F,modes:=[delayed_write|M]}}],
module_levels:=[]} = rpc:call(Node,logger,get_config,[]),
%% Same, but with disk_log handler
- ok = rpc:call(Node,logger,remove_handler,[default]),% so it can be added again
ok = rpc:call(Node,application,unset_env,[kernel,error_logger]),
ok = rpc:call(Node,application,set_env,[kernel,logger,
[{handler,default,logger_disk_log_h,
#{config=>#{file=>F}}}]]),
- ok = rpc:call(Node,logger,internal_init_logger,[]),
- ok = rpc:call(Node,logger,add_handlers,[kernel]),
+ ok = rpc:call(Node,logger,reconfigure,[]),
#{primary:=#{filter_default:=log,filters:=[]},
handlers:=[#{id:=default,filters:=DF,config:=#{file:=F}}],
module_levels:=[]} = rpc:call(Node,logger,get_config,[]),
%% Set primary filters and module level. No default handler.
- ok = rpc:call(Node,logger,remove_handler,[default]),% so it can be added again
ok = rpc:call(Node,application,unset_env,[kernel,error_logger]),
ok = rpc:call(Node,application,set_env,
[kernel,logger,[{handler,default,undefined},
{filters,stop,[{f1,{fun(_,_) -> log end,ok}}]},
{module_level,debug,[?MODULE]}]]),
- ok = rpc:call(Node,logger,internal_init_logger,[]),
- ok = rpc:call(Node,logger,add_handlers,[kernel]),
+ ok = rpc:call(Node,logger,reconfigure,[]),
#{primary:=#{filter_default:=stop,filters:=[_]},
- handlers:=[],
+ handlers:=[#{id:=simple}],
module_levels:=[{?MODULE,debug}]} = rpc:call(Node,logger,get_config,[]),
%% Bad config
@@ -1129,38 +1114,38 @@ kernel_config(Config) ->
ok = rpc:call(Node,application,set_env,[kernel,error_logger,bad]),
{error,{bad_config,{kernel,{error_logger,bad}}}} =
- rpc:call(Node,logger,internal_init_logger,[]),
+ rpc:call(Node,logger,reconfigure,[]),
ok = rpc:call(Node,application,unset_env,[kernel,error_logger]),
ok = rpc:call(Node,application,set_env,[kernel,logger_level,bad]),
{error,{bad_config,{kernel,{logger_level,bad}}}} =
- rpc:call(Node,logger,internal_init_logger,[]),
+ rpc:call(Node,logger,reconfigure,[]),
ok = rpc:call(Node,application,unset_env,[kernel,logger_level]),
ok = rpc:call(Node,application,set_env,
[kernel,logger,[{filters,stop,[bad]}]]),
{error,{bad_config,{kernel,{invalid_filters,[bad]}}}} =
- rpc:call(Node,logger,internal_init_logger,[]),
+ rpc:call(Node,logger,reconfigure,[]),
ok = rpc:call(Node,application,set_env,
[kernel,logger,[{filters,stop,[bad]}]]),
{error,{bad_config,{kernel,{invalid_filters,[bad]}}}} =
- rpc:call(Node,logger,internal_init_logger,[]),
+ rpc:call(Node,logger,reconfigure,[]),
ok = rpc:call(Node,application,set_env,
[kernel,logger,[{filters,stop,[{f1,bad}]}]]),
{error,{bad_config,{kernel,{invalid_filter,{f1,bad}}}}} =
- rpc:call(Node,logger,internal_init_logger,[]),
+ rpc:call(Node,logger,reconfigure,[]),
ok = rpc:call(Node,application,set_env,
[kernel,logger,MF=[{filters,stop,[]},{filters,log,[]}]]),
{error,{bad_config,{kernel,{multiple_filters,MF}}}} =
- rpc:call(Node,logger,internal_init_logger,[]),
+ rpc:call(Node,logger,reconfigure,[]),
ok = rpc:call(Node,application,set_env,
[kernel,logger,[{module_level,bad,[?MODULE]}]]),
{error,{bad_config,{kernel,{invalid_level,bad}}}} =
- rpc:call(Node,logger,internal_init_logger,[]),
+ rpc:call(Node,logger,reconfigure,[]),
ok.