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