1%%
2%% %CopyrightBegin%
3%%
4%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
5%%
6%% Licensed under the Apache License, Version 2.0 (the "License");
7%% you may not use this file except in compliance with the License.
8%% You may obtain a copy of the License at
9%%
10%%     http://www.apache.org/licenses/LICENSE-2.0
11%%
12%% Unless required by applicable law or agreed to in writing, software
13%% distributed under the License is distributed on an "AS IS" BASIS,
14%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15%% See the License for the specific language governing permissions and
16%% limitations under the License.
17%%
18%% %CopyrightEnd%
19%%
20-module(error_logger).
21
22-include("logger_internal.hrl").
23
24-export([start/0,start_link/0,stop/0,
25         format/2,error_msg/1,error_msg/2,error_report/1,
26	 error_report/2,info_report/1,info_report/2,warning_report/1,
27	 warning_report/2,error_info/1,
28	 info_msg/1,info_msg/2,warning_msg/1,warning_msg/2,
29	 logfile/1,tty/1,
30	 add_report_handler/1,add_report_handler/2,
31         delete_report_handler/1,
32         which_report_handlers/0]).
33
34%% logger callbacks
35-export([adding_handler/1, removing_handler/1, log/2]).
36
37-export([get_format_depth/0, limit_term/1]).
38
39%%-----------------------------------------------------------------
40%% Types used in this file
41%%-----------------------------------------------------------------
42
43-type msg_tag() :: 'error' | 'error_report'
44		 | 'info' | 'info_msg' | 'info_report'
45		 | 'warning_msg' | 'warning_report'.
46
47%%% BIF
48
49-export([warning_map/0]).
50
51-spec warning_map() -> Tag when
52      Tag :: error | warning | info.
53
54warning_map() ->
55    erlang:nif_error(undef).
56
57%%% End of BIF
58
59%%-----------------------------------------------------------------
60
61%%%-----------------------------------------------------------------
62%%% Start the event manager process under logger_sup, which is part of
63%%% the kernel application's supervision tree.
64-spec start() -> 'ok' | {'error', any()}.
65
66start() ->
67    case whereis(?MODULE) of
68        undefined ->
69            ErrorLogger =
70                #{id => ?MODULE,
71                  start => {?MODULE, start_link, []},
72                  restart => transient,
73                  shutdown => 2000,
74                  type => worker,
75                  modules => dynamic},
76            case supervisor:start_child(logger_sup, ErrorLogger) of
77                {ok,Pid} ->
78                    ok = logger_handler_watcher:register_handler(?MODULE,Pid);
79                Error ->
80                    Error
81            end;
82        _ ->
83            ok
84    end.
85
86%%%-----------------------------------------------------------------
87%%% Start callback specified in child specification to supervisor, see start/0
88-spec start_link() -> {'ok', pid()} | {'error', any()}.
89
90start_link() ->
91    gen_event:start_link({local, ?MODULE},
92                         [{spawn_opt,[{message_queue_data, off_heap}]}]).
93
94%%%-----------------------------------------------------------------
95%%% Stop the event manager
96-spec stop() -> ok.
97stop() ->
98    case whereis(?MODULE) of
99        undefined ->
100            ok;
101        _Pid ->
102            _ = gen_event:stop(?MODULE,{shutdown,stopped},infinity),
103            _ = supervisor:delete_child(logger_sup,?MODULE),
104            ok
105    end.
106
107%%%-----------------------------------------------------------------
108%%% Callbacks for logger
109-spec adding_handler(logger:handler_config()) ->
110                            {ok,logger:handler_config()} | {error,term()}.
111adding_handler(#{id:=?MODULE}=Config) ->
112    case start() of
113        ok ->
114            {ok,Config};
115        Error ->
116            Error
117    end.
118
119-spec removing_handler(logger:handler_config()) -> ok.
120removing_handler(#{id:=?MODULE}) ->
121    stop(),
122    ok.
123
124-spec log(logger:log_event(),logger:handler_config()) -> ok.
125log(#{level:=Level,msg:=Msg,meta:=Meta},_Config) ->
126    do_log(Level,Msg,Meta).
127
128do_log(Level,{report,Msg},#{?MODULE:=#{tag:=Tag,type:=Type}}=Meta) ->
129    %% From error_logger:*_report/1,2, or logger call which added
130    %% error_logger data to obtain backwards compatibility with
131    %% error_logger:*_report/1,2
132    Report =
133        case Msg of
134            #{label:=_,report:=R} -> R;
135            _ -> Msg
136        end,
137    notify(Level,Tag,Type,Report,Meta);
138do_log(Level,{report,Msg},#{?MODULE:=#{tag:=Tag}}=Meta) ->
139    {Format,Args} =
140        case Msg of
141            #{label:=_,format:=F,args:=A} ->
142                %% From error_logger:*_msg/1,2.
143                %% In order to be backwards compatible with handling
144                %% of faulty parameters to error_logger:*_msg/1,2,
145                %% don't use report_cb here.
146                {F,A};
147            _ ->
148                %% From logger call which added error_logger data to
149                %% obtain backwards compatibility with error_logger:*_msg/1,2
150                case get_report_cb(Meta) of
151                    RCBFun when is_function(RCBFun,1) ->
152                        try RCBFun(Msg) of
153                            {F,A} when is_list(F), is_list(A) ->
154                                {F,A};
155                            Other ->
156                                {"REPORT_CB ERROR: ~tp; Returned: ~tp",[Msg,Other]}
157                        catch C:R:S ->
158                                {"REPORT_CB CRASH: ~tp; Reason: ~tp",[Msg,{C,R,S}]}
159                        end;
160                    RCBFun when is_function(RCBFun,2) ->
161                        try RCBFun(Msg,#{depth=>get_format_depth(),
162                                         chars_limit=>unlimited,
163                                         single_line=>false}) of
164                            Chardata when ?IS_STRING(Chardata) ->
165                                {"~ts",[Chardata]};
166                            Other ->
167                                {"REPORT_CB ERROR: ~tp; Returned: ~tp",[Msg,Other]}
168                        catch C:R ->
169                                {"REPORT_CB CRASH: ~tp; Reason: ~tp",[Msg,{C,R}]}
170                        end
171                end
172        end,
173    notify(Level,Tag,Format,Args,Meta);
174do_log(Level,{Format,Args},#{?MODULE:=#{tag:=Tag}}=Meta)
175  when is_list(Format), is_list(Args) ->
176    %% From logger call which added error_logger data to obtain
177    %% backwards compatibility with error_logger:*_msg/1,2
178    notify(Level,Tag,Format,Args,Meta);
179do_log(_Level,_Msg,_Meta) ->
180    %% Ignore the rest - i.e. to get backwards compatibility with
181    %% error_logger, you must use the error_logger API for logging.
182    %% Some modules within OTP go around this by adding an
183    %% error_logger field to its metadata. This is done only to allow
184    %% complete backwards compatibility for log events originating
185    %% from within OTP, while still using the new logger interface.
186    ok.
187
188-spec notify(logger:level(), msg_tag(), any(), any(), map()) -> 'ok'.
189notify(Level,Tag0,FormatOrType0,ArgsOrReport,#{pid:=Pid0,gl:=GL,?MODULE:=My}) ->
190    {Tag,FormatOrType} = maybe_map_warnings(Level,Tag0,FormatOrType0),
191    Pid = case maps:get(emulator,My,false) of
192              true -> emulator;
193              _ -> Pid0
194          end,
195    gen_event:notify(?MODULE,{Tag,GL,{Pid,FormatOrType,ArgsOrReport}}).
196
197%% For backwards compatibility with really old even handlers, check
198%% the warning map and update tag and type.
199maybe_map_warnings(warning,Tag,FormatOrType) ->
200    case error_logger:warning_map() of
201        warning ->
202            {Tag,FormatOrType};
203        Level ->
204            {fix_warning_tag(Level,Tag),fix_warning_type(Level,FormatOrType)}
205    end;
206maybe_map_warnings(_,Tag,FormatOrType) ->
207    {Tag,FormatOrType}.
208
209fix_warning_tag(error,warning_msg) -> error;
210fix_warning_tag(error,warning_report) -> error_report;
211fix_warning_tag(info,warning_msg) -> info_msg;
212fix_warning_tag(info,warning_report) -> info_report;
213fix_warning_tag(_,Tag) -> Tag.
214
215fix_warning_type(error,std_warning) -> std_error;
216fix_warning_type(info,std_warning) -> std_info;
217fix_warning_type(_,Type) -> Type.
218
219get_report_cb(#{?MODULE:=#{report_cb:=RBFun}}) ->
220    RBFun;
221get_report_cb(#{report_cb:=RBFun}) ->
222    RBFun;
223get_report_cb(_) ->
224    fun logger:format_report/1.
225
226%%-----------------------------------------------------------------
227%% These two simple old functions generate events tagged 'error'
228%% Used for simple messages; error or information.
229%%-----------------------------------------------------------------
230
231-spec error_msg(Format) -> 'ok' when
232      Format :: string().
233
234error_msg(Format) ->
235    error_msg(Format,[]).
236
237-spec error_msg(Format, Data) -> 'ok' when
238      Format :: string(),
239      Data :: list().
240
241error_msg(Format, Args) ->
242    logger:log(error,
243               #{label=>{?MODULE,error_msg},
244                 format=>Format,
245                 args=>Args},
246               meta(error)).
247
248-spec format(Format, Data) -> 'ok' when
249      Format :: string(),
250      Data :: list().
251
252format(Format, Args) ->
253    error_msg(Format, Args).
254
255%%-----------------------------------------------------------------
256%% This functions should be used for error reports.  Events
257%% are tagged 'error_report'.
258%% The 'std_error' error_report type can always be used.
259%%-----------------------------------------------------------------
260
261-type report() ::
262        [{Tag :: term(), Data :: term()} | term()] | string() | term().
263
264-spec error_report(Report) -> 'ok' when
265      Report :: report().
266
267error_report(Report) ->
268    error_report(std_error, Report).
269
270-spec error_report(Type, Report) -> 'ok' when
271      Type :: term(),
272      Report :: report().
273
274error_report(Type, Report) ->
275    logger:log(error,
276               #{label=>{?MODULE,error_report},
277                 report=>Report},
278               meta(error_report,Type)).
279
280%%-----------------------------------------------------------------
281%% This function should be used for warning reports.
282%% These might be mapped to error reports or info reports,
283%% depending on emulator flags. Events that ore not mapped
284%% are tagged 'info_report'.
285%% The 'std_warning' info_report type can always be used and is
286%% mapped to std_info or std_error accordingly.
287%%-----------------------------------------------------------------
288
289-spec warning_report(Report) -> 'ok' when
290      Report :: report().
291
292warning_report(Report) ->
293    warning_report(std_warning, Report).
294
295-spec warning_report(Type, Report) -> 'ok' when
296      Type :: any(),
297      Report :: report().
298
299warning_report(Type, Report) ->
300    logger:log(warning,
301               #{label=>{?MODULE,warning_report},
302                 report=>Report},
303               meta(warning_report,Type)).
304
305%%-----------------------------------------------------------------
306%% This function provides similar functions as error_msg for
307%% warning messages, like warning report it might get mapped to
308%% other types of reports.
309%%-----------------------------------------------------------------
310
311-spec warning_msg(Format) -> 'ok' when
312      Format :: string().
313
314warning_msg(Format) ->
315    warning_msg(Format,[]).
316
317-spec warning_msg(Format, Data) -> 'ok' when
318      Format :: string(),
319      Data :: list().
320
321warning_msg(Format, Args) ->
322    logger:log(warning,
323               #{label=>{?MODULE,warning_msg},
324                 format=>Format,
325                 args=>Args},
326               meta(warning_msg)).
327
328%%-----------------------------------------------------------------
329%% This function should be used for information reports.  Events
330%% are tagged 'info_report'.
331%% The 'std_info' info_report type can always be used.
332%%-----------------------------------------------------------------
333
334-spec info_report(Report) -> 'ok' when
335      Report :: report().
336
337info_report(Report) ->
338    info_report(std_info, Report).
339
340-spec info_report(Type, Report) -> 'ok' when
341      Type :: any(),
342      Report :: report().
343
344info_report(Type, Report) ->
345    logger:log(notice,
346               #{label=>{?MODULE,info_report},
347                 report=>Report},
348               meta(info_report,Type)).
349
350%%-----------------------------------------------------------------
351%% This function provides similar functions as error_msg for
352%% information messages.
353%%-----------------------------------------------------------------
354
355-spec info_msg(Format) -> 'ok' when
356      Format :: string().
357
358info_msg(Format) ->
359    info_msg(Format,[]).
360
361-spec info_msg(Format, Data) -> 'ok' when
362      Format :: string(),
363      Data :: list().
364
365info_msg(Format, Args) ->
366    logger:log(notice,
367               #{label=>{?MODULE,info_msg},
368                 format=>Format,
369                 args=>Args},
370               meta(info_msg)).
371
372%%-----------------------------------------------------------------
373%% Used by the init process.  Events are tagged 'info'.
374%%-----------------------------------------------------------------
375
376-spec error_info(Error :: any()) -> 'ok'.
377
378%% unused?
379error_info(Error) ->
380    {Format,Args} =
381        case string_p(Error) of
382            true -> {Error,[]};
383            false -> {"~p",[Error]}
384        end,
385    MyMeta = #{tag=>info,type=>Error},
386    logger:log(notice, Format, Args, #{?MODULE=>MyMeta,domain=>[Error]}).
387
388%%-----------------------------------------------------------------
389%% Create metadata
390meta(Tag) ->
391    meta(Tag,undefined).
392meta(Tag,Type) ->
393    meta(Tag,Type,#{report_cb=>fun report_to_format/1}).
394meta(Tag,undefined,Meta0) ->
395    Meta0#{?MODULE=>#{tag=>Tag}};
396meta(Tag,Type,Meta0) ->
397    maybe_add_domain(Tag,Type,Meta0#{?MODULE=>#{tag=>Tag,type=>Type}}).
398
399%% This is to prevent events of non standard type from being printed
400%% with the standard logger. Similar to how error_logger_tty_h
401%% discards events of non standard type.
402maybe_add_domain(error_report,std_error,Meta) -> Meta;
403maybe_add_domain(info_report,std_info,Meta) -> Meta;
404maybe_add_domain(warning_report,std_warning,Meta) -> Meta;
405maybe_add_domain(_,Type,Meta) -> Meta#{domain=>[Type]}.
406
407%% -----------------------------------------------------------------
408%% Report formatting - i.e. Term => {Format,Args}
409%% This was earlier done in the event handler (error_logger_tty_h, etc)
410%% -----------------------------------------------------------------
411report_to_format(#{label:={?MODULE,_},
412                   report:=Report}) when is_map(Report) ->
413    %% logger:format_otp_report does maps:to_list, and for backwards
414    %% compatibility reasons we don't want that.
415    {"~tp\n",[Report]};
416report_to_format(#{label:={?MODULE,_},
417                   format:=Format,
418                   args:=Args}) ->
419    %% This is not efficient, but needed for backwards compatibility
420    %% in giving faulty arguments to the *_msg functions.
421    try io_lib:scan_format(Format,Args) of
422        _ -> {Format,Args}
423    catch _:_ ->
424            {"ERROR: ~tp - ~tp",[Format,Args]}
425    end;
426report_to_format(Term) ->
427    logger:format_otp_report(Term).
428
429string_p(List) when is_list(List) ->
430    string_p1(lists:flatten(List));
431string_p(_) ->
432    false.
433
434string_p1([]) ->
435    false;
436string_p1(FlatList) ->
437    io_lib:printable_list(FlatList).
438
439%% -----------------------------------------------------------------
440%% Stuff directly related to the event manager
441%% -----------------------------------------------------------------
442-spec add_report_handler(Handler) -> any() when
443      Handler :: module().
444
445add_report_handler(Module) when is_atom(Module) ->
446    add_report_handler(Module, []).
447
448-spec add_report_handler(Handler, Args) -> Result when
449      Handler :: module(),
450      Args :: gen_event:handler_args(),
451      Result :: gen_event:add_handler_ret().
452
453add_report_handler(Module, Args) when is_atom(Module) ->
454    _ = logger:add_handler(?MODULE,?MODULE,#{level=>info,filter_default=>log}),
455    gen_event:add_handler(?MODULE, Module, Args).
456
457-spec delete_report_handler(Handler) -> Result when
458      Handler :: module(),
459      Result :: gen_event:del_handler_ret().
460
461delete_report_handler(Module) when is_atom(Module) ->
462    case whereis(?MODULE) of
463        Pid when is_pid(Pid) ->
464            Return = gen_event:delete_handler(?MODULE, Module, []),
465            case gen_event:which_handlers(?MODULE) of
466                [] ->
467                    %% Don't want a lot of logs here if it's not needed
468                    _ = logger:remove_handler(?MODULE),
469                    ok;
470                _ ->
471                    ok
472            end,
473            Return;
474        _ ->
475            ok
476    end.
477
478which_report_handlers() ->
479    case whereis(?MODULE) of
480        Pid when is_pid(Pid) ->
481            gen_event:which_handlers(?MODULE);
482        undefined ->
483            []
484    end.
485
486%% Log all errors to File for all eternity
487
488-type open_error() :: file:posix() | badarg | system_limit.
489
490-spec logfile(Request :: {open, Filename}) -> ok | {error, OpenReason} when
491                  Filename ::file:name(),
492                  OpenReason :: allready_have_logfile | open_error()
493           ; (Request :: close) -> ok | {error, CloseReason} when
494                  CloseReason :: module_not_found
495	   ; (Request :: filename) -> Filename | {error, FilenameReason} when
496                  Filename :: file:name(),
497                  FilenameReason :: no_log_file.
498
499logfile({open, File}) ->
500    case lists:member(error_logger_file_h,which_report_handlers()) of
501	true ->
502	    {error, allready_have_logfile};
503	_ ->
504            add_report_handler(error_logger_file_h, File)
505    end;
506logfile(close) ->
507    case whereis(?MODULE) of
508        Pid when is_pid(Pid) ->
509            case gen_event:delete_handler(?MODULE, error_logger_file_h, normal) of
510                {error,Reason} ->
511                    {error,Reason};
512                _ ->
513                    ok
514            end;
515        _ ->
516            {error,module_not_found}
517    end;
518logfile(filename) ->
519    case whereis(?MODULE) of
520        Pid when is_pid(Pid) ->
521            case gen_event:call(?MODULE, error_logger_file_h, filename) of
522                {error,_} ->
523                    {error, no_log_file};
524                Val ->
525                    Val
526            end;
527        _ ->
528            {error, no_log_file}
529    end.
530
531%% Possibly turn off all tty printouts, maybe we only want the errors
532%% to go to a file
533
534-spec tty(Flag) -> 'ok' when
535      Flag :: boolean().
536
537tty(true) ->
538    _ = case lists:member(error_logger_tty_h, which_report_handlers()) of
539            false ->
540                case logger:get_handler_config(default) of
541                    {ok,#{module:=logger_std_h,config:=#{type:=standard_io}}} ->
542                        logger:remove_handler_filter(default,
543                                                     error_logger_tty_false);
544                    _ ->
545                        logger:add_handler(error_logger_tty_true,logger_std_h,
546                                           #{filter_default=>stop,
547                                             filters=>?DEFAULT_HANDLER_FILTERS(
548                                                         [otp]),
549                                             formatter=>{?DEFAULT_FORMATTER,
550                                                         ?DEFAULT_FORMAT_CONFIG},
551                                             config=>#{type=>standard_io}})
552                end;
553            true ->
554                ok
555        end,
556    ok;
557tty(false) ->
558    delete_report_handler(error_logger_tty_h),
559    _ = logger:remove_handler(error_logger_tty_true),
560    _ = case logger:get_handler_config(default) of
561            {ok,#{module:=logger_std_h,config:=#{type:=standard_io}}} ->
562                logger:add_handler_filter(default,error_logger_tty_false,
563                                          {fun(_,_) -> stop end, ok});
564            _ ->
565                ok
566        end,
567    ok.
568
569%%%-----------------------------------------------------------------
570-spec limit_term(term()) -> term().
571
572limit_term(Term) ->
573    case get_format_depth() of
574        unlimited -> Term;
575        D -> io_lib:limit_term(Term, D)
576    end.
577
578-spec get_format_depth() -> 'unlimited' | pos_integer().
579
580get_format_depth() ->
581    case application:get_env(kernel, error_logger_format_depth) of
582	{ok, Depth} when is_integer(Depth) ->
583	    max(10, Depth);
584        {ok, unlimited} ->
585            unlimited;
586	undefined ->
587	    unlimited
588    end.
589