You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@apisix.apache.org by sp...@apache.org on 2022/03/28 02:16:43 UTC

[apisix] branch master updated: feat(file-logger): cache & reopen file handler (#6721)

This is an automated email from the ASF dual-hosted git repository.

spacewander pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/apisix.git


The following commit(s) were added to refs/heads/master by this push:
     new 55eb58a  feat(file-logger): cache & reopen file handler (#6721)
55eb58a is described below

commit 55eb58ab85ac7e108de36271fd9cf29fe2fa3324
Author: 罗泽轩 <sp...@gmail.com>
AuthorDate: Mon Mar 28 10:16:35 2022 +0800

    feat(file-logger): cache & reopen file handler (#6721)
---
 apisix/plugins/file-logger.lua                   |  57 ++++++++-
 t/plugin/{file-logger.t => file-logger-reopen.t} | 156 +++++++++--------------
 t/plugin/file-logger.t                           |  20 ++-
 3 files changed, 134 insertions(+), 99 deletions(-)

diff --git a/apisix/plugins/file-logger.lua b/apisix/plugins/file-logger.lua
index d7c9b7d..e624b0b 100644
--- a/apisix/plugins/file-logger.lua
+++ b/apisix/plugins/file-logger.lua
@@ -19,6 +19,7 @@ local core         =   require("apisix.core")
 local plugin       =   require("apisix.plugin")
 local ngx          =   ngx
 local io_open      =   io.open
+local is_apisix_or, process = pcall(require, "resty.apisix.process")
 
 
 local plugin_name = "file-logger"
@@ -60,9 +61,57 @@ function _M.check_schema(conf, schema_type)
 end
 
 
+local open_file_cache
+if is_apisix_or then
+    -- TODO: switch to a cache which supports inactive time,
+    -- so that unused files would not be cached
+    local path_to_file = core.lrucache.new({
+        type = "plugin",
+    })
+
+    local function open_file_handler(conf, handler)
+        local file, err = io_open(conf.path, 'a+')
+        if not file then
+            return nil, err
+        end
+
+        handler.file = file
+        handler.open_time = ngx.now() * 1000
+        return handler
+    end
+
+    function open_file_cache(conf)
+        local last_reopen_time = process.get_last_reopen_ms()
+
+        local handler, err = path_to_file(conf.path, 0, open_file_handler, conf, {})
+        if not handler then
+            return nil, err
+        end
+
+        if handler.open_time < last_reopen_time then
+            core.log.notice("reopen cached log file: ", conf.path)
+            handler.file:close()
+
+            local ok, err = open_file_handler(conf, handler)
+            if not ok then
+                return nil, err
+            end
+        end
+
+        return handler.file
+    end
+end
+
+
 local function write_file_data(conf, log_message)
     local msg = core.json.encode(log_message)
-    local file, err = io_open(conf.path, 'a+')
+
+    local file, err
+    if open_file_cache then
+        file, err = open_file_cache(conf)
+    else
+        file, err = io_open(conf.path, 'a+')
+    end
 
     if not file then
         core.log.error("failed to open file: ", conf.path, ", error info: ", err)
@@ -73,7 +122,11 @@ local function write_file_data(conf, log_message)
         else
             file:flush()
         end
-        file:close()
+
+        -- file will be closed by gc, if open_file_cache exists
+        if not open_file_cache then
+            file:close()
+        end
     end
 end
 
diff --git a/t/plugin/file-logger.t b/t/plugin/file-logger-reopen.t
similarity index 62%
copy from t/plugin/file-logger.t
copy to t/plugin/file-logger-reopen.t
index 464ff6b..c211935 100644
--- a/t/plugin/file-logger.t
+++ b/t/plugin/file-logger-reopen.t
@@ -14,7 +14,16 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 #
-use t::APISIX 'no_plan';
+use t::APISIX;
+
+my $nginx_binary = $ENV{'TEST_NGINX_BINARY'} || 'nginx';
+my $version = eval { `$nginx_binary -V 2>&1` };
+
+if ($version !~ m/\/apisix-nginx-module/) {
+    plan(skip_all => "apisix-nginx-module not installed");
+} else {
+    plan('no_plan');
+}
 
 no_long_string();
 no_root_location();
@@ -36,40 +45,7 @@ run_tests;
 
 __DATA__
 
-=== TEST 1: sanity
---- config
-    location /t {
-        content_by_lua_block {
-            local configs = {
-                -- full configuration
-                {
-                    path = "file.log"
-                },
-                -- property "path" is required
-                {
-                    path = nil
-                }
-            }
-
-            local plugin = require("apisix.plugins.file-logger")
-
-            for i = 1, #configs do
-                ok, err = plugin.check_schema(configs[i])
-                if err then
-                    ngx.say(err)
-                else
-                    ngx.say("done")
-                end
-            end
-        }
-    }
---- response_body_like
-done
-property "path" is required
-
-
-
-=== TEST 2: add plugin metadata
+=== TEST 1: prepare
 --- config
     location /t {
         content_by_lua_block {
@@ -86,20 +62,10 @@ property "path" is required
 
             if code >= 300 then
                 ngx.status = code
+                ngx.say(body)
+                return
             end
-            ngx.say(body)
-        }
-    }
---- response_body
-passed
-
 
-
-=== TEST 3: add plugin
---- config
-    location /t {
-        content_by_lua_block {
-            local t = require("lib.test_admin").test
             local code, body = t('/apisix/admin/routes/1',
                  ngx.HTTP_PUT,
                  [[{
@@ -129,73 +95,77 @@ passed
 
 
 
-=== TEST 4: verify plugin
+=== TEST 2: cache file
 --- config
     location /t {
         content_by_lua_block {
             local core = require("apisix.core")
             local t = require("lib.test_admin").test
             local code = t("/hello", ngx.HTTP_GET)
-            local fd, err = io.open("file.log", 'r')
-            local msg
-
-            if fd then
-                msg = fd:read()
-            else
-                core.log.error("failed to open file: file.log, error info: ", err)
-            end
-            fd:close()
-
-            local new_msg = core.json.decode(msg)
-            if new_msg.client_ip == '127.0.0.1' and new_msg.route_id == '1'
-                and new_msg.host == '127.0.0.1'
-            then
-                msg = "write file log success"
-                ngx.status = code
-                ngx.say(msg)
-            end
+            assert(io.open("file.log", 'r'))
+            os.remove("file.log")
+            local code = t("/hello", ngx.HTTP_GET)
+            local _, err = io.open("file.log", 'r')
+            ngx.say(err)
         }
     }
 --- response_body
-write file log success
+file.log: No such file or directory
 
 
 
-=== TEST 5: failed to open the path
+=== TEST 3: reopen file
 --- config
     location /t {
         content_by_lua_block {
             local core = require("apisix.core")
             local t = require("lib.test_admin").test
-            local code, body = t('/apisix/admin/routes/1',
-                 ngx.HTTP_PUT,
-                 [[{
-                        "plugins": {
-                            "file-logger": {
-                                "path": "/log/file.log"
-                            }
-                        },
-                        "upstream": {
-                            "nodes": {
-                                "127.0.0.1:1982": 1
-                            },
-                            "type": "roundrobin"
-                        },
-                        "uri": "/hello"
-                }]]
-                )
+            local code = t("/hello", ngx.HTTP_GET)
+            assert(io.open("file.log", 'r'))
+            os.remove("file.log")
 
-            if code >= 300 then
-                ngx.status = code
-                ngx.say(body)
+            local process = require "ngx.process"
+            local resty_signal = require "resty.signal"
+            local pid = process.get_master_pid()
+
+            local ok, err = resty_signal.kill(pid, "USR1")
+            if not ok then
+                ngx.log(ngx.ERR, "failed to kill process of pid ", pid, ": ", err)
+                return
             end
 
-            local code, messages = t("/hello", GET)
-            core.log.warn("messages: ", messages)
-            if code >= 300 then
+            local code = t("/hello", ngx.HTTP_GET)
+
+            -- file is reopened
+            local fd, err = io.open("file.log", 'r')
+            local msg
+
+            if not fd then
+                core.log.error("failed to open file: file.log, error info: ", err)
+                return
+            end
+
+            msg = fd:read()
+
+            local new_msg = core.json.decode(msg)
+            if new_msg.client_ip == '127.0.0.1' and new_msg.route_id == '1'
+                and new_msg.host == '127.0.0.1'
+            then
+                msg = "write file log success"
                 ngx.status = code
+                ngx.say(msg)
             end
+
+            os.remove("file.log")
+            local code = t("/hello", ngx.HTTP_GET)
+            local _, err = io.open("file.log", 'r')
+            ngx.say(err)
         }
     }
---- error_log
-failed to open file: /log/file.log, error info: /log/file.log: No such file or directory
+--- response_body
+write file log success
+file.log: No such file or directory
+--- grep_error_log eval
+qr/reopen cached log file: file.log/
+--- grep_error_log_out
+reopen cached log file: file.log
diff --git a/t/plugin/file-logger.t b/t/plugin/file-logger.t
index 464ff6b..f2860f9 100644
--- a/t/plugin/file-logger.t
+++ b/t/plugin/file-logger.t
@@ -139,12 +139,12 @@ passed
             local fd, err = io.open("file.log", 'r')
             local msg
 
-            if fd then
-                msg = fd:read()
-            else
+            if not fd then
                 core.log.error("failed to open file: file.log, error info: ", err)
+                return
             end
-            fd:close()
+
+            msg = fd:read()
 
             local new_msg = core.json.decode(msg)
             if new_msg.client_ip == '127.0.0.1' and new_msg.route_id == '1'
@@ -154,10 +154,22 @@ passed
                 ngx.status = code
                 ngx.say(msg)
             end
+
+            --- a new request is logged
+            t("/hello", ngx.HTTP_GET)
+            msg = fd:read("*l")
+            local new_msg = core.json.decode(msg)
+            if new_msg.client_ip == '127.0.0.1' and new_msg.route_id == '1'
+                and new_msg.host == '127.0.0.1'
+            then
+                msg = "write file log success"
+                ngx.say(msg)
+            end
         }
     }
 --- response_body
 write file log success
+write file log success