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

openSUSE Build Service is sponsored by