aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lib/kernel/doc/src/logger.xml25
-rw-r--r--lib/kernel/doc/src/logger_chapter.xml6
-rw-r--r--lib/kernel/src/logger.erl18
-rw-r--r--lib/kernel/src/logger_server.erl26
-rw-r--r--lib/kernel/test/logger_formatter_SUITE.erl61
5 files changed, 130 insertions, 6 deletions
diff --git a/lib/kernel/doc/src/logger.xml b/lib/kernel/doc/src/logger.xml
index f7e740e90d..be733685cc 100644
--- a/lib/kernel/doc/src/logger.xml
+++ b/lib/kernel/doc/src/logger.xml
@@ -774,6 +774,31 @@ logger:set_handler_config(HandlerId,maps:merge(Old,Config)).
</func>
<func>
+ <name name="update_formatter_config" arity="2"/>
+ <fsummary>Update the formatter configuration for the specified handler.</fsummary>
+ <desc>
+ <p>Update the formatter configuration for the specified handler.</p>
+ <p>The new configuration is merged with the existing formatter
+ configuration.</p>
+ <p>To overwrite the existing configuration without any merge,
+ use <seealso marker="#set_handler_config-3">
+ <c>set_handler_config(HandlerId,formatter,
+ {FormatterModule,FormatterConfig})</c></seealso>.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="update_formatter_config" arity="3"/>
+ <fsummary>Update the formatter configuration for the specified handler.</fsummary>
+ <desc>
+ <p>Update the formatter configuration for the specified handler.</p>
+ <p>This is equivalent
+ to <br/><seealso marker="#update_formatter_config-2">
+ <c>update_formatter_config(<anno>HandlerId</anno>,#{<anno>Key</anno>=><anno>Value</anno>})</c></seealso></p>
+ </desc>
+ </func>
+
+ <func>
<name name="compare_levels" arity="2"/>
<fsummary>Compare the severity of two log levels.</fsummary>
<desc>
diff --git a/lib/kernel/doc/src/logger_chapter.xml b/lib/kernel/doc/src/logger_chapter.xml
index 21b460e72a..522d0ce29d 100644
--- a/lib/kernel/doc/src/logger_chapter.xml
+++ b/lib/kernel/doc/src/logger_chapter.xml
@@ -157,7 +157,7 @@
<p>A formatter is defined as a module exporting the following
function:</p>
- <code>format(Log,Extra) -> unicode:chardata()</code>
+ <code>format(Log,FConfig) -> unicode:chardata()</code>
<p>The formatter callback is called by each handler, and the
returned string can be printed to the handler's destination
@@ -413,12 +413,12 @@
return <c>ignore</c>.</p>
<p>Default is <c>log</c>.</p>
</item>
- <tag><c>formatter = {Module::module(),Extra::term()}</c></tag>
+ <tag><c>formatter = {FModule::module(),FConfig::map()}</c></tag>
<item>
<p>See <seealso marker="#Formatter">Formatter</seealso> for more
information.</p>
<p>The default module is <seealso marker="logger_formatter">
- <c>logger_formatter</c></seealso>, and <c>Extra</c> is
+ <c>logger_formatter</c></seealso>, and <c>FConfig</c> is
it's configuration map.</p>
</item>
<tag>HandlerConfig, <c>term() = term()</c></tag>
diff --git a/lib/kernel/src/logger.erl b/lib/kernel/src/logger.erl
index 51743822af..d60be180bc 100644
--- a/lib/kernel/src/logger.erl
+++ b/lib/kernel/src/logger.erl
@@ -41,6 +41,7 @@
set_logger_config/1, set_logger_config/2,
set_handler_config/2, set_handler_config/3,
update_logger_config/1, update_handler_config/2,
+ update_formatter_config/2, update_formatter_config/3,
get_logger_config/0, get_handler_config/1,
add_handlers/1]).
@@ -92,7 +93,7 @@
-type config() :: #{level => level(),
filter_default => log | stop,
filters => [{filter_id(),filter()}],
- formatter => {module(),term()},
+ formatter => {module(),map()},
term() => term()}.
-type timestamp() :: integer().
@@ -386,6 +387,21 @@ get_logger_config() ->
get_handler_config(HandlerId) ->
logger_config:get(?LOGGER_TABLE,HandlerId).
+-spec update_formatter_config(HandlerId,FormatterConfig) ->
+ ok | {error,term()} when
+ HandlerId :: config(),
+ FormatterConfig :: map().
+update_formatter_config(HandlerId,FormatterConfig) ->
+ logger_server:update_formatter_config(HandlerId,FormatterConfig).
+
+-spec update_formatter_config(HandlerId,Key,Value) ->
+ ok | {error,term()} when
+ HandlerId :: config(),
+ Key :: atom(),
+ Value :: term().
+update_formatter_config(HandlerId,Key,Value) ->
+ logger_server:update_formatter_config(HandlerId,#{Key=>Value}).
+
-spec set_module_level(Module,Level) -> ok | {error,term()} when
Module :: module(),
Level :: level().
diff --git a/lib/kernel/src/logger_server.erl b/lib/kernel/src/logger_server.erl
index 67befef156..18a784c8c2 100644
--- a/lib/kernel/src/logger_server.erl
+++ b/lib/kernel/src/logger_server.erl
@@ -27,7 +27,8 @@
add_filter/2, remove_filter/2,
set_module_level/2, reset_module_level/1,
cache_module_level/1,
- set_config/2, set_config/3, update_config/2]).
+ set_config/2, set_config/3, update_config/2,
+ update_formatter_config/2]).
%% gen_server callbacks
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
@@ -111,6 +112,13 @@ update_config(Owner, Config) ->
Error
end.
+update_formatter_config(HandlerId, FormatterConfig)
+ when is_map(FormatterConfig) ->
+ call({update_formatter_config,HandlerId,FormatterConfig});
+update_formatter_config(_HandlerId, FormatterConfig) ->
+ {error,{invalid_formatter_config,FormatterConfig}}.
+
+
%%%===================================================================
%%% gen_server callbacks
%%%===================================================================
@@ -216,6 +224,22 @@ handle_call({set_config,HandlerId,Config}, From, #state{tid=Tid}=State) ->
_ ->
{reply,{error,{not_found,HandlerId}},State}
end;
+handle_call({update_formatter_config,HandlerId,NewFConfig},_From,
+ #state{tid=Tid}=State) ->
+ Reply =
+ case logger_config:get(Tid,HandlerId) of
+ {ok,{_Mod,#{formatter:={FMod,OldFConfig}}=Config}} ->
+ try
+ FConfig = maps:merge(OldFConfig,NewFConfig),
+ check_formatter({FMod,FConfig}),
+ do_set_config(Tid,HandlerId,
+ Config#{formatter=>{FMod,FConfig}})
+ catch throw:Reason -> {error,Reason}
+ end;
+ _ ->
+ {error,{not_found,HandlerId}}
+ end,
+ {reply,Reply,State};
handle_call({set_module_level,Module,Level}, _From, #state{tid=Tid}=State) ->
Reply = logger_config:set_module_level(Tid,Module,Level),
{reply,Reply,State};
diff --git a/lib/kernel/test/logger_formatter_SUITE.erl b/lib/kernel/test/logger_formatter_SUITE.erl
index c171165944..934fe4deef 100644
--- a/lib/kernel/test/logger_formatter_SUITE.erl
+++ b/lib/kernel/test/logger_formatter_SUITE.erl
@@ -68,7 +68,8 @@ all() ->
level_or_msg_in_meta,
faulty_log,
faulty_config,
- faulty_msg].
+ faulty_msg,
+ update_config].
default(_Config) ->
String1 = format(info,{"~p",[term]},#{},#{}),
@@ -532,6 +533,54 @@ faulty_msg(_Config) ->
#{})),
ok.
+%% Test that formatter config can be changed, and that the default
+%% template is updated accordingly
+update_config(_Config) ->
+ logger:add_handler_filter(default,silence,{fun(_,_) -> stop end,ok}),
+ ok = logger:add_handler(?MODULE,?MODULE,#{}),
+ D = lists:seq(1,1000),
+ logger:info("~p~n",[D]),
+ {Lines1,C1} = check_log(),
+ [ct:log(L) || L <- Lines1],
+ ct:log("~p",[C1]),
+ [Line1] = Lines1,
+ [_Time,"info: "++D1] = string:split(Line1," "),
+ true = length(D1)>3000,
+ true = #{}==C1,
+
+ ok = logger:update_formatter_config(?MODULE,single_line,false),
+ logger:info("~p~n",[D]),
+ {Lines2,C2} = check_log(),
+ [ct:log(L) || L <- Lines2],
+ ct:log("~p",[C2]),
+ true = length(Lines2)>50,
+ true = #{single_line=>false}==C2,
+
+ ok = logger:update_formatter_config(?MODULE,#{legacy_header=>true}),
+ logger:info("~p~n",[D]),
+ {Lines3,C3} = check_log(),
+ [ct:log(L) || L <- Lines3],
+ ct:log("~p",[C3]),
+ ["=INFO REPORT==== "++_|D3] = Lines3,
+ true = length(D3)>50,
+ true = #{legacy_header=>true,single_line=>false}==C3,
+
+ ok = logger:update_formatter_config(?MODULE,single_line,true),
+ logger:info("~p~n",[D]),
+ {Lines4,C4} = check_log(),
+ [ct:log(L) || L <- Lines4],
+ ct:log("~p",[C4]),
+ ["=INFO REPORT==== "++_,D4] = Lines4,
+ true = length(D4)>3000,
+ true = #{legacy_header=>true,single_line=>true}==C4,
+
+ ok.
+
+update_config(cleanup,_Config) ->
+ _ = logger:remove_handler(?MODULE),
+ _ = logger:remove_handler_filter(default,silence),
+ ok.
+
%%%-----------------------------------------------------------------
%%% Internal
format(Level,Msg,Meta,Config) ->
@@ -575,3 +624,13 @@ add_time(#{time:=_}=Meta) ->
Meta;
add_time(Meta) ->
Meta#{time=>timestamp()}.
+
+%%%-----------------------------------------------------------------
+%%% handler callback
+log(Log,#{formatter:={M,C}}) ->
+ put(log,{M:format(Log,C),C}),
+ ok.
+
+check_log() ->
+ {S,C} = erase(log),
+ {string:lexemes(S,"\n"),C}.