您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

131 行
4.5 KiB

  1. -module(lager_rotator_default).
  2. -include_lib("kernel/include/file.hrl").
  3. -behaviour(lager_rotator_behaviour).
  4. -export([
  5. create_logfile/2, open_logfile/2, ensure_logfile/4, rotate_logfile/2
  6. ]).
  7. -ifdef(TEST).
  8. -include_lib("eunit/include/eunit.hrl").
  9. -endif.
  10. create_logfile(Name, Buffer) ->
  11. open_logfile(Name, Buffer).
  12. open_logfile(Name, Buffer) ->
  13. case filelib:ensure_dir(Name) of
  14. ok ->
  15. Options = [append, raw] ++
  16. case Buffer of
  17. {Size, Interval} when is_integer(Interval), Interval >= 0, is_integer(Size), Size >= 0 ->
  18. [{delayed_write, Size, Interval}];
  19. _ -> []
  20. end,
  21. case file:open(Name, Options) of
  22. {ok, FD} ->
  23. case file:read_file_info(Name) of
  24. {ok, FInfo} ->
  25. Inode = FInfo#file_info.inode,
  26. {ok, {FD, Inode, FInfo#file_info.size}};
  27. X -> X
  28. end;
  29. Y -> Y
  30. end;
  31. Z -> Z
  32. end.
  33. ensure_logfile(Name, FD, Inode, Buffer) ->
  34. case file:read_file_info(Name) of
  35. {ok, FInfo} ->
  36. Inode2 = FInfo#file_info.inode,
  37. case Inode == Inode2 of
  38. true ->
  39. {ok, {FD, Inode, FInfo#file_info.size}};
  40. false ->
  41. %% delayed write can cause file:close not to do a close
  42. _ = file:close(FD),
  43. _ = file:close(FD),
  44. case open_logfile(Name, Buffer) of
  45. {ok, {FD2, Inode3, Size}} ->
  46. %% inode changed, file was probably moved and
  47. %% recreated
  48. {ok, {FD2, Inode3, Size}};
  49. Error ->
  50. Error
  51. end
  52. end;
  53. _ ->
  54. %% delayed write can cause file:close not to do a close
  55. _ = file:close(FD),
  56. _ = file:close(FD),
  57. case open_logfile(Name, Buffer) of
  58. {ok, {FD2, Inode3, Size}} ->
  59. %% file was removed
  60. {ok, {FD2, Inode3, Size}};
  61. Error ->
  62. Error
  63. end
  64. end.
  65. %% renames failing are OK
  66. rotate_logfile(File, 0) ->
  67. file:delete(File);
  68. rotate_logfile(File, 1) ->
  69. case file:rename(File, File++".0") of
  70. ok ->
  71. ok;
  72. _ ->
  73. rotate_logfile(File, 0)
  74. end;
  75. rotate_logfile(File, Count) ->
  76. _ = file:rename(File ++ "." ++ integer_to_list(Count - 2), File ++ "." ++ integer_to_list(Count - 1)),
  77. rotate_logfile(File, Count - 1).
  78. -ifdef(TEST).
  79. rotate_file_test() ->
  80. RotCount = 10,
  81. TestDir = lager_util:create_test_dir(),
  82. TestLog = filename:join(TestDir, "rotation.log"),
  83. Outer = fun(N) ->
  84. ?assertEqual(ok, file:write_file(TestLog, erlang:integer_to_list(N))),
  85. Inner = fun(M) ->
  86. File = lists:flatten([TestLog, $., erlang:integer_to_list(M)]),
  87. ?assert(filelib:is_regular(File)),
  88. %% check the expected value is in the file
  89. Number = erlang:list_to_binary(integer_to_list(N - M - 1)),
  90. ?assertEqual({ok, Number}, file:read_file(File))
  91. end,
  92. Count = erlang:min(N, RotCount),
  93. % The first time through, Count == 0, so the sequence is empty,
  94. % effectively skipping the inner loop so a rotation can occur that
  95. % creates the file that Inner looks for.
  96. % Don't shoot the messenger, it was worse before this refactoring.
  97. lists:foreach(Inner, lists:seq(0, Count-1)),
  98. rotate_logfile(TestLog, RotCount)
  99. end,
  100. lists:foreach(Outer, lists:seq(0, (RotCount * 2))),
  101. lager_util:delete_test_dir(TestDir).
  102. rotate_file_fail_test() ->
  103. TestDir = lager_util:create_test_dir(),
  104. TestLog = filename:join(TestDir, "rotation.log"),
  105. %% set known permissions on it
  106. os:cmd("chmod -R u+rwx " ++ TestDir),
  107. %% write a file
  108. file:write_file(TestLog, "hello"),
  109. %% hose up the permissions
  110. os:cmd("chmod u-w " ++ TestDir),
  111. ?assertMatch({error, _}, rotate_logfile(TestLog, 10)),
  112. ?assert(filelib:is_regular(TestLog)),
  113. %% fix the permissions
  114. os:cmd("chmod u+w " ++ TestDir),
  115. ?assertMatch(ok, rotate_logfile(TestLog, 10)),
  116. ?assert(filelib:is_regular(TestLog ++ ".0")),
  117. ?assertEqual(false, filelib:is_regular(TestLog)),
  118. lager_util:delete_test_dir(TestDir).
  119. -endif.