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_SUITE).
21
22-include_lib("common_test/include/ct.hrl").
23
24%%-----------------------------------------------------------------
25%% We don't have to test the normal behaviour here, i.e. the tty
26%% handler.
27%% We will add an own error handler in order to verify that the
28%% error_logger deliver the expected events.
29%%-----------------------------------------------------------------
30
31-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
32	 init_per_group/2,end_per_group/2,
33         off_heap/1,
34	 error_report/1, info_report/1, error/1, info/1,
35	 emulator/1, via_logger_process/1, other_node/1,
36         tty/1, logfile/1, add/1, delete/1, format_depth/1]).
37
38-export([generate_error/2]).
39
40-export([init/1,
41	 handle_event/2, handle_call/2, handle_info/2,
42	 terminate/2]).
43
44
45suite() ->
46    [{ct_hooks,[ts_install_cth]},
47     {timetrap,{minutes,1}}].
48
49all() ->
50    [off_heap, error_report, info_report, error, info, emulator,
51     via_logger_process, other_node, tty, logfile, add, delete,
52     format_depth].
53
54groups() ->
55    [].
56
57init_per_suite(Config) ->
58    logger:add_handler(error_logger,error_logger,
59                       #{level=>info,filter_default=>log}),
60    Config.
61
62end_per_suite(_Config) ->
63    logger:remove_handler(error_logger),
64    ok.
65
66init_per_group(_GroupName, Config) ->
67    Config.
68
69end_per_group(_GroupName, Config) ->
70    Config.
71
72
73%%-----------------------------------------------------------------
74
75off_heap(_Config) ->
76    %% The error_logger process may receive a huge amount of
77    %% messages. Make sure that they are stored off heap to
78    %% avoid exessive GCs.
79    MQD = message_queue_data,
80    {MQD,off_heap} = process_info(whereis(error_logger), MQD),
81    ok.
82
83%%-----------------------------------------------------------------
84
85error_report(Config) when is_list(Config) ->
86    error_logger:add_report_handler(?MODULE, self()),
87    Rep1 = [{tag1,"data1"},{tag2,data2},{tag3,3}],
88    Rep2 = [testing,"testing",{tag1,"tag1"}],
89    Rep3 = "This is a string !",
90    Rep4 = {this,is,a,tuple},
91    ok = error_logger:error_report(Rep1),
92    reported(error_report, std_error, Rep1),
93    ok = error_logger:error_report(Rep2),
94    reported(error_report, std_error, Rep2),
95    ok = error_logger:error_report(Rep3),
96    reported(error_report, std_error, Rep3),
97    ok = error_logger:error_report(Rep4),
98    reported(error_report, std_error, Rep4),
99
100    ok = error_logger:error_report(test_type, Rep1),
101    reported(error_report, test_type, Rep1),
102    ok = error_logger:error_report(test_type, Rep2),
103    reported(error_report, test_type, Rep2),
104    ok = error_logger:error_report(test_type, Rep3),
105    reported(error_report, test_type, Rep3),
106    ok = error_logger:error_report(test_type, Rep4),
107    reported(error_report, test_type, Rep4),
108
109    ok = error_logger:error_report("test_type", Rep1),
110    reported(error_report, "test_type", Rep1),
111    ok = error_logger:error_report({test,type}, Rep2),
112    reported(error_report, {test,type}, Rep2),
113    ok = error_logger:error_report([test,type], Rep3),
114    reported(error_report, [test,type], Rep3),
115    ok = error_logger:error_report(1, Rep4),
116    reported(error_report, 1, Rep4),
117
118    my_yes = error_logger:delete_report_handler(?MODULE),
119    ok.
120
121%%-----------------------------------------------------------------
122
123info_report(Config) when is_list(Config) ->
124    error_logger:add_report_handler(?MODULE, self()),
125    Rep1 = [{tag1,"data1"},{tag2,data2},{tag3,3}],
126    Rep2 = [testing,"testing",{tag1,"tag1"}],
127    Rep3 = "This is a string !",
128    Rep4 = {this,is,a,tuple},
129    ok = error_logger:info_report(Rep1),
130    reported(info_report, std_info, Rep1),
131    ok = error_logger:info_report(Rep2),
132    reported(info_report, std_info, Rep2),
133    ok = error_logger:info_report(Rep3),
134    reported(info_report, std_info, Rep3),
135    ok = error_logger:info_report(Rep4),
136    reported(info_report, std_info, Rep4),
137
138    ok = error_logger:info_report(test_type, Rep1),
139    reported(info_report, test_type, Rep1),
140    ok = error_logger:info_report(test_type, Rep2),
141    reported(info_report, test_type, Rep2),
142    ok = error_logger:info_report(test_type, Rep3),
143    reported(info_report, test_type, Rep3),
144    ok = error_logger:info_report(test_type, Rep4),
145    reported(info_report, test_type, Rep4),
146
147    ok = error_logger:info_report("test_type", Rep1),
148    reported(info_report, "test_type", Rep1),
149    ok = error_logger:info_report({test,type}, Rep2),
150    reported(info_report, {test,type}, Rep2),
151    ok = error_logger:info_report([test,type], Rep3),
152    reported(info_report, [test,type], Rep3),
153    ok = error_logger:info_report(1, Rep4),
154    reported(info_report, 1, Rep4),
155
156    my_yes = error_logger:delete_report_handler(?MODULE),
157    ok.
158
159%%-----------------------------------------------------------------
160
161error(Config) when is_list(Config) ->
162    error_logger:add_report_handler(?MODULE, self()),
163    Msg1 = "This is a plain text string~n",
164    Msg2 = "This is a text with arguments ~p~n",
165    Arg2 = "This is the argument",
166    Msg3 = {erroneous,msg},
167
168    ok = error_logger:error_msg(Msg1),
169    reported(error, Msg1, []),
170    ok = error_logger:error_msg(Msg2, Arg2),
171    reported(error, Msg2, Arg2),
172    ok = error_logger:error_msg(Msg3),
173    reported(error, Msg3, []),
174
175    ok = error_logger:error_msg(Msg1, []),
176    reported(error, Msg1, []),
177    ok = error_logger:error_msg(Msg2, Arg2),
178    reported(error, Msg2, Arg2),
179    ok = error_logger:error_msg(Msg3, []),
180    reported(error, Msg3, []),
181
182    ok = error_logger:format(Msg1, []),
183    reported(error, Msg1, []),
184    ok = error_logger:format(Msg2, Arg2),
185    reported(error, Msg2, Arg2),
186    ok = error_logger:format(Msg3, []),
187    reported(error, Msg3, []),
188
189    my_yes = error_logger:delete_report_handler(?MODULE),
190    ok.
191
192%%-----------------------------------------------------------------
193
194info(Config) when is_list(Config) ->
195    error_logger:add_report_handler(?MODULE, self()),
196    Msg1 = "This is a plain text string~n",
197    Msg2 = "This is a text with arguments ~p~n",
198    Arg2 = "This is the argument",
199    Msg3 = {erroneous,msg},
200
201    ok = error_logger:info_msg(Msg1),
202    reported(info_msg, Msg1, []),
203    ok = error_logger:info_msg(Msg2, Arg2),
204    reported(info_msg, Msg2, Arg2),
205    ok = error_logger:info_msg(Msg3),
206    reported(info_msg, Msg3, []),
207
208    ok = error_logger:info_msg(Msg1, []),
209    reported(info_msg, Msg1, []),
210    ok = error_logger:info_msg(Msg2, Arg2),
211    reported(info_msg, Msg2, Arg2),
212    ok = error_logger:info_msg(Msg3, []),
213    reported(info_msg, Msg3, []),
214
215    my_yes = error_logger:delete_report_handler(?MODULE),
216    ok.
217
218%%-----------------------------------------------------------------
219
220emulator(Config) when is_list(Config) ->
221    error_logger:add_report_handler(?MODULE, self()),
222    Msg = "Error in process ~p on node ~p with exit value:~n~p~n",
223    Error = {badmatch,4},
224    Stack = [{module, function, 2, []}],
225    Pid = spawn(?MODULE, generate_error, [Error, Stack]),
226    reported(error, Msg, [Pid, node(), {Error, Stack}]),
227    my_yes = error_logger:delete_report_handler(?MODULE),
228    ok.
229
230generate_error(Error, Stack) ->
231    erlang:raise(error, Error, Stack).
232
233%%-----------------------------------------------------------------
234
235via_logger_process(Config) ->
236    case os:type() of
237        {win32,_} ->
238            {skip,"Skip on windows - cant change file mode"};
239        _ ->
240            error_logger:add_report_handler(?MODULE, self()),
241            Dir = filename:join(?config(priv_dir,Config),"dummydir"),
242            Msg = "File operation error: eacces. Target: " ++
243                Dir ++ ". Function: list_dir. ",
244            ok = file:make_dir(Dir),
245            ok = file:change_mode(Dir,8#0222),
246            error = erl_prim_loader:list_dir(Dir),
247            ok = file:change_mode(Dir,8#0664),
248            _ = file:del_dir(Dir),
249            reported(error_report, std_error, Msg),
250            my_yes = error_logger:delete_report_handler(?MODULE),
251            ok
252    end.
253
254%%-----------------------------------------------------------------
255
256other_node(_Config) ->
257    error_logger:add_report_handler(?MODULE, self()),
258    {ok,Node} = test_server:start_node(?FUNCTION_NAME,slave,[]),
259    ok = rpc:call(Node,logger,add_handler,[error_logger,error_logger,
260                                           #{level=>info,filter_default=>log}]),
261    rpc:call(Node,error_logger,error_report,[hi_from_remote]),
262    reported(error_report,std_error,hi_from_remote),
263    test_server:stop_node(Node),
264    ok.
265
266
267%%-----------------------------------------------------------------
268%% We don't enables or disables tty error logging here. We do not
269%% want to interact with the test run.
270%%-----------------------------------------------------------------
271
272tty(Config) when is_list(Config) ->
273    {'EXIT', _Reason} = (catch error_logger:tty(dummy)),
274    ok.
275
276%%-----------------------------------------------------------------
277%% If where already exists a logfile we skip this test case !!
278%%-----------------------------------------------------------------
279
280logfile(Config) when is_list(Config) ->
281    case error_logger:logfile(filename) of
282	{error, no_log_file} -> % Ok, we continues.
283	    do_logfile();
284	_ ->
285	    ok
286    end.
287
288do_logfile() ->
289    {error, _} = error_logger:logfile(close),
290    {error, _} = error_logger:logfile({open,{error}}),
291    ok = error_logger:logfile({open, "dummy_logfile.log"}),
292    "dummy_logfile.log" = error_logger:logfile(filename),
293    ok = error_logger:logfile(close),
294    {'EXIT',_} = (catch error_logger:logfile(dummy)),
295    ok.
296
297%%-----------------------------------------------------------------
298
299add(Config) when is_list(Config) ->
300    {'EXIT',_} = (catch error_logger:add_report_handler("dummy")),
301    {'EXIT',_} = error_logger:add_report_handler(non_existing),
302    my_error = error_logger:add_report_handler(?MODULE, [error]),
303    ok.
304
305%%-----------------------------------------------------------------
306
307delete(Config) when is_list(Config) ->
308    {'EXIT',_} = (catch error_logger:delete_report_handler("dummy")),
309    {error,_} = error_logger:delete_report_handler(non_existing),
310    ok.
311
312%%-----------------------------------------------------------------
313
314format_depth(_Config) ->
315    ok = application:set_env(kernel,error_logger_format_depth,30),
316    30 = error_logger:get_format_depth(),
317    ok = application:set_env(kernel,error_logger_format_depth,3),
318    10 = error_logger:get_format_depth(),
319    ok = application:set_env(kernel,error_logger_format_depth,11),
320    11 = error_logger:get_format_depth(),
321    ok = application:set_env(kernel,error_logger_format_depth,unlimited),
322    unlimited = error_logger:get_format_depth(),
323    ok = application:unset_env(kernel,error_logger_format_depth),
324    unlimited = error_logger:get_format_depth(),
325    ok.
326
327%%-----------------------------------------------------------------
328%% Check that the report has been received.
329%%-----------------------------------------------------------------
330reported(Tag, Type, Report) ->
331    receive
332	{Tag, Type, Report} ->
333	    test_server:messages_get(),
334	    ok
335    after 1000 ->
336	    ct:fail({no_report_received,test_server:messages_get()})
337    end.
338
339%%-----------------------------------------------------------------
340%% The error_logger handler (gen_event behaviour).
341%% Sends a notification to the Tester process about the events
342%% generated by the Tester process.
343%%-----------------------------------------------------------------
344init(Tester) when is_pid(Tester) ->
345    {ok, Tester};
346init(Config) when is_list(Config) ->
347    my_error.
348
349handle_event({Tag, _GL, {_EPid, Type, Report}}, Tester) ->
350    Tester ! {Tag, Type, Report},
351    {ok, Tester};
352handle_event(_Event, Tester) ->
353    {ok, Tester}.
354
355handle_info({emulator, _GL, String}, Tester) ->
356    Tester ! {emulator, String},
357    {ok, Tester};
358handle_info(_, Tester) ->
359    {ok, Tester}.
360
361handle_call(_Query, Tester) -> {ok, {error, bad_query}, Tester}.
362
363terminate(_Reason, _Tester) ->
364    my_yes.
365