2012-10-10 22:14:06 +00:00
|
|
|
%% -------------------------------------------------------------------
|
|
|
|
%%
|
|
|
|
%% Copyright (c) 2012 Basho Technologies, Inc.
|
|
|
|
%%
|
|
|
|
%% 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.
|
|
|
|
%%
|
|
|
|
%% -------------------------------------------------------------------
|
|
|
|
|
2012-08-27 17:50:18 +00:00
|
|
|
%% @doc This lager backend keeps a buffer of logs in memory and returns them all
|
|
|
|
%% when the handler terminates.
|
|
|
|
|
2012-08-23 16:45:41 +00:00
|
|
|
-module(riak_test_lager_backend).
|
|
|
|
|
|
|
|
-behavior(gen_event).
|
|
|
|
|
2012-08-27 17:50:18 +00:00
|
|
|
%% gen_event callbacks
|
2012-08-23 16:45:41 +00:00
|
|
|
-export([init/1,
|
|
|
|
handle_call/2,
|
|
|
|
handle_event/2,
|
|
|
|
handle_info/2,
|
|
|
|
terminate/2,
|
|
|
|
code_change/3]).
|
2012-12-01 01:08:29 +00:00
|
|
|
-export([get_logs/0]).
|
2012-08-23 16:45:41 +00:00
|
|
|
|
2012-08-27 17:50:18 +00:00
|
|
|
%% holds the log messages for retreival on terminate
|
2012-08-23 16:45:41 +00:00
|
|
|
-record(state, {level, verbose, log = []}).
|
|
|
|
|
|
|
|
-ifdef(TEST).
|
|
|
|
-include_lib("eunit/include/eunit.hrl").
|
|
|
|
-compile([{parse_transform, lager_transform}]).
|
|
|
|
-endif.
|
|
|
|
|
2012-08-30 20:58:49 +00:00
|
|
|
-include_lib("lager/include/lager.hrl").
|
2012-08-23 16:45:41 +00:00
|
|
|
|
2012-12-01 01:08:29 +00:00
|
|
|
-spec get_logs() -> [iolist()] | {error, term()}.
|
|
|
|
get_logs() ->
|
|
|
|
gen_event:call(lager_event, ?MODULE, get_logs, infinity).
|
|
|
|
|
|
|
|
|
2012-08-27 17:50:18 +00:00
|
|
|
-spec(init(integer()|atom()|[term()]) -> {ok, #state{}} | {error, atom()}).
|
|
|
|
%% @private
|
|
|
|
%% @doc Initializes the event handler
|
2012-08-23 16:45:41 +00:00
|
|
|
init(Level) when is_atom(Level) ->
|
2013-07-18 20:08:33 +00:00
|
|
|
init([Level, false]);
|
2012-08-23 16:45:41 +00:00
|
|
|
init([Level, Verbose]) ->
|
2013-07-18 20:08:33 +00:00
|
|
|
try parse_level(Level) of
|
|
|
|
Lvl ->
|
|
|
|
{ok, #state{level=Lvl, verbose=Verbose}}
|
|
|
|
catch
|
|
|
|
_:_ ->
|
2012-08-23 16:45:41 +00:00
|
|
|
{error, bad_log_level}
|
|
|
|
end.
|
2012-08-27 17:50:18 +00:00
|
|
|
|
2012-08-27 18:27:47 +00:00
|
|
|
-spec(handle_event(tuple(), #state{}) -> {ok, #state{}}).
|
2012-08-27 17:50:18 +00:00
|
|
|
%% @private
|
|
|
|
%% @doc handles the event, adding the log message to the gen_event's state.
|
2012-12-01 01:08:29 +00:00
|
|
|
%% this function attempts to handle logging events in both the simple tuple
|
|
|
|
%% and new record (introduced after lager 1.2.1) formats.
|
|
|
|
handle_event({log, Dest, Level, {Date, Time}, [LevelStr, Location, Message]}, %% lager 1.2.1
|
2012-08-23 16:45:41 +00:00
|
|
|
#state{level=L, verbose=Verbose, log = Logs} = State) when Level > L ->
|
|
|
|
case lists:member(riak_test_lager_backend, Dest) of
|
|
|
|
true ->
|
|
|
|
Log = case Verbose of
|
|
|
|
true ->
|
|
|
|
[Date, " ", Time, " ", LevelStr, Location, Message];
|
|
|
|
_ ->
|
|
|
|
[Time, " ", LevelStr, Message]
|
|
|
|
end,
|
|
|
|
{ok, State#state{log=[Log|Logs]}};
|
|
|
|
false ->
|
|
|
|
{ok, State}
|
|
|
|
end;
|
2012-12-01 01:08:29 +00:00
|
|
|
handle_event({log, Level, {Date, Time}, [LevelStr, Location, Message]}, %% lager 1.2.1
|
2012-08-23 16:45:41 +00:00
|
|
|
#state{level=LogLevel, verbose=Verbose, log = Logs} = State) when Level =< LogLevel ->
|
|
|
|
Log = case Verbose of
|
|
|
|
true ->
|
|
|
|
[Date, " ", Time, " ", LevelStr, Location, Message];
|
|
|
|
_ ->
|
|
|
|
[Time, " ", LevelStr, Message]
|
|
|
|
end,
|
|
|
|
{ok, State#state{log=[Log|Logs]}};
|
2013-07-18 20:08:33 +00:00
|
|
|
handle_event({log, Msg},
|
|
|
|
#state{level=Level, verbose=Verbose, log = Logs} = State) -> %% lager 2.0.0
|
|
|
|
case lager_util:is_loggable(Msg, Level, ?MODULE) of
|
|
|
|
true ->
|
2013-10-04 02:45:09 +00:00
|
|
|
Format = log_format(Verbose),
|
|
|
|
Log = lager_default_formatter:format(Msg, Format),
|
2013-07-18 20:08:33 +00:00
|
|
|
{ok, State#state{log=[Log|Logs]}};
|
|
|
|
false ->
|
|
|
|
{ok, State}
|
2012-12-01 01:08:29 +00:00
|
|
|
end;
|
|
|
|
handle_event(Event, State) ->
|
|
|
|
{ok, State#state{log = [Event|State#state.log]}}.
|
2012-08-23 16:45:41 +00:00
|
|
|
|
2012-08-27 18:27:47 +00:00
|
|
|
-spec(handle_call(any(), #state{}) -> {ok, any(), #state{}}).
|
2012-08-27 17:50:18 +00:00
|
|
|
%% @private
|
|
|
|
%% @doc gets and sets loglevel. This is part of the lager backend api.
|
2012-08-23 16:45:41 +00:00
|
|
|
handle_call(get_loglevel, #state{level=Level} = State) ->
|
|
|
|
{ok, Level, State};
|
|
|
|
handle_call({set_loglevel, Level}, State) ->
|
2013-07-18 20:08:33 +00:00
|
|
|
try parse_level(Level) of
|
|
|
|
Lvl ->
|
|
|
|
{ok, ok, State#state{level=Lvl}}
|
|
|
|
catch
|
|
|
|
_:_ ->
|
2012-08-23 16:45:41 +00:00
|
|
|
{ok, {error, bad_log_level}, State}
|
|
|
|
end;
|
2012-12-01 01:08:29 +00:00
|
|
|
handle_call(get_logs, #state{log = Logs} = State) ->
|
|
|
|
{ok, Logs, State};
|
2012-08-23 16:45:41 +00:00
|
|
|
handle_call(_, State) ->
|
|
|
|
{ok, ok, State}.
|
|
|
|
|
2012-08-27 17:50:18 +00:00
|
|
|
-spec(handle_info(any(), #state{}) -> {ok, #state{}}).
|
|
|
|
%% @private
|
|
|
|
%% @doc gen_event callback, does nothing.
|
2012-08-23 16:45:41 +00:00
|
|
|
handle_info(_, State) ->
|
|
|
|
{ok, State}.
|
|
|
|
|
2012-08-27 17:50:18 +00:00
|
|
|
-spec(code_change(any(), #state{}, any()) -> {ok, #state{}}).
|
|
|
|
%% @private
|
|
|
|
%% @doc gen_event callback, does nothing.
|
2012-08-23 16:45:41 +00:00
|
|
|
code_change(_OldVsn, State, _Extra) ->
|
|
|
|
{ok, State}.
|
|
|
|
|
2012-08-27 17:50:18 +00:00
|
|
|
-spec(terminate(any(), #state{}) -> {ok, list()}).
|
|
|
|
%% @doc gen_event callback, does nothing.
|
2012-08-23 16:45:41 +00:00
|
|
|
terminate(_Reason, #state{log=Logs}) ->
|
|
|
|
{ok, lists:reverse(Logs)}.
|
2012-08-23 17:46:17 +00:00
|
|
|
|
2013-07-18 20:08:33 +00:00
|
|
|
parse_level(Level) ->
|
|
|
|
try lager_util:config_to_mask(Level) of
|
|
|
|
Res ->
|
|
|
|
Res
|
|
|
|
catch
|
|
|
|
error:undef ->
|
|
|
|
%% must be lager < 2.0
|
|
|
|
lager_util:level_to_num(Level)
|
|
|
|
end.
|
|
|
|
|
2013-10-04 02:45:09 +00:00
|
|
|
log_format(true) ->
|
|
|
|
[date, " " , time, " [", severity, "] ",
|
|
|
|
{pid, ""},
|
|
|
|
{module, [
|
|
|
|
module,
|
|
|
|
{function, [":", function], ""},
|
|
|
|
{line, [":", line], ""},
|
|
|
|
" "], ""},
|
|
|
|
message, "\r\n"];
|
|
|
|
log_format(false) ->
|
|
|
|
[time, " [", severity, "] ", message, "\r\n"].
|
|
|
|
|
|
|
|
|
2012-08-23 17:46:17 +00:00
|
|
|
-ifdef(TEST).
|
|
|
|
|
|
|
|
log_test_() ->
|
|
|
|
{foreach,
|
|
|
|
fun() ->
|
|
|
|
error_logger:tty(false),
|
|
|
|
application:load(lager),
|
|
|
|
application:set_env(lager, handlers, [{riak_test_lager_backend, debug}]),
|
|
|
|
application:set_env(lager, error_logger_redirect, false),
|
|
|
|
lager:start()
|
|
|
|
end,
|
|
|
|
fun(_) ->
|
|
|
|
application:stop(lager),
|
|
|
|
error_logger:tty(true)
|
|
|
|
end,
|
|
|
|
[
|
|
|
|
{"Test logging",
|
|
|
|
fun() ->
|
|
|
|
lager:info("Here's a message"),
|
|
|
|
lager:debug("Here's another message"),
|
|
|
|
{ok, Logs} = gen_event:delete_handler(lager_event, riak_test_lager_backend, []),
|
|
|
|
?assertEqual(3, length(Logs)),
|
|
|
|
|
|
|
|
?assertMatch([_, "[debug]", "Lager installed handler riak_test_lager_backend into lager_event"], re:split(lists:nth(1, Logs), " ", [{return, list}, {parts, 3}])),
|
|
|
|
?assertMatch([_, "[info]", "Here's a message"], re:split(lists:nth(2, Logs), " ", [{return, list}, {parts, 3}])),
|
|
|
|
?assertMatch([_, "[debug]", "Here's another message"], re:split(lists:nth(3, Logs), " ", [{return, list}, {parts, 3}]))
|
|
|
|
|
|
|
|
end
|
|
|
|
}
|
|
|
|
]
|
|
|
|
}.
|
|
|
|
|
|
|
|
|
|
|
|
set_loglevel_test_() ->
|
|
|
|
{foreach,
|
|
|
|
fun() ->
|
|
|
|
error_logger:tty(false),
|
|
|
|
application:load(lager),
|
|
|
|
application:set_env(lager, handlers, [{riak_test_lager_backend, info}]),
|
|
|
|
application:set_env(lager, error_logger_redirect, false),
|
|
|
|
lager:start()
|
|
|
|
end,
|
|
|
|
fun(_) ->
|
|
|
|
application:stop(lager),
|
|
|
|
error_logger:tty(true)
|
|
|
|
end,
|
|
|
|
[
|
|
|
|
{"Get/set loglevel test",
|
|
|
|
fun() ->
|
|
|
|
?assertEqual(info, lager:get_loglevel(riak_test_lager_backend)),
|
|
|
|
lager:set_loglevel(riak_test_lager_backend, debug),
|
|
|
|
?assertEqual(debug, lager:get_loglevel(riak_test_lager_backend))
|
|
|
|
end
|
|
|
|
},
|
|
|
|
{"Get/set invalid loglevel test",
|
|
|
|
fun() ->
|
|
|
|
?assertEqual(info, lager:get_loglevel(riak_test_lager_backend)),
|
|
|
|
?assertEqual({error, bad_log_level},
|
|
|
|
lager:set_loglevel(riak_test_lager_backend, fatfinger)),
|
|
|
|
?assertEqual(info, lager:get_loglevel(riak_test_lager_backend))
|
|
|
|
end
|
|
|
|
}
|
|
|
|
|
|
|
|
]
|
|
|
|
}.
|
|
|
|
|
2012-08-30 20:58:49 +00:00
|
|
|
-endif.
|