File 0280-logger-Re-create-folders-for-file-logger-if-deleted.patch of Package erlang
From fd4f13e1b768877146ed98101986e45b7c9cd81b Mon Sep 17 00:00:00 2001
From: Lukas Larsson <lukas@erlang.org>
Date: Thu, 31 Mar 2022 15:38:07 +0200
Subject: [PATCH] logger: Re-create folders for file logger if deleted
If the folder(s) for a log file is deleted, we want to
re-create it if possible in order to make sure that we
do our best in getting the log message into the disk.
Closes #5828
---
lib/kernel/src/logger_std_h.erl | 45 ++++++++++++----------
lib/kernel/test/logger_std_h_SUITE.erl | 52 +++++++++++++++++++++++++-
2 files changed, 76 insertions(+), 21 deletions(-)
diff --git a/lib/kernel/src/logger_std_h.erl b/lib/kernel/src/logger_std_h.erl
index 13fe00b72d..d146c64b3b 100644
--- a/lib/kernel/src/logger_std_h.erl
+++ b/lib/kernel/src/logger_std_h.erl
@@ -484,20 +484,29 @@ ensure_file(#{inode:=INode0,file_name:=FileName,modes:=Modes}=State) ->
State#{last_check=>timestamp()};
_ ->
close_log_file(State),
- case file:open(FileName,Modes) of
- {ok,Fd} ->
- {ok,#file_info{inode=INode}} =
- file:read_file_info(FileName,[raw]),
- State#{fd=>Fd,inode=>INode,
- last_check=>timestamp(),
- synced=>true,sync_res=>ok};
- Error ->
- exit({could_not_reopen_file,Error})
- end
+ {ok, Fd} = ensure_open(FileName, Modes),
+ {ok,#file_info{inode=INode}} =
+ file:read_file_info(FileName,[raw]),
+ State#{fd=>Fd,inode=>INode,
+ last_check=>timestamp(),
+ synced=>true,sync_res=>ok}
end;
ensure_file(State) ->
State.
+ensure_open(Filename, Modes) ->
+ case filelib:ensure_dir(Filename) of
+ ok ->
+ case file:open(Filename, Modes) of
+ {ok, Fd} ->
+ {ok, Fd};
+ Error ->
+ exit({could_not_reopen_file,Error})
+ end;
+ Error ->
+ exit({could_not_create_dir_for_file,Error})
+ end.
+
write_to_dev(Bin,#{dev:=DevName}=State) ->
io:put_chars(DevName, Bin),
State;
@@ -574,21 +583,19 @@ rotate_file(#{file_name:=FileName,modes:=Modes,rotation:=Rotation}=State) ->
State1 = sync_dev(State),
_ = delayed_write_close(State),
rotate_files(FileName,maps:get(count,Rotation),maps:get(compress,Rotation)),
- case file:open(FileName,Modes) of
- {ok,Fd} ->
- {ok,#file_info{inode=INode}} = file:read_file_info(FileName,[raw]),
- State1#{fd=>Fd,inode=>INode,rotation=>Rotation#{curr_size=>0}};
- Error ->
- exit({could_not_reopen_file,Error})
- end.
+ {ok, Fd} = ensure_open(FileName,Modes),
+ {ok,#file_info{inode=INode}} = file:read_file_info(FileName,[raw]),
+ State1#{fd=>Fd,inode=>INode,rotation=>Rotation#{curr_size=>0}}.
rotate_files(FileName,0,_Compress) ->
_ = file:delete(FileName),
ok;
rotate_files(FileName,1,Compress) ->
FileName0 = FileName++".0",
- _ = file:rename(FileName,FileName0),
- if Compress -> compress_file(FileName0);
+ Rename = file:rename(FileName,FileName0),
+ %% Rename may fail if file has been deleted. If it has, then
+ %% we do not need to compress it...
+ if Rename =:= ok, Compress -> compress_file(FileName0);
true -> ok
end,
ok;
diff --git a/lib/kernel/test/logger_std_h_SUITE.erl b/lib/kernel/test/logger_std_h_SUITE.erl
index 33310e8fad..6b3de38416 100644
--- a/lib/kernel/test/logger_std_h_SUITE.erl
+++ b/lib/kernel/test/logger_std_h_SUITE.erl
@@ -1379,6 +1379,10 @@ handler_requests_under_load(cleanup, _Config) ->
recreate_deleted_log(Config) ->
{Log,_HConfig,_StdHConfig} =
start_handler(?MODULE, ?FUNCTION_NAME, Config),
+
+ %% Make sure that if we delete the directory it is created
+ [ok = file:del_dir_r(filename:dirname(Log)) || element(1,os:type()) =/= win32],
+
logger:notice("first",?domain),
logger_std_h:filesync(?MODULE),
ok = file:rename(Log,Log++".old"),
@@ -1386,6 +1390,7 @@ recreate_deleted_log(Config) ->
logger_std_h:filesync(?MODULE),
{ok,<<"first\n">>} = file:read_file(Log++".old"),
{ok,<<"second\n">>} = file:read_file(Log),
+
ok.
recreate_deleted_log(cleanup, _Config) ->
ok = stop_handler(?MODULE).
@@ -1500,6 +1505,48 @@ rotate_size_compressed(Config) ->
{error,enoent} = file:read_file_info(Log++".2"),
{error,enoent} = file:read_file_info(Log++".2.gz"),
+ case os:type() of
+ {unix,_} ->
+ %% Test that logging does not break when directory is deleted at rotation
+ [logger:notice(Str,?domain) || _ <- lists:seq(1,50)],
+ logger_std_h:filesync(?MODULE),
+ {ok,#file_info{size=1000}} = file:read_file_info(Log),
+ ok = file:del_dir_r(filename:dirname(Log)),
+ {error,enoent} = file:read_file_info(Log),
+ logger:notice("bbbb",?domain),
+ logger:notice("bbbb",?domain),
+ logger_std_h:filesync(?MODULE),
+ {ok,#file_info{size=5}} = file:read_file_info(Log),
+ {error,enoent} = file:read_file_info(Log++".0"),
+ {ok,#file_info{size=25}} = file:read_file_info(Log++".0.gz"),
+ {error,enoent} = file:read_file_info(Log++".1"),
+ {error,enoent} = file:read_file_info(Log++".1.gz"),
+ {error,enoent} = file:read_file_info(Log++".2"),
+ {error,enoent} = file:read_file_info(Log++".2.gz"),
+
+ %% Test that logging without sync does not break
+ %% when directory is deleted at rotation
+ ok = logger:update_handler_config(?MODULE, #{config=>#{ file_check => 10000 } }),
+ [logger:notice(Str,?domain) || _ <- lists:seq(1,49)],
+ [logger:notice("bbbb",?domain) || _ <- lists:seq(1,3)],
+ logger_std_h:filesync(?MODULE),
+ {ok,#file_info{size=1000}} = file:read_file_info(Log),
+ ok = file:del_dir_r(filename:dirname(Log)),
+ {error,enoent} = file:read_file_info(Log),
+ logger:notice("bbbb",?domain),
+ logger:notice("bbbb",?domain),
+ logger_std_h:filesync(?MODULE),
+ {ok,#file_info{size=5}} = file:read_file_info(Log),
+ {error,enoent} = file:read_file_info(Log++".0"),
+ {error,enoent} = file:read_file_info(Log++".0.gz"),
+ {error,enoent} = file:read_file_info(Log++".1"),
+ {error,enoent} = file:read_file_info(Log++".1.gz"),
+ {error,enoent} = file:read_file_info(Log++".2"),
+ {error,enoent} = file:read_file_info(Log++".2.gz");
+ {win32,_} ->
+ ok
+ end,
+
ok.
rotate_size_compressed(cleanup,_Config) ->
ok = stop_handler(?MODULE).
@@ -1830,8 +1877,9 @@ start_handler(Name, FuncName, Config) ->
{Log,HConfig,StdHConfig}.
get_handler_log_name(FuncName, Config) ->
- Dir = ?config(priv_dir,Config),
- filename:join(Dir, lists:concat([FuncName,".log"])).
+ filename:join([?config(priv_dir,Config),
+ FuncName,
+ lists:concat([FuncName,".log"])]).
filter_only_this_domain(Name) ->
[{remote_gl,{fun logger_filters:remote_gl/2,stop}},
--
2.34.1