Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
home:Ledest:erlang:23
erlang
3791-feat-kernel-allow-reconfiguration-of-logge...
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File 3791-feat-kernel-allow-reconfiguration-of-logger.patch of Package erlang
From f7916862465ad18eb1b71a17a714449a20f29733 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Niemier?= <lukasz@niemier.pl> Date: Tue, 23 Mar 2021 12:07:48 +0100 Subject: [PATCH] feat(kernel): allow reconfiguration of logger This adds function `logger:reconfigure/0` that allows to reset logger configuration to what is configured in `kernel` application configuration. This function is meant to be used by build/run tools like Rebar3 or Mix to provide "production-like" way to configure logging in reliable way. This function is obviously not safe to be called during application runtime, as it may cause losing some log messages, but it is by far better solution than what we have now, where Rebar3 tries to reimplement such functionality on their own (risking incompatibilities if `logger` configuration will be expanded one day) or just ignore it, and requires users to configure logging on their own (like Mix does, that just relies that users will use Elixir's Logger). Lack of such functionality prevents Elixir from further integration with Erlang's Logger. Additionally this hides `logger:internal_init_logger/0` call, as `logger:reconfigure/0` already does the same thing, just with additional step to cleanup state before running initialization step, which in clean startup is just no-op. Co-authored-by: Mikko Ahlroth <mikko@ahlroth.fi> Co-authored-by: Lukas Larsson <garazdawi@gmail.com> --- lib/kernel/doc/src/logger.xml | 12 +++++++ lib/kernel/src/logger.erl | 30 ++++++++++++++-- lib/kernel/test/logger_SUITE.erl | 59 ++++++++++++-------------------- 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=""/> + <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. -- 2.31.1
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor