diff --git a/README.md b/README.md index 77526b80..fca11464 100644 --- a/README.md +++ b/README.md @@ -95,6 +95,7 @@ require('copilot').setup({ print_log_level = vim.log.levels.WARN, trace_lsp = "off", -- "off" | "messages" | "verbose" trace_lsp_progress = false, + log_lsp_messages = false, }, copilot_node_command = 'node', -- Node.js version must be > 18.x workspace_folders = {}, @@ -194,8 +195,8 @@ require("copilot").setup { ### logger -When `log_to_file` is true, logs will be written to the `file` for anything of `file_log_level` or higher. -When `print_log` is true, logs will be printed to NeoVim (using `notify`) for anything of `print_log_level` or higher. +Logs will be written to the `file` for anything of `file_log_level` or higher. +Logs will be printed to NeoVim (using `notify`) for anything of `print_log_level` or higher. File logging is done asynchronously to minimize performance impacts, however there is still some overhead. Log levels used are the ones defined in `vim.log`: @@ -213,8 +214,14 @@ vim.log = { } ``` -`trace_lsp` can either be `off`, `messages` which will output the LSP messages, or `verbose` which adds additonal information to the message. -When `trace_lsp_progress` is true, LSP progress messages will also be logged. +`trace_lsp` controls logging of LSP trace messages (`$/logTrace`) can either be: + +- `off` +- `messages` which will output the LSP messages +- `verbose` which adds additonal information to the message. + +When `trace_lsp_progress` is true, LSP progress messages (`$/progress`) will also be logged. +When `log_lsp_messages` is true, LSP log messages (`window/logMessage`) events will be logged. Careful turning on all logging features as the log files may get very large over time, and are not pruned by the application. diff --git a/lua/copilot/client.lua b/lua/copilot/client.lua index d53f9532..6ea5dd2d 100644 --- a/lua/copilot/client.lua +++ b/lua/copilot/client.lua @@ -189,6 +189,37 @@ function M.use_client(callback) ) end +local function get_handlers() + local handlers = { + PanelSolution = api.handlers.PanelSolution, + PanelSolutionsDone = api.handlers.PanelSolutionsDone, + statusNotification = api.handlers.statusNotification, + ["copilot/openURL"] = api.handlers["copilot/openURL"], + } + + -- optional handlers + local logger_conf = config.get("logger") --[[@as copilot_config_logging]] + if logger_conf.trace_lsp ~= "off" then + handlers = vim.tbl_extend("force", handlers, { + ["$/logTrace"] = logger.handle_lsp_trace, + }) + end + + if logger_conf.trace_lsp_progress then + handlers = vim.tbl_extend("force", handlers, { + ["$/progress"] = logger.handle_lsp_progress, + }) + end + + if logger_conf.log_lsp_messages then + handlers = vim.tbl_extend("force", handlers, { + ["window/logMessage"] = logger.handle_log_lsp_messages, + }) + end + + return handlers +end + local function prepare_client_config(overrides) local node = config.get("copilot_node_command") @@ -217,36 +248,6 @@ local function prepare_client_config(overrides) workspaceFolders = true, } - local handlers = { - PanelSolution = api.handlers.PanelSolution, - PanelSolutionsDone = api.handlers.PanelSolutionsDone, - statusNotification = api.handlers.statusNotification, - ["copilot/openURL"] = api.handlers["copilot/openURL"], - -- set up "window/logMessage" handler here instead of in `logger.lua`, since some other lsp servers don't support this method, such as jsonlsp - ["window/logMessage"] = function(_, result, _) - if not result then - return - end - - local message = string.format("LSP message: %s", result.message) - local message_type = result.type --[[@as integer]] - - if message_type == 1 then - logger.error(message) - elseif message_type == 2 then - logger.warn(message) - elseif message_type == 3 then - logger.info(message) - elseif message_type == 4 then - logger.info(message) - elseif message_type == 5 then - logger.debug(message) - else - logger.trace(message) - end - end, - } - local root_dir = config.get_root_dir() local workspace_folders = { --- @type workspace_folder @@ -325,7 +326,7 @@ local function prepare_client_config(overrides) end) end end, - handlers = handlers, + handlers = get_handlers(), init_options = { copilotIntegrationId = "vscode-chat", -- Fix LSP warning: editorInfo and editorPluginInfo will soon be required in initializationOptions diff --git a/lua/copilot/config.lua b/lua/copilot/config.lua index 00805c7f..9763c59d 100644 --- a/lua/copilot/config.lua +++ b/lua/copilot/config.lua @@ -37,14 +37,13 @@ local default_config = { }, ---@class copilot_config_logging logger = { - log_to_file = false, file = vim.fn.stdpath("log") .. "/copilot-lua.log", - file_log_level = vim.log.levels.WARN, - print_log = true, + file_log_level = vim.log.levels.OFF, print_log_level = vim.log.levels.WARN, ---@type string<'off'|'messages'|'verbose'> trace_lsp = "off", trace_lsp_progress = false, + log_lsp_messages = false, }, ---@deprecated ft_disable = nil, diff --git a/lua/copilot/logger.lua b/lua/copilot/logger.lua index bf7692f4..6f0f4b64 100644 --- a/lua/copilot/logger.lua +++ b/lua/copilot/logger.lua @@ -2,10 +2,8 @@ local uv = vim.uv ---@class logger local mod = { - log_to_file = false, log_file = vim.fn.stdpath("log") .. "/copilot-lua.log", - file_log_level = vim.log.levels.WARN, - print_log = true, + file_log_level = vim.log.levels.OFF, print_log_level = vim.log.levels.WARN, } @@ -75,11 +73,11 @@ end ---@param data any ---@param force_print boolean function mod.log(log_level, msg, data, force_print) - if mod.log_to_file and (mod.file_log_level <= log_level) then + if mod.file_log_level <= log_level then write_log(log_level, mod.log_file, msg, data) end - if force_print or (mod.print_log and (mod.print_log_level <= log_level)) then + if force_print or (mod.print_log_level <= log_level) then notify_log(log_level, msg, data) end end @@ -125,27 +123,44 @@ function mod.setup(conf) mod.log_file = conf.file mod.file_log_level = conf.file_log_level mod.print_log_level = conf.print_log_level - mod.log_to_file = conf.log_to_file - mod.print_log = conf.print_log +end - if conf.trace_lsp ~= "off" then - vim.lsp.handlers["$/logTrace"] = function(_, result, _) - if not result then - return - end +function mod.handle_lsp_trace(_, result, _) + if not result then + return + end - mod.trace(string.format("LSP trace - %s", result.message), result.verbose) - end + mod.trace(string.format("LSP trace - %s", result.message), result.verbose) +end + +function mod.handle_lsp_progress(_, result, _) + if not result then + return end - if conf.trace_lsp_progress then - vim.lsp.handlers["$/progress"] = function(_, result, _) - if not result then - return - end + mod.trace(string.format("LSP progress - token %s", result.token), result.value) +end - mod.trace(string.format("LSP progress - token %s", result.token), result.value) - end +function mod.handle_log_lsp_messages(_, result, _) + if not result then + return + end + + local message = string.format("LSP message: %s", result.message) + local message_type = result.type --[[@as integer]] + + if message_type == 1 then + mod.error(message) + elseif message_type == 2 then + mod.warn(message) + elseif message_type == 3 then + mod.info(message) + elseif message_type == 4 then + mod.info(message) + elseif message_type == 5 then + mod.debug(message) + else + mod.trace(message) end end