Browse Source

Stop leaving test files in the current directory. Just. Stop. It.

Uses lager_util:create_test_dir/0 and lager_util:delete_test_dir/1 to give tests, or groups thereof, their own clean directory to work in.
Turn off whitespace diffs to review, as much code is shifted left to allow sane wrapping within around 100 columns.
pull/384/head
Ted Burghart 8 years ago
parent
commit
6fac9ebc69
3 changed files with 782 additions and 599 deletions
  1. +111
    -94
      src/lager_crash_log.erl
  2. +573
    -450
      src/lager_file_backend.erl
  3. +98
    -55
      test/lager_rotate.erl

+ 111
- 94
src/lager_crash_log.erl View File

@ -1,4 +1,6 @@
%% Copyright (c) 2011-2012 Basho Technologies, Inc. All Rights Reserved.
%% -------------------------------------------------------------------
%%
%% Copyright (c) 2011-2017 Basho Technologies, Inc.
%%
%% This file is provided to you under the Apache License,
%% Version 2.0 (the "License"); you may not use this file
@ -13,6 +15,8 @@
%% KIND, either express or implied. See the License for the
%% specific language governing permissions and limitations
%% under the License.
%%
%% -------------------------------------------------------------------
%% @doc Lager crash log writer. This module implements a gen_server which writes
%% error_logger error messages out to a file in their original format. The
@ -236,105 +240,118 @@ do_log({log, Event}, #state{name=Name, fd=FD, inode=Inode, flap=Flap,
filesystem_test_() ->
{foreach,
fun() ->
file:write_file("crash_test.log", ""),
error_logger:tty(false),
application:load(lager),
application:set_env(lager, handlers, [{lager_test_backend, info}]),
application:set_env(lager, error_logger_redirect, true),
application:unset_env(lager, crash_log),
lager:start(),
timer:sleep(100),
lager_test_backend:flush()
end,
fun(_) ->
case whereis(lager_crash_log) of
P when is_pid(P) ->
exit(P, kill);
_ -> ok
end,
file:delete("crash_test.log"),
application:stop(lager),
application:stop(goldrush),
error_logger:tty(true)
CrashLog = filename:join(lager_util:create_test_dir(), "crash_test.log"),
file:write_file(CrashLog, []),
error_logger:tty(false),
application:load(lager),
application:set_env(lager, handlers, [{lager_test_backend, info}]),
application:set_env(lager, error_logger_redirect, true),
application:unset_env(lager, crash_log),
lager:start(),
timer:sleep(100),
lager_test_backend:flush(),
CrashLog
end,
[
fun(CrashLog) ->
case whereis(lager_crash_log) of
P when is_pid(P) ->
exit(P, kill);
_ ->
ok
end,
application:stop(lager),
application:stop(goldrush),
lager_util:delete_test_dir(filename:dirname(CrashLog)),
error_logger:tty(true)
end, [
fun(CrashLog) ->
{"under normal circumstances, file should be opened",
fun() ->
{ok, _} = ?MODULE:start_link("crash_test.log", 65535, 0, undefined, 0),
_ = gen_event:which_handlers(error_logger),
sync_error_logger:error_msg("Test message\n"),
{ok, Bin} = file:read_file("crash_test.log"),
?assertMatch([_, "Test message\n"], re:split(Bin, "\n", [{return, list}, {parts, 2}]))
end
},
fun() ->
{ok, _} = ?MODULE:start_link(CrashLog, 65535, 0, undefined, 0),
_ = gen_event:which_handlers(error_logger),
sync_error_logger:error_msg("Test message\n"),
{ok, Bin} = file:read_file(CrashLog),
?assertMatch([_, "Test message\n"], re:split(Bin, "\n", [{return, list}, {parts, 2}]))
end}
end,
fun(CrashLog) ->
{"file can't be opened on startup triggers an error message",
fun() ->
{ok, FInfo} = file:read_file_info("crash_test.log"),
file:write_file_info("crash_test.log", FInfo#file_info{mode = 0}),
{ok, _} = ?MODULE:start_link("crash_test.log", 65535, 0, undefined, 0),
?assertEqual(1, lager_test_backend:count()),
{_Level, _Time, Message,_Metadata} = lager_test_backend:pop(),
?assertEqual("Failed to open crash log file crash_test.log with error: permission denied", lists:flatten(Message))
end
},
fun() ->
{ok, FInfo} = file:read_file_info(CrashLog),
file:write_file_info(CrashLog, FInfo#file_info{mode = 0}),
{ok, _} = ?MODULE:start_link(CrashLog, 65535, 0, undefined, 0),
?assertEqual(1, lager_test_backend:count()),
{_Level, _Time, Message,_Metadata} = lager_test_backend:pop(),
?assertEqual(
"Failed to open crash log file " ++ CrashLog ++ " with error: permission denied",
lists:flatten(Message))
end}
end,
fun(CrashLog) ->
{"file that becomes unavailable at runtime should trigger an error message",
fun() ->
{ok, _} = ?MODULE:start_link("crash_test.log", 65535, 0, undefined, 0),
?assertEqual(0, lager_test_backend:count()),
sync_error_logger:error_msg("Test message\n"),
_ = gen_event:which_handlers(error_logger),
?assertEqual(1, lager_test_backend:count()),
file:delete("crash_test.log"),
file:write_file("crash_test.log", ""),
{ok, FInfo} = file:read_file_info("crash_test.log"),
file:write_file_info("crash_test.log", FInfo#file_info{mode = 0}),
sync_error_logger:error_msg("Test message\n"),
_ = gen_event:which_handlers(error_logger),
?assertEqual(3, lager_test_backend:count()),
lager_test_backend:pop(),
{_Level, _Time, Message,_Metadata} = lager_test_backend:pop(),
?assertEqual("Failed to reopen crash log crash_test.log with error: permission denied", lists:flatten(Message))
end
},
fun() ->
{ok, _} = ?MODULE:start_link(CrashLog, 65535, 0, undefined, 0),
?assertEqual(0, lager_test_backend:count()),
sync_error_logger:error_msg("Test message\n"),
_ = gen_event:which_handlers(error_logger),
?assertEqual(1, lager_test_backend:count()),
file:delete(CrashLog),
file:write_file(CrashLog, ""),
{ok, FInfo} = file:read_file_info(CrashLog),
file:write_file_info(CrashLog, FInfo#file_info{mode = 0}),
sync_error_logger:error_msg("Test message\n"),
_ = gen_event:which_handlers(error_logger),
?assertEqual(3, lager_test_backend:count()),
lager_test_backend:pop(),
{_Level, _Time, Message,_Metadata} = lager_test_backend:pop(),
?assertEqual(
"Failed to reopen crash log " ++ CrashLog ++ " with error: permission denied",
lists:flatten(Message))
end}
end,
fun(CrashLog) ->
{"unavailable files that are fixed at runtime should start having log messages written",
fun() ->
{ok, FInfo} = file:read_file_info("crash_test.log"),
OldPerms = FInfo#file_info.mode,
file:write_file_info("crash_test.log", FInfo#file_info{mode = 0}),
{ok, _} = ?MODULE:start_link("crash_test.log", 65535, 0, undefined, 0),
?assertEqual(1, lager_test_backend:count()),
{_Level, _Time, Message,_Metadata} = lager_test_backend:pop(),
?assertEqual("Failed to open crash log file crash_test.log with error: permission denied", lists:flatten(Message)),
file:write_file_info("crash_test.log", FInfo#file_info{mode = OldPerms}),
sync_error_logger:error_msg("Test message~n"),
_ = gen_event:which_handlers(error_logger),
{ok, Bin} = file:read_file("crash_test.log"),
?assertMatch([_, "Test message\n"], re:split(Bin, "\n", [{return, list}, {parts, 2}]))
end
},
fun() ->
{ok, FInfo} = file:read_file_info(CrashLog),
OldPerms = FInfo#file_info.mode,
file:write_file_info(CrashLog, FInfo#file_info{mode = 0}),
{ok, _} = ?MODULE:start_link(CrashLog, 65535, 0, undefined, 0),
?assertEqual(1, lager_test_backend:count()),
{_Level, _Time, Message,_Metadata} = lager_test_backend:pop(),
?assertEqual(
"Failed to open crash log file " ++ CrashLog ++ " with error: permission denied",
lists:flatten(Message)),
file:write_file_info(CrashLog, FInfo#file_info{mode = OldPerms}),
sync_error_logger:error_msg("Test message~n"),
_ = gen_event:which_handlers(error_logger),
{ok, Bin} = file:read_file(CrashLog),
?assertMatch([_, "Test message\n"], re:split(Bin, "\n", [{return, list}, {parts, 2}]))
end}
end,
fun(CrashLog) ->
{"external logfile rotation/deletion should be handled",
fun() ->
{ok, _} = ?MODULE:start_link("crash_test.log", 65535, 0, undefined, 0),
?assertEqual(0, lager_test_backend:count()),
sync_error_logger:error_msg("Test message~n"),
_ = gen_event:which_handlers(error_logger),
{ok, Bin} = file:read_file("crash_test.log"),
?assertMatch([_, "Test message\n"], re:split(Bin, "\n", [{return, list}, {parts, 2}])),
file:delete("crash_test.log"),
file:write_file("crash_test.log", ""),
sync_error_logger:error_msg("Test message1~n"),
_ = gen_event:which_handlers(error_logger),
{ok, Bin1} = file:read_file("crash_test.log"),
?assertMatch([_, "Test message1\n"], re:split(Bin1, "\n", [{return, list}, {parts, 2}])),
file:rename("crash_test.log", "crash_test.log.0"),
sync_error_logger:error_msg("Test message2~n"),
_ = gen_event:which_handlers(error_logger),
{ok, Bin2} = file:read_file("crash_test.log"),
?assertMatch([_, "Test message2\n"], re:split(Bin2, "\n", [{return, list}, {parts, 2}]))
end
}
]
}.
fun() ->
{ok, _} = ?MODULE:start_link(CrashLog, 65535, 0, undefined, 0),
?assertEqual(0, lager_test_backend:count()),
sync_error_logger:error_msg("Test message~n"),
_ = gen_event:which_handlers(error_logger),
{ok, Bin} = file:read_file(CrashLog),
?assertMatch([_, "Test message\n"], re:split(Bin, "\n", [{return, list}, {parts, 2}])),
file:delete(CrashLog),
file:write_file(CrashLog, ""),
sync_error_logger:error_msg("Test message1~n"),
_ = gen_event:which_handlers(error_logger),
{ok, Bin1} = file:read_file(CrashLog),
?assertMatch([_, "Test message1\n"], re:split(Bin1, "\n", [{return, list}, {parts, 2}])),
file:rename(CrashLog, CrashLog ++ ".0"),
sync_error_logger:error_msg("Test message2~n"),
_ = gen_event:which_handlers(error_logger),
{ok, Bin2} = file:read_file(CrashLog),
?assertMatch([_, "Test message2\n"], re:split(Bin2, "\n", [{return, list}, {parts, 2}]))
end}
end
]}.
-endif.

+ 573
- 450
src/lager_file_backend.erl
File diff suppressed because it is too large
View File


+ 98
- 55
test/lager_rotate.erl View File

@ -1,3 +1,23 @@
%% -------------------------------------------------------------------
%%
%% Copyright (c) 2016-2017 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.
%%
%% -------------------------------------------------------------------
-module(lager_rotate).
-compile(export_all).
@ -6,54 +26,71 @@
-include_lib("eunit/include/eunit.hrl").
-endif.
-record(state, {
dir :: string(),
log1 :: string(),
log1r :: string(),
log2 :: string(),
log2r :: string(),
sink :: string(),
sinkr :: string()
}).
rotate_test_() ->
{foreach,
fun() ->
file:write_file("test1.log", ""),
file:write_file("test2.log", ""),
file:write_file("test3.log", ""),
file:delete("test1.log.0"),
file:delete("test2.log.0"),
file:delete("test3.log.0"),
error_logger:tty(false),
application:load(lager),
application:set_env(lager, handlers,
[{lager_file_backend, [{file, "test1.log"}, {level, info}]},
{lager_file_backend, [{file, "test2.log"}, {level, info}]}]),
application:set_env(lager, extra_sinks,
[{sink_event,
[{handlers,
[{lager_file_backend, [{file, "test3.log"}, {level, info}]}]}
]}]),
application:set_env(lager, error_logger_redirect, false),
application:set_env(lager, async_threshold, undefined),
lager:start()
end,
fun(_) ->
file:delete("test1.log"),
file:delete("test2.log"),
file:delete("test3.log"),
file:delete("test1.log.0"),
file:delete("test2.log.0"),
file:delete("test3.log.0"),
application:stop(lager),
application:stop(goldrush),
error_logger:tty(true)
Dir = lager_util:create_test_dir(),
Log1 = filename:join(Dir, "test1.log"),
Log2 = filename:join(Dir, "test2.log"),
Sink = filename:join(Dir, "sink.log"),
State = #state{
dir = Dir,
log1 = Log1,
log1r = Log1 ++ ".0",
log2 = Log2,
log2r = Log2 ++ ".0",
sink = Sink,
sinkr = Sink ++ ".0"
},
file:write_file(Log1, []),
file:write_file(Log2, []),
file:write_file(Sink, []),
error_logger:tty(false),
application:load(lager),
application:set_env(lager, handlers, [
{lager_file_backend, [{file, Log1}, {level, info}]},
{lager_file_backend, [{file, Log2}, {level, info}]} ]),
application:set_env(lager, extra_sinks, [
{sink_event,
[{handlers,
[{lager_file_backend, [{file, Sink}, {level, info}]}]}
]}]),
application:set_env(lager, error_logger_redirect, false),
application:set_env(lager, async_threshold, undefined),
lager:start(),
State
end,
[{"Rotate single file",
fun(#state{dir = Dir}) ->
application:stop(lager),
application:stop(goldrush),
lager_util:delete_test_dir(Dir),
error_logger:tty(true)
end, [
fun(State) ->
{"Rotate single file",
fun() ->
lager:log(error, self(), "Test message 1"),
lager:log(sink_event, error, self(), "Sink test message 1", []),
lager:rotate_handler({lager_file_backend, "test1.log"}),
ok = wait_until(fun() -> filelib:is_regular("test1.log.0") end, 10),
lager:rotate_handler({lager_file_backend, State#state.log1}),
ok = wait_until(fun() -> filelib:is_regular(State#state.log1r) end, 10),
lager:log(error, self(), "Test message 2"),
lager:log(sink_event, error, self(), "Sink test message 2", []),
{ok, File1} = file:read_file("test1.log"),
{ok, File2} = file:read_file("test2.log"),
{ok, SinkFile} = file:read_file("test3.log"),
{ok, File1Old} = file:read_file("test1.log.0"),
{ok, File1} = file:read_file(State#state.log1),
{ok, File2} = file:read_file(State#state.log2),
{ok, SinkFile} = file:read_file(State#state.sink),
{ok, File1Old} = file:read_file(State#state.log1r),
have_no_log(File1, <<"Test message 1">>),
have_log(File1, <<"Test message 2">>),
@ -66,19 +103,21 @@ rotate_test_() ->
have_log(SinkFile, <<"Sink test message 1">>),
have_log(SinkFile, <<"Sink test message 2">>)
end},
{"Rotate sink",
end}
end,
fun(State) ->
{"Rotate sink",
fun() ->
lager:log(error, self(), "Test message 1"),
lager:log(sink_event, error, self(), "Sink test message 1", []),
lager:rotate_sink(sink_event),
ok = wait_until(fun() -> filelib:is_regular("test3.log.0") end, 10),
ok = wait_until(fun() -> filelib:is_regular(State#state.sinkr) end, 10),
lager:log(error, self(), "Test message 2"),
lager:log(sink_event, error, self(), "Sink test message 2", []),
{ok, File1} = file:read_file("test1.log"),
{ok, File2} = file:read_file("test2.log"),
{ok, SinkFile} = file:read_file("test3.log"),
{ok, SinkFileOld} = file:read_file("test3.log.0"),
{ok, File1} = file:read_file(State#state.log1),
{ok, File2} = file:read_file(State#state.log2),
{ok, SinkFile} = file:read_file(State#state.sink),
{ok, SinkFileOld} = file:read_file(State#state.sinkr),
have_log(File1, <<"Test message 1">>),
have_log(File1, <<"Test message 2">>),
@ -91,21 +130,23 @@ rotate_test_() ->
have_no_log(SinkFile, <<"Sink test message 1">>),
have_log(SinkFile, <<"Sink test message 2">>)
end},
{"Rotate all",
end}
end,
fun(State) ->
{"Rotate all",
fun() ->
lager:log(error, self(), "Test message 1"),
lager:log(sink_event, error, self(), "Sink test message 1", []),
lager:rotate_all(),
ok = wait_until(fun() -> filelib:is_regular("test3.log.0") end, 10),
ok = wait_until(fun() -> filelib:is_regular(State#state.sinkr) end, 10),
lager:log(error, self(), "Test message 2"),
lager:log(sink_event, error, self(), "Sink test message 2", []),
{ok, File1} = file:read_file("test1.log"),
{ok, File2} = file:read_file("test2.log"),
{ok, SinkFile} = file:read_file("test3.log"),
{ok, File1Old} = file:read_file("test1.log.0"),
{ok, File2Old} = file:read_file("test2.log.0"),
{ok, SinkFileOld} = file:read_file("test3.log.0"),
{ok, File1} = file:read_file(State#state.log1),
{ok, File2} = file:read_file(State#state.log2),
{ok, SinkFile} = file:read_file(State#state.sink),
{ok, File1Old} = file:read_file(State#state.log1r),
{ok, File2Old} = file:read_file(State#state.log2r),
{ok, SinkFileOld} = file:read_file(State#state.sinkr),
have_no_log(File1, <<"Test message 1">>),
have_log(File1, <<"Test message 2">>),
@ -125,7 +166,9 @@ rotate_test_() ->
have_log(File2Old, <<"Test message 1">>),
have_no_log(File2Old, <<"Test message 2">>)
end}]}.
end}
end
]}.
have_log(Data, Log) ->
{_,_} = binary:match(Data, Log).

Loading…
Cancel
Save