|
|
- -module(lager_rotator_default).
-
- -include_lib("kernel/include/file.hrl").
-
- -behaviour(lager_rotator_behaviour).
-
- -export([
- create_logfile/2, open_logfile/2, ensure_logfile/4, rotate_logfile/2
- ]).
-
- -ifdef(TEST).
- -include_lib("eunit/include/eunit.hrl").
- -endif.
-
- create_logfile(Name, Buffer) ->
- open_logfile(Name, Buffer).
-
- open_logfile(Name, Buffer) ->
- case filelib:ensure_dir(Name) of
- ok ->
- Options = [append, raw] ++
- case Buffer of
- {Size, Interval} when is_integer(Interval), Interval >= 0, is_integer(Size), Size >= 0 ->
- [{delayed_write, Size, Interval}];
- _ -> []
- end,
- case file:open(Name, Options) of
- {ok, FD} ->
- case file:read_file_info(Name) of
- {ok, FInfo} ->
- Inode = FInfo#file_info.inode,
- {ok, {FD, Inode, FInfo#file_info.size}};
- X -> X
- end;
- Y -> Y
- end;
- Z -> Z
- end.
-
- ensure_logfile(Name, FD, Inode, Buffer) ->
- case file:read_file_info(Name) of
- {ok, FInfo} ->
- Inode2 = FInfo#file_info.inode,
- case Inode == Inode2 of
- true ->
- {ok, {FD, Inode, FInfo#file_info.size}};
- false ->
- %% delayed write can cause file:close not to do a close
- _ = file:close(FD),
- _ = file:close(FD),
- case open_logfile(Name, Buffer) of
- {ok, {FD2, Inode3, Size}} ->
- %% inode changed, file was probably moved and
- %% recreated
- {ok, {FD2, Inode3, Size}};
- Error ->
- Error
- end
- end;
- _ ->
- %% delayed write can cause file:close not to do a close
- _ = file:close(FD),
- _ = file:close(FD),
- case open_logfile(Name, Buffer) of
- {ok, {FD2, Inode3, Size}} ->
- %% file was removed
- {ok, {FD2, Inode3, Size}};
- Error ->
- Error
- end
- end.
-
- %% renames failing are OK
- rotate_logfile(File, 0) ->
- file:delete(File);
- rotate_logfile(File, 1) ->
- case file:rename(File, File++".0") of
- ok ->
- ok;
- _ ->
- rotate_logfile(File, 0)
- end;
- rotate_logfile(File, Count) ->
- _ = file:rename(File ++ "." ++ integer_to_list(Count - 2), File ++ "." ++ integer_to_list(Count - 1)),
- rotate_logfile(File, Count - 1).
-
- -ifdef(TEST).
-
- rotate_file_test() ->
- RotCount = 10,
- TestDir = lager_util:create_test_dir(),
- TestLog = filename:join(TestDir, "rotation.log"),
- Outer = fun(N) ->
- ?assertEqual(ok, file:write_file(TestLog, erlang:integer_to_list(N))),
- Inner = fun(M) ->
- File = lists:flatten([TestLog, $., erlang:integer_to_list(M)]),
- ?assert(filelib:is_regular(File)),
- %% check the expected value is in the file
- Number = erlang:list_to_binary(integer_to_list(N - M - 1)),
- ?assertEqual({ok, Number}, file:read_file(File))
- end,
- Count = erlang:min(N, RotCount),
- % The first time through, Count == 0, so the sequence is empty,
- % effectively skipping the inner loop so a rotation can occur that
- % creates the file that Inner looks for.
- % Don't shoot the messenger, it was worse before this refactoring.
- lists:foreach(Inner, lists:seq(0, Count-1)),
- rotate_logfile(TestLog, RotCount)
- end,
- lists:foreach(Outer, lists:seq(0, (RotCount * 2))),
- lager_util:delete_test_dir(TestDir).
-
- rotate_file_fail_test() ->
- TestDir = lager_util:create_test_dir(),
- TestLog = filename:join(TestDir, "rotation.log"),
- %% set known permissions on it
- os:cmd("chmod -R u+rwx " ++ TestDir),
- %% write a file
- file:write_file(TestLog, "hello"),
- %% hose up the permissions
- os:cmd("chmod u-w " ++ TestDir),
- ?assertMatch({error, _}, rotate_logfile(TestLog, 10)),
- ?assert(filelib:is_regular(TestLog)),
- %% fix the permissions
- os:cmd("chmod u+w " ++ TestDir),
- ?assertMatch(ok, rotate_logfile(TestLog, 10)),
- ?assert(filelib:is_regular(TestLog ++ ".0")),
- ?assertEqual(false, filelib:is_regular(TestLog)),
- lager_util:delete_test_dir(TestDir).
-
- -endif.
|