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

274 行
11 KiB

  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. %% @doc Console backend for lager. Configured with a single option, the loglevel
  17. %% desired.
  18. -module(lager_console_backend).
  19. -behaviour(gen_event).
  20. -export([init/1, handle_call/2, handle_event/2, handle_info/2, terminate/2,
  21. code_change/3]).
  22. -record(state, {level, formatter,format_config}).
  23. -ifdef(TEST).
  24. -include_lib("eunit/include/eunit.hrl").
  25. -compile([{parse_transform, lager_transform}]).
  26. -endif.
  27. -include("lager.hrl").
  28. -define(TERSE_FORMAT,[time, " [", severity,"] ", message, "\r\n"]).
  29. %% @private
  30. init(Level) when is_atom(Level) ->
  31. init([Level,{lager_default_formatter,?TERSE_FORMAT}]);
  32. init([Level, true]) -> % for backwards compatibility
  33. init([Level,{lager_default_formatter,[{eol, "\r\n"}]}]);
  34. init([Level,false]) -> % for backwards compatibility
  35. init([Level,{lager_default_formatter,?TERSE_FORMAT}]);
  36. init([Level,{Formatter,FormatterConfig}]) when is_atom(Level), is_atom(Formatter)->
  37. case lists:member(Level, ?LEVELS) of
  38. true ->
  39. {ok, #state{level=lager_util:level_to_num(Level),
  40. formatter=Formatter,
  41. format_config=FormatterConfig}};
  42. _ ->
  43. {error, bad_log_level}
  44. end.
  45. %% @private
  46. handle_call(get_loglevel, #state{level=Level} = State) ->
  47. {ok, Level, State};
  48. handle_call({set_loglevel, Level}, State) ->
  49. case lists:member(Level, ?LEVELS) of
  50. true ->
  51. {ok, ok, State#state{level=lager_util:level_to_num(Level)}};
  52. _ ->
  53. {ok, {error, bad_log_level}, State}
  54. end;
  55. handle_call(_Request, State) ->
  56. {ok, ok, State}.
  57. %% @private
  58. handle_event({log, Message},
  59. #state{level=L,formatter=Formatter,format_config=FormatConfig} = State) ->
  60. case lager_util:is_loggable(Message, L, ?MODULE) of
  61. true ->
  62. io:put_chars(user, Formatter:format(Message,FormatConfig)),
  63. {ok, State};
  64. false ->
  65. {ok, State}
  66. end;
  67. handle_event(_Event, State) ->
  68. {ok, State}.
  69. %% @private
  70. handle_info(_Info, State) ->
  71. {ok, State}.
  72. %% @private
  73. terminate(_Reason, _State) ->
  74. ok.
  75. %% @private
  76. code_change(_OldVsn, State, _Extra) ->
  77. {ok, State}.
  78. -ifdef(TEST).
  79. console_log_test_() ->
  80. %% tiny recursive fun that pretends to be a group leader
  81. F = fun(Self) ->
  82. fun() ->
  83. YComb = fun(Fun) ->
  84. receive
  85. {io_request, From, ReplyAs, {put_chars, unicode, _Msg}} = Y ->
  86. From ! {io_reply, ReplyAs, ok},
  87. Self ! Y,
  88. Fun(Fun);
  89. Other ->
  90. ?debugFmt("unexpected message ~p~n", [Other]),
  91. Self ! Other
  92. end
  93. end,
  94. YComb(YComb)
  95. end
  96. end,
  97. {foreach,
  98. fun() ->
  99. error_logger:tty(false),
  100. application:load(lager),
  101. application:set_env(lager, handlers, []),
  102. application:set_env(lager, error_logger_redirect, false),
  103. application:start(compiler),
  104. application:start(syntax_tools),
  105. application:start(lager),
  106. whereis(user)
  107. end,
  108. fun(User) ->
  109. unregister(user),
  110. register(user, User),
  111. application:stop(lager),
  112. error_logger:tty(true)
  113. end,
  114. [
  115. {"regular console logging",
  116. fun() ->
  117. Pid = spawn(F(self())),
  118. gen_event:add_handler(lager_event, lager_console_backend, info),
  119. unregister(user),
  120. register(user, Pid),
  121. erlang:group_leader(Pid, whereis(lager_event)),
  122. lager_mochiglobal:put(loglevel, {?INFO, []}),
  123. lager:log(info, self(), "Test message"),
  124. receive
  125. {io_request, From, ReplyAs, {put_chars, unicode, Msg}} ->
  126. From ! {io_reply, ReplyAs, ok},
  127. ?assertMatch([_, "[info]", "Test message\r\n"], re:split(Msg, " ", [{return, list}, {parts, 3}]))
  128. after
  129. 500 ->
  130. ?assert(false)
  131. end
  132. end
  133. },
  134. {"verbose console logging",
  135. fun() ->
  136. Pid = spawn(F(self())),
  137. unregister(user),
  138. register(user, Pid),
  139. erlang:group_leader(Pid, whereis(lager_event)),
  140. gen_event:add_handler(lager_event, lager_console_backend, [info, true]),
  141. lager_mochiglobal:put(loglevel, {?INFO, []}),
  142. lager:info("Test message"),
  143. lager:info("Test message"),
  144. PidStr = pid_to_list(self()),
  145. receive
  146. {io_request, _, _, {put_chars, unicode, Msg}} ->
  147. ?assertMatch([_, _, "[info]", PidStr, _,"Test message\r\n"], re:split(Msg, "[ @]", [{return, list}, {parts, 6}]))
  148. after
  149. 500 ->
  150. ?assert(false)
  151. end
  152. end
  153. },
  154. {"tracing should work",
  155. fun() ->
  156. Pid = spawn(F(self())),
  157. unregister(user),
  158. register(user, Pid),
  159. gen_event:add_handler(lager_event, lager_console_backend, info),
  160. erlang:group_leader(Pid, whereis(lager_event)),
  161. lager_mochiglobal:put(loglevel, {?INFO, []}),
  162. lager:debug("Test message"),
  163. receive
  164. {io_request, From, ReplyAs, {put_chars, unicode, _Msg}} ->
  165. From ! {io_reply, ReplyAs, ok},
  166. ?assert(false)
  167. after
  168. 500 ->
  169. ?assert(true)
  170. end,
  171. {ok, _} = lager:trace_console([{module, ?MODULE}]),
  172. lager:debug("Test message"),
  173. receive
  174. {io_request, From1, ReplyAs1, {put_chars, unicode, Msg1}} ->
  175. From1 ! {io_reply, ReplyAs1, ok},
  176. ?assertMatch([_, "[debug]", "Test message\r\n"], re:split(Msg1, " ", [{return, list}, {parts, 3}]))
  177. after
  178. 500 ->
  179. ?assert(false)
  180. end
  181. end
  182. },
  183. {"tracing doesn't duplicate messages",
  184. fun() ->
  185. Pid = spawn(F(self())),
  186. unregister(user),
  187. register(user, Pid),
  188. gen_event:add_handler(lager_event, lager_console_backend, info),
  189. lager_mochiglobal:put(loglevel, {?INFO, []}),
  190. erlang:group_leader(Pid, whereis(lager_event)),
  191. lager:debug("Test message"),
  192. receive
  193. {io_request, From, ReplyAs, {put_chars, unicode, _Msg}} ->
  194. From ! {io_reply, ReplyAs, ok},
  195. ?assert(false)
  196. after
  197. 500 ->
  198. ?assert(true)
  199. end,
  200. {ok, _} = lager:trace_console([{module, ?MODULE}]),
  201. lager:error("Test message"),
  202. receive
  203. {io_request, From1, ReplyAs1, {put_chars, unicode, Msg1}} ->
  204. From1 ! {io_reply, ReplyAs1, ok},
  205. ?assertMatch([_, "[error]", "Test message\r\n"], re:split(Msg1, " ", [{return, list}, {parts, 3}]))
  206. after
  207. 1000 ->
  208. ?assert(false)
  209. end,
  210. %% make sure this event wasn't duplicated
  211. receive
  212. {io_request, From2, ReplyAs2, {put_chars, unicode, _Msg2}} ->
  213. From2 ! {io_reply, ReplyAs2, ok},
  214. ?assert(false)
  215. after
  216. 500 ->
  217. ?assert(true)
  218. end
  219. end
  220. }
  221. ]
  222. }.
  223. set_loglevel_test_() ->
  224. {foreach,
  225. fun() ->
  226. error_logger:tty(false),
  227. application:load(lager),
  228. application:set_env(lager, handlers, [{lager_console_backend, info}]),
  229. application:set_env(lager, error_logger_redirect, false),
  230. application:start(lager)
  231. end,
  232. fun(_) ->
  233. application:stop(lager),
  234. error_logger:tty(true)
  235. end,
  236. [
  237. {"Get/set loglevel test",
  238. fun() ->
  239. ?assertEqual(info, lager:get_loglevel(lager_console_backend)),
  240. lager:set_loglevel(lager_console_backend, debug),
  241. ?assertEqual(debug, lager:get_loglevel(lager_console_backend))
  242. end
  243. },
  244. {"Get/set invalid loglevel test",
  245. fun() ->
  246. ?assertEqual(info, lager:get_loglevel(lager_console_backend)),
  247. ?assertEqual({error, bad_log_level},
  248. lager:set_loglevel(lager_console_backend, fatfinger)),
  249. ?assertEqual(info, lager:get_loglevel(lager_console_backend))
  250. end
  251. }
  252. ]
  253. }.
  254. -endif.