diff --git a/src/lager.erl b/src/lager.erl index 01cb5bc..2264e70 100644 --- a/src/lager.erl +++ b/src/lager.erl @@ -108,7 +108,7 @@ trace_file(File, Filter, Level) -> false -> %% install the handler supervisor:start_child(lager_handler_watcher_sup, - [lager_event, {lager_file_backend, File}, {File, none}]); + [lager_event, {lager_file_backend, File}, {File, Level}]); _ -> {ok, exists} end, diff --git a/src/lager_console_backend.erl b/src/lager_console_backend.erl index f0765eb..9591fcb 100644 --- a/src/lager_console_backend.erl +++ b/src/lager_console_backend.erl @@ -43,24 +43,26 @@ init([Level, true]) -> % for backwards compatibility 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), + try lager_util:config_to_level(Level) of + Levels -> + {ok, #state{level=Levels, formatter=Formatter, - format_config=FormatterConfig}}; - _ -> + format_config=FormatterConfig}} + catch + _:_ -> {error, bad_log_level} end. %% @private -handle_call(get_loglevel, #state{level=Level} = State) -> - {ok, Level, State}; +handle_call(get_loglevel, #state{level=[Level|_]} = State) -> + {ok, lager_util:level_to_num(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)}}; - _ -> + try lager_util:config_to_level(Level) of + Levels -> + {ok, ok, State#state{level=Levels}} + catch + _:_ -> {ok, {error, bad_log_level}, State} end; handle_call(_Request, State) -> @@ -233,8 +235,67 @@ console_log_test_() -> ?assert(true) end end + }, + {"blacklisting a loglevel works", + 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, []}), + lager:set_loglevel(lager_console_backend, '!=info'), + erlang:group_leader(Pid, whereis(lager_event)), + 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 + 1000 -> + ?assert(false) + end, + %% info is blacklisted + lager:info("Test message"), + receive + {io_request, From2, ReplyAs2, {put_chars, unicode, _Msg2}} -> + From2 ! {io_reply, ReplyAs2, ok}, + ?assert(false) + after + 500 -> + ?assert(true) + end + end + }, + {"whitelisting a loglevel works", + 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, []}), + lager:set_loglevel(lager_console_backend, '=debug'), + erlang:group_leader(Pid, whereis(lager_event)), + 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 + 1000 -> + ?assert(false) + end, + %% info is blacklisted + lager:error("Test message"), + receive + {io_request, From2, ReplyAs2, {put_chars, unicode, _Msg2}} -> + From2 ! {io_reply, ReplyAs2, ok}, + ?assert(false) + after + 500 -> + ?assert(true) + end + end } - ] }. @@ -256,7 +317,12 @@ 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)) + ?assertEqual(debug, lager:get_loglevel(lager_console_backend)), + lager:set_loglevel(lager_console_backend, '!=debug'), + ?assertEqual(info, lager:get_loglevel(lager_console_backend)), + lager:set_loglevel(lager_console_backend, '!=info'), + ?assertEqual(debug, lager:get_loglevel(lager_console_backend)), + ok end }, {"Get/set invalid loglevel test", diff --git a/src/lager_file_backend.erl b/src/lager_file_backend.erl index 6a5048f..227f048 100644 --- a/src/lager_file_backend.erl +++ b/src/lager_file_backend.erl @@ -64,12 +64,12 @@ init([LogFile,{Formatter,FormatterConfig}]) -> schedule_rotation(Name, Date), State = case lager_util:open_logfile(Name, true) of {ok, {FD, Inode, _}} -> - #state{name=Name, level=lager_util:level_to_num(Level), + #state{name=Name, level=Level, fd=FD, inode=Inode, size=Size, date=Date, count=Count, formatter=Formatter, formatter_config=FormatterConfig}; {error, Reason} -> ?INT_LOG(error, "Failed to open log file ~s with error ~s", [Name, file:format_error(Reason)]), - #state{name=Name, level=lager_util:level_to_num(Level), + #state{name=Name, level=Level, flap=true, size=Size, date=Date, count=Count, formatter=Formatter, formatter_config=FormatterConfig} end, @@ -83,10 +83,15 @@ init(LogFile) -> %% @private handle_call({set_loglevel, Level}, #state{name=Ident} = State) -> - ?INT_LOG(notice, "Changed loglevel of ~s to ~p", [Ident, Level]), - {ok, ok, State#state{level=lager_util:level_to_num(Level)}}; -handle_call(get_loglevel, #state{level=Level} = State) -> - {ok, Level, State}; + case validate_loglevel(Level) of + false -> + {ok, {error, bad_loglevel}, State}; + Levels -> + ?INT_LOG(notice, "Changed loglevel of ~s to ~p", [Ident, Level]), + {ok, ok, State#state{level=Levels}} + end; +handle_call(get_loglevel, #state{level=[Level|_]} = State) -> + {ok, lager_util:level_to_num(Level), State}; handle_call(_Request, State) -> {ok, ok, State}. @@ -159,16 +164,16 @@ write(#state{name=Name, fd=FD, inode=Inode, flap=Flap, size=RotSize, end. validate_logfile({Name, Level}) -> - case lists:member(Level, ?LEVELS) of - true -> - {Name, Level, 0, undefined, 0}; - _ -> + case validate_loglevel(Level) of + false -> ?INT_LOG(error, "Invalid log level of ~p for ~s.", [Level, Name]), - false + false; + Levels -> + {Name, Levels, 0, undefined, 0} end; validate_logfile({Name, Level, Size, Date, Count}) -> - ValidLevel = (lists:member(Level, ?LEVELS)), + ValidLevel = validate_loglevel(Level), ValidSize = (is_integer(Size) andalso Size >= 0), ValidCount = (is_integer(Count) andalso Count >= 0), case {ValidLevel, ValidSize, ValidCount} of @@ -184,13 +189,13 @@ validate_logfile({Name, Level, Size, Date, Count}) -> ?INT_LOG(error, "Invalid rotation count of ~p for ~s.", [Count, Name]), false; - {true, true, true} -> + {Levels, true, true} -> case lager_util:parse_rotation_date_spec(Date) of {ok, Spec} -> - {Name, Level, Size, Spec, Count}; + {Name, Levels, Size, Spec, Count}; {error, _} when Date == "" -> %% blank ones are fine. - {Name, Level, Size, undefined, Count}; + {Name, Levels, Size, undefined, Count}; {error, _} -> ?INT_LOG(error, "Invalid rotation date of ~p for ~s.", [Date, Name]), @@ -201,6 +206,16 @@ validate_logfile(H) -> ?INT_LOG(error, "Invalid log file config ~p.", [H]), false. +validate_loglevel(Level) -> + try lager_util:config_to_level(Level) of + Levels -> + Levels + catch + _:_ -> + false + end. + + schedule_rotation(_, undefined) -> ok; schedule_rotation(Name, Date) -> @@ -211,10 +226,10 @@ schedule_rotation(Name, Date) -> get_loglevel_test() -> {ok, Level, _} = handle_call(get_loglevel, - #state{name="bar", level=lager_util:level_to_num(info), fd=0, inode=0}), + #state{name="bar", level=lager_util:config_to_level(info), fd=0, inode=0}), ?assertEqual(Level, lager_util:level_to_num(info)), {ok, Level2, _} = handle_call(get_loglevel, - #state{name="foo", level=lager_util:level_to_num(warning), fd=0, inode=0}), + #state{name="foo", level=lager_util:config_to_level(warning), fd=0, inode=0}), ?assertEqual(Level2, lager_util:level_to_num(warning)). rotation_test() -> diff --git a/src/lager_util.erl b/src/lager_util.erl index 2b51fe1..c800ccc 100644 --- a/src/lager_util.erl +++ b/src/lager_util.erl @@ -377,7 +377,11 @@ check_trace_iter(Attrs, [{Key, Match}|T]) -> false end. --spec is_loggable(lager_msg:lager_msg(),integer(),term()) -> boolean(). +-spec is_loggable(lager_msg:lager_msg(),integer()|list(),term()) -> boolean(). +is_loggable(Msg, SeverityList, MyName) when is_list(SeverityList) -> + %% using syslog style comparison flags + lists:member(lager_msg:severity(Msg), SeverityList) orelse + lists:member(MyName, lager_msg:destinations(Msg)); is_loggable(Msg ,SeverityThreshold,MyName) -> lager_msg:severity_as_int(Msg) =< SeverityThreshold orelse lists:member(MyName, lager_msg:destinations(Msg)).