erlang lager 預設是以設定中的 filename 加上 .1 .2 的 postfix 作為 logfile rotate 的依據,但通常在使用 logfile,會希望直接在 logfile 看到產生該 log 的日期,這時需要使用 Custom Log Rotation 的功能,自己撰寫 log_rotator。
首先我們先找到 lager 原始程式碼中預設的 lagerrotatordefault.erl,先複製成 mylagerlog_rotator,然後修改裡面的程式碼。
-module(my_lager_log_rotator).
-include_lib("kernel/include/file.hrl").
-behaviour(lager_rotator_behaviour).
-export([
create_logfile/2, open_logfile/2, ensure_logfile/4, rotate_logfile/2
]).
create_logfile(Name, Buffer) ->
{{Y, M, D}, {H, _, _}} = calendar:now_to_local_time(os:timestamp()),
DateHour = {Y, M, D, H},
FileName = filename(Name, DateHour, 1),
file:delete(Name),
file:make_symlink(filename:absname(FileName), Name),
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_link(Name) of
{ok, _} ->
lager_ensure_logfile(Name, FD, Inode, Buffer);
_ ->
create_logfile(Name, Buffer)
end.
lager_ensure_logfile(Name, undefined, _Inode, Buffer) ->
open_logfile(Name, Buffer);
lager_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) ->
%% %% open the file in write-only mode to truncate/create it
%% case file:open(File, [write]) of
%% {ok, FD} ->
%% file:close(FD),
%% ok;
%% Error ->
%% Error
%% end;
%%rotate_logfile(File0, 1) ->
%% File1 = File0 ++ ".0",
%% _ = file:rename(File0, File1),
%% rotate_logfile(File0, 0);
%%rotate_logfile(File0, Count) ->
%% File1 = File0 ++ "." ++ integer_to_list(Count - 2),
%% File2 = File0 ++ "." ++ integer_to_list(Count - 1),
%% _ = file:rename(File1, File2),
%% rotate_logfile(File0, Count - 1).
%%
rotate_logfile(Name, _Count) ->
case file:read_link(Name) of
{ok, LinkedName} ->
case filelib:file_size(LinkedName) of
0 ->
%% if the files size is zero, it is removed
catch file:delete(LinkedName);
_ ->
void
end;
_ ->
void
end,
{ok, {FD, _, _}} = create_logfile(Name, []),
file:close(FD).
%% @doc Create name of a new file
%% @private
filename(BaseFileName, DateHour, Branch) ->
FileName = lists:append([BaseFileName,
suffix(DateHour, false), ".", integer_to_list(Branch)
]),
case filelib:is_file(FileName) of
true ->
filename(BaseFileName, DateHour, Branch + 1);
_ ->
FileName
end.
%% @doc Zero-padding number
%% @private
zeropad(Num, MinLength) ->
NumStr = integer_to_list(Num),
zeropad_str(NumStr, MinLength - length(NumStr)).
zeropad_str(NumStr, Zeros) when Zeros > 0 ->
zeropad_str([$0 | NumStr], Zeros - 1);
zeropad_str(NumStr, _) ->
NumStr.
%% @doc Create a suffix
%% @private
suffix({Y, M, D, H}, WithHour) ->
YS = zeropad(Y, 4),
MS = zeropad(M, 2),
DS = zeropad(D, 2),
HS = zeropad(H, 2),
case WithHour of
true ->
lists:flatten([$., YS, MS, DS, $., HS]);
_ ->
lists:flatten([$., YS, MS, DS])
end.
將 mylagerlogrotator 套用在 lager 的設定檔的 lagerfile_backend 中,{rotator, my_lager_log_rotator}
。
[
{lager, [
{log_root, "./log"},
{crash_log, "crash.log"},
{error_logger_redirect, false},
{colored, true},
{colors, [
{debug, "\e[0;36m" },
{info, "\e[1;37m" },
{notice, "\e[1;36m" },
{warning, "\e[1;33m" },
{error, "\e[1;31m" },
{critical, "\e[1;35m" },
{alert, "\e[1;44m" },
{emergency, "\e[1;41m" }
]},
{handlers, [
{lager_console_backend, [{level, debug}, {formatter, lager_default_formatter},
{formatter_config, [date, " ", time, color, " ", pid, " ", module, ":", line, " [", severity, "] ", message, "\e[0m\n"]}]},
{lager_file_backend, [{file, "debug.log"}, {level, debug}, {size, 3000}, {date, "$H00"}, {count, 2},
{formatter_config, [date, " ", time, " ", pid, " ", module, ":", line, " [", severity, "] ", message, "\n"]}, {rotator, my_lager_log_rotator}]}
]}
]}
].
現在就會產生像這樣的 logfile
debug.log (symbolic link to debug.log.20190426.2)
debug.log.20190426.1
debug.log.20190426.2
目前還會需要調整的是設定檔中的 count,如果在 logfile 加上日期,count 應該是要代表保留幾天的資料,但目前還是依照 lager 原本的定義,為保留幾個同樣 prefix 檔名的 logfile。
沒有留言:
張貼留言