25개 이상의 토픽을 선택하실 수 없습니다. Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

568 lines
26 KiB

14 년 전
14 년 전
14 년 전
14 년 전
14 년 전
14 년 전
14 년 전
14 년 전
14 년 전
14 년 전
  1. %% Copyright (c) 2011 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. -behaviour(gen_event).
  18. -export([init/1, handle_call/2, handle_event/2, handle_info/2, terminate/2,
  19. code_change/3]).
  20. -record(state, {level, buffer, ignored}).
  21. -compile([{parse_transform, lager_transform}]).
  22. -ifdef(TEST).
  23. -include_lib("eunit/include/eunit.hrl").
  24. -endif.
  25. init(Level) ->
  26. {ok, #state{level=lager_util:level_to_num(Level), buffer=[], ignored=[]}}.
  27. handle_call(count, #state{buffer=Buffer} = State) ->
  28. {ok, length(Buffer), State};
  29. handle_call(count_ignored, #state{ignored=Ignored} = State) ->
  30. {ok, length(Ignored), State};
  31. handle_call(flush, State) ->
  32. {ok, ok, State#state{buffer=[], ignored=[]}};
  33. handle_call(pop, #state{buffer=Buffer} = State) ->
  34. case Buffer of
  35. [] ->
  36. {ok, undefined, State};
  37. [H|T] ->
  38. {ok, H, State#state{buffer=T}}
  39. end;
  40. handle_call(get_loglevel, #state{level=Level} = State) ->
  41. {ok, Level, State};
  42. handle_call({set_loglevel, Level}, State) ->
  43. {ok, ok, State#state{level=lager_util:level_to_num(Level)}};
  44. handle_call(_Request, State) ->
  45. {ok, ok, State}.
  46. handle_event({log, Level, Time, Message}, #state{level=LogLevel,
  47. buffer=Buffer} = State) when Level >= LogLevel ->
  48. {ok, State#state{buffer=Buffer ++ [{Level, Time, Message}]}};
  49. handle_event({log, _Level, _Time, _Message}, #state{ignored=Ignored} = State) ->
  50. {ok, State#state{ignored=Ignored ++ [ignored]}};
  51. handle_event(_Event, State) ->
  52. {ok, State}.
  53. handle_info(_Info, State) ->
  54. {ok, State}.
  55. terminate(_Reason, _State) ->
  56. ok.
  57. code_change(_OldVsn, State, _Extra) ->
  58. {ok, State}.
  59. -ifdef(TEST).
  60. pop() ->
  61. gen_event:call(lager_event, ?MODULE, pop).
  62. count() ->
  63. gen_event:call(lager_event, ?MODULE, count).
  64. count_ignored() ->
  65. gen_event:call(lager_event, ?MODULE, count_ignored).
  66. lager_test_() ->
  67. {foreach,
  68. fun setup/0,
  69. fun cleanup/1,
  70. [
  71. {"observe that there is nothing up my sleeve",
  72. fun() ->
  73. ?assertEqual(undefined, pop()),
  74. ?assertEqual(0, count())
  75. end
  76. },
  77. {"logging works",
  78. fun() ->
  79. lager:warning("test message"),
  80. ?assertEqual(1, count()),
  81. {Level, _Time, Message} = pop(),
  82. ?assertMatch(Level, lager_util:level_to_num(warning)),
  83. [LevelStr, _LocStr, MsgStr] = re:split(Message, " ", [{return, list}, {parts, 3}]),
  84. ?assertEqual("[warning]", LevelStr),
  85. ?assertEqual("test message", MsgStr),
  86. ok
  87. end
  88. },
  89. {"logging with arguments works",
  90. fun() ->
  91. lager:warning("test message ~p", [self()]),
  92. ?assertEqual(1, count()),
  93. {Level, _Time, Message} = pop(),
  94. ?assertMatch(Level, lager_util:level_to_num(warning)),
  95. [LevelStr, _LocStr, MsgStr] = re:split(Message, " ", [{return, list}, {parts, 3}]),
  96. ?assertEqual("[warning]", LevelStr),
  97. ?assertEqual(lists:flatten(io_lib:format("test message ~p", [self()])), MsgStr),
  98. ok
  99. end
  100. },
  101. {"logging works from inside a begin/end block",
  102. fun() ->
  103. ?assertEqual(0, count()),
  104. begin
  105. lager:warning("test message 2")
  106. end,
  107. ?assertEqual(1, count()),
  108. ok
  109. end
  110. },
  111. {"logging works from inside a list comprehension",
  112. fun() ->
  113. ?assertEqual(0, count()),
  114. [lager:warning("test message") || _N <- lists:seq(1, 10)],
  115. ?assertEqual(10, count()),
  116. ok
  117. end
  118. },
  119. {"logging works from a begin/end block inside a list comprehension",
  120. fun() ->
  121. ?assertEqual(0, count()),
  122. [ begin lager:warning("test message") end || _N <- lists:seq(1, 10)],
  123. ?assertEqual(10, count()),
  124. ok
  125. end
  126. },
  127. {"logging works from a nested list comprehension",
  128. fun() ->
  129. ?assertEqual(0, count()),
  130. [ [lager:warning("test message") || _N <- lists:seq(1, 10)] ||
  131. _I <- lists:seq(1, 10)],
  132. ?assertEqual(100, count()),
  133. ok
  134. end
  135. },
  136. {"log messages below the threshold are ignored",
  137. fun() ->
  138. ?assertEqual(0, count()),
  139. lager:debug("this message will be ignored"),
  140. ?assertEqual(0, count()),
  141. ?assertEqual(0, count_ignored()),
  142. lager_mochiglobal:put(loglevel, 0),
  143. lager:debug("this message should be ignored"),
  144. ?assertEqual(0, count()),
  145. ?assertEqual(1, count_ignored()),
  146. lager:set_loglevel(?MODULE, debug),
  147. lager:debug("this message should be logged"),
  148. ?assertEqual(1, count()),
  149. ?assertEqual(1, count_ignored()),
  150. ?assertEqual(debug, lager:get_loglevel(?MODULE)),
  151. ok
  152. end
  153. }
  154. ]
  155. }.
  156. setup() ->
  157. application:load(lager),
  158. application:set_env(lager, handlers, [{?MODULE, info}]),
  159. application:set_env(lager, error_logger_redirect, false),
  160. application:start(lager),
  161. gen_event:call(lager_event, ?MODULE, flush).
  162. cleanup(_) ->
  163. application:stop(lager),
  164. application:unload(lager).
  165. crash(Type) ->
  166. spawn(fun() -> gen_server:call(crash, Type) end),
  167. timer:sleep(100).
  168. error_logger_redirect_crash_test_() ->
  169. {foreach,
  170. fun() ->
  171. application:load(lager),
  172. application:set_env(lager, error_logger_redirect, true),
  173. application:set_env(lager, handlers, [{?MODULE, error}]),
  174. application:start(lager),
  175. crash:start()
  176. end,
  177. fun(_) ->
  178. application:stop(lager),
  179. application:unload(lager),
  180. case whereis(crash) of
  181. undefined -> ok;
  182. Pid -> exit(Pid, kill)
  183. end
  184. end,
  185. [
  186. {"again, there is nothing up my sleeve",
  187. fun() ->
  188. ?assertEqual(undefined, pop()),
  189. ?assertEqual(0, count())
  190. end
  191. },
  192. {"bad return value",
  193. fun() ->
  194. Pid = whereis(crash),
  195. crash(bad_return),
  196. {_, _, Msg} = pop(),
  197. Expected = lists:flatten(io_lib:format("[error] ~w gen_server crash terminated with reason: bad return value: bleh", [Pid])),
  198. ?assertEqual(Expected, lists:flatten(Msg))
  199. end
  200. },
  201. {"case clause",
  202. fun() ->
  203. Pid = whereis(crash),
  204. crash(case_clause),
  205. {_, _, Msg} = pop(),
  206. Expected = lists:flatten(io_lib:format("[error] ~w gen_server crash terminated with reason: no case clause matching {} in crash:handle_call/3", [Pid])),
  207. ?assertEqual(Expected, lists:flatten(Msg))
  208. end
  209. },
  210. {"function clause",
  211. fun() ->
  212. Pid = whereis(crash),
  213. crash(function_clause),
  214. {_, _, Msg} = pop(),
  215. Expected = lists:flatten(io_lib:format("[error] ~w gen_server crash terminated with reason: no function clause matching crash:function({})", [Pid])),
  216. ?assertEqual(Expected, lists:flatten(Msg))
  217. end
  218. },
  219. {"if clause",
  220. fun() ->
  221. Pid = whereis(crash),
  222. crash(if_clause),
  223. {_, _, Msg} = pop(),
  224. Expected = lists:flatten(io_lib:format("[error] ~w gen_server crash terminated with reason: no true branch found while evaluating if expression in crash:handle_call/3", [Pid])),
  225. ?assertEqual(Expected, lists:flatten(Msg))
  226. end
  227. },
  228. {"try clause",
  229. fun() ->
  230. Pid = whereis(crash),
  231. crash(try_clause),
  232. {_, _, Msg} = pop(),
  233. Expected = lists:flatten(io_lib:format("[error] ~w gen_server crash terminated with reason: no try clause matching [] in crash:handle_call/3", [Pid])),
  234. ?assertEqual(Expected, lists:flatten(Msg))
  235. end
  236. },
  237. {"undefined function",
  238. fun() ->
  239. Pid = whereis(crash),
  240. crash(undef),
  241. {_, _, Msg} = pop(),
  242. Expected = lists:flatten(io_lib:format("[error] ~w gen_server crash terminated with reason: call to undefined function crash:booger/0 from crash:handle_call/3", [Pid])),
  243. ?assertEqual(Expected, lists:flatten(Msg))
  244. end
  245. },
  246. {"bad math",
  247. fun() ->
  248. Pid = whereis(crash),
  249. crash(badarith),
  250. {_, _, Msg} = pop(),
  251. Expected = lists:flatten(io_lib:format("[error] ~w gen_server crash terminated with reason: bad arithmetic expression in crash:handle_call/3", [Pid])),
  252. ?assertEqual(Expected, lists:flatten(Msg))
  253. end
  254. },
  255. {"bad match",
  256. fun() ->
  257. Pid = whereis(crash),
  258. crash(badmatch),
  259. {_, _, Msg} = pop(),
  260. Expected = lists:flatten(io_lib:format("[error] ~w gen_server crash terminated with reason: no match of right hand value {} in crash:handle_call/3", [Pid])),
  261. ?assertEqual(Expected, lists:flatten(Msg))
  262. end
  263. },
  264. {"bad arity",
  265. fun() ->
  266. Pid = whereis(crash),
  267. crash(badarity),
  268. {_, _, Msg} = pop(),
  269. Expected = lists:flatten(io_lib:format("[error] ~w gen_server crash terminated with reason: fun called with wrong arity of 1 instead of 3 in crash:handle_call/3", [Pid])),
  270. ?assertEqual(Expected, lists:flatten(Msg))
  271. end
  272. },
  273. {"bad arg1",
  274. fun() ->
  275. Pid = whereis(crash),
  276. crash(badarg1),
  277. {_, _, Msg} = pop(),
  278. Expected = lists:flatten(io_lib:format("[error] ~w gen_server crash terminated with reason: bad argument in crash:handle_call/3", [Pid])),
  279. ?assertEqual(Expected, lists:flatten(Msg))
  280. end
  281. },
  282. {"bad arg2",
  283. fun() ->
  284. Pid = whereis(crash),
  285. crash(badarg2),
  286. {_, _, Msg} = pop(),
  287. Expected = lists:flatten(io_lib:format("[error] ~w gen_server crash terminated with reason: bad argument in call to erlang:iolist_to_binary([[102,111,111],bar]) in crash:handle_call/3", [Pid])),
  288. ?assertEqual(Expected, lists:flatten(Msg))
  289. end
  290. },
  291. {"noproc",
  292. fun() ->
  293. Pid = whereis(crash),
  294. crash(noproc),
  295. {_, _, Msg} = pop(),
  296. Expected = lists:flatten(io_lib:format("[error] ~w gen_server crash terminated with reason: no such process or port in call to gen_event:call(foo, bar, baz)", [Pid])),
  297. ?assertEqual(Expected, lists:flatten(Msg))
  298. end
  299. },
  300. {"badfun",
  301. fun() ->
  302. Pid = whereis(crash),
  303. crash(badfun),
  304. {_, _, Msg} = pop(),
  305. Expected = lists:flatten(io_lib:format("[error] ~w gen_server crash terminated with reason: bad function booger in crash:handle_call/3", [Pid])),
  306. ?assertEqual(Expected, lists:flatten(Msg))
  307. end
  308. }
  309. ]
  310. }.
  311. error_logger_redirect_test_() ->
  312. {foreach,
  313. fun() ->
  314. application:load(lager),
  315. application:set_env(lager, error_logger_redirect, true),
  316. application:set_env(lager, handlers, [{?MODULE, info}]),
  317. application:start(lager),
  318. timer:sleep(100),
  319. gen_event:call(lager_event, ?MODULE, flush)
  320. end,
  321. fun(_) ->
  322. application:stop(lager),
  323. application:unload(lager)
  324. end,
  325. [
  326. {"error reports are printed",
  327. fun() ->
  328. error_logger:error_report([{this, is}, a, {silly, format}]),
  329. timer:sleep(100),
  330. {_, _, Msg} = pop(),
  331. Expected = lists:flatten(io_lib:format("[error] ~w this: is, a, silly: format", [self()])),
  332. ?assertEqual(Expected, lists:flatten(Msg))
  333. end
  334. },
  335. {"string error reports are printed",
  336. fun() ->
  337. error_logger:error_report("this is less silly"),
  338. timer:sleep(100),
  339. {_, _, Msg} = pop(),
  340. Expected = lists:flatten(io_lib:format("[error] ~w this is less silly", [self()])),
  341. ?assertEqual(Expected, lists:flatten(Msg))
  342. end
  343. },
  344. {"error messages are printed",
  345. fun() ->
  346. error_logger:error_msg("doom, doom has come upon you all"),
  347. timer:sleep(100),
  348. {_, _, Msg} = pop(),
  349. Expected = lists:flatten(io_lib:format("[error] ~w doom, doom has come upon you all", [self()])),
  350. ?assertEqual(Expected, lists:flatten(Msg))
  351. end
  352. },
  353. {"info reports are printed",
  354. fun() ->
  355. error_logger:info_report([{this, is}, a, {silly, format}]),
  356. timer:sleep(100),
  357. {_, _, Msg} = pop(),
  358. Expected = lists:flatten(io_lib:format("[info] ~w this: is, a, silly: format", [self()])),
  359. ?assertEqual(Expected, lists:flatten(Msg))
  360. end
  361. },
  362. {"single term info reports are printed",
  363. fun() ->
  364. error_logger:info_report({foolish, bees}),
  365. timer:sleep(100),
  366. {_, _, Msg} = pop(),
  367. Expected = lists:flatten(io_lib:format("[info] ~w {foolish,bees}", [self()])),
  368. ?assertEqual(Expected, lists:flatten(Msg))
  369. end
  370. },
  371. {"single term error reports are printed",
  372. fun() ->
  373. error_logger:error_report({foolish, bees}),
  374. timer:sleep(100),
  375. {_, _, Msg} = pop(),
  376. Expected = lists:flatten(io_lib:format("[error] ~w {foolish,bees}", [self()])),
  377. ?assertEqual(Expected, lists:flatten(Msg))
  378. end
  379. },
  380. {"string info reports are printed",
  381. fun() ->
  382. error_logger:info_report("this is less silly"),
  383. timer:sleep(100),
  384. {_, _, Msg} = pop(),
  385. Expected = lists:flatten(io_lib:format("[info] ~w this is less silly", [self()])),
  386. ?assertEqual(Expected, lists:flatten(Msg))
  387. end
  388. },
  389. {"info messages are printed",
  390. fun() ->
  391. error_logger:info_msg("doom, doom has come upon you all"),
  392. timer:sleep(100),
  393. {_, _, Msg} = pop(),
  394. Expected = lists:flatten(io_lib:format("[info] ~w doom, doom has come upon you all", [self()])),
  395. ?assertEqual(Expected, lists:flatten(Msg))
  396. end
  397. },
  398. {"warning messages are printed at the correct level",
  399. fun() ->
  400. error_logger:warning_msg("doom, doom has come upon you all"),
  401. Map = error_logger:warning_map(),
  402. timer:sleep(100),
  403. {_, _, Msg} = pop(),
  404. Expected = lists:flatten(io_lib:format("[~w] ~w doom, doom has come upon you all", [Map, self()])),
  405. ?assertEqual(Expected, lists:flatten(Msg))
  406. end
  407. },
  408. {"warning reports are printed at the correct level",
  409. fun() ->
  410. error_logger:warning_report([{i, like}, pie]),
  411. Map = error_logger:warning_map(),
  412. timer:sleep(100),
  413. {_, _, Msg} = pop(),
  414. Expected = lists:flatten(io_lib:format("[~w] ~w i: like, pie", [Map, self()])),
  415. ?assertEqual(Expected, lists:flatten(Msg))
  416. end
  417. },
  418. {"single term warning reports are printed at the correct level",
  419. fun() ->
  420. error_logger:warning_report({foolish, bees}),
  421. Map = error_logger:warning_map(),
  422. timer:sleep(100),
  423. {_, _, Msg} = pop(),
  424. Expected = lists:flatten(io_lib:format("[~w] ~w {foolish,bees}", [Map, self()])),
  425. ?assertEqual(Expected, lists:flatten(Msg))
  426. end
  427. },
  428. {"application stop reports",
  429. fun() ->
  430. error_logger:info_report([{application, foo}, {exited, quittin_time}, {type, lazy}]),
  431. timer:sleep(100),
  432. {_, _, Msg} = pop(),
  433. Expected = lists:flatten(io_lib:format("[info] ~w Application foo exited with reason: quittin_time", [self()])),
  434. ?assertEqual(Expected, lists:flatten(Msg))
  435. end
  436. },
  437. {"supervisor reports",
  438. fun() ->
  439. error_logger:error_report(supervisor_report, [{errorContext, france}, {offender, [{name, mini_steve}, {mfargs, {a, b, [c]}}, {pid, bleh}]}, {reason, fired}, {supervisor, {local, steve}}]),
  440. timer:sleep(100),
  441. {_, _, Msg} = pop(),
  442. Expected = lists:flatten(io_lib:format("[error] ~w Supervisor steve had child mini_steve started with a:b(c) at bleh exit with reason fired in context france", [self()])),
  443. ?assertEqual(Expected, lists:flatten(Msg))
  444. end
  445. },
  446. {"supervisor_bridge reports",
  447. fun() ->
  448. error_logger:error_report(supervisor_report, [{errorContext, france}, {offender, [{mod, mini_steve}, {pid, bleh}]}, {reason, fired}, {supervisor, {local, steve}}]),
  449. timer:sleep(100),
  450. {_, _, Msg} = pop(),
  451. Expected = lists:flatten(io_lib:format("[error] ~w Supervisor steve had child at module mini_steve at bleh exit with reason fired in context france", [self()])),
  452. ?assertEqual(Expected, lists:flatten(Msg))
  453. end
  454. },
  455. {"application progress report",
  456. fun() ->
  457. error_logger:info_report(progress, [{application, foo}, {started_at, node()}]),
  458. timer:sleep(100),
  459. {_, _, Msg} = pop(),
  460. Expected = lists:flatten(io_lib:format("[info] ~w Application foo started on node ~w", [self(), node()])),
  461. ?assertEqual(Expected, lists:flatten(Msg))
  462. end
  463. },
  464. {"supervisor progress report",
  465. fun() ->
  466. error_logger:info_report(progress, [{supervisor, {local, foo}}, {started, [{mfargs, {foo, bar, 1}}, {pid, baz}]}]),
  467. timer:sleep(100),
  468. {_, _, Msg} = pop(),
  469. Expected = lists:flatten(io_lib:format("[info] ~w Supervisor foo started foo:bar/1 at pid baz", [self()])),
  470. ?assertEqual(Expected, lists:flatten(Msg))
  471. end
  472. },
  473. {"crash report for emfile",
  474. fun() ->
  475. error_logger:error_report(crash_report, [[{pid, self()}, {error_info, {error, {emfile, [{stack, trace, 1}]}, []}}], []]),
  476. timer:sleep(100),
  477. {_, _, Msg} = pop(),
  478. Expected = lists:flatten(io_lib:format("[error] ~w CRASH REPORT Process ~w with 0 neighbours crashed with reason: maximum number of file descriptors exhausted, check ulimit -n", [self(), self()])),
  479. ?assertEqual(Expected, lists:flatten(Msg))
  480. end
  481. },
  482. {"crash report for system process limit",
  483. fun() ->
  484. error_logger:error_report(crash_report, [[{pid, self()}, {error_info, {error, {system_limit, [{erlang, spawn, 1}]}, []}}], []]),
  485. timer:sleep(100),
  486. {_, _, Msg} = pop(),
  487. Expected = lists:flatten(io_lib:format("[error] ~w CRASH REPORT Process ~w with 0 neighbours crashed with reason: system limit: maximum number of processes exceeded", [self(), self()])),
  488. ?assertEqual(Expected, lists:flatten(Msg))
  489. end
  490. },
  491. {"crash report for system process limit2",
  492. fun() ->
  493. error_logger:error_report(crash_report, [[{pid, self()}, {error_info, {error, {system_limit, [{erlang, spawn_opt, 1}]}, []}}], []]),
  494. timer:sleep(100),
  495. {_, _, Msg} = pop(),
  496. Expected = lists:flatten(io_lib:format("[error] ~w CRASH REPORT Process ~w with 0 neighbours crashed with reason: system limit: maximum number of processes exceeded", [self(), self()])),
  497. ?assertEqual(Expected, lists:flatten(Msg))
  498. end
  499. },
  500. {"crash report for system port limit",
  501. fun() ->
  502. error_logger:error_report(crash_report, [[{pid, self()}, {error_info, {error, {system_limit, [{erlang, open_port, 1}]}, []}}], []]),
  503. timer:sleep(100),
  504. {_, _, Msg} = pop(),
  505. Expected = lists:flatten(io_lib:format("[error] ~w CRASH REPORT Process ~w with 0 neighbours crashed with reason: system limit: maximum number of ports exceeded", [self(), self()])),
  506. ?assertEqual(Expected, lists:flatten(Msg))
  507. end
  508. },
  509. {"crash report for system port limit",
  510. fun() ->
  511. error_logger:error_report(crash_report, [[{pid, self()}, {error_info, {error, {system_limit, [{erlang, list_to_atom, 1}]}, []}}], []]),
  512. timer:sleep(100),
  513. {_, _, Msg} = pop(),
  514. Expected = lists:flatten(io_lib:format("[error] ~w 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(), self()])),
  515. ?assertEqual(Expected, lists:flatten(Msg))
  516. end
  517. },
  518. {"messages should not be generated if they don't satisfy the threshold",
  519. fun() ->
  520. lager:set_loglevel(?MODULE, error),
  521. error_logger:info_report([hello, world]),
  522. timer:sleep(100),
  523. ?assertEqual(0, count()),
  524. ?assertEqual(0, count_ignored()),
  525. lager:set_loglevel(?MODULE, info),
  526. error_logger:info_report([hello, world]),
  527. timer:sleep(100),
  528. ?assertEqual(1, count()),
  529. ?assertEqual(0, count_ignored()),
  530. lager:set_loglevel(?MODULE, error),
  531. lager_mochiglobal:put(loglevel, 0),
  532. error_logger:info_report([hello, world]),
  533. timer:sleep(100),
  534. ?assertEqual(1, count()),
  535. ?assertEqual(1, count_ignored())
  536. end
  537. }
  538. ]
  539. }.
  540. -endif.