Skip to content

Commit 287a34a

Browse files
refactor: rewrite logger
1 parent 826118b commit 287a34a

File tree

11 files changed

+122
-195
lines changed

11 files changed

+122
-195
lines changed

lua/rest-nvim/client/curl.lua

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ local client = {}
1111
local found_curl, curl = pcall(require, "cURL.safe")
1212

1313
local utils = require("rest-nvim.utils")
14+
local logger = require("rest-nvim.logger")
1415

1516
-- TODO: add support for submitting forms in the `client.request` function
1617

@@ -116,15 +117,12 @@ end
116117
---@param statistics_tbl RestConfigResultStats Statistics table
117118
---@return table Request statistics
118119
local function get_stats(req, statistics_tbl)
119-
local logger = _G._rest_nvim.logger
120-
121120
local stats = {}
122121

123122
local function get_stat(req_, stat_)
124123
local curl_info = curl["INFO_" .. stat_:upper()]
125124
if not curl_info then
126-
---@diagnostic disable-next-line need-check-nil
127-
logger:error(
125+
logger.error(
128126
"The cURL request stat field '"
129127
.. stat_("' was not found.\nPlease take a look at: https://curl.se/libcurl/c/curl_easy_getinfo.html")
130128
)
@@ -163,10 +161,9 @@ end
163161
---@return table? info The request information (url, method, headers, body, etc)
164162
function client.request_(request)
165163
local info = {}
166-
local logger = assert(_G._rest_nvim.logger)
167164
if not found_curl then
168165
---@diagnostic disable-next-line need-check-nil
169-
logger:error("lua-curl could not be found, therefore the cURL client will not work.")
166+
logger.error("lua-curl could not be found, therefore the cURL client will not work.")
170167
return
171168
end
172169
local host = request.headers["host"]
@@ -248,7 +245,7 @@ function client.request_(request)
248245
end
249246
req:setopt_httppost(form)
250247
else
251-
logger:error(("'%s' type body is not supported yet"):format(request.body.__TYPE))
248+
logger.error(("'%s' type body is not supported yet"):format(request.body.__TYPE))
252249
return
253250
end
254251
end
@@ -273,7 +270,7 @@ function client.request_(request)
273270
info.headers = table.concat(res_headers):gsub("\r", "")
274271
info.body = table.concat(res_result)
275272
else
276-
logger:error("Something went wrong when making the request with cURL:\n" .. curl_error(err:no()))
273+
logger.error("Something went wrong when making the request with cURL:\n" .. curl_error(err:no()))
277274
return
278275
end
279276
req:close()

lua/rest-nvim/commands.lua

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ local commands = {}
3636

3737
local dotenv = require("rest-nvim.dotenv")
3838
local request = require("rest-nvim.request")
39+
local logger = require("rest-nvim.logger")
40+
3941

4042
---@type table<string, RestCmd>
4143
local rest_command_tbl = {
@@ -111,10 +113,8 @@ local function rest(opts)
111113
local args = #fargs > 1 and vim.list_slice(fargs, 2, #fargs) or {}
112114
local command = rest_command_tbl[cmd]
113115

114-
local logger = assert(_G._rest_nvim.logger)
115-
116116
if not command then
117-
logger:error("Unknown command: " .. cmd)
117+
logger.error("Unknown command: " .. cmd)
118118
return
119119
end
120120

lua/rest-nvim/config/init.lua

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,6 @@ local logger = require("rest-nvim.logger")
6565
---@field result RestConfigResult Request results buffer behavior
6666
---@field highlight RestConfigHighlight Request highlighting
6767
---@field _debug_info? RestConfigDebug Configurations debug information, set automatically
68-
---@field logger? Logger Logging system, set automatically
6968

7069
---rest.nvim default configuration
7170
---@type RestConfig
@@ -132,6 +131,7 @@ local default_config = {
132131
enable = true,
133132
timeout = 750,
134133
},
134+
_log_level = vim.log.levels.WARN,
135135
}
136136

137137
---Set user-defined configurations for rest.nvim
@@ -148,19 +148,13 @@ function config.set(user_configs)
148148

149149
local ok, err = check.validate(conf)
150150

151-
-- We do not want to validate `logger` value so we are setting it after the validation
152-
conf.logger = logger:new({
153-
level_name = conf.logs.level,
154-
save_logs = conf.logs.save,
155-
})
156-
157151
if not ok then
158152
---@cast err string
159-
conf.logger:error(err)
153+
conf.logger.error(err)
160154
end
161155

162156
if #conf._debug_info.unrecognized_configs > 0 then
163-
conf.logger:warn("Unrecognized configs found in setup: " .. vim.inspect(conf._debug_info.unrecognized_configs))
157+
conf.logger.warn("Unrecognized configs found in setup: " .. vim.inspect(conf._debug_info.unrecognized_configs))
164158
end
165159

166160
return conf

lua/rest-nvim/logger.lua

Lines changed: 80 additions & 139 deletions
Original file line numberDiff line numberDiff line change
@@ -2,176 +2,117 @@
22
---
33
---@brief [[
44
---
5-
---Logging library for rest.nvim, slightly inspired by rmagatti/logger.nvim
5+
---Logging library for rest.nvim, inspired by nvim-neorocks/rocks.nvim
66
---Intended for use by internal and third-party modules.
77
---
8-
---Default logger instance is made during the `setup` and can be accessed
9-
---by anyone through the `_G._rest_nvim.logger` configuration field
10-
---that is set automatically.
11-
---
12-
---------------------------------------------------------------------------------
13-
---
14-
---Usage:
15-
---
16-
---```lua
17-
---local logger = require("rest-nvim.logger"):new({ level = "debug" })
18-
---
19-
---logger:set_log_level("info")
20-
---
21-
---logger:info("This is an info log")
22-
--- -- [rest.nvim] INFO: This is an info log
23-
---```
24-
---
258
---@brief ]]
269

27-
---@class Logger
2810
local logger = {}
2911

30-
-- NOTE: vim.loop has been renamed to vim.uv in Neovim >= 0.10 and will be removed later
31-
local uv = vim.uv or vim.loop
12+
---@type fun(any)
13+
function logger.trace(_) end
14+
---@type fun(any)
15+
function logger.debug(_) end
16+
---@type fun(any)
17+
function logger.info(_) end
18+
---@type fun(any)
19+
function logger.warn(_) end
20+
---@type fun(any)
21+
function logger.error(_) end
3222

33-
---@see vim.log.levels
34-
---@class LoggerLevels
35-
local levels = {
36-
trace = vim.log.levels.TRACE,
37-
debug = vim.log.levels.DEBUG,
38-
info = vim.log.levels.INFO,
39-
warn = vim.log.levels.WARN,
40-
error = vim.log.levels.ERROR,
41-
}
23+
local default_log_path = vim.fn.stdpath("log") --[[@as string]]
4224

43-
---@class LoggerConfig
44-
---@field level_name string Logging level name. Default is `"info"`
45-
---@field save_logs boolean Whether to save log messages into a `.log` file. Default is `true`
46-
local default_config = {
47-
level_name = "info",
48-
save_logs = true,
49-
}
25+
local LARGE = 1e9
5026

51-
local default_log_path = vim.fn.stdpath("log") --[[@as string]]
27+
local log_date_format = "%F %H:%M:%S"
5228

5329
---Get the rest.nvim log file path.
5430
---@package
5531
---@return string filepath
5632
function logger.get_logfile()
57-
return vim.fs.joinpath(default_log_path, "rest-nvim.log")
58-
end
59-
60-
---Store the logger output in a file at `vim.fn.stdpath("log")`
61-
---@see vim.fn.stdpath
62-
---@param msg string Logger message to be saved
63-
local function store_log(msg)
64-
local date = os.date("%F %r") -- 2024-01-26 01:25:05 PM
65-
local log_msg = date .. " | " .. msg .. "\n"
66-
local log_path = logger.get_logfile()
67-
68-
-- 644 sets read and write permissions for the owner, and it sets read-only
69-
-- mode for the group and others
70-
uv.fs_open(log_path, "a+", tonumber(644, 8), function(err, file)
71-
if file and not err then
72-
local file_pipe = uv.new_pipe(false)
73-
---@cast file_pipe uv_pipe_t
74-
uv.pipe_open(file_pipe, file)
75-
uv.write(file_pipe, log_msg)
76-
uv.fs_close(file)
77-
end
78-
end)
33+
return vim.fs.joinpath(default_log_path, "rest-nvim.log")
7934
end
8035

81-
---Create a new logger instance
82-
---@param opts LoggerConfig Logger configuration
83-
---@return Logger
84-
function logger:new(opts)
85-
opts = opts or {}
86-
local conf = vim.tbl_deep_extend("force", default_config, opts)
87-
self.level = levels[conf.level_name]
88-
self.save_logs = conf.save_logs
89-
90-
self.__index = function(_, index)
91-
if type(self[index]) == "function" then
92-
return function(...)
93-
-- Make any logger function call with "." access result in the syntactic sugar ":" access
94-
self[index](self, ...)
95-
end
96-
else
97-
return self[index]
98-
end
36+
local logfile, openerr
37+
---@private
38+
---Opens log file. Returns true if file is open, false on error
39+
---@return boolean
40+
local function open_logfile()
41+
-- Try to open file only once
42+
if logfile then
43+
return true
9944
end
100-
setmetatable(opts, self)
101-
102-
return self
103-
end
104-
105-
---Set the log level for the logger
106-
---@param level string New logging level
107-
---@see vim.log.levels
108-
function logger:set_log_level(level)
109-
self.level = levels[level]
110-
end
111-
112-
---Log a trace message
113-
---@param msg string Log message
114-
function logger:trace(msg)
115-
msg = "[rest.nvim] TRACE: " .. msg
116-
if self.level == vim.log.levels.TRACE then
117-
vim.notify(msg, levels.trace)
45+
if openerr then
46+
return false
11847
end
11948

120-
if self.save_logs then
121-
store_log(msg)
49+
vim.fn.mkdir(default_log_path, "-p")
50+
logfile, openerr = io.open(logger.get_logfile(), "w+")
51+
if not logfile then
52+
local err_msg = string.format("Failed to open rest.nvim log file: %s", openerr)
53+
vim.notify(err_msg, vim.log.levels.ERROR)
54+
return false
12255
end
123-
end
12456

125-
---Log a debug message
126-
---@param msg string Log message
127-
function logger:debug(msg)
128-
msg = "[rest.nvim] DEBUG: " .. msg
129-
if self.level == vim.log.levels.DEBUG then
130-
vim.notify(msg, levels.debug)
57+
local log_info = vim.uv.fs_stat(logger.get_logfile())
58+
if log_info and log_info.size > LARGE then
59+
local warn_msg =
60+
string.format("rest.nvim log is large (%d MB): %s", log_info.size / (1000 * 1000), logger.get_logfile())
61+
vim.notify(warn_msg, vim.log.levels.WARN)
13162
end
13263

133-
if self.save_logs then
134-
store_log(msg)
135-
end
64+
-- Start message for logging
65+
logfile:write(string.format("[START][%s] rest.nvim logging initiated\n", os.date(log_date_format)))
66+
return true
13667
end
13768

138-
---Log an info message
139-
---@param msg string Log message
140-
function logger:info(msg)
141-
msg = "[rest.nvim] INFO: " .. msg
142-
local valid_levels = { vim.log.levels.INFO, vim.log.levels.DEBUG }
143-
if vim.tbl_contains(valid_levels, self.level) then
144-
vim.notify(msg, levels.info)
145-
end
146-
147-
if self.save_logs then
148-
store_log(msg)
149-
end
69+
local log_levels = vim.deepcopy(vim.log.levels)
70+
for levelstr, levelnr in pairs(log_levels) do
71+
log_levels[levelnr] = levelstr
15072
end
15173

152-
---Log a warning message
153-
---@param msg string Log message
154-
function logger:warn(msg)
155-
msg = "[rest.nvim] WARN: " .. msg
156-
local valid_levels = { vim.log.levels.INFO, vim.log.levels.DEBUG, vim.log.levels.WARN }
157-
if vim.tbl_contains(valid_levels, self.level) then
158-
vim.notify(msg, levels.warn)
159-
end
160-
161-
if self.save_logs then
162-
store_log(msg)
74+
---Set the log level for the logger
75+
---@param level (string|integer) New logging level
76+
---@see vim.log.levels
77+
function logger.set_log_level(level)
78+
if type(level) == "string" then
79+
logger.level = assert(log_levels[level:upper()], string.format("rest.nvim: Invalid log level: %q", level))
80+
else
81+
assert(log_levels[level], string.format("rest.nvim: Invalid log level: %d", level))
82+
logger.level = level
16383
end
16484
end
16585

166-
---Log an error message
167-
---@param msg string Log message
168-
function logger:error(msg)
169-
msg = "[rest.nvim] ERROR: " .. msg
170-
vim.notify(msg, levels.error)
171-
172-
if self.save_logs then
173-
store_log(msg)
86+
for level, levelnr in pairs(vim.log.levels) do
87+
logger[level:lower()] = function(...)
88+
if logger.level == vim.log.levels.OFF or not open_logfile() then
89+
return false
90+
end
91+
local argc = select("#", ...)
92+
if levelnr < logger.level then
93+
return false
94+
end
95+
if argc == 0 then
96+
return true
97+
end
98+
local info = debug.getinfo(2, "Sl")
99+
local fileinfo = string.format("%s:%s", info.short_src, info.currentline)
100+
local parts = { level, "|", os.date(log_date_format), "|", fileinfo, "|" }
101+
for i = 1, argc do
102+
local arg = select(i, ...)
103+
if arg == nil then
104+
table.insert(parts, "<nil>")
105+
elseif type(arg) == "string" then
106+
table.insert(parts, arg)
107+
else
108+
table.insert(parts, vim.inspect(arg))
109+
end
110+
end
111+
logfile:write(table.concat(parts, " "), "\n")
112+
logfile:flush()
174113
end
175114
end
176115

116+
logger.set_log_level(vim.tbl_get(_G, "_rest_nvim", "_log_level") or vim.log.levels.WARN)
117+
177118
return logger

0 commit comments

Comments
 (0)