1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
-module(lager_common_test_backend).
-behavior(gen_event).
%% gen_event callbacks
-export([init/1,
handle_call/2,
handle_event/2,
handle_info/2,
terminate/2,
code_change/3]).
-export([get_logs/0,
bounce/0,
bounce/1]).
%% holds the log messages for retreival on terminate
-record(state, {level :: {mask, integer()},
formatter :: atom(),
format_config :: any(),
log = [] :: list()}).
-include("lager.hrl").
-define(TERSE_FORMAT,[time, " ", color, "[", severity,"] ", message]).
%% @doc Before every test, just
%% lager_common_test_backend:bounce(Level) with the log level of your
%% choice. Every message will be passed along to ct:pal for your
%% viewing in the common_test reports. Also, you can call
%% lager_common_test_backend:get_logs/0 to get a list of all log
%% messages this backend has received during your test. You can then
%% search that list for expected log messages.
-spec get_logs() -> [iolist()] | {error, term()}.
get_logs() ->
gen_event:call(lager_event, ?MODULE, get_logs, infinity).
bounce() ->
bounce(error).
bounce(Level) ->
_ = application:stop(lager),
application:set_env(lager, suppress_application_start_stop, true),
application:set_env(lager, handlers,
[
{lager_common_test_backend, [Level, false]}
]),
ok = lager:start(),
%% we care more about getting all of our messages here than being
%% careful with the amount of memory that we're using.
error_logger_lager_h:set_high_water(100000),
ok.
-spec(init(integer()|atom()|[term()]) -> {ok, #state{}} | {error, atom()}).
%% @private
%% @doc Initializes the event handler
init([Level, true]) -> % for backwards compatibility
init([Level,{lager_default_formatter,[{eol, "\n"}]}]);
init([Level,false]) -> % for backwards compatibility
init([Level,{lager_default_formatter,?TERSE_FORMAT ++ ["\n"]}]);
init([Level,{Formatter,FormatterConfig}]) when is_atom(Formatter) ->
case lists:member(Level, ?LEVELS) of
true ->
{ok, #state{level=lager_util:config_to_mask(Level),
formatter=Formatter,
format_config=FormatterConfig}};
_ ->
{error, bad_log_level}
end;
init(Level) ->
init([Level,{lager_default_formatter,?TERSE_FORMAT ++ ["\n"]}]).
-spec(handle_event(tuple(), #state{}) -> {ok, #state{}}).
%% @private
handle_event({log, Message},
#state{level=L,formatter=Formatter,format_config=FormatConfig,log=Logs} = State) ->
case lager_util:is_loggable(Message,L,?MODULE) of
true ->
Log = Formatter:format(Message,FormatConfig),
ct:pal(Log),
{ok, State#state{log=[Log|Logs]}};
false ->
{ok, State}
end;
handle_event(Event, State) ->
ct:pal(Event),
{ok, State#state{log = [Event|State#state.log]}}.
-spec(handle_call(any(), #state{}) -> {ok, any(), #state{}}).
%% @private
%% @doc gets and sets loglevel. This is part of the lager backend api.
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:config_to_mask(Level)}};
_ ->
{ok, {error, bad_log_level}, State}
end;
handle_call(get_logs, #state{log = Logs} = State) ->
{ok, lists:reverse(Logs), State};
handle_call(_, State) ->
{ok, ok, State}.
-spec(handle_info(any(), #state{}) -> {ok, #state{}}).
%% @private
%% @doc gen_event callback, does nothing.
handle_info(_, State) ->
{ok, State}.
-spec(code_change(any(), #state{}, any()) -> {ok, #state{}}).
%% @private
%% @doc gen_event callback, does nothing.
code_change(_OldVsn, State, _Extra) ->
{ok, State}.
-spec(terminate(any(), #state{}) -> {ok, list()}).
%% @doc gen_event callback, does nothing.
terminate(_Reason, #state{log=Logs}) ->
{ok, lists:reverse(Logs)}.