.dotfiles/nvim/mason/packages/lua-language-server/libexec/script/log.lua

166 lines
3.7 KiB
Lua

local fs = require 'bee.filesystem'
local time = require 'bee.time'
local monotonic = time.monotonic
local osDate = os.date
local ioOpen = io.open
local tablePack = table.pack
local tableConcat = table.concat
local tostring = tostring
local debugTraceBack = debug.traceback
local mathModf = math.modf
local debugGetInfo = debug.getinfo
local ioStdErr = io.stderr
local m = {}
m.file = nil
m.startTime = time.time() - monotonic()
m.size = 0
m.maxSize = 100 * 1024 * 1024
m.level = 'info'
m.levelMap = {
['trace'] = 1,
['debug'] = 2,
['info'] = 3,
['warn'] = 4,
['error'] = 5,
}
local function trimSrc(src)
if src:sub(1, 1) == '@' then
src = src:sub(2)
end
return src
end
local function init_log_file()
if not m.file then
m.file = ioOpen(m.path, 'w')
if not m.file then
return
end
m.file:write('')
m.file:close()
m.file = ioOpen(m.path, 'ab')
if not m.file then
return
end
m.file:setvbuf 'no'
end
end
local function pushLog(level, ...)
if not m.path then
return
end
local t = tablePack(...)
for i = 1, t.n do
t[i] = tostring(t[i])
end
local str = tableConcat(t, '\t', 1, t.n)
if level == 'error' then
str = str .. '\n' .. debugTraceBack(nil, 3)
end
local info = debugGetInfo(3, 'Sl')
local text = m.raw(0, level, str, info.source, info.currentline, monotonic())
return text
end
function m.trace(...)
pushLog('trace', ...)
end
function m.debug(...)
pushLog('debug', ...)
end
function m.info(...)
pushLog('info', ...)
end
function m.warn(...)
pushLog('warn', ...)
end
function m.error(...)
-- Don't use tail calls,
-- Otherwise, the count of `debug.getinfo` will be wrong
local msg = pushLog('error', ...)
return msg
end
function m.raw(thd, level, msg, source, currentline, clock)
if m.levelMap[level] < (m.levelMap[m.level] or m.levelMap['info']) then
return msg
end
if level == 'error' then
ioStdErr:write(msg .. '\n')
if not m.firstError then
m.firstError = msg
end
end
if m.size > m.maxSize then
return msg
end
init_log_file()
local sec, ms = mathModf((m.startTime + clock) / 1000)
local timestr = osDate('%H:%M:%S', sec)
local agl = ''
if #level < 5 then
agl = (' '):rep(5 - #level)
end
local buf
if currentline == -1 then
buf = ('[%s.%03.f][%s]%s[#%d]: %s\n'):format(timestr, ms * 1000, level, agl, thd, msg)
else
buf = ('[%s.%03.f][%s]%s[#%d:%s:%s]: %s\n'):format(timestr, ms * 1000, level, agl, thd, trimSrc(source), currentline, msg)
end
m.size = m.size + #buf
if m.file then
if m.size > m.maxSize then
m.file:write(buf:sub(1, m.size - m.maxSize))
m.file:write('[REACH MAX SIZE]')
else
m.file:write(buf)
end
end
if m.print then
print(buf)
end
return buf
end
function m.init(root, path)
local lastBuf
if m.file then
m.file:close()
m.file = nil
local file = ioOpen(m.path, 'rb')
if file then
lastBuf = file:read(m.maxSize)
file:close()
end
end
m.path = path:string()
m.prefixLen = #root:string()
m.size = 0
pcall(function ()
if not fs.exists(path:parent_path()) then
fs.create_directories(path:parent_path())
end
end)
if lastBuf then
init_log_file()
if m.file then
m.file:write(lastBuf)
m.size = m.size + #lastBuf
end
end
end
return m