%% %% %CopyrightBegin% %% %% Copyright Ericsson AB 2018. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. %% You may obtain a copy of the License at %% %% http://www.apache.org/licenses/LICENSE-2.0 %% %% Unless required by applicable law or agreed to in writing, software %% distributed under the License is distributed on an "AS IS" BASIS, %% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %% See the License for the specific language governing permissions and %% limitations under the License. %% %% %CopyrightEnd% %% -module(logger_legacy_SUITE). -compile(export_all). -include_lib("common_test/include/ct.hrl"). -include_lib("kernel/include/logger.hrl"). -include_lib("kernel/src/logger_internal.hrl"). %%%----------------------------------------------------------------- %%% This test suite test that log events from within OTP can be %%% delivered to legacy error_logger event handlers on the same format %%% as before 'logger' was introduced. %%% %%% Before changing the expected format of any of the log events in %%% this suite, please make sure that the backwards incompatibility it %%% introduces is ok. %%% ----------------------------------------------------------------- -define(check(Expected), receive Expected -> [] = test_server:messages_get() after 1000 -> ct:fail({report_not_received, {line,?LINE}, {got,test_server:messages_get()}}) end). -define(check_no_flush(Expected), receive Expected -> ok after 1000 -> ct:fail({report_not_received, {line,?LINE}, {got,test_server:messages_get()}}) end). suite() -> [{timetrap,{seconds,30}}]. init_per_suite(Config) -> logger:add_handler(error_logger,error_logger, #{level=>info,filter_default=>stop}), Config. end_per_suite(_Config) -> logger:remove_handler(error_logger), ok. init_per_group(std, Config) -> ok = logger:set_handler_config( error_logger,filters, [{domain,{fun logger_filters:domain/2, {log,prefix_of,[beam,erlang,otp]}}}]), Config; init_per_group(sasl, Config) -> ok = logger:set_handler_config( error_logger,filters, [{domain,{fun logger_filters:domain/2, {log,prefix_of,[beam,erlang,otp,sasl]}}}]), %% cth_log_redirect checks if sasl is started before displaying %% any sasl reports - so just to see the real sasl reports in tc %% log: application:start(sasl), Config; init_per_group(_Group, Config) -> Config. end_per_group(sasl, _Config) -> application:stop(sasl), ok; end_per_group(_Group, _Config) -> ok. init_per_testcase(_TestCase, Config) -> error_logger:add_report_handler(?MODULE,{event_handler,self()}), Config. end_per_testcase(Case, Config) -> %% Using gen_event directly here, instead of %% error_logger:delete_report_handler. This is to avoid %% automatically stopping the error_logger process due to removing %% the last handler. gen_event:delete_handler(error_logger,?MODULE,[]), try apply(?MODULE,Case,[cleanup,Config]) catch error:undef -> ok end, ok. groups() -> [{std,[],[gen_server, gen_event, gen_fsm, gen_statem]}, {sasl,[],[sasl_reports, supervisor_handle_info]}]. all() -> [{group,std}, {group,sasl}]. gen_server(_Config) -> {ok,Pid} = gen_server:start(?MODULE,gen_server,[]), Msg = fun() -> a=b end, Pid ! Msg, ?check({warning_msg,"** Undefined handle_info in ~p"++_,[?MODULE,Msg]}), ok = gen_server:cast(Pid,Msg), ?check({error,"** Generic server ~tp terminating"++_, [Pid,{'$gen_cast',Msg},gen_server,{{badmatch,b},_}]}). gen_event(_Config) -> {ok,Pid} = gen_event:start(), ok = gen_event:add_handler(Pid,?MODULE,gen_event), Msg = fun() -> a=b end, Pid ! Msg, ?check({warning_msg,"** Undefined handle_info in ~tp"++_,[?MODULE,Msg]}), gen_event:notify(Pid,Msg), ?check({error,"** gen_event handler ~p crashed."++_, [?MODULE,Pid,Msg,gen_event,{{badmatch,b},_}]}). gen_fsm(_Config) -> {ok,Pid} = gen_fsm:start(?MODULE,gen_fsm,[]), Msg = fun() -> a=b end, Pid ! Msg, ?check({warning_msg,"** Undefined handle_info in ~p"++_,[?MODULE,Msg]}), gen_fsm:send_all_state_event(Pid,Msg), ?check({error,"** State machine ~tp terminating"++_, [Pid,Msg,mystate,gen_fsm,{{badmatch,b},_}]}). gen_statem(_Config) -> {ok,Pid} = gen_statem:start(?MODULE,gen_statem,[]), Msg = fun() -> a=b end, Pid ! Msg, ?check({error,"** State machine ~tp terminating"++_, [Pid,{info,Msg},{mystate,gen_statem},error,{badmatch,b}|_]}). sasl_reports(Config) -> App = {application,?MODULE,[{description, ""}, {vsn, "1.0"}, {modules, [?MODULE]}, {registered, []}, {applications, []}, {mod, {?MODULE, []}}]}, AppStr = io_lib:format("~p.",[App]), Dir = ?config(priv_dir,Config), AppFile = filename:join(Dir,?MODULE_STRING++".app"), ok = file:write_file(AppFile,AppStr), true = code:add_patha(Dir), ok = application:start(?MODULE), SupName = sup_name(), Pid = whereis(SupName), [{ch,ChPid,_,_}] = supervisor:which_children(Pid), Node = node(), ?check_no_flush({info_report,progress,[{application,?MODULE}, {started_at,Node}]}), ?check({info_report,progress,[{supervisor,{local,SupName}}, {started,[{pid,ChPid}|_]}]}), ok = gen_server:cast(ChPid, fun() -> spawn_link(fun() -> receive x->ok end end) end), Msg = fun() -> a=b end, ok = gen_server:cast(ChPid,Msg), ?check_no_flush({error,"** Generic server ~tp terminating"++_, [ChPid,{'$gen_cast',Msg},gen_server,{{badmatch,b},_}]}), ?check_no_flush({error_report,crash_report, [[{initial_call,_}, {pid,ChPid}, {registered_name,[]}, {error_info,{error,{badmatch,b},_}}, {ancestors,_}, {message_queue_len,_}, {messages,_}, {links,[Pid,Neighbour]}, {dictionary,_}, {trap_exit,_}, {status,_}, {heap_size,_}, {stack_size,_}, {reductions,_}], [{neighbour,[{pid,Neighbour}, {registered_name,_}, {initial_call,_}, {current_function,_}, {ancestors,_}, {message_queue_len,_}, {links,[ChPid]}, {trap_exit,_}, {status,_}, {heap_size,_}, {stack_size,_}, {reductions,_}, {current_stacktrace,_}]}]]}), ?check_no_flush({error_report,supervisor_report, [{supervisor,{local,SupName}}, {errorContext,child_terminated}, {reason,{{badmatch,b},_}}, {offender,[{pid,ChPid}|_]}]}), ?check({info_report,progress,[{supervisor,{local,SupName}}, {started,_}]}), ok = application:stop(?MODULE), ?check({info_report,std_info,[{application,?MODULE}, {exited,stopped}, {type,temporary}]}). sasl_reports(cleanup,_Config) -> application:stop(?MODULE). supervisor_handle_info(_Config) -> {ok,Pid} = supervisor:start_link({local,sup_name()},?MODULE,supervisor), ?check({info_report,progress,[{supervisor,_},{started,_}]}), Pid ! msg, ?check({error,"Supervisor received unexpected message: ~tp~n",[msg]}). supervisor_handle_info(cleanup,_Config) -> Pid = whereis(sup_name()), unlink(Pid), exit(Pid,shutdown). %%%----------------------------------------------------------------- %%% Callbacks for error_logger event handler, gen_server, gen_statem, %%% gen_fsm, gen_event, supervisor and application. start(_,_) -> supervisor:start_link({local,sup_name()},?MODULE,supervisor). init(supervisor) -> {ok,{#{},[#{id=>ch,start=>{gen_server,start_link,[?MODULE,gen_server,[]]}}]}}; init(StateMachine) when StateMachine==gen_statem; StateMachine==gen_fsm -> {ok,mystate,StateMachine}; init(State) -> {ok,State}. %% error_logger event handler handle_event({Tag,_Gl,{_Pid,Type,Report}},{_,Pid}=State) -> Pid ! {Tag,Type,Report}, {ok,State}; %% other gen_event handle_event(Fun,State) when is_function(Fun) -> Fun(), {next_state,State}. %% gen_fsm handle_event(Fun,State,Data) when is_function(Fun) -> Fun(), {next_state,State,Data}. %% gen_statem handle_event(info,Fun,State,Data) when is_function(Fun) -> Fun(), {next_state,State,Data}. %% gen_server handle_cast(Fun,State) when is_function(Fun) -> Fun(), {noreply,State}. %% gen_statem callback_mode() -> handle_event_function. %%%----------------------------------------------------------------- %%% Internal sup_name() -> list_to_atom(?MODULE_STRING++"_sup").