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