diff options
author | Siri Hansen <[email protected]> | 2018-04-24 14:55:29 +0200 |
---|---|---|
committer | Siri Hansen <[email protected]> | 2018-04-26 14:37:31 +0200 |
commit | 05e1548e5b452d4bfe3bc6837a1a1b51a6367f72 (patch) | |
tree | 83a136fcf3c3a3830ee1fe426d049217ad85c757 /lib/kernel | |
parent | 0deea4a8f369013ec00e231d0c2c37e4ab3f0ba1 (diff) | |
download | otp-05e1548e5b452d4bfe3bc6837a1a1b51a6367f72.tar.gz otp-05e1548e5b452d4bfe3bc6837a1a1b51a6367f72.tar.bz2 otp-05e1548e5b452d4bfe3bc6837a1a1b51a6367f72.zip |
Remove error_logger process and add logger process
Diffstat (limited to 'lib/kernel')
-rw-r--r-- | lib/kernel/doc/src/error_logger.xml | 19 | ||||
-rw-r--r-- | lib/kernel/doc/src/kernel_app.xml | 154 | ||||
-rw-r--r-- | lib/kernel/src/code_server.erl | 14 | ||||
-rw-r--r-- | lib/kernel/src/error_logger.erl | 545 | ||||
-rw-r--r-- | lib/kernel/src/kernel.erl | 26 |
5 files changed, 447 insertions, 311 deletions
diff --git a/lib/kernel/doc/src/error_logger.xml b/lib/kernel/doc/src/error_logger.xml index 91bf57cb91..cb6165c73e 100644 --- a/lib/kernel/doc/src/error_logger.xml +++ b/lib/kernel/doc/src/error_logger.xml @@ -31,6 +31,16 @@ <module>error_logger</module> <modulesummary>Erlang error logger.</modulesummary> <description> + + <note> + <p>In OTP-21, a new API for logging was added to Erlang/OTP. The + old <c>error_logger</c> module can still be used by legacy + code, but new code should use the new API instead.</p> + <p>See <seealso marker="logger"><c>logger(3)</c></seealso> and + the <seealso marker="logger_chapter">Logging</seealso> chapter + in the user's guide for more information.</p> + </note> + <p>The Erlang <em>error logger</em> is an event manager (see <seealso marker="doc/design_principles:des_princ">OTP Design Principles</seealso> and <seealso marker="stdlib:gen_event"><c>gen_event(3)</c></seealso>), @@ -171,14 +181,17 @@ ok</pre> <func> <name name="get_format_depth" arity="0"/> <fsummary>Get the value of the Kernel application variable - <c>error_logger_format_depth</c>.</fsummary> + <c>logger_format_depth</c>.</fsummary> <desc> <p>Returns <c>max(10, Depth)</c>, where <c>Depth</c> is the value of - <seealso marker="kernel:kernel_app#error_logger_format_depth"> - error_logger_format_depth</seealso> + <seealso marker="kernel_app#logger_format_depth"> + logger_format_depth</seealso> in the Kernel application, if Depth is an integer. Otherwise, <c>unlimited</c> is returned.</p> + <p>For backwards compatibility, the value + of <c>error_logger_format_depth</c> is used + if <c>logger_format_depth</c> is not set.</p> </desc> </func> <func> diff --git a/lib/kernel/doc/src/kernel_app.xml b/lib/kernel/doc/src/kernel_app.xml index 0762cebc94..554d675383 100644 --- a/lib/kernel/doc/src/kernel_app.xml +++ b/lib/kernel/doc/src/kernel_app.xml @@ -51,10 +51,13 @@ </description> <section> - <title>Error Logger Event Handlers</title> - <p>Two standard error logger event handlers are defined in - the Kernel application. These are described in - <seealso marker="error_logger"><c>error_logger(3)</c></seealso>.</p> + <title>Logger Handlers</title> + <p>Two standard logger handlers are defined in + the Kernel application. These are described in the + <seealso marker="logger_chapter">Kernel User's Guide</seealso>, + and in <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> </section> <section> @@ -113,6 +116,7 @@ </section> <section> + <marker id="configuration"/> <title>Configuration</title> <p>The following configuration parameters are defined for the Kernel application. For more information about configuration parameters, @@ -176,34 +180,105 @@ <p>Permissions are described in <seealso marker="application#permit/2"><c>application:permit/2</c></seealso>.</p> </item> - <tag><c>error_logger = Value</c></tag> + <tag><c>logger_dest = Value</c></tag> <item> <p><c>Value</c> is one of:</p> <taglist> <tag><c>tty</c></tag> - <item><p>Installs the standard event handler, which prints error - reports to <c>stdio</c>. This is the default option.</p></item> + <item><p>Installs the standard handler, <seealso marker="logger_std_h"> + <c>logger_std_h(3)</c></seealso>, with <c>type</c> set + to <c>standard_io</c>. This is the default + option.</p></item> <tag><c>{file, FileName}</c></tag> - <item><p>Installs the standard event handler, which prints error - reports to file <c>FileName</c>, where <c>FileName</c> + <item><p>Installs the standard handler, <seealso marker="logger_std_h"> + <c>logger_std_h(3)</c></seealso>, with <c>type</c> set + to <c>{file, FileName}</c>, where <c>FileName</c> is a string. The file is opened with encoding UTF-8.</p></item> + <tag><c>{disk_log, FileName}</c></tag> + <item><p>Installs the disk_log handler, <seealso marker="logger_disk_log_h"> + <c>logger_disk_log_h(3)</c></seealso>, with <c>file</c> set + to <c>FileName</c> (a string), and possibly other disk_log + parameters set by the environment variables + <c>logger_disk_log_type</c>, <c>logger_disk_log_maxfiles</c> and + <c>logger_disk_log_maxbytes</c>, + see <seealso marker="#disk_log_vars">below</seealso>. The + file is opened with encoding UTF-8.</p></item> <tag><c>false</c></tag> <item> - <p>No standard event handler is installed, but - the initial, primitive event handler is kept, printing + <p>No standard handler is installed, but + the initial, primitive handler is kept, printing raw event messages to <c>tty</c>.</p> </item> <tag><c>silent</c></tag> <item> - <p>Error logging is turned off.</p> + <p>No standard handler is started, and the initial, + primitive handler is removed.</p> </item> </taglist> </item> - <tag><c>error_logger_format_depth = Depth</c></tag> + <tag><c>logger_level = Level</c></tag> + <item> + <p><c>Value = emergency | alert | critical | error | warning | + notice | info | debug</c></p> + <p>This parameter specifies which log levels to log. The + specified level, and all levels that are more severe, will + be logged.</p> + <p>This configuration parameter is used both for the global + logger level, and for the standard handler started by + the Kernel application (see <c>logger_dest</c> variable above).</p> + <p>The default value is <c>info</c></p> + </item> + <tag><marker id="disk_log_vars"/> + <c>logger_disk_log_type = halt | wrap</c></tag> + <item/> + <tag><c>logger_disk_log_maxfiles = integer()</c></tag> + <item/> + <tag><c>logger_disk_log_maxbytes = integer()</c></tag> + <item> + <p>If <c>logger_dest</c> is set to {disk_log,File}, then these + parameters specify the configuration to use when opening the + disk log file. They specify the type of disk log, the + maximum number of files (if the type is wrap) and the + maximum size of each file, respectively.</p> + <p>The default values are:</p> + <code> +logger_disk_log_type = wrap +logger_disk_log_maxfiles = 10 +logger_disk_log_maxbytes = 1048576</code> + </item> + <tag><marker id="logger_sasl_compatible"/> + <c>logger_sasl_compatible = boolean()</c></tag> + <item> + <p>If this parameter is set to true, then the logger handler + started by kernel will not log any progress-, crash-, or + supervisor reports. If the SASL application is starated, + these log events will be sent to a second handler instance + named sasl_h, according to values of the SASL environment + variables <c>sasl_error_logger</c> + and <c>sasl_errlog_type</c>, see + <seealso marker="sasl:sasl_app#configuration">SASL(6) + </seealso></p> + <p>The default value is <c>false</c></p> + <p>See chapter <seealso marker="logger_chapter#compatibility">Backwards + compatibility with error_logger</seealso> for more + information about handling of the so called SASL reports.</p> + </item> + <tag><marker id="logger_log_progress"/> + <c>logger_log_progress = boolean()</c></tag> + <item> + <p>If <c>logger_sasl_compatible = false</c>, + then <c>logger_log_progress</c> specifies if progress + reports from <c>supervisor</c> + and <c>application_controller</c> shall be logged or + not.</p> + <p>If <c>logger_sasl_compatible = false</c>, + then <c>logger_log_progress</c> is ignored.</p> + </item> + <tag><marker id="logger_format_depth"/> + <c>logger_format_depth = Depth</c></tag> <item> - <marker id="error_logger_format_depth"></marker> <p>Can be used to limit the size of the - formatted output from the error logger event handlers.</p> + formatted output from the logger handlers.</p> <note><p>This configuration parameter was introduced in OTP 18.1 and is experimental. Based on user feedback, it @@ -214,16 +289,16 @@ useless.</p></note> <p><c>Depth</c> is a positive integer representing the maximum - depth to which terms are printed by the error logger event + depth to which terms are printed by the logger handlers included in OTP. This - configuration parameter is used by the two event handlers - defined by the Kernel application and the two event - handlers in the SASL application. - (If you have implemented your own error handlers, this configuration - parameter has no effect on them.)</p> + configuration parameter is used by the default formatter, + <seealso marker="logger_formatter"><c>logger_formatter(3)</c></seealso>, + unless the formatter's <c>depth</c> parameter is explicitly set. + (If you have implemented your own formatter, this configuration + parameter has no effect on that.)</p> <p><c>Depth</c> is used as follows: Format strings - passed to the event handlers are rewritten. + received by the formatter are rewritten. The format controls <c>~p</c> and <c>~w</c> are replaced with <c>~P</c> and <c>~W</c>, respectively, and <c>Depth</c> is used as the depth parameter. For details, see @@ -234,7 +309,20 @@ <c>30</c>. We recommend to test crashing various processes in your application, examine the logs from the crashes, and then increase or decrease the value.</p></note> - </item> + </item> + <tag><c>logger_max_size = integer() | unlimited</c></tag> + <item> + <p>This parameter specifies the maximum size (bytes) each + log event can have when printed by the standard logger + handler. If the resulting string after formatting an event + is bigger than this, it will be truncated before printed + to the handler's destination.</p> + </item> + <tag><c>logger_utc = boolean()</c></tag> + <item> + <p>If set to <c>true</c>, the default formatter will display + all dates in Universal Coordinated Time.</p> + </item> <tag><c>global_groups = [GroupTuple]</c></tag> <item> <marker id="global_groups"></marker> @@ -497,6 +585,26 @@ MaxT = TickTime + TickTime / 4</code> </section> <section> + <title>Deprecated Configuration Parameters</title> + <p>In OTP-21, a new API for logging was added to Erlang/OTP. The + old <c>error_logger</c> event manager, and event handlers + running on this manager, will still work, but they are not used + by default.</p> + <p>The following application environment variables can still be + set, but they will only be used if the corresponding new logger + variables are not set.</p> + <taglist> + <tag><c>error_logger</c></tag> + <item>Replaced by <c>logger_dest</c></item> + <tag><c>error_logger_format_depth</c></tag> + <item>Replaced by <c>logger_format_depth</c></item> + </taglist> + <p>See <seealso marker="logger_chapter#compatibility">Backwards + compatibility with error_logger</seealso> for more + information.</p> + </section> + + <section> <title>See Also</title> <p><seealso marker="app"><c>app(4)</c></seealso>, <seealso marker="application"><c>application(3)</c></seealso>, diff --git a/lib/kernel/src/code_server.erl b/lib/kernel/src/code_server.erl index f5a890cb95..bbfa2a995d 100644 --- a/lib/kernel/src/code_server.erl +++ b/lib/kernel/src/code_server.erl @@ -1434,14 +1434,20 @@ all_loaded(Db) -> -spec error_msg(io:format(), [term()]) -> 'ok'. error_msg(Format, Args) -> - Msg = {notify,{error, group_leader(), {self(), Format, Args}}}, - error_logger ! Msg, + logger ! {log,error,Format,Args, + #{pid=>self(), + gl=>group_leader(), + time=>erlang:monotonic_time(microsecond), + error_logger=>#{tag=>error}}}, ok. -spec info_msg(io:format(), [term()]) -> 'ok'. info_msg(Format, Args) -> - Msg = {notify,{info_msg, group_leader(), {self(), Format, Args}}}, - error_logger ! Msg, + logger ! {log,info,Format,Args, + #{pid=>self(), + gl=>group_leader(), + time=>erlang:monotonic_time(microsecond), + error_logger=>#{tag=>info_msg}}}, ok. objfile_extension() -> diff --git a/lib/kernel/src/error_logger.erl b/lib/kernel/src/error_logger.erl index 585507c545..0706220a94 100644 --- a/lib/kernel/src/error_logger.erl +++ b/lib/kernel/src/error_logger.erl @@ -19,22 +19,23 @@ %% -module(error_logger). --export([start/0,start_link/0,format/2,error_msg/1,error_msg/2,error_report/1, +-include("logger_internal.hrl"). + +-export([start/0,start_link/0,stop/0, + format/2,error_msg/1,error_msg/2,error_report/1, error_report/2,info_report/1,info_report/2,warning_report/1, warning_report/2,error_info/1, info_msg/1,info_msg/2,warning_msg/1,warning_msg/2, - logfile/1,tty/1,swap_handler/1, + logfile/1,tty/1, add_report_handler/1,add_report_handler/2, - delete_report_handler/1]). + delete_report_handler/1, + which_report_handlers/0]). --export([init/1, - handle_event/2, handle_call/2, handle_info/2, - terminate/2]). +%% logger callbacks +-export([adding_handler/2, removing_handler/1, log/2]). -export([get_format_depth/0, limit_term/1]). --define(buffer_size, 10). - %%----------------------------------------------------------------- %% Types used in this file %%----------------------------------------------------------------- @@ -43,8 +44,6 @@ | 'info' | 'info_msg' | 'info_report' | 'warning_msg' | 'warning_report'. --type state() :: {non_neg_integer(), non_neg_integer(), [term()]}. - %%% BIF -export([warning_map/0]). @@ -59,26 +58,137 @@ warning_map() -> %%----------------------------------------------------------------- --spec start() -> {'ok', pid()} | {'error', any()}. +%%%----------------------------------------------------------------- +%%% Start the event manager process under logger_sup, which is part of +%%% the kernel application's supervision tree. +-spec start() -> 'ok' | {'error', any()}. start() -> - case gen_event:start({local, error_logger}) of - {ok, Pid} -> - simple_logger(?buffer_size), - {ok, Pid}; - Error -> Error + case whereis(?MODULE) of + undefined -> + ErrorLogger = + #{id => ?MODULE, + start => {?MODULE, start_link, []}, + restart => transient, + shutdown => 2000, + type => worker, + modules => dynamic}, + case supervisor:start_child(logger_sup, ErrorLogger) of + {ok,_} -> + ok; + Error -> + Error + end; + _ -> + ok end. +%%%----------------------------------------------------------------- +%%% Start callback specified in child specification to supervisor, see start/0 -spec start_link() -> {'ok', pid()} | {'error', any()}. start_link() -> - case gen_event:start_link({local, error_logger}) of - {ok, Pid} -> - simple_logger(?buffer_size), - {ok, Pid}; - Error -> Error + gen_event:start_link({local, ?MODULE}, + [{spawn_opt,[{message_queue_data, off_heap}]}]). + +%%%----------------------------------------------------------------- +%%% Stop the event manager +-spec stop() -> ok. +stop() -> + _ = supervisor:terminate_child(logger_sup,?MODULE), + _ = supervisor:delete_child(logger_sup,?MODULE), + ok. + +%%%----------------------------------------------------------------- +%%% Callbacks for logger +-spec adding_handler(logger:handler_id(),logger:config()) -> + {ok,logger:config()} | {error,term()}. +adding_handler(?MODULE,Config) -> + case start() of + ok -> + {ok,Config}; + Error -> + Error end. +-spec removing_handler(logger:handler_id()) -> ok. +removing_handler(?MODULE) -> + stop(), + ok. + +-spec log(logger:log(),logger:config()) -> ok. +log(#{level:=Level,msg:=Msg,meta:=Meta},_Config) -> + do_log(Level,Msg,Meta). + +do_log(Level,{report,Msg},#{?MODULE:=#{tag:=Tag,type:=Type}}=Meta) -> + %% From error_logger:*_report/1,2, or logger call which added + %% error_logger data to obtain backwards compatibility with + %% error_logger:*_report/1,2 + Report = + case Msg of + #{label:=_,report:=R} -> R; + _ -> Msg + end, + notify(Level,Tag,Type,Report,Meta); +do_log(Level,{report,Msg},#{?MODULE:=#{tag:=Tag}}=Meta) -> + {Format,Args} = + case Msg of + #{label:=_,format:=F,args:=A} -> + %% From error_logger:*_msg/1,2. + %% In order to be backwards compatible with handling + %% of faulty parameters to error_logger:*_msg/1,2, + %% don't use report_cb here. + {F,A}; + _ -> + %% From logger call which added error_logger data to + %% obtain backwards compatibility with error_logger:*_msg/1,2 + RCBFun=maps:get(report_cb,Meta,fun logger:format_report/1), + try RCBFun(Msg) of + {F,A} when is_list(F), is_list(A) -> + {F,A}; + Other -> + {"REPORT_CB ERROR: ~tp; Returned: ~tp",[Msg,Other]} + catch C:R -> + {"REPORT_CB CRASH: ~tp; Reason: ~tp",[Msg,{C,R}]} + end + end, + notify(Level,Tag,Format,Args,Meta); +do_log(Level,{Format,Args},#{?MODULE:=#{tag:=Tag}}=Meta) + when is_list(Format), is_list(Args) -> + %% From logger call which added error_logger data to obtain + %% backwards compatibility with error_logger:*_msg/1,2 + notify(Level,Tag,Format,Args,Meta); +do_log(_Level,_Msg,_Meta) -> + %% Ignore the rest - i.e. to get backwards compatibility with + %% error_logger, you must use the error_logger API for logging. + %% Some modules within OTP go around this by adding an + %% error_logger field to its metadata. This is done only to allow + %% complete backwards compatibility for log events originating + %% from within OTP, while still using the new logger interface. + ok. + +-spec notify(logger:level(), msg_tag(), any(), any(), map()) -> 'ok'. +notify(Level,Tag0,FormatOrType0,ArgsOrReport,#{pid:=Pid0,gl:=GL,?MODULE:=My}) -> + Tag = fix_warning_tag(Level,Tag0), + Pid = case maps:get(emulator,My,false) of + true -> emulator; + _ -> Pid0 + end, + FormatOrType = fix_warning_type(Level,FormatOrType0), + gen_event:notify(?MODULE,{Tag,GL,{Pid,FormatOrType,ArgsOrReport}}). + +%% This is to fix the case when the client has explicitly added the +%% error logger tag and type in metadata, and not checked the warning map. +fix_warning_tag(error,warning_msg) -> error; +fix_warning_tag(error,warning_report) -> error_report; +fix_warning_tag(info,warning_msg) -> info_msg; +fix_warning_tag(info,warning_report) -> info_report; +fix_warning_tag(_,Tag) -> Tag. + +fix_warning_type(error,std_warning) -> std_error; +fix_warning_type(info,std_warning) -> std_info; +fix_warning_type(_,Type) -> Type. + %%----------------------------------------------------------------- %% These two simple old functions generate events tagged 'error' %% Used for simple messages; error or information. @@ -95,14 +205,18 @@ error_msg(Format) -> Data :: list(). error_msg(Format, Args) -> - notify({error, group_leader(), {self(), Format, Args}}). + logger:log(error, + #{label=>{?MODULE,error_msg}, + format=>Format, + args=>Args}, + meta(error)). -spec format(Format, Data) -> 'ok' when Format :: string(), Data :: list(). format(Format, Args) -> - notify({error, group_leader(), {self(), Format, Args}}). + error_msg(Format, Args). %%----------------------------------------------------------------- %% This functions should be used for error reports. Events @@ -124,7 +238,10 @@ error_report(Report) -> Report :: report(). error_report(Type, Report) -> - notify({error_report, group_leader(), {self(), Type, Report}}). + logger:log(error, + #{label=>{?MODULE,error_report}, + report=>Report}, + meta(error_report,Type)). %%----------------------------------------------------------------- %% This function should be used for warning reports. @@ -146,7 +263,8 @@ warning_report(Report) -> Report :: report(). warning_report(Type, Report) -> - {Tag, NType} = case error_logger:warning_map() of + Level = error_logger:warning_map(), + {Tag, NType} = case Level of info -> if Type =:= std_warning -> @@ -164,7 +282,10 @@ warning_report(Type, Report) -> {error_report, Type} end end, - notify({Tag, group_leader(), {self(), NType, Report}}). + logger:log(Level, + #{label=>{?MODULE,warning_report}, + report=>Report}, + meta(Tag,NType)). %%----------------------------------------------------------------- %% This function provides similar functions as error_msg for @@ -183,7 +304,8 @@ warning_msg(Format) -> Data :: list(). warning_msg(Format, Args) -> - Tag = case error_logger:warning_map() of + Level = error_logger:warning_map(), + Tag = case Level of warning -> warning_msg; info -> @@ -191,7 +313,11 @@ warning_msg(Format, Args) -> error -> error end, - notify({Tag, group_leader(), {self(), Format, Args}}). + logger:log(Level, + #{label=>{?MODULE,warning_msg}, + format=>Format, + args=>Args}, + meta(Tag)). %%----------------------------------------------------------------- %% This function should be used for information reports. Events @@ -210,7 +336,10 @@ info_report(Report) -> Report :: report(). info_report(Type, Report) -> - notify({info_report, group_leader(), {self(), Type, Report}}). + logger:log(info, + #{label=>{?MODULE,info_report}, + report=>Report}, + meta(info_report,Type)). %%----------------------------------------------------------------- %% This function provides similar functions as error_msg for @@ -228,7 +357,11 @@ info_msg(Format) -> Data :: list(). info_msg(Format, Args) -> - notify({info_msg, group_leader(), {self(), Format, Args}}). + logger:log(info, + #{label=>{?MODULE,info_msg}, + format=>Format, + args=>Args}, + meta(info_msg)). %%----------------------------------------------------------------- %% Used by the init process. Events are tagged 'info'. @@ -236,38 +369,75 @@ info_msg(Format, Args) -> -spec error_info(Error :: any()) -> 'ok'. +%% unused? error_info(Error) -> - notify({info, group_leader(), {self(), Error, []}}). - --spec notify({msg_tag(), pid(), {pid(), any(), any()}}) -> 'ok'. - -notify(Msg) -> - gen_event:notify(error_logger, Msg). - --type swap_handler_type() :: 'false' | 'silent' | 'tty' | {'logfile', string()}. --spec swap_handler(Type :: swap_handler_type()) -> any(). - -swap_handler(tty) -> - R = gen_event:swap_handler(error_logger, {error_logger, swap}, - {error_logger_tty_h, []}), - ok = simple_logger(), - R; -swap_handler({logfile, File}) -> - R = gen_event:swap_handler(error_logger, {error_logger, swap}, - {error_logger_file_h, File}), - ok = simple_logger(), - R; -swap_handler(silent) -> - _ = gen_event:delete_handler(error_logger, error_logger, delete), - ok = simple_logger(); -swap_handler(false) -> - ok. % keep primitive event handler as-is + {Format,Args} = + case string_p(Error) of + true -> {Error,[]}; + false -> {"~p",[Error]} + end, + MyMeta = #{tag=>info,type=>Error}, + logger:log(info, Format, Args, #{?MODULE=>MyMeta,domain=>[Error]}). + +%%----------------------------------------------------------------- +%% Create metadata +meta(Tag) -> + meta(Tag,undefined). +meta(Tag,Type) -> + meta(Tag,Type,#{report_cb=>fun report_to_format/1}). +meta(Tag,undefined,Meta0) -> + Meta0#{?MODULE=>#{tag=>Tag}}; +meta(Tag,Type,Meta0) -> + maybe_add_domain(Tag,Type,Meta0#{?MODULE=>#{tag=>Tag,type=>Type}}). + +%% This is to prevent events of non standard type from being printed +%% with the standard logger. Similar to how error_logger_tty_h +%% discards events of non standard type. +maybe_add_domain(error_report,std_error,Meta) -> Meta; +maybe_add_domain(info_report,std_info,Meta) -> Meta; +maybe_add_domain(warning_report,std_warning,Meta) -> Meta; +maybe_add_domain(_,Type,Meta) -> Meta#{domain=>[Type]}. + +%% ----------------------------------------------------------------- +%% Report formatting - i.e. Term => {Format,Args} +%% This was earlier done in the event handler (error_logger_tty_h, etc) +%% ----------------------------------------------------------------- +report_to_format(#{label:={?MODULE,_}, + report:=Report}) when is_map(Report) -> + %% logger:format_otp_report does maps:to_list, and for backwards + %% compatibility reasons we don't want that. + {"~tp\n",[Report]}; +report_to_format(#{label:={?MODULE,_}, + format:=Format, + args:=Args}) -> + %% This is not efficient, but needed for backwards compatibility + %% in giving faulty arguments to the *_msg functions. + try io_lib:scan_format(Format,Args) of + _ -> {Format,Args} + catch _:_ -> + {"ERROR: ~tp - ~tp",[Format,Args]} + end; +report_to_format(Term) -> + logger:format_otp_report(Term). +string_p(List) when is_list(List) -> + string_p1(lists:flatten(List)); +string_p(_) -> + false. + +string_p1([]) -> + false; +string_p1(FlatList) -> + io_lib:printable_list(FlatList). + +%% ----------------------------------------------------------------- +%% Stuff directly related to the event manager +%% ----------------------------------------------------------------- -spec add_report_handler(Handler) -> any() when Handler :: module(). add_report_handler(Module) when is_atom(Module) -> - gen_event:add_handler(error_logger, Module, []). + add_report_handler(Module, []). -spec add_report_handler(Handler, Args) -> Result when Handler :: module(), @@ -275,24 +445,37 @@ add_report_handler(Module) when is_atom(Module) -> Result :: gen_event:add_handler_ret(). add_report_handler(Module, Args) when is_atom(Module) -> - gen_event:add_handler(error_logger, Module, Args). + _ = logger:add_handler(?MODULE,?MODULE,#{level=>info,filter_default=>log}), + gen_event:add_handler(?MODULE, Module, Args). -spec delete_report_handler(Handler) -> Result when Handler :: module(), Result :: gen_event:del_handler_ret(). delete_report_handler(Module) when is_atom(Module) -> - gen_event:delete_handler(error_logger, Module, []). - -%% Start the lowest level error_logger handler with Buffer. - -simple_logger(Buffer_size) when is_integer(Buffer_size) -> - gen_event:add_handler(error_logger, error_logger, Buffer_size). - -%% Start the lowest level error_logger handler without Buffer. + case whereis(?MODULE) of + Pid when is_pid(Pid) -> + Return = gen_event:delete_handler(?MODULE, Module, []), + case gen_event:which_handlers(?MODULE) of + [] -> + %% Don't want a lot of logs here if it's not needed + _ = logger:remove_handler(?MODULE), + ok; + _ -> + ok + end, + Return; + _ -> + ok + end. -simple_logger() -> - gen_event:add_handler(error_logger, error_logger, []). +which_report_handlers() -> + case whereis(?MODULE) of + Pid when is_pid(Pid) -> + gen_event:which_handlers(?MODULE); + undefined -> + [] + end. %% Log all errors to File for all eternity @@ -308,26 +491,35 @@ simple_logger() -> FilenameReason :: no_log_file. logfile({open, File}) -> - case lists:member(error_logger_file_h, - gen_event:which_handlers(error_logger)) of + case lists:member(error_logger_file_h,which_report_handlers()) of true -> {error, allready_have_logfile}; _ -> - gen_event:add_handler(error_logger, error_logger_file_h, File) + add_report_handler(error_logger_file_h, File) end; logfile(close) -> - case gen_event:delete_handler(error_logger, error_logger_file_h, normal) of - {error,Reason} -> - {error,Reason}; - _ -> - ok + case whereis(?MODULE) of + Pid when is_pid(Pid) -> + case gen_event:delete_handler(?MODULE, error_logger_file_h, normal) of + {error,Reason} -> + {error,Reason}; + _ -> + ok + end; + _ -> + {error,module_not_found} end; logfile(filename) -> - case gen_event:call(error_logger, error_logger_file_h, filename) of - {error,_} -> - {error, no_log_file}; - Val -> - Val + case whereis(?MODULE) of + Pid when is_pid(Pid) -> + case gen_event:call(?MODULE, error_logger_file_h, filename) of + {error,_} -> + {error, no_log_file}; + Val -> + Val + end; + _ -> + {error, no_log_file} end. %% Possibly turn off all tty printouts, maybe we only want the errors @@ -337,193 +529,17 @@ logfile(filename) -> Flag :: boolean(). tty(true) -> - Hs = gen_event:which_handlers(error_logger), - case lists:member(error_logger_tty_h, Hs) of + case lists:member(error_logger_tty_h, which_report_handlers()) of false -> - gen_event:add_handler(error_logger, error_logger_tty_h, []); - true -> + add_report_handler(error_logger_tty_h, []); + true -> ignore end, ok; tty(false) -> - gen_event:delete_handler(error_logger, error_logger_tty_h, []), - ok. - + delete_report_handler(error_logger_tty_h). -%%% --------------------------------------------------- -%%% This is the default error_logger handler. -%%% --------------------------------------------------- - --spec init(term()) -> {'ok', state() | []}. - -init(Max) when is_integer(Max) -> - {ok, {Max, 0, []}}; -%% This one is called if someone took over from us, and now wants to -%% go back. -init({go_back, _PostState}) -> - {ok, {?buffer_size, 0, []}}; -init(_) -> - %% The error logger process may receive a huge amount of - %% messages. Make sure that they are stored off heap to - %% avoid exessive GCs. - process_flag(message_queue_data, off_heap), - {ok, []}. - --spec handle_event(term(), state()) -> {'ok', state()}. - -handle_event({Type, GL, Msg}, State) when node(GL) =/= node() -> - gen_event:notify({error_logger, node(GL)},{Type, GL, Msg}), - %% handle_event2({Type, GL, Msg}, State); %% Shall we do something - {ok, State}; %% at this node too ??? -handle_event({info_report, _, {_, Type, _}}, State) when Type =/= std_info -> - {ok, State}; %% Ignore other info reports here -handle_event(Event, State) -> - handle_event2(Event, State). - --spec handle_info(term(), state()) -> {'ok', state()}. - -handle_info({emulator, GL, Chars}, State) when node(GL) =/= node() -> - {error_logger, node(GL)} ! {emulator, GL, add_node(Chars,self())}, - {ok, State}; -handle_info({emulator, GL, Chars}, State) -> - handle_event2({emulator, GL, Chars}, State); -handle_info(_, State) -> - {ok, State}. - --spec handle_call(term(), state()) -> {'ok', {'error', 'bad_query'}, state()}. - -handle_call(_Query, State) -> {ok, {error, bad_query}, State}. - --spec terminate(term(), state()) -> {'error_logger', [term()]}. - -terminate(swap, {_, 0, Buff}) -> - {error_logger, Buff}; -terminate(swap, {_, Lost, Buff}) -> - Myevent = {info, group_leader(), {self(), {lost_messages, Lost}, []}}, - {error_logger, [tag_event(Myevent)|Buff]}; -terminate(_, _) -> - {error_logger, []}. - -handle_event2(Event, {1, Lost, Buff}) -> - display(tag_event(Event)), - {ok, {1, Lost+1, Buff}}; -handle_event2(Event, {N, Lost, Buff}) -> - Tagged = tag_event(Event), - display(Tagged), - {ok, {N-1, Lost, [Tagged|Buff]}}; -handle_event2(_, State) -> - {ok, State}. - -tag_event(Event) -> - {erlang:localtime(), Event}. - -display({Tag,{error,_,{_,Format,Args}}}) -> - display2(Tag,Format,Args); -display({Tag,{error_report,_,{_,Type,Report}}}) -> - display2(Tag,Type,Report); -display({Tag,{info_report,_,{_,Type,Report}}}) -> - display2(Tag,Type,Report); -display({Tag,{info,_,{_,Error,_}}}) -> - display2(Tag,Error,[]); -display({Tag,{info_msg,_,{_,Format,Args}}}) -> - display2(Tag,Format,Args); -display({Tag,{warning_report,_,{_,Type,Report}}}) -> - display2(Tag,Type,Report); -display({Tag,{warning_msg,_,{_,Format,Args}}}) -> - display2(Tag,Format,Args); -display({Tag,{emulator,_,Chars}}) -> - display2(Tag,Chars,[]). - -add_node(X, Pid) when is_atom(X) -> - add_node(atom_to_list(X), Pid); -add_node(X, Pid) -> - lists:concat([X,"** at node ",node(Pid)," **~n"]). - -%% Can't do io_lib:format - -display2({{_Y,_Mo,_D},{_H,_Mi,_S}} = Date, F, A) -> - display_date(Date), - display3(string_p(F), F, A). - -display_date({{Y,Mo,D},{H,Mi,S}}) -> - erlang:display_string( - integer_to_list(Y) ++ "-" ++ - two_digits(Mo) ++ "-" ++ - two_digits(D) ++ " " ++ - two_digits(H) ++ ":" ++ - two_digits(Mi) ++ ":" ++ - two_digits(S) ++ " "). - -two_digits(N) when 0 =< N, N =< 9 -> - [$0, $0 + N]; -two_digits(N) -> - integer_to_list(N). - -display3(true, F, A) -> - %% Format string with arguments - erlang:display_string(F ++ "\n"), - [begin - erlang:display_string("\t"), - erlang:display(Arg) - end || Arg <- A], - ok; -display3(false, Atom, A) when is_atom(Atom) -> - %% The widest atom seems to be 'supervisor_report' at 17. - ColumnWidth = 20, - AtomString = atom_to_list(Atom), - AtomLength = length(AtomString), - Padding = lists:duplicate(ColumnWidth - AtomLength, $\s), - erlang:display_string(AtomString ++ Padding), - display4(A); -display3(_, F, A) -> - erlang:display({F, A}). - -display4([A, []]) -> - %% Not sure why crash reports look like this. - display4(A); -display4(A = [_|_]) -> - case lists:all(fun({Key,_Value}) -> is_atom(Key); (_) -> false end, A) of - true -> - erlang:display_string("\n"), - lists:foreach( - fun({Key, Value}) -> - erlang:display_string( - " " ++ - atom_to_list(Key) ++ - ": "), - erlang:display(Value) - end, A); - false -> - erlang:display(A) - end; -display4(A) -> - erlang:display(A). - -string_p([]) -> - false; -string_p(Term) -> - string_p1(Term). - -string_p1([H|T]) when is_integer(H), H >= $\040, H =< $\176 -> - string_p1(T); -string_p1([H|T]) when is_integer(H), H >= 16#A0, H < 16#D800; - is_integer(H), H > 16#DFFF, H < 16#FFFE; - is_integer(H), H > 16#FFFF, H =< 16#10FFFF -> - string_p1(T); -string_p1([$\n|T]) -> string_p1(T); -string_p1([$\r|T]) -> string_p1(T); -string_p1([$\t|T]) -> string_p1(T); -string_p1([$\v|T]) -> string_p1(T); -string_p1([$\b|T]) -> string_p1(T); -string_p1([$\f|T]) -> string_p1(T); -string_p1([$\e|T]) -> string_p1(T); -string_p1([H|T]) when is_list(H) -> - case string_p1(H) of - true -> string_p1(T); - _ -> false - end; -string_p1([]) -> true; -string_p1(_) -> false. +%%%----------------------------------------------------------------- -spec limit_term(term()) -> term(). @@ -536,9 +552,4 @@ limit_term(Term) -> -spec get_format_depth() -> 'unlimited' | pos_integer(). get_format_depth() -> - case application:get_env(kernel, error_logger_format_depth) of - {ok, Depth} when is_integer(Depth) -> - max(10, Depth); - undefined -> - unlimited - end. + logger:get_format_depth(). diff --git a/lib/kernel/src/kernel.erl b/lib/kernel/src/kernel.erl index 0382764b39..20aa47f602 100644 --- a/lib/kernel/src/kernel.erl +++ b/lib/kernel/src/kernel.erl @@ -40,8 +40,7 @@ start(_, []) -> ok = gen_event:add_handler(erl_signal_server, erl_signal_handler, []) end, %% add error handler - Type = get_error_logger_type(), - case error_logger:swap_handler(Type) of + case logger:setup_standard_handler() of ok -> {ok, Pid, []}; Error -> %% Not necessary since the node will crash anyway: @@ -62,16 +61,6 @@ config_change(Changed, New, Removed) -> do_global_groups_change(Changed, New, Removed), ok. -get_error_logger_type() -> - case application:get_env(kernel, error_logger) of - {ok, tty} -> tty; - {ok, {file, File}} when is_list(File) -> {logfile, File}; - {ok, false} -> false; - {ok, silent} -> silent; - undefined -> tty; % default value - {ok, Bad} -> exit({bad_config, {kernel, {error_logger, Bad}}}) - end. - %%%----------------------------------------------------------------- %%% The process structure in kernel is as shown in the figure. %%% @@ -153,9 +142,18 @@ init([]) -> type => supervisor, modules => [?MODULE]}, + + LoggerSup = #{id => logger_sup, + start => {logger_sup, start_link, []}, + restart => permanent, + shutdown => infinity, + type => supervisor, + modules => [logger_sup]}, + case init:get_argument(mode) of {ok, [["minimal"]]} -> - {ok, {SupFlags, [Code, File, StdError, User, Config, RefC, SafeSup]}}; + {ok, {SupFlags, + [Code, File, StdError, User, Config, RefC, SafeSup, LoggerSup]}}; _ -> Rpc = #{id => rex, start => {rpc, start_link, []}, @@ -206,7 +204,7 @@ init([]) -> {ok, {SupFlags, [Code, Rpc, Global, InetDb | DistAC] ++ [NetSup, GlGroup, File, SigSrv, - StdError, User, Config, RefC, SafeSup] ++ Timer}} + StdError, User, Config, RefC, SafeSup, LoggerSup] ++ Timer}} end; init(safe) -> SupFlags = #{strategy => one_for_one, |