diff options
Diffstat (limited to 'runtime/lua/vim/lsp/log.lua')
| -rw-r--r-- | runtime/lua/vim/lsp/log.lua | 81 | 
1 files changed, 52 insertions, 29 deletions
| diff --git a/runtime/lua/vim/lsp/log.lua b/runtime/lua/vim/lsp/log.lua index e0b5653587..fff42fd011 100644 --- a/runtime/lua/vim/lsp/log.lua +++ b/runtime/lua/vim/lsp/log.lua @@ -8,7 +8,7 @@ local log = {}  -- Log level dictionary with reverse lookup as well.  --  -- Can be used to lookup the number from the name or the name from the number. --- Levels by name: "TRACE", "DEBUG", "INFO", "WARN", "ERROR" +-- Levels by name: "TRACE", "DEBUG", "INFO", "WARN", "ERROR", "OFF"  -- Level numbers begin with "TRACE" at 0  log.levels = vim.deepcopy(vim.log.levels) @@ -25,27 +25,47 @@ do    end    local logfilename = path_join(vim.fn.stdpath('cache'), 'lsp.log') +  -- TODO: Ideally the directory should be created in open_logfile(), right +  -- before opening the log file, but open_logfile() can be called from libuv +  -- callbacks, where using fn.mkdir() is not allowed. +  vim.fn.mkdir(vim.fn.stdpath('cache'), "p") +    --- Returns the log filename.    ---@returns (string) log filename    function log.get_filename()      return logfilename    end -  vim.fn.mkdir(vim.fn.stdpath('cache'), "p") -  local logfile = assert(io.open(logfilename, "a+")) - -  local log_info = vim.loop.fs_stat(logfilename) -  if log_info and log_info.size > 1e9 then -    local warn_msg = string.format( -      "LSP client log is large (%d MB): %s", -      log_info.size / (1000 * 1000), -      logfilename -    ) -    vim.notify(warn_msg) +  local logfile, openerr +  ---@private +  --- Opens log file. Returns true if file is open, false on error +  local function open_logfile() +    -- Try to open file only once +    if logfile then return true end +    if openerr then return false end + +    logfile, openerr = io.open(logfilename, "a+") +    if not logfile then +      local err_msg = string.format("Failed to open LSP client log file: %s", openerr) +      vim.notify(err_msg, vim.log.levels.ERROR) +      return false +    end + +    local log_info = vim.loop.fs_stat(logfilename) +    if log_info and log_info.size > 1e9 then +      local warn_msg = string.format( +        "LSP client log is large (%d MB): %s", +        log_info.size / (1000 * 1000), +        logfilename +      ) +      vim.notify(warn_msg) +    end + +    -- Start message for logging +    logfile:write(string.format("[START][%s] LSP logging initiated\n", os.date(log_date_format))) +    return true    end -  -- Start message for logging -  logfile:write(string.format("[START][%s] LSP logging initiated\n", os.date(log_date_format)))    for level, levelnr in pairs(log.levels) do      -- Also export the log level on the root object.      log[level] = levelnr @@ -63,23 +83,26 @@ do      -- ```      --      -- This way you can avoid string allocations if the log level isn't high enough. -    log[level:lower()] = function(...) -      local argc = select("#", ...) -      if levelnr < current_log_level then return false end -      if argc == 0 then return true end -      local info = debug.getinfo(2, "Sl") -      local header = string.format("[%s][%s] ...%s:%s", level, os.date(log_date_format), string.sub(info.short_src, #info.short_src - 15), info.currentline) -      local parts = { header } -      for i = 1, argc do -        local arg = select(i, ...) -        if arg == nil then -          table.insert(parts, "nil") -        else -          table.insert(parts, format_func(arg)) +    if level ~= "OFF" then +      log[level:lower()] = function(...) +        local argc = select("#", ...) +        if levelnr < current_log_level then return false end +        if argc == 0 then return true end +        if not open_logfile() then return false end +        local info = debug.getinfo(2, "Sl") +        local header = string.format("[%s][%s] ...%s:%s", level, os.date(log_date_format), string.sub(info.short_src, #info.short_src - 15), info.currentline) +        local parts = { header } +        for i = 1, argc do +          local arg = select(i, ...) +          if arg == nil then +            table.insert(parts, "nil") +          else +            table.insert(parts, format_func(arg)) +          end          end +        logfile:write(table.concat(parts, '\t'), "\n") +        logfile:flush()        end -      logfile:write(table.concat(parts, '\t'), "\n") -      logfile:flush()      end    end  end | 
