|
|
- %% Copyright (c) 2011-2012 Basho Technologies, Inc. All Rights Reserved.
- %%
- %% This file is provided to you under the Apache License,
- %% Version 2.0 (the "License"); you may not use this file
- %% except in compliance with the License. You may obtain
- %% a copy of the License at
- %%
- %% http://www.apache.org/licenses/LICENSE-2.0
- %%
- %% Unless required by applicable law or agreed to in writing,
- %% software distributed under the License is distributed on an
- %% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- %% KIND, either express or implied. See the License for the
- %% specific language governing permissions and limitations
- %% under the License.
-
- %% @doc Console backend for lager. Configured with a single option, the loglevel
- %% desired.
-
- -module(lager_console_backend).
-
- -behaviour(gen_event).
-
- -export([init/1, handle_call/2, handle_event/2, handle_info/2, terminate/2,
- code_change/3]).
-
- -record(state, {level, formatter,format_config}).
-
- -ifdef(TEST).
- -include_lib("eunit/include/eunit.hrl").
- -compile([{parse_transform, lager_transform}]).
- -endif.
-
- -include("lager.hrl").
-
- -define(TERSE_FORMAT,[time, " [", severity,"] ", message, "\r\n"]).
-
- %% @private
- init(Level) when is_atom(Level) ->
- init([Level,{lager_default_formatter,?TERSE_FORMAT}]);
- init([Level, true]) -> % for backwards compatibility
- init([Level,{lager_default_formatter,[{eol, "\r\n"}]}]);
- init([Level,false]) -> % for backwards compatibility
- init([Level,{lager_default_formatter,?TERSE_FORMAT}]);
- init([Level,{Formatter,FormatterConfig}]) when is_atom(Level), is_atom(Formatter)->
- case lists:member(Level, ?LEVELS) of
- true ->
- {ok, #state{level=lager_util:level_to_num(Level),
- formatter=Formatter,
- format_config=FormatterConfig}};
- _ ->
- {error, bad_log_level}
- end.
-
-
- %% @private
- handle_call(get_loglevel, #state{level=Level} = State) ->
- {ok, Level, State};
- handle_call({set_loglevel, Level}, State) ->
- case lists:member(Level, ?LEVELS) of
- true ->
- {ok, ok, State#state{level=lager_util:level_to_num(Level)}};
- _ ->
- {ok, {error, bad_log_level}, State}
- end;
- handle_call(_Request, State) ->
- {ok, ok, State}.
-
- %% @private
- handle_event({log, Message},
- #state{level=L,formatter=Formatter,format_config=FormatConfig} = State) ->
- case lager_util:is_loggable(Message, L, ?MODULE) of
- true ->
- io:put_chars(user, Formatter:format(Message,FormatConfig)),
- {ok, State};
- false ->
- {ok, State}
- end;
- handle_event(_Event, State) ->
- {ok, State}.
-
- %% @private
- handle_info(_Info, State) ->
- {ok, State}.
-
- %% @private
- terminate(_Reason, _State) ->
- ok.
-
- %% @private
- code_change(_OldVsn, State, _Extra) ->
- {ok, State}.
-
- -ifdef(TEST).
- console_log_test_() ->
- %% tiny recursive fun that pretends to be a group leader
- F = fun(Self) ->
- fun() ->
- YComb = fun(Fun) ->
- receive
- {io_request, From, ReplyAs, {put_chars, unicode, _Msg}} = Y ->
- From ! {io_reply, ReplyAs, ok},
- Self ! Y,
- Fun(Fun);
- Other ->
- ?debugFmt("unexpected message ~p~n", [Other]),
- Self ! Other
- end
- end,
- YComb(YComb)
- end
- end,
- {foreach,
- fun() ->
- error_logger:tty(false),
- application:load(lager),
- application:set_env(lager, handlers, []),
- application:set_env(lager, error_logger_redirect, false),
- application:start(compiler),
- application:start(syntax_tools),
- application:start(lager),
- whereis(user)
- end,
- fun(User) ->
- unregister(user),
- register(user, User),
- application:stop(lager),
- error_logger:tty(true)
- end,
- [
- {"regular console logging",
- fun() ->
- Pid = spawn(F(self())),
- gen_event:add_handler(lager_event, lager_console_backend, info),
- unregister(user),
- register(user, Pid),
- erlang:group_leader(Pid, whereis(lager_event)),
- lager_mochiglobal:put(loglevel, {?INFO, []}),
- lager:log(info, self(), "Test message"),
- receive
- {io_request, From, ReplyAs, {put_chars, unicode, Msg}} ->
- From ! {io_reply, ReplyAs, ok},
- ?assertMatch([_, "[info]", "Test message\r\n"], re:split(Msg, " ", [{return, list}, {parts, 3}]))
- after
- 500 ->
- ?assert(false)
- end
- end
- },
- {"verbose console logging",
- fun() ->
- Pid = spawn(F(self())),
- unregister(user),
- register(user, Pid),
- erlang:group_leader(Pid, whereis(lager_event)),
- gen_event:add_handler(lager_event, lager_console_backend, [info, true]),
- lager_mochiglobal:put(loglevel, {?INFO, []}),
- lager:info("Test message"),
- lager:info("Test message"),
- PidStr = pid_to_list(self()),
- receive
- {io_request, _, _, {put_chars, unicode, Msg}} ->
- ?assertMatch([_, _, "[info]", PidStr, _,"Test message\r\n"], re:split(Msg, "[ @]", [{return, list}, {parts, 6}]))
- after
- 500 ->
- ?assert(false)
- end
- end
- },
- {"tracing should work",
- fun() ->
- Pid = spawn(F(self())),
- unregister(user),
- register(user, Pid),
- gen_event:add_handler(lager_event, lager_console_backend, info),
- erlang:group_leader(Pid, whereis(lager_event)),
- lager_mochiglobal:put(loglevel, {?INFO, []}),
- lager:debug("Test message"),
- receive
- {io_request, From, ReplyAs, {put_chars, unicode, _Msg}} ->
- From ! {io_reply, ReplyAs, ok},
- ?assert(false)
- after
- 500 ->
- ?assert(true)
- end,
- {ok, _} = lager:trace_console([{module, ?MODULE}]),
- lager:debug("Test message"),
- receive
- {io_request, From1, ReplyAs1, {put_chars, unicode, Msg1}} ->
- From1 ! {io_reply, ReplyAs1, ok},
- ?assertMatch([_, "[debug]", "Test message\r\n"], re:split(Msg1, " ", [{return, list}, {parts, 3}]))
- after
- 500 ->
- ?assert(false)
- end
- end
- },
- {"tracing doesn't duplicate messages",
- fun() ->
- Pid = spawn(F(self())),
- unregister(user),
- register(user, Pid),
- gen_event:add_handler(lager_event, lager_console_backend, info),
- lager_mochiglobal:put(loglevel, {?INFO, []}),
- erlang:group_leader(Pid, whereis(lager_event)),
- lager:debug("Test message"),
- receive
- {io_request, From, ReplyAs, {put_chars, unicode, _Msg}} ->
- From ! {io_reply, ReplyAs, ok},
- ?assert(false)
- after
- 500 ->
- ?assert(true)
- end,
- {ok, _} = lager:trace_console([{module, ?MODULE}]),
- lager:error("Test message"),
- receive
- {io_request, From1, ReplyAs1, {put_chars, unicode, Msg1}} ->
- From1 ! {io_reply, ReplyAs1, ok},
- ?assertMatch([_, "[error]", "Test message\r\n"], re:split(Msg1, " ", [{return, list}, {parts, 3}]))
- after
- 1000 ->
- ?assert(false)
- end,
- %% make sure this event wasn't duplicated
- receive
- {io_request, From2, ReplyAs2, {put_chars, unicode, _Msg2}} ->
- From2 ! {io_reply, ReplyAs2, ok},
- ?assert(false)
- after
- 500 ->
- ?assert(true)
- end
- end
- }
-
- ]
- }.
-
- set_loglevel_test_() ->
- {foreach,
- fun() ->
- error_logger:tty(false),
- application:load(lager),
- application:set_env(lager, handlers, [{lager_console_backend, info}]),
- application:set_env(lager, error_logger_redirect, false),
- application:start(lager)
- end,
- fun(_) ->
- application:stop(lager),
- error_logger:tty(true)
- end,
- [
- {"Get/set loglevel test",
- fun() ->
- ?assertEqual(info, lager:get_loglevel(lager_console_backend)),
- lager:set_loglevel(lager_console_backend, debug),
- ?assertEqual(debug, lager:get_loglevel(lager_console_backend))
- end
- },
- {"Get/set invalid loglevel test",
- fun() ->
- ?assertEqual(info, lager:get_loglevel(lager_console_backend)),
- ?assertEqual({error, bad_log_level},
- lager:set_loglevel(lager_console_backend, fatfinger)),
- ?assertEqual(info, lager:get_loglevel(lager_console_backend))
- end
- }
-
- ]
- }.
-
- -endif.
|