您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

570 行
26 KiB

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