Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add support for custom named log file names for log-rotate plugin #9619

Closed
wants to merge 12 commits into from
1 change: 1 addition & 0 deletions apisix/core/config_local.lua
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ end
-- local local_conf = core.config.local_conf()
-- local fallback_sni = core.table.try_read_attr(
-- local_conf, "apisix", "ssl", "fallback_sni") -- "a.test2.com"
-- -- `nil` is returned if the attribute doesn't exist
monkeyDluffy6017 marked this conversation as resolved.
Show resolved Hide resolved
function _M.local_conf(force)
if not force and config_data then
return config_data
Expand Down
58 changes: 42 additions & 16 deletions apisix/plugins/log-rotate.lua
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,10 @@ local COMPRESSION_FILE_SUFFIX = ".tar.gz" -- compression file suffix
local rotate_time
local default_logs
local enable_compression = false
local DEFAULT_ACCESS_LOG_FILENAME = "access.log"
local DEFAULT_ERROR_LOG_FILENAME = "error.log"
local DEFAULT_ACCESS_LOG_FILENAME = "logs/access.log"
local DEFAULT_ERROR_LOG_FILENAME = "logs/error.log"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's better not to change this, the variable name is FILENAME, it should not include the file path

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Then I think we can change the variable name because we do require a path which currently is hardcoded to logs/access.log with hardcoding at two different places. I am changing the variable name to more appropriate DEFAULT_*_LOG_PATH @monkeyDluffy6017

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes I had changed the variable name.

local custom_access_log_filename
local custom_error_log_filename

local schema = {
type = "object",
Expand All @@ -72,11 +74,11 @@ local function file_exists(path)
return file ~= nil
end


-- get the log directory path
monkeyDluffy6017 marked this conversation as resolved.
Show resolved Hide resolved
local function get_log_path_info(file_type)
local_conf = core.config.local_conf()
local conf_path
if file_type == "error.log" then
if file_type == custom_error_log_filename or file_type == DEFAULT_ERROR_LOG_FILENAME then
conf_path = local_conf and local_conf.nginx_config and
local_conf.nginx_config.error_log
else
Expand All @@ -101,15 +103,15 @@ local function get_log_path_info(file_type)
end
end

return prefix .. "logs/", file_type
return prefix , file_type
end


local function tab_sort_comp(a, b)
return a > b
end


-- scans the log directory and returns a sorted table of matching log files
monkeyDluffy6017 marked this conversation as resolved.
Show resolved Hide resolved
local function scan_log_folder(log_file_name)
local t = {}

Expand All @@ -130,6 +132,18 @@ local function scan_log_folder(log_file_name)
return t, log_dir
end

local function get_custom_logfile_name()
monkeyDluffy6017 marked this conversation as resolved.
Show resolved Hide resolved
local local_conf = core.config.local_conf()

local custom_error_log_filename =
core.table.try_read_attr(local_conf, "nginx_config", "error_log")
local custom_access_log_filename =
core.table.try_read_attr(local_conf, "nginx_config", "http", "access_log")

return custom_access_log_filename, custom_error_log_filename

end


local function rename_file(log, date_str)
local new_file
Expand All @@ -143,10 +157,18 @@ local function rename_file(log, date_str)
core.log.info("file exist: ", new_file)
return new_file
end

local ok, err = os_rename(log.file, new_file)
monkeyDluffy6017 marked this conversation as resolved.
Show resolved Hide resolved
local filename = log.file
-- create the file if it does not exist
local exists = lfs.attributes(filename, "mode") == "file"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have a funciton file_exists already

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Revolyssup please check this

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

okay I'll replace it with that function

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@monkeyDluffy6017 made the change

if not exists then
local file = io_open(filename, "w")
if file then
file:close()
end
end
Copy link
Contributor

@monkeyDluffy6017 monkeyDluffy6017 Jun 15, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do you create a new file here, i think it's better to record an error log and exit the function

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it not desirable to automatically create the log file if it does not exist? @monkeyDluffy6017

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Revolyssup please check this

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@monkeyDluffy6017 So should I error out when the file doesn't exist or create the file as a fallback?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it necessay to add this check?
The original logic looked fine, os.rename would log when it failed and then skip

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@monkeyDluffy6017 removed this check

local ok, err = os_rename(filename, new_file)
monkeyDluffy6017 marked this conversation as resolved.
Show resolved Hide resolved
if not ok then
core.log.error("move file from ", log.file, " to ", new_file,
core.log.error("move file from ", filename, " to ", new_file,
" res:", ok, " msg:", err)
return
end
Expand Down Expand Up @@ -258,6 +280,8 @@ local function rotate()
local max_kept = MAX_KEPT
local max_size = MAX_SIZE
local attr = plugin.plugin_attr(plugin_name)
local access_log_filename = custom_access_log_filename or DEFAULT_ACCESS_LOG_FILENAME
local error_log_filename = custom_error_log_filename or DEFAULT_ERROR_LOG_FILENAME
if attr then
interval = attr.interval or interval
max_kept = attr.max_kept or max_kept
Expand All @@ -272,8 +296,8 @@ local function rotate()
if not default_logs then
-- first init default log filepath and filename
default_logs = {}
init_default_logs(default_logs, DEFAULT_ACCESS_LOG_FILENAME)
init_default_logs(default_logs, DEFAULT_ERROR_LOG_FILENAME)
init_default_logs(default_logs, access_log_filename)
init_default_logs(default_logs, error_log_filename)
end

ngx_update_time()
Expand All @@ -286,23 +310,23 @@ local function rotate()
end

if now_time >= rotate_time then
local files = {DEFAULT_ACCESS_LOG_FILENAME, DEFAULT_ERROR_LOG_FILENAME}
local files = {access_log_filename, error_log_filename}
rotate_file(files, now_time, max_kept)

-- reset rotate time
rotate_time = rotate_time + interval

elseif max_size > 0 then
local access_log_file_size = file_size(default_logs[DEFAULT_ACCESS_LOG_FILENAME].file)
local error_log_file_size = file_size(default_logs[DEFAULT_ERROR_LOG_FILENAME].file)
local access_log_file_size = file_size(default_logs[access_log_filename].file)
local error_log_file_size = file_size(default_logs[error_log_filename].file)
local files = core.table.new(2, 0)

if access_log_file_size >= max_size then
core.table.insert(files, DEFAULT_ACCESS_LOG_FILENAME)
core.table.insert(files, access_log_filename)
end

if error_log_file_size >= max_size then
core.table.insert(files, DEFAULT_ERROR_LOG_FILENAME)
core.table.insert(files, error_log_filename)
end

rotate_file(files, now_time, max_kept)
Expand All @@ -312,6 +336,8 @@ end

function _M.init()
timers.register_timer("plugin#log-rotate", rotate, true)
custom_access_log_filename, custom_error_log_filename = get_custom_logfile_name()
timers.register_timer("plugin#log-rotate", rotate, true)
monkeyDluffy6017 marked this conversation as resolved.
Show resolved Hide resolved
end


Expand Down
2 changes: 2 additions & 0 deletions t/plugin/log-rotate.t
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ __DATA__
--- config
location /t {
content_by_lua_block {
local io = require("io")
ngx.log(ngx.ERR, "start xxxxxx")
ngx.sleep(2.5)
local has_split_access_file = false
Expand Down Expand Up @@ -105,6 +106,7 @@ start xxxxxx
--- config
location /t {
content_by_lua_block {
local io = require("io")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you will have to revert these changes.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It fails lint check when I try to use global "io"

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You have imported "io" but haven't used it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have used it below in the for loop

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Strange, I don't see any other additions except importing "io" module in to this file 🤔

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ngx.sleep(0.5)
local t = require("lib.test_admin").test
local code, _, org_body = t('/apisix/admin/plugins/reload',
Expand Down
4 changes: 2 additions & 2 deletions t/plugin/log-rotate2.t
Original file line number Diff line number Diff line change
Expand Up @@ -181,13 +181,13 @@ plugins:
- log-rotate
plugin_attr:
log-rotate:
interval: 1
interval: 2
max_kept: 1
enable_compression: true
--- config
location /t {
content_by_lua_block {
ngx.sleep(3.5)
ngx.sleep(2.5)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why is this change needed?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The tests are flaky and fail intermittently and with this timeout configuration they stopped failing.

local has_split_access_file = false
local has_split_error_file = false
local lfs = require("lfs")
Expand Down
76 changes: 76 additions & 0 deletions t/plugin/log-rotate3.t
Original file line number Diff line number Diff line change
Expand Up @@ -132,3 +132,79 @@ start xxxxxx
}
--- response_body
passed



=== TEST 4: max_kept effective on differently named compression files
monkeyDluffy6017 marked this conversation as resolved.
Show resolved Hide resolved
--- extra_yaml_config
plugins:
- log-rotate
plugin_attr:
log-rotate:
interval: 2
max_kept: 1
enable_compression: true
--- yaml_config
nginx_config:
user: root
error_log: logs/err1.log
http:
access_log: logs/acc1.log
--- config
location /t {
content_by_lua_block {
ngx.sleep(2.5)
local has_split_access_file = false
local has_split_error_file = false
local lfs = require("lfs")
local count = 0
for file_name in lfs.dir(ngx.config.prefix() .. "/logs/") do
if string.match(file_name, ".tar.gz$") then
count = count + 1
end
end
--- only two compression file
ngx.say(count)
}
}
--- response_body
2
--- timeout: 5



=== TEST 5: check whether new log files were created
--- extra_yaml_config
plugins:
- log-rotate
plugin_attr:
log-rotate:
interval: 2
max_kept: 1
enable_compression: false
--- yaml_config
nginx_config:
user: root
error_log: logs/test-error.log
http:
access_log: logs/test-access.log
--- config
location /t {
content_by_lua_block {
ngx.sleep(2.5)
local has_split_access_file = false
local has_split_error_file = false
local lfs = require("lfs")
local count = 0
for file_name in lfs.dir(ngx.config.prefix() .. "/logs/") do
if string.match(file_name, "error.log$") or string.match(file_name, "access.log$") then
count = count + 1
end
end
--- 5 files: 2 older log files and 2 newer + fake-server-access.log
ngx.say(count)
}
}
--- response_body
5
--- timeout: 5