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