Skip to content

Commit 256393d

Browse files
authored
feat: add logger and redirect existing prints/notifies through it (#383)
Fixes #356
1 parent 25ab971 commit 256393d

File tree

10 files changed

+287
-46
lines changed

10 files changed

+287
-46
lines changed

README.md

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,15 @@ require('copilot').setup({
8787
cvs = false,
8888
["."] = false,
8989
},
90+
logger = {
91+
log_to_file = false,
92+
file = vim.fn.stdpath("log") .. "/copilot-lua.log",
93+
file_log_level = vim.log.levels.WARN,
94+
print_log = true,
95+
print_log_level = vim.log.levels.WARN,
96+
trace_lsp = "off", -- "off" | "messages" | "verbose"
97+
trace_lsp_progress = false,
98+
},
9099
copilot_node_command = 'node', -- Node.js version must be > 18.x
91100
workspace_folders = {},
92101
copilot_model = "", -- Current LSP default is gpt-35-turbo, supports gpt-4o-copilot
@@ -183,6 +192,32 @@ require("copilot").setup {
183192
}
184193
```
185194

195+
### logger
196+
197+
When `log_to_file` is true, logs will be written to the `file` for anything of `file_log_level` or higher.
198+
When `print_log` is true, logs will be printed to NeoVim (using `notify`) for anything of `print_log_level` or higher.
199+
File logging is done asynchronously to minimize performance impacts, however there is still some overhead.
200+
201+
Log levels used are the ones defined in `vim.log`:
202+
203+
```lua
204+
vim.log = {
205+
levels = {
206+
TRACE = 0,
207+
DEBUG = 1,
208+
INFO = 2,
209+
WARN = 3,
210+
ERROR = 4,
211+
OFF = 5,
212+
},
213+
}
214+
```
215+
216+
`trace_lsp` can either be `off`, `messages` which will output the LSP messages, or `verbose` which adds additonal information to the message.
217+
When `trace_lsp_progress` is true, LSP progress messages will also be logged.
218+
219+
Careful turning on all logging features as the log files may get very large over time, and are not pruned by the application.
220+
186221
### copilot_node_command
187222

188223
Use this field to provide the path to a specific node version such as one installed by nvm. Node.js version must be 18.x or newer.

lua/copilot/auth.lua

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
local api = require("copilot.api")
22
local c = require("copilot.client")
3+
local logger = require("copilot.logger")
34

45
local M = {}
56

@@ -145,7 +146,7 @@ local function find_config_path()
145146
if vim.fn.isdirectory(config) > 0 then
146147
return config
147148
else
148-
print("Error: could not find config path")
149+
logger.error("could not find config path")
149150
end
150151
end
151152
end

lua/copilot/client.lua

Lines changed: 24 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
local api = require("copilot.api")
22
local config = require("copilot.config")
33
local util = require("copilot.util")
4+
local logger = require("copilot.logger")
45

56
local is_disabled = false
67

@@ -9,6 +10,7 @@ local M = {
910
id = nil,
1011
--- @class copilot_capabilities:lsp.ClientCapabilities
1112
--- @field copilot table<'openURL', boolean>
13+
--- @field workspace table<'workspaceFolders', boolean>
1214
capabilities = nil,
1315
config = nil,
1416
node_version = nil,
@@ -21,7 +23,8 @@ local M = {
2123
local function store_client_id(id)
2224
if M.id and M.id ~= id then
2325
if vim.lsp.get_client_by_id(M.id) then
24-
error("unexpectedly started multiple copilot servers")
26+
logger.error("unexpectedly started multiple copilot servers")
27+
return
2528
end
2629
end
2730

@@ -92,7 +95,7 @@ end
9295
---@param force? boolean
9396
function M.buf_attach(force)
9497
if is_disabled then
95-
print("[Copilot] Offline")
98+
logger.warn("copilot is disabled")
9699
return
97100
end
98101

@@ -101,7 +104,7 @@ function M.buf_attach(force)
101104
end
102105

103106
if not M.config then
104-
vim.notify("[Copilot] Cannot attach: configuration not initialized", vim.log.levels.ERROR)
107+
logger.error("cannot attach: configuration not initialized")
105108
return
106109
end
107110

@@ -110,14 +113,14 @@ function M.buf_attach(force)
110113

111114
local ok, client_id_or_err = pcall(lsp_start, M.config)
112115
if not ok then
113-
vim.notify(string.format("[Copilot] Failed to start LSP client: %s", client_id_or_err), vim.log.levels.ERROR)
116+
logger.error(string.format("failed to start LSP client: %s", client_id_or_err))
114117
return
115118
end
116119

117120
if client_id_or_err then
118121
store_client_id(client_id_or_err)
119122
else
120-
vim.notify("[Copilot] LSP client failed to start (no client ID returned)", vim.log.levels.ERROR)
123+
logger.error("LSP client failed to start (no client ID returned)")
121124
end
122125
end
123126

@@ -138,21 +141,22 @@ end
138141
---@param callback fun(client:table):nil
139142
function M.use_client(callback)
140143
if is_disabled then
141-
print("[Copilot] Offline")
144+
logger.warn("copilot is offline")
142145
return
143146
end
144147

145148
local client = M.get() --[[@as table]]
146149

147150
if not client then
148151
if not M.config then
149-
error("copilot.setup is not called yet")
152+
logger.error("copilot.setup is not called yet")
153+
return
150154
end
151155

152156
local client_id, err = vim.lsp.start_client(M.config)
153157

154158
if not client_id then
155-
error(string.format("[Copilot] Error starting LSP Client: %s", err))
159+
logger.error(string.format("error starting LSP client: %s", err))
156160
return
157161
end
158162

@@ -169,7 +173,7 @@ function M.use_client(callback)
169173
local timer, err, _ = vim.loop.new_timer()
170174

171175
if not timer then
172-
error(string.format("[Copilot] Error creating timer: %s", err))
176+
logger.error(string.format("error creating timer: %s", err))
173177
return
174178
end
175179

@@ -191,15 +195,15 @@ local function prepare_client_config(overrides)
191195

192196
if vim.fn.executable(node) ~= 1 then
193197
local err = string.format("copilot_node_command(%s) is not executable", node)
194-
vim.notify("[Copilot] " .. err, vim.log.levels.ERROR)
198+
logger.error(err)
195199
M.startup_error = err
196200
return
197201
end
198202

199203
local agent_path = vim.api.nvim_get_runtime_file("copilot/dist/language-server.js", false)[1]
200204
if not agent_path or vim.fn.filereadable(agent_path) == 0 then
201205
local err = string.format("Could not find language-server.js (bad install?) : %s", tostring(agent_path))
202-
vim.notify("[Copilot] " .. err, vim.log.levels.ERROR)
206+
logger.error(err)
203207
M.startup_error = err
204208
return
205209
end
@@ -272,11 +276,14 @@ local function prepare_client_config(overrides)
272276
set_editor_info_params.authProvider = provider_url and {
273277
url = provider_url,
274278
} or nil
279+
280+
logger.debug("data for setEditorInfo LSP call", set_editor_info_params)
275281
api.set_editor_info(client, set_editor_info_params, function(err)
276282
if err then
277-
vim.notify(string.format("[copilot] setEditorInfo failure: %s", err), vim.log.levels.ERROR)
283+
logger.error(string.format("setEditorInfo failure: %s", err))
278284
end
279285
end)
286+
logger.trace("setEditorInfo has been called")
280287
M.initialized = true
281288
end)
282289
end,
@@ -299,6 +306,7 @@ local function prepare_client_config(overrides)
299306
copilotIntegrationId = "vscode-chat",
300307
},
301308
workspace_folders = workspace_folders,
309+
trace = config.get("trace") or "off",
302310
}, overrides)
303311
end
304312

@@ -339,12 +347,12 @@ end
339347

340348
function M.add_workspace_folder(folder_path)
341349
if type(folder_path) ~= "string" then
342-
vim.notify("[Copilot] Workspace folder path must be a string", vim.log.levels.ERROR)
350+
logger.error("workspace folder path must be a string")
343351
return false
344352
end
345353

346354
if vim.fn.isdirectory(folder_path) ~= 1 then
347-
vim.notify("[Copilot] Invalid workspace folder: " .. folder_path, vim.log.levels.ERROR)
355+
logger.error("invalid workspace folder: " .. folder_path)
348356
return false
349357
end
350358

@@ -379,9 +387,9 @@ function M.add_workspace_folder(folder_path)
379387
removed = {},
380388
},
381389
})
382-
vim.notify("[Copilot] Added workspace folder: " .. folder_path, vim.log.levels.INFO)
390+
logger.notify("added workspace folder: " .. folder_path)
383391
else
384-
vim.notify("[Copilot] Workspace folder added for next session: " .. folder_path, vim.log.levels.INFO)
392+
logger.notify("workspace folder will be added on next session: " .. folder_path)
385393
end
386394

387395
return true

lua/copilot/config.lua

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
local logger = require("copilot.logger")
2+
13
---@class copilot_config
24
local default_config = {
35
---@class copilot_config_panel
@@ -33,6 +35,17 @@ local default_config = {
3335
dismiss = "<C-]>",
3436
},
3537
},
38+
---@class copilot_config_logging
39+
logger = {
40+
log_to_file = false,
41+
file = vim.fn.stdpath("log") .. "/copilot-lua.log",
42+
file_log_level = vim.log.levels.WARN,
43+
print_log = true,
44+
print_log_level = vim.log.levels.WARN,
45+
---@type string<'off'|'messages'|'verbose'>
46+
trace_lsp = "off",
47+
trace_lsp_progress = false,
48+
},
3649
---@deprecated
3750
ft_disable = nil,
3851
---@type table<string, boolean>
@@ -52,12 +65,13 @@ local default_config = {
5265
}
5366

5467
local mod = {
68+
---@type copilot_config
5569
config = nil,
5670
}
5771

5872
function mod.setup(opts)
5973
if mod.config then
60-
vim.notify("[Copilot] config is already set", vim.log.levels.WARN)
74+
logger.warn("config is already set")
6175
return mod.config
6276
end
6377

@@ -80,7 +94,8 @@ end
8094
---@param key? string
8195
function mod.get(key)
8296
if not mod.config then
83-
error("[Copilot] not initialized")
97+
logger.error("not initialized")
98+
return
8499
end
85100

86101
if key then
@@ -94,7 +109,8 @@ end
94109
---@param value any
95110
function mod.set(key, value)
96111
if not mod.config then
97-
error("[Copilot] not initialized")
112+
logger.error("not initialized")
113+
return
98114
end
99115

100116
mod.config[key] = value

lua/copilot/init.lua

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
local M = { setup_done = false }
22
local config = require("copilot.config")
33
local highlight = require("copilot.highlight")
4+
local logger = require("copilot.logger")
5+
local client = require("copilot.client")
46

57
local create_cmds = function()
68
vim.api.nvim_create_user_command("CopilotDetach", function()
@@ -39,6 +41,11 @@ M.setup = function(opts)
3941
end
4042

4143
require("copilot.command").enable()
44+
logger.setup(conf.logger)
45+
46+
logger.debug("active plugin config:", config)
47+
-- logged here to ensure the logger is setup
48+
logger.debug("active LSP config (may change runtime):", client.config)
4249

4350
M.setup_done = true
4451
end

0 commit comments

Comments
 (0)