|
|
@ -15,66 +15,62 @@ |
|
|
|
-include_lib("eunit/include/eunit.hrl"). |
|
|
|
-endif. |
|
|
|
|
|
|
|
createLogFile(Name, Buffer) -> |
|
|
|
openLogFile(Name, Buffer). |
|
|
|
createLogFile(FileName, Buffer) -> |
|
|
|
openLogFile(FileName, Buffer). |
|
|
|
|
|
|
|
openLogFile(Name, Buffer) -> |
|
|
|
case filelib:ensure_dir(Name) of |
|
|
|
openLogFile(FileName, Buffer) -> |
|
|
|
case filelib:ensure_dir(FileName) of |
|
|
|
ok -> |
|
|
|
Options = [append, raw] ++ |
|
|
|
Options = |
|
|
|
case Buffer of |
|
|
|
{Size0, Interval} when is_integer(Interval), Interval >= 0, is_integer(Size0), Size0 >= 0 -> |
|
|
|
[{delayed_write, Size0, Interval}]; |
|
|
|
_ -> [] |
|
|
|
{Size, Interval} -> |
|
|
|
[append, raw, {delayed_write, Size, Interval}]; |
|
|
|
_ -> |
|
|
|
[append, raw] |
|
|
|
end, |
|
|
|
case file:open(Name, Options) of |
|
|
|
{ok, FD} -> |
|
|
|
case file:read_file_info(Name, [raw]) of |
|
|
|
{ok, FInfo0} -> |
|
|
|
Inode = FInfo0#file_info.inode, |
|
|
|
{ok, CTime} = maybe_update_ctime(Name, FInfo0), |
|
|
|
Size1 = FInfo0#file_info.size, |
|
|
|
{ok, {FD, Inode, CTime, Size1}}; |
|
|
|
X -> X |
|
|
|
case file:open(FileName, Options) of |
|
|
|
{ok, Fd} -> |
|
|
|
case file:read_file_info(FileName, [raw]) of |
|
|
|
{ok, FileInfo} -> |
|
|
|
#file_info{size = FileSize, inode = Inode} = FileInfo, |
|
|
|
CTime = tryUpdateCTime(FileName, FileInfo), |
|
|
|
{ok, Fd, Inode, CTime, FileSize}; |
|
|
|
RfiErr -> RfiErr |
|
|
|
end; |
|
|
|
Y -> Y |
|
|
|
OpErr -> OpErr |
|
|
|
end; |
|
|
|
Z -> Z |
|
|
|
EnDirErr -> EnDirErr |
|
|
|
end. |
|
|
|
|
|
|
|
ensureLogFile(Name, undefined, _Inode, _CTime, Buffer) -> |
|
|
|
openLogFile(Name, Buffer); |
|
|
|
ensureLogFile(Name, FD, Inode0, CTime0, Buffer) -> |
|
|
|
case rumUtil:has_file_changed(Name, Inode0, CTime0) of |
|
|
|
{true, _FInfo} -> |
|
|
|
reopen_logfile(Name, FD, Buffer); |
|
|
|
{_, FInfo} -> |
|
|
|
{ok, {FD, Inode0, CTime0, FInfo#file_info.size}} |
|
|
|
ensureLogFile(FileName, Fd, Inode, CTime, Buffer) -> |
|
|
|
case Fd of |
|
|
|
undefined -> |
|
|
|
openLogFile(FileName, Buffer); |
|
|
|
_ -> |
|
|
|
case rumUtil:isFileChanged(FileName, Inode, CTime) of |
|
|
|
{true, _FInfo} -> |
|
|
|
reopenLogfile(FileName, Fd, Buffer); |
|
|
|
{_, FInfo} -> |
|
|
|
{ok, Fd, Inode, CTime, FInfo#file_info.size} |
|
|
|
end |
|
|
|
end. |
|
|
|
|
|
|
|
reopen_logfile(Name, FD0, Buffer) -> |
|
|
|
%% Flush and close any file handles. |
|
|
|
%% delayed write can cause file:close not to do a close |
|
|
|
_ = file:datasync(FD0), |
|
|
|
_ = file:close(FD0), |
|
|
|
_ = file:close(FD0), |
|
|
|
case openLogFile(Name, Buffer) of |
|
|
|
{ok, {_FD1, _Inode, _Size, _CTime} = FileInfo} -> |
|
|
|
%% inode changed, file was probably moved and |
|
|
|
%% recreated |
|
|
|
{ok, FileInfo}; |
|
|
|
Error -> |
|
|
|
Error |
|
|
|
end. |
|
|
|
reopenLogfile(FileName, Fd, Buffer) -> |
|
|
|
%% Flush and close any file handles. delayed write can cause file:close not to do a close |
|
|
|
_ = file:datasync(Fd), |
|
|
|
_ = file:close(Fd), |
|
|
|
_ = file:close(Fd), |
|
|
|
openLogFile(FileName, Buffer). |
|
|
|
|
|
|
|
%% renames failing are OK |
|
|
|
%% IMY-TODO 文件名格式修改调整 |
|
|
|
rotateLogFile(File, 0) -> |
|
|
|
%% open the file in write-only mode to truncate/create it |
|
|
|
case file:open(File, [write]) of |
|
|
|
{ok, FD} -> |
|
|
|
_ = file:close(FD), |
|
|
|
_ = file:close(FD), |
|
|
|
{ok, _CTime} = maybe_update_ctime(File), |
|
|
|
tryUpdateCTime(File), |
|
|
|
ok; |
|
|
|
Error -> |
|
|
|
Error |
|
|
@ -89,28 +85,25 @@ rotateLogFile(File0, Count) -> |
|
|
|
_ = file:rename(File1, File2), |
|
|
|
rotateLogFile(File0, Count - 1). |
|
|
|
|
|
|
|
maybe_update_ctime(Name) -> |
|
|
|
tryUpdateCTime(Name) -> |
|
|
|
case file:read_file_info(Name, [raw]) of |
|
|
|
{ok, FInfo} -> |
|
|
|
maybe_update_ctime(Name, FInfo); |
|
|
|
tryUpdateCTime(Name, FInfo); |
|
|
|
_ -> |
|
|
|
{ok, calendar:local_time()} |
|
|
|
erlang:localtime() |
|
|
|
end. |
|
|
|
|
|
|
|
maybe_update_ctime(Name, FInfo) -> |
|
|
|
{OsType, _} = os:type(), |
|
|
|
do_update_ctime(OsType, Name, FInfo). |
|
|
|
|
|
|
|
do_update_ctime(win32, Name, FInfo0) -> |
|
|
|
% Note: we force the creation time to be the current time. |
|
|
|
% On win32 this may prevent the ctime from being updated: |
|
|
|
% https://stackoverflow.com/q/8804342/1466825 |
|
|
|
NewCtime = calendar:local_time(), |
|
|
|
FInfo1 = FInfo0#file_info{ctime = NewCtime}, |
|
|
|
ok = file:write_file_info(Name, FInfo1, [raw]), |
|
|
|
{ok, NewCtime}; |
|
|
|
do_update_ctime(_, _Name, FInfo) -> |
|
|
|
{ok, FInfo#file_info.ctime}. |
|
|
|
tryUpdateCTime(Name, FileInfo) -> |
|
|
|
case os:type() of |
|
|
|
{win32, _} -> |
|
|
|
%注意:我们将创建时间强制为当前时间。在win32上,这可能会阻止ctime的更新:https://stackoverflow.com/q/8804342/1466825 |
|
|
|
NewCtime = erlang:localtime(), |
|
|
|
NewFileInfo = FileInfo#file_info{ctime = NewCtime}, |
|
|
|
ok = file:write_file_info(Name, NewFileInfo, [raw]), |
|
|
|
NewCtime; |
|
|
|
_ -> |
|
|
|
element(#file_info.ctime, FileInfo) |
|
|
|
end. |
|
|
|
|
|
|
|
-ifdef(TEST). |
|
|
|
|
|
|
|