Non puoi selezionare più di 25 argomenti Gli argomenti devono iniziare con una lettera o un numero, possono includere trattini ('-') e possono essere lunghi fino a 35 caratteri.

802 righe
41 KiB

14 anni fa
14 anni fa
14 anni fa
14 anni fa
14 anni fa
14 anni fa
14 anni fa
14 anni fa
  1. %% Copyright (c) 2011-2012 Basho Technologies, Inc. All Rights Reserved.
  2. %%
  3. %% This file is provided to you under the Apache License,
  4. %% Version 2.0 (the "License"); you may not use this file
  5. %% except in compliance with the License. You may obtain
  6. %% a copy of the License at
  7. %%
  8. %% http://www.apache.org/licenses/LICENSE-2.0
  9. %%
  10. %% Unless required by applicable law or agreed to in writing,
  11. %% software distributed under the License is distributed on an
  12. %% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  13. %% KIND, either express or implied. See the License for the
  14. %% specific language governing permissions and limitations
  15. %% under the License.
  16. -module(lager_test_backend).
  17. -include("lager.hrl").
  18. -behaviour(gen_event).
  19. -export([init/1, handle_call/2, handle_event/2, handle_info/2, terminate/2,
  20. code_change/3]).
  21. -record(state, {level, buffer, ignored}).
  22. -compile([{parse_transform, lager_transform}]).
  23. -ifdef(TEST).
  24. -include_lib("eunit/include/eunit.hrl").
  25. -export([pop/0, count/0, count_ignored/0, flush/0, print_state/0]).
  26. -endif.
  27. init(Level) ->
  28. {ok, #state{level=lager_util:config_to_mask(Level), buffer=[], ignored=[]}}.
  29. handle_call(count, #state{buffer=Buffer} = State) ->
  30. {ok, length(Buffer), State};
  31. handle_call(count_ignored, #state{ignored=Ignored} = State) ->
  32. {ok, length(Ignored), State};
  33. handle_call(flush, State) ->
  34. {ok, ok, State#state{buffer=[], ignored=[]}};
  35. handle_call(pop, #state{buffer=Buffer} = State) ->
  36. case Buffer of
  37. [] ->
  38. {ok, undefined, State};
  39. [H|T] ->
  40. {ok, H, State#state{buffer=T}}
  41. end;
  42. handle_call(get_loglevel, #state{level=Level} = State) ->
  43. {ok, Level, State};
  44. handle_call({set_loglevel, Level}, State) ->
  45. {ok, ok, State#state{level=lager_util:config_to_mask(Level)}};
  46. handle_call(print_state, State) ->
  47. spawn(fun() -> lager:info("State ~p", [lager:pr(State, ?MODULE)]) end),
  48. timer:sleep(100),
  49. {ok, ok, State};
  50. handle_call(print_bad_state, State) ->
  51. spawn(fun() -> lager:info("State ~p", [lager:pr({state, 1}, ?MODULE)]) end),
  52. timer:sleep(100),
  53. {ok, ok, State};
  54. handle_call(_Request, State) ->
  55. {ok, ok, State}.
  56. handle_event({log, Msg},
  57. #state{level=LogLevel,buffer=Buffer,ignored=Ignored} = State) ->
  58. case lager_util:is_loggable(Msg, LogLevel, ?MODULE) of
  59. true ->
  60. {ok, State#state{buffer=Buffer ++
  61. [{lager_msg:severity_as_int(Msg),
  62. lager_msg:timestamp(Msg),
  63. lager_msg:message(Msg), lager_msg:metadata(Msg)}]}};
  64. _ ->
  65. {ok, State#state{ignored=Ignored ++ [ignored]}}
  66. end;
  67. handle_event(_Event, State) ->
  68. {ok, State}.
  69. handle_info(_Info, State) ->
  70. {ok, State}.
  71. terminate(_Reason, _State) ->
  72. ok.
  73. code_change(_OldVsn, State, _Extra) ->
  74. {ok, State}.
  75. -ifdef(TEST).
  76. pop() ->
  77. gen_event:call(lager_event, ?MODULE, pop).
  78. count() ->
  79. gen_event:call(lager_event, ?MODULE, count).
  80. count_ignored() ->
  81. gen_event:call(lager_event, ?MODULE, count_ignored).
  82. flush() ->
  83. gen_event:call(lager_event, ?MODULE, flush).
  84. print_state() ->
  85. gen_event:call(lager_event, ?MODULE, print_state).
  86. print_bad_state() ->
  87. gen_event:call(lager_event, ?MODULE, print_bad_state).
  88. has_line_numbers() ->
  89. %% are we R15 or greater
  90. Rel = erlang:system_info(otp_release),
  91. {match, [Major]} = re:run(Rel, "^R(\\d+)[A|B](|0(\\d))$", [{capture, [1], list}]),
  92. list_to_integer(Major) >= 15.
  93. not_running_test() ->
  94. ?assertEqual({error, lager_not_running}, lager:log(info, self(), "not running")).
  95. lager_test_() ->
  96. {foreach,
  97. fun setup/0,
  98. fun cleanup/1,
  99. [
  100. {"observe that there is nothing up my sleeve",
  101. fun() ->
  102. ?assertEqual(undefined, pop()),
  103. ?assertEqual(0, count())
  104. end
  105. },
  106. {"logging works",
  107. fun() ->
  108. lager:warning("test message"),
  109. ?assertEqual(1, count()),
  110. {Level, _Time, Message, _Metadata} = pop(),
  111. ?assertMatch(Level, lager_util:level_to_num(warning)),
  112. ?assertEqual("test message", Message),
  113. ok
  114. end
  115. },
  116. {"logging with arguments works",
  117. fun() ->
  118. lager:warning("test message ~p", [self()]),
  119. ?assertEqual(1, count()),
  120. {Level, _Time, Message,_Metadata} = pop(),
  121. ?assertMatch(Level, lager_util:level_to_num(warning)),
  122. ?assertEqual(lists:flatten(io_lib:format("test message ~p", [self()])), lists:flatten(Message)),
  123. ok
  124. end
  125. },
  126. {"logging works from inside a begin/end block",
  127. fun() ->
  128. ?assertEqual(0, count()),
  129. begin
  130. lager:warning("test message 2")
  131. end,
  132. ?assertEqual(1, count()),
  133. ok
  134. end
  135. },
  136. {"logging works from inside a list comprehension",
  137. fun() ->
  138. ?assertEqual(0, count()),
  139. [lager:warning("test message") || _N <- lists:seq(1, 10)],
  140. ?assertEqual(10, count()),
  141. ok
  142. end
  143. },
  144. {"logging works from a begin/end block inside a list comprehension",
  145. fun() ->
  146. ?assertEqual(0, count()),
  147. [ begin lager:warning("test message") end || _N <- lists:seq(1, 10)],
  148. ?assertEqual(10, count()),
  149. ok
  150. end
  151. },
  152. {"logging works from a nested list comprehension",
  153. fun() ->
  154. ?assertEqual(0, count()),
  155. [ [lager:warning("test message") || _N <- lists:seq(1, 10)] ||
  156. _I <- lists:seq(1, 10)],
  157. ?assertEqual(100, count()),
  158. ok
  159. end
  160. },
  161. {"log messages below the threshold are ignored",
  162. fun() ->
  163. ?assertEqual(0, count()),
  164. lager:debug("this message will be ignored"),
  165. ?assertEqual(0, count()),
  166. ?assertEqual(0, count_ignored()),
  167. lager_config:set(loglevel, {element(2, lager_util:config_to_mask(debug)), []}),
  168. lager:debug("this message should be ignored"),
  169. ?assertEqual(0, count()),
  170. ?assertEqual(1, count_ignored()),
  171. lager:set_loglevel(?MODULE, debug),
  172. lager:debug("this message should be logged"),
  173. ?assertEqual(1, count()),
  174. ?assertEqual(1, count_ignored()),
  175. ?assertEqual(debug, lager:get_loglevel(?MODULE)),
  176. ok
  177. end
  178. },
  179. {"tracing works",
  180. fun() ->
  181. lager_config:set(loglevel, {element(2, lager_util:config_to_mask(error)), []}),
  182. ok = lager:info("hello world"),
  183. ?assertEqual(0, count()),
  184. lager:trace(?MODULE, [{module, ?MODULE}], debug),
  185. %% elegible for tracing
  186. ok = lager:info("hello world"),
  187. %% NOT elegible for tracing
  188. ok = lager:log(info, [{pid, self()}], "hello world"),
  189. ?assertEqual(1, count()),
  190. ok
  191. end
  192. },
  193. {"tracing works with custom attributes",
  194. fun() ->
  195. lager:set_loglevel(?MODULE, error),
  196. lager_config:set(loglevel, {element(2, lager_util:config_to_mask(error)), []}),
  197. lager:info([{requestid, 6}], "hello world"),
  198. ?assertEqual(0, count()),
  199. lager:trace(?MODULE, [{requestid, 6}, {foo, bar}], debug),
  200. lager:info([{requestid, 6}, {foo, bar}], "hello world"),
  201. ?assertEqual(1, count()),
  202. lager:trace(?MODULE, [{requestid, '*'}], debug),
  203. lager:info([{requestid, 6}], "hello world"),
  204. ?assertEqual(2, count()),
  205. lager:clear_all_traces(),
  206. lager:info([{requestid, 6}], "hello world"),
  207. ?assertEqual(2, count()),
  208. ok
  209. end
  210. },
  211. {"tracing honors loglevel",
  212. fun() ->
  213. lager:set_loglevel(?MODULE, error),
  214. {ok, T} = lager:trace(?MODULE, [{module, ?MODULE}], notice),
  215. ok = lager:info("hello world"),
  216. ?assertEqual(0, count()),
  217. ok = lager:notice("hello world"),
  218. ?assertEqual(1, count()),
  219. lager:stop_trace(T),
  220. ok = lager:notice("hello world"),
  221. ?assertEqual(1, count()),
  222. ok
  223. end
  224. },
  225. {"record printing works",
  226. fun() ->
  227. print_state(),
  228. {Level, _Time, Message, _Metadata} = pop(),
  229. ?assertMatch(Level, lager_util:level_to_num(info)),
  230. {mask, Mask} = lager_util:config_to_mask(info),
  231. ?assertEqual("State #state{level={mask,"++integer_to_list(Mask)++"},buffer=[],ignored=[]}", lists:flatten(Message)),
  232. ok
  233. end
  234. },
  235. {"record printing fails gracefully",
  236. fun() ->
  237. print_bad_state(),
  238. {Level, _Time, Message, _Metadata} = pop(),
  239. ?assertMatch(Level, lager_util:level_to_num(info)),
  240. ?assertEqual("State {state,1}", lists:flatten(Message)),
  241. ok
  242. end
  243. },
  244. {"record printing fails gracefully when no lager_record attribute",
  245. fun() ->
  246. spawn(fun() -> lager:info("State ~p", [lager:pr({state, 1}, lager)]) end),
  247. timer:sleep(100),
  248. {Level, _Time, Message, _Metadata} = pop(),
  249. ?assertMatch(Level, lager_util:level_to_num(info)),
  250. ?assertEqual("State {state,1}", lists:flatten(Message)),
  251. ok
  252. end
  253. },
  254. {"record printing fails gracefully when input is not a tuple",
  255. fun() ->
  256. spawn(fun() -> lager:info("State ~p", [lager:pr(ok, lager)]) end),
  257. timer:sleep(100),
  258. {Level, _Time, Message, _Metadata} = pop(),
  259. ?assertMatch(Level, lager_util:level_to_num(info)),
  260. ?assertEqual("State ok", lists:flatten(Message)),
  261. ok
  262. end
  263. },
  264. {"record printing fails gracefully when module is invalid",
  265. fun() ->
  266. spawn(fun() -> lager:info("State ~p", [lager:pr({state, 1}, not_a_module)]) end),
  267. timer:sleep(100),
  268. {Level, _Time, Message, _Metadata} = pop(),
  269. ?assertMatch(Level, lager_util:level_to_num(info)),
  270. ?assertEqual("State {state,1}", lists:flatten(Message)),
  271. ok
  272. end
  273. }
  274. ]
  275. }.
  276. setup() ->
  277. error_logger:tty(false),
  278. application:load(lager),
  279. application:set_env(lager, handlers, [{?MODULE, info}]),
  280. application:set_env(lager, error_logger_redirect, false),
  281. application:start(lager),
  282. gen_event:call(lager_event, ?MODULE, flush).
  283. cleanup(_) ->
  284. application:stop(lager),
  285. error_logger:tty(true).
  286. crash(Type) ->
  287. spawn(fun() -> gen_server:call(crash, Type) end),
  288. timer:sleep(100),
  289. _ = gen_event:which_handlers(error_logger),
  290. ok.
  291. test_body(Expected, Actual) ->
  292. case has_line_numbers() of
  293. true ->
  294. FileLine = string:substr(Actual, length(Expected)+1),
  295. Body = string:substr(Actual, 1, length(Expected)),
  296. ?assertEqual(Expected, Body),
  297. case string:substr(FileLine, 1, 6) of
  298. [] ->
  299. %% sometimes there's no line information...
  300. ?assert(true);
  301. " line " ->
  302. ?assert(true);
  303. Other ->
  304. ?debugFmt("unexpected trailing data ~p", [Other]),
  305. ?assert(false)
  306. end;
  307. false ->
  308. ?assertEqual(Expected, Actual)
  309. end.
  310. error_logger_redirect_crash_test_() ->
  311. TestBody=fun(Name,CrashReason,Expected) -> {Name,
  312. fun() ->
  313. Pid = whereis(crash),
  314. crash(CrashReason),
  315. {Level, _, Msg,Metadata} = pop(),
  316. test_body(Expected, lists:flatten(Msg)),
  317. ?assertEqual(Pid,proplists:get_value(pid,Metadata)),
  318. ?assertEqual(lager_util:level_to_num(error),Level)
  319. end
  320. }
  321. end,
  322. {foreach,
  323. fun() ->
  324. error_logger:tty(false),
  325. application:load(lager),
  326. application:set_env(lager, error_logger_redirect, true),
  327. application:set_env(lager, handlers, [{?MODULE, error}]),
  328. application:start(lager),
  329. crash:start()
  330. end,
  331. fun(_) ->
  332. application:stop(lager),
  333. case whereis(crash) of
  334. undefined -> ok;
  335. Pid -> exit(Pid, kill)
  336. end,
  337. error_logger:tty(true)
  338. end,
  339. [
  340. {"again, there is nothing up my sleeve",
  341. fun() ->
  342. ?assertEqual(undefined, pop()),
  343. ?assertEqual(0, count())
  344. end
  345. },
  346. TestBody("bad return value",bad_return,"gen_server crash terminated with reason: bad return value: bleh"),
  347. TestBody("bad return value with string",bad_return_string,"gen_server crash terminated with reason: bad return value: {tuple,{tuple,\"string\"}}"),
  348. TestBody("bad return uncaught throw",throw,"gen_server crash terminated with reason: bad return value: a_ball"),
  349. TestBody("case clause",case_clause,"gen_server crash terminated with reason: no case clause matching {} in crash:handle_call/3"),
  350. TestBody("case clause string",case_clause_string,"gen_server crash terminated with reason: no case clause matching \"crash\" in crash:handle_call/3"),
  351. TestBody("function clause",function_clause,"gen_server crash terminated with reason: no function clause matching crash:function({})"),
  352. TestBody("if clause",if_clause,"gen_server crash terminated with reason: no true branch found while evaluating if expression in crash:handle_call/3"),
  353. TestBody("try clause",try_clause,"gen_server crash terminated with reason: no try clause matching [] in crash:handle_call/3"),
  354. TestBody("undefined function",undef,"gen_server crash terminated with reason: call to undefined function crash:booger/0 from crash:handle_call/3"),
  355. TestBody("bad math",badarith,"gen_server crash terminated with reason: bad arithmetic expression in crash:handle_call/3"),
  356. TestBody("bad match",badmatch,"gen_server crash terminated with reason: no match of right hand value {} in crash:handle_call/3"),
  357. TestBody("bad arity",badarity,"gen_server crash terminated with reason: fun called with wrong arity of 1 instead of 3 in crash:handle_call/3"),
  358. TestBody("bad arg1",badarg1,"gen_server crash terminated with reason: bad argument in crash:handle_call/3"),
  359. TestBody("bad arg2",badarg2,"gen_server crash terminated with reason: bad argument in call to erlang:iolist_to_binary([\"foo\",bar]) in crash:handle_call/3"),
  360. TestBody("bad record",badrecord,"gen_server crash terminated with reason: bad record state in crash:handle_call/3"),
  361. TestBody("noproc",noproc,"gen_server crash terminated with reason: no such process or port in call to gen_event:call(foo, bar, baz)"),
  362. TestBody("badfun",badfun,"gen_server crash terminated with reason: bad function booger in crash:handle_call/3")
  363. ]
  364. }.
  365. error_logger_redirect_test_() ->
  366. {foreach,
  367. fun() ->
  368. error_logger:tty(false),
  369. application:load(lager),
  370. application:set_env(lager, error_logger_redirect, true),
  371. application:set_env(lager, handlers, [{?MODULE, info}]),
  372. application:start(lager),
  373. lager:log(error, self(), "flush flush"),
  374. timer:sleep(100),
  375. gen_event:call(lager_event, ?MODULE, flush)
  376. end,
  377. fun(_) ->
  378. application:stop(lager),
  379. error_logger:tty(true)
  380. end,
  381. [
  382. {"error reports are printed",
  383. fun() ->
  384. sync_error_logger:error_report([{this, is}, a, {silly, format}]),
  385. _ = gen_event:which_handlers(error_logger),
  386. {Level, _, Msg,Metadata} = pop(),
  387. ?assertEqual(lager_util:level_to_num(error),Level),
  388. ?assertEqual(self(),proplists:get_value(pid,Metadata)),
  389. Expected = "this: is, a, silly: format",
  390. ?assertEqual(Expected, lists:flatten(Msg))
  391. end
  392. },
  393. {"string error reports are printed",
  394. fun() ->
  395. sync_error_logger:error_report("this is less silly"),
  396. _ = gen_event:which_handlers(error_logger),
  397. {Level, _, Msg,Metadata} = pop(),
  398. ?assertEqual(lager_util:level_to_num(error),Level),
  399. ?assertEqual(self(),proplists:get_value(pid,Metadata)),
  400. Expected = "this is less silly",
  401. ?assertEqual(Expected, lists:flatten(Msg))
  402. end
  403. },
  404. {"error messages are printed",
  405. fun() ->
  406. sync_error_logger:error_msg("doom, doom has come upon you all"),
  407. _ = gen_event:which_handlers(error_logger),
  408. {Level, _, Msg,Metadata} = pop(),
  409. ?assertEqual(lager_util:level_to_num(error),Level),
  410. ?assertEqual(self(),proplists:get_value(pid,Metadata)),
  411. Expected = "doom, doom has come upon you all",
  412. ?assertEqual(Expected, lists:flatten(Msg))
  413. end
  414. },
  415. {"error messages are truncated at 4096 characters",
  416. fun() ->
  417. sync_error_logger:error_msg("doom, doom has come upon you all ~p", [string:copies("doom", 10000)]),
  418. _ = gen_event:which_handlers(error_logger),
  419. {_, _, Msg,_Metadata} = pop(),
  420. ?assert(length(lists:flatten(Msg)) < 5100)
  421. end
  422. },
  423. {"info reports are printed",
  424. fun() ->
  425. sync_error_logger:info_report([{this, is}, a, {silly, format}]),
  426. _ = gen_event:which_handlers(error_logger),
  427. {Level, _, Msg,Metadata} = pop(),
  428. ?assertEqual(lager_util:level_to_num(info),Level),
  429. ?assertEqual(self(),proplists:get_value(pid,Metadata)),
  430. Expected = "this: is, a, silly: format",
  431. ?assertEqual(Expected, lists:flatten(Msg))
  432. end
  433. },
  434. {"info reports are truncated at 4096 characters",
  435. fun() ->
  436. sync_error_logger:info_report([[{this, is}, a, {silly, format}] || _ <- lists:seq(0, 600)]),
  437. _ = gen_event:which_handlers(error_logger),
  438. {Level, _, Msg,Metadata} = pop(),
  439. ?assertEqual(lager_util:level_to_num(info),Level),
  440. ?assertEqual(self(),proplists:get_value(pid,Metadata)),
  441. ?assert(length(lists:flatten(Msg)) < 5000)
  442. end
  443. },
  444. {"single term info reports are printed",
  445. fun() ->
  446. sync_error_logger:info_report({foolish, bees}),
  447. _ = gen_event:which_handlers(error_logger),
  448. {Level, _, Msg,Metadata} = pop(),
  449. ?assertEqual(lager_util:level_to_num(info),Level),
  450. ?assertEqual(self(),proplists:get_value(pid,Metadata)),
  451. ?assertEqual("{foolish,bees}", lists:flatten(Msg))
  452. end
  453. },
  454. {"single term error reports are printed",
  455. fun() ->
  456. sync_error_logger:error_report({foolish, bees}),
  457. _ = gen_event:which_handlers(error_logger),
  458. {Level, _, Msg,Metadata} = pop(),
  459. ?assertEqual(lager_util:level_to_num(error),Level),
  460. ?assertEqual(self(),proplists:get_value(pid,Metadata)),
  461. ?assertEqual("{foolish,bees}", lists:flatten(Msg))
  462. end
  463. },
  464. {"string info reports are printed",
  465. fun() ->
  466. sync_error_logger:info_report("this is less silly"),
  467. _ = gen_event:which_handlers(error_logger),
  468. {Level, _, Msg,Metadata} = pop(),
  469. ?assertEqual(lager_util:level_to_num(info),Level),
  470. ?assertEqual(self(),proplists:get_value(pid,Metadata)),
  471. ?assertEqual("this is less silly", lists:flatten(Msg))
  472. end
  473. },
  474. {"string info reports are truncated at 4096 characters",
  475. fun() ->
  476. sync_error_logger:info_report(string:copies("this is less silly", 1000)),
  477. _ = gen_event:which_handlers(error_logger),
  478. {Level, _, Msg,Metadata} = pop(),
  479. ?assertEqual(lager_util:level_to_num(info),Level),
  480. ?assertEqual(self(),proplists:get_value(pid,Metadata)),
  481. ?assert(length(lists:flatten(Msg)) < 5100)
  482. end
  483. },
  484. {"strings in a mixed report are printed as strings",
  485. fun() ->
  486. sync_error_logger:info_report(["this is less silly", {than, "this"}]),
  487. _ = gen_event:which_handlers(error_logger),
  488. {Level, _, Msg,Metadata} = pop(),
  489. ?assertEqual(lager_util:level_to_num(info),Level),
  490. ?assertEqual(self(),proplists:get_value(pid,Metadata)),
  491. ?assertEqual("\"this is less silly\", than: \"this\"", lists:flatten(Msg))
  492. end
  493. },
  494. {"info messages are printed",
  495. fun() ->
  496. sync_error_logger:info_msg("doom, doom has come upon you all"),
  497. _ = gen_event:which_handlers(error_logger),
  498. {Level, _, Msg,Metadata} = pop(),
  499. ?assertEqual(lager_util:level_to_num(info),Level),
  500. ?assertEqual(self(),proplists:get_value(pid,Metadata)),
  501. ?assertEqual("doom, doom has come upon you all", lists:flatten(Msg))
  502. end
  503. },
  504. {"info messages are truncated at 4096 characters",
  505. fun() ->
  506. sync_error_logger:info_msg("doom, doom has come upon you all ~p", [string:copies("doom", 10000)]),
  507. _ = gen_event:which_handlers(error_logger),
  508. {Level, _, Msg,Metadata} = pop(),
  509. ?assertEqual(lager_util:level_to_num(info),Level),
  510. ?assertEqual(self(),proplists:get_value(pid,Metadata)),
  511. ?assert(length(lists:flatten(Msg)) < 5100)
  512. end
  513. },
  514. {"warning messages are printed at the correct level",
  515. fun() ->
  516. sync_error_logger:warning_msg("doom, doom has come upon you all"),
  517. Map = error_logger:warning_map(),
  518. _ = gen_event:which_handlers(error_logger),
  519. {Level, _, Msg,Metadata} = pop(),
  520. ?assertEqual(lager_util:level_to_num(Map),Level),
  521. ?assertEqual(self(),proplists:get_value(pid,Metadata)),
  522. ?assertEqual("doom, doom has come upon you all", lists:flatten(Msg))
  523. end
  524. },
  525. {"warning reports are printed at the correct level",
  526. fun() ->
  527. sync_error_logger:warning_report([{i, like}, pie]),
  528. Map = error_logger:warning_map(),
  529. _ = gen_event:which_handlers(error_logger),
  530. {Level, _, Msg,Metadata} = pop(),
  531. ?assertEqual(lager_util:level_to_num(Map),Level),
  532. ?assertEqual(self(),proplists:get_value(pid,Metadata)),
  533. ?assertEqual("i: like, pie", lists:flatten(Msg))
  534. end
  535. },
  536. {"single term warning reports are printed at the correct level",
  537. fun() ->
  538. sync_error_logger:warning_report({foolish, bees}),
  539. Map = error_logger:warning_map(),
  540. _ = gen_event:which_handlers(error_logger),
  541. {Level, _, Msg,Metadata} = pop(),
  542. ?assertEqual(lager_util:level_to_num(Map),Level),
  543. ?assertEqual(self(),proplists:get_value(pid,Metadata)),
  544. ?assertEqual("{foolish,bees}", lists:flatten(Msg))
  545. end
  546. },
  547. {"application stop reports",
  548. fun() ->
  549. sync_error_logger:info_report([{application, foo}, {exited, quittin_time}, {type, lazy}]),
  550. _ = gen_event:which_handlers(error_logger),
  551. {Level, _, Msg,Metadata} = pop(),
  552. ?assertEqual(lager_util:level_to_num(info),Level),
  553. ?assertEqual(self(),proplists:get_value(pid,Metadata)),
  554. ?assertEqual("Application foo exited with reason: quittin_time", lists:flatten(Msg))
  555. end
  556. },
  557. {"supervisor reports",
  558. fun() ->
  559. sync_error_logger:error_report(supervisor_report, [{errorContext, france}, {offender, [{name, mini_steve}, {mfargs, {a, b, [c]}}, {pid, bleh}]}, {reason, fired}, {supervisor, {local, steve}}]),
  560. _ = gen_event:which_handlers(error_logger),
  561. {Level, _, Msg,Metadata} = pop(),
  562. ?assertEqual(lager_util:level_to_num(error),Level),
  563. ?assertEqual(self(),proplists:get_value(pid,Metadata)),
  564. ?assertEqual("Supervisor steve had child mini_steve started with a:b(c) at bleh exit with reason fired in context france", lists:flatten(Msg))
  565. end
  566. },
  567. {"supervisor reports with real error",
  568. fun() ->
  569. sync_error_logger:error_report(supervisor_report, [{errorContext, france}, {offender, [{name, mini_steve}, {mfargs, {a, b, [c]}}, {pid, bleh}]}, {reason, {function_clause,[{crash,handle_info,[foo]}]}}, {supervisor, {local, steve}}]),
  570. _ = gen_event:which_handlers(error_logger),
  571. {Level, _, Msg,Metadata} = pop(),
  572. ?assertEqual(lager_util:level_to_num(error),Level),
  573. ?assertEqual(self(),proplists:get_value(pid,Metadata)),
  574. ?assertEqual("Supervisor steve had child mini_steve started with a:b(c) at bleh exit with reason no function clause matching crash:handle_info(foo) in context france", lists:flatten(Msg))
  575. end
  576. },
  577. {"supervisor_bridge reports",
  578. fun() ->
  579. sync_error_logger:error_report(supervisor_report, [{errorContext, france}, {offender, [{mod, mini_steve}, {pid, bleh}]}, {reason, fired}, {supervisor, {local, steve}}]),
  580. _ = gen_event:which_handlers(error_logger),
  581. {Level, _, Msg,Metadata} = pop(),
  582. ?assertEqual(lager_util:level_to_num(error),Level),
  583. ?assertEqual(self(),proplists:get_value(pid,Metadata)),
  584. ?assertEqual("Supervisor steve had child at module mini_steve at bleh exit with reason fired in context france", lists:flatten(Msg))
  585. end
  586. },
  587. {"application progress report",
  588. fun() ->
  589. sync_error_logger:info_report(progress, [{application, foo}, {started_at, node()}]),
  590. _ = gen_event:which_handlers(error_logger),
  591. {Level, _, Msg,Metadata} = pop(),
  592. ?assertEqual(lager_util:level_to_num(info),Level),
  593. ?assertEqual(self(),proplists:get_value(pid,Metadata)),
  594. Expected = lists:flatten(io_lib:format("Application foo started on node ~w", [node()])),
  595. ?assertEqual(Expected, lists:flatten(Msg))
  596. end
  597. },
  598. {"supervisor progress report",
  599. fun() ->
  600. lager:set_loglevel(?MODULE, debug),
  601. sync_error_logger:info_report(progress, [{supervisor, {local, foo}}, {started, [{mfargs, {foo, bar, 1}}, {pid, baz}]}]),
  602. _ = gen_event:which_handlers(error_logger),
  603. {Level, _, Msg,Metadata} = pop(),
  604. ?assertEqual(lager_util:level_to_num(debug),Level),
  605. ?assertEqual(self(),proplists:get_value(pid,Metadata)),
  606. ?assertEqual("Supervisor foo started foo:bar/1 at pid baz", lists:flatten(Msg))
  607. end
  608. },
  609. {"crash report for emfile",
  610. fun() ->
  611. sync_error_logger:error_report(crash_report, [[{pid, self()}, {registered_name, []}, {error_info, {error, emfile, [{stack, trace, 1}]}}], []]),
  612. _ = gen_event:which_handlers(error_logger),
  613. {Level, _, Msg,Metadata} = pop(),
  614. ?assertEqual(lager_util:level_to_num(error),Level),
  615. ?assertEqual(self(),proplists:get_value(pid,Metadata)),
  616. Expected = lists:flatten(io_lib:format("CRASH REPORT Process ~w with 0 neighbours crashed with reason: maximum number of file descriptors exhausted, check ulimit -n", [self()])),
  617. ?assertEqual(Expected, lists:flatten(Msg))
  618. end
  619. },
  620. {"crash report for system process limit",
  621. fun() ->
  622. sync_error_logger:error_report(crash_report, [[{pid, self()}, {registered_name, []}, {error_info, {error, system_limit, [{erlang, spawn, 1}]}}], []]),
  623. _ = gen_event:which_handlers(error_logger),
  624. {Level, _, Msg,Metadata} = pop(),
  625. ?assertEqual(lager_util:level_to_num(error),Level),
  626. ?assertEqual(self(),proplists:get_value(pid,Metadata)),
  627. Expected = lists:flatten(io_lib:format("CRASH REPORT Process ~w with 0 neighbours crashed with reason: system limit: maximum number of processes exceeded", [self()])),
  628. ?assertEqual(Expected, lists:flatten(Msg))
  629. end
  630. },
  631. {"crash report for system process limit2",
  632. fun() ->
  633. sync_error_logger:error_report(crash_report, [[{pid, self()}, {registered_name, []}, {error_info, {error, system_limit, [{erlang, spawn_opt, 1}]}}], []]),
  634. _ = gen_event:which_handlers(error_logger),
  635. {Level, _, Msg,Metadata} = pop(),
  636. ?assertEqual(lager_util:level_to_num(error),Level),
  637. ?assertEqual(self(),proplists:get_value(pid,Metadata)),
  638. Expected = lists:flatten(io_lib:format("CRASH REPORT Process ~w with 0 neighbours crashed with reason: system limit: maximum number of processes exceeded", [self()])),
  639. ?assertEqual(Expected, lists:flatten(Msg))
  640. end
  641. },
  642. {"crash report for system port limit",
  643. fun() ->
  644. sync_error_logger:error_report(crash_report, [[{pid, self()}, {registered_name, []}, {error_info, {error, system_limit, [{erlang, open_port, 1}]}}], []]),
  645. _ = gen_event:which_handlers(error_logger),
  646. {Level, _, Msg,Metadata} = pop(),
  647. ?assertEqual(lager_util:level_to_num(error),Level),
  648. ?assertEqual(self(),proplists:get_value(pid,Metadata)),
  649. Expected = lists:flatten(io_lib:format("CRASH REPORT Process ~w with 0 neighbours crashed with reason: system limit: maximum number of ports exceeded", [self()])),
  650. ?assertEqual(Expected, lists:flatten(Msg))
  651. end
  652. },
  653. {"crash report for system port limit",
  654. fun() ->
  655. sync_error_logger:error_report(crash_report, [[{pid, self()}, {registered_name, []}, {error_info, {error, system_limit, [{erlang, list_to_atom, 1}]}}], []]),
  656. _ = gen_event:which_handlers(error_logger),
  657. {Level, _, Msg,Metadata} = pop(),
  658. ?assertEqual(lager_util:level_to_num(error),Level),
  659. ?assertEqual(self(),proplists:get_value(pid,Metadata)),
  660. Expected = lists:flatten(io_lib:format("CRASH REPORT Process ~w with 0 neighbours crashed with reason: system limit: tried to create an atom larger than 255, or maximum atom count exceeded", [self()])),
  661. ?assertEqual(Expected, lists:flatten(Msg))
  662. end
  663. },
  664. {"crash report for system ets table limit",
  665. fun() ->
  666. sync_error_logger:error_report(crash_report, [[{pid, self()}, {registered_name, test}, {error_info, {error, system_limit, [{ets,new,[segment_offsets,[ordered_set,public]]},{mi_segment,open_write,1},{mi_buffer_converter,handle_cast,2},{gen_server,handle_msg,5},{proc_lib,init_p_do_apply,3}]}}], []]),
  667. _ = gen_event:which_handlers(error_logger),
  668. {Level, _, Msg,Metadata} = pop(),
  669. ?assertEqual(lager_util:level_to_num(error),Level),
  670. ?assertEqual(self(),proplists:get_value(pid,Metadata)),
  671. Expected = lists:flatten(io_lib:format("CRASH REPORT Process ~w with 0 neighbours crashed with reason: system limit: maximum number of ETS tables exceeded", [test])),
  672. ?assertEqual(Expected, lists:flatten(Msg))
  673. end
  674. },
  675. {"crash report for unknown system limit should be truncated at 500 characters",
  676. fun() ->
  677. sync_error_logger:error_report(crash_report, [[{pid, self()}, {error_info, {error, system_limit, [{wtf,boom,[string:copies("aaaa", 4096)]}]}}], []]),
  678. _ = gen_event:which_handlers(error_logger),
  679. {_, _, Msg,_Metadata} = pop(),
  680. ?assert(length(lists:flatten(Msg)) > 550),
  681. ?assert(length(lists:flatten(Msg)) < 600)
  682. end
  683. },
  684. {"crash reports for 'special processes' should be handled right - function_clause",
  685. fun() ->
  686. {ok, Pid} = special_process:start(),
  687. unlink(Pid),
  688. Pid ! function_clause,
  689. timer:sleep(500),
  690. _ = gen_event:which_handlers(error_logger),
  691. {_, _, Msg, _Metadata} = pop(),
  692. Expected = lists:flatten(io_lib:format("CRASH REPORT Process ~p with 0 neighbours crashed with reason: no function clause matching special_process:foo(bar)",
  693. [Pid])),
  694. test_body(Expected, lists:flatten(Msg))
  695. end
  696. },
  697. {"crash reports for 'special processes' should be handled right - case_clause",
  698. fun() ->
  699. {ok, Pid} = special_process:start(),
  700. unlink(Pid),
  701. Pid ! {case_clause, wtf},
  702. timer:sleep(500),
  703. _ = gen_event:which_handlers(error_logger),
  704. {_, _, Msg, _Metadata} = pop(),
  705. Expected = lists:flatten(io_lib:format("CRASH REPORT Process ~p with 0 neighbours crashed with reason: no case clause matching wtf in special_process:loop/0",
  706. [Pid])),
  707. test_body(Expected, lists:flatten(Msg))
  708. end
  709. },
  710. {"crash reports for 'special processes' should be handled right - exit",
  711. fun() ->
  712. {ok, Pid} = special_process:start(),
  713. unlink(Pid),
  714. Pid ! exit,
  715. timer:sleep(500),
  716. _ = gen_event:which_handlers(error_logger),
  717. {_, _, Msg, _Metadata} = pop(),
  718. Expected = lists:flatten(io_lib:format("CRASH REPORT Process ~p with 0 neighbours exited with reason: byebye in special_process:loop/0",
  719. [Pid])),
  720. test_body(Expected, lists:flatten(Msg))
  721. end
  722. },
  723. {"crash reports for 'special processes' should be handled right - error",
  724. fun() ->
  725. {ok, Pid} = special_process:start(),
  726. unlink(Pid),
  727. Pid ! error,
  728. timer:sleep(500),
  729. _ = gen_event:which_handlers(error_logger),
  730. {_, _, Msg, _Metadata} = pop(),
  731. Expected = lists:flatten(io_lib:format("CRASH REPORT Process ~p with 0 neighbours crashed with reason: mybad in special_process:loop/0",
  732. [Pid])),
  733. test_body(Expected, lists:flatten(Msg))
  734. end
  735. },
  736. {"messages should not be generated if they don't satisfy the threshold",
  737. fun() ->
  738. lager:set_loglevel(?MODULE, error),
  739. sync_error_logger:info_report([hello, world]),
  740. _ = gen_event:which_handlers(error_logger),
  741. ?assertEqual(0, count()),
  742. ?assertEqual(0, count_ignored()),
  743. lager:set_loglevel(?MODULE, info),
  744. sync_error_logger:info_report([hello, world]),
  745. _ = gen_event:which_handlers(error_logger),
  746. ?assertEqual(1, count()),
  747. ?assertEqual(0, count_ignored()),
  748. lager:set_loglevel(?MODULE, error),
  749. lager_config:set(loglevel, {element(2, lager_util:config_to_mask(debug)), []}),
  750. sync_error_logger:info_report([hello, world]),
  751. _ = gen_event:which_handlers(error_logger),
  752. ?assertEqual(1, count()),
  753. ?assertEqual(1, count_ignored())
  754. end
  755. }
  756. ]
  757. }.
  758. safe_format_test() ->
  759. ?assertEqual("foo bar", lists:flatten(lager:safe_format("~p ~p", [foo, bar], 1024))),
  760. ?assertEqual("FORMAT ERROR: \"~p ~p ~p\" [foo,bar]", lists:flatten(lager:safe_format("~p ~p ~p", [foo, bar], 1024))),
  761. ok.
  762. -endif.