fix(sync): add backend name prefix to all OAuth log messages (#122)

* fix(sync): add backend name prefix to all OAuth log messages (#121)

Problem: four log messages in `oauth.lua` lacked the `self.name` backend
prefix, producing generic notifications instead of identifying which
backend (`gcal`/`gtasks`) triggered the message.

Solution: prepend `self.name .. ': '` to the four unprefixed messages
and drop the hardcoded "Google" from the browser prompt since `self.name`
already identifies the service.

* fix(sync): canonicalize all log prefixes across sync backends (#121)

Problem: log messages in `oauth.lua`, `gcal.lua`, `gtasks.lua`, and
`s3.lua` were inconsistent — some lacked a backend prefix, others used
sentence-case or bare error strings without identifying the source.

Solution: prefix all user-facing log messages with their backend name
(`gcal:`, `gtasks:`, `S3:`, `Google:`). Capitalize `S3` and `Google`
display names. Normalize casing and separator style (em dash) across
all sync log sites.
This commit is contained in:
Barrett Ruth 2026-03-10 11:26:16 -04:00
parent b9b0b233d9
commit dbf0ab1221
4 changed files with 44 additions and 44 deletions

View file

@ -159,7 +159,7 @@ function M.push()
oauth.with_token(oauth.google_client, 'gcal', function(access_token)
local calendars, cal_err = get_all_calendars(access_token)
if cal_err or not calendars then
log.error(cal_err or 'Failed to fetch calendars.')
log.error('gcal: ' .. (cal_err or 'failed to fetch calendars'))
return
end
@ -185,7 +185,7 @@ function M.push()
local del_err =
delete_event(access_token, cal_id --[[@as string]], event_id --[[@as string]])
if del_err then
log.warn('Failed to delete calendar event: ' .. del_err)
log.warn('gcal: failed to delete calendar event — ' .. del_err)
failed = failed + 1
else
unlink_remote(task, extra, now_ts)
@ -203,7 +203,7 @@ function M.push()
if event_id and cal_id then
local upd_err = update_event(access_token, cal_id, event_id, task)
if upd_err then
log.warn('Failed to update calendar event: ' .. upd_err)
log.warn('gcal: failed to update calendar event — ' .. upd_err)
failed = failed + 1
else
updated = updated + 1
@ -211,12 +211,12 @@ function M.push()
else
local lid, lid_err = find_or_create_calendar(access_token, cat, calendars)
if lid_err or not lid then
log.warn('Failed to create calendar: ' .. (lid_err or 'unknown'))
log.warn('gcal: failed to create calendar — ' .. (lid_err or 'unknown'))
failed = failed + 1
else
local new_id, create_err = create_event(access_token, lid, task)
if create_err then
log.warn('Failed to create calendar event: ' .. create_err)
log.warn('gcal: failed to create calendar event — ' .. create_err)
failed = failed + 1
elseif new_id then
if not task._extra then

View file

@ -267,7 +267,7 @@ local function push_pass(access_token, tasklists, s, now_ts, by_gtasks_id)
if allow_remote_delete() then
local err = delete_gtask(access_token, list_id, gtid)
if err then
log.warn('Failed to delete remote task: ' .. err)
log.warn('gtasks: failed to delete remote task — ' .. err)
failed = failed + 1
else
unlink_remote(task, now_ts)
@ -286,7 +286,7 @@ local function push_pass(access_token, tasklists, s, now_ts, by_gtasks_id)
if not synced_at or task.modified > synced_at then
local err = update_gtask(access_token, list_id, gtid, task_to_gtask(task))
if err then
log.warn('Failed to update remote task: ' .. err)
log.warn('gtasks: failed to update remote task — ' .. err)
failed = failed + 1
else
task._extra = task._extra or {}
@ -300,7 +300,7 @@ local function push_pass(access_token, tasklists, s, now_ts, by_gtasks_id)
if not err and lid then
local new_id, create_err = create_gtask(access_token, lid, task_to_gtask(task))
if create_err then
log.warn('Failed to create remote task: ' .. create_err)
log.warn('gtasks: failed to create remote task — ' .. create_err)
failed = failed + 1
elseif new_id then
if not task._extra then
@ -339,7 +339,7 @@ local function pull_pass(access_token, tasklists, s, now_ts, by_gtasks_id)
for list_name, list_id in pairs(tasklists) do
local items, err = list_gtasks(access_token, list_id)
if err then
log.warn('Failed to fetch task list "' .. list_name .. '": ' .. err)
log.warn('gtasks: failed to fetch task list "' .. list_name .. '" ' .. err)
failed = failed + 1
else
fetched_list_ids[list_id] = true
@ -414,7 +414,7 @@ end
local function sync_setup(access_token)
local tasklists, tl_err = get_all_tasklists(access_token)
if tl_err or not tasklists then
log.error(tl_err or 'Failed to fetch task lists.')
log.error('gtasks: ' .. (tl_err or 'failed to fetch task lists'))
return nil, nil, nil
end
local s = require('pending').store()

View file

@ -447,12 +447,12 @@ function OAuthClient:auth(on_complete)
end)
vim.ui.open(auth_url)
log.info('Opening browser for Google authorization...')
log.info(self.name .. ': Opening browser for authorization...')
vim.defer_fn(function()
if not server_closed then
close_server()
log.warn('OAuth callback timed out (120s).')
log.warn(self.name .. ': OAuth callback timed out (120s).')
end
end, 120000)
end
@ -490,14 +490,14 @@ function OAuthClient:_exchange_code(creds, code, code_verifier, port, on_complet
if result.code ~= 0 then
self:clear_tokens()
log.error('Token exchange failed.')
log.error(self.name .. ': Token exchange failed.')
return
end
local ok, decoded = pcall(vim.json.decode, result.stdout or '')
if not ok or not decoded.access_token then
self:clear_tokens()
log.error('Invalid token response.')
log.error(self.name .. ': Invalid token response.')
return
end
@ -540,7 +540,7 @@ M._BUNDLED_CLIENT_SECRET = BUNDLED_CLIENT_SECRET
M.BUNDLED_CLIENT_ID = BUNDLED_CLIENT_ID
M.google_client = M.new({
name = 'google',
name = 'Google',
scope = 'https://www.googleapis.com/auth/tasks' .. ' https://www.googleapis.com/auth/calendar',
port = 18392,
config_key = 'google',

View file

@ -69,7 +69,7 @@ end
local function create_bucket()
local name = util.input({ prompt = 'S3 bucket name (pending.nvim): ' })
if not name then
log.info('s3: bucket creation cancelled')
log.info('S3: bucket creation cancelled')
return
end
if name == '' then
@ -108,7 +108,7 @@ local function create_bucket()
.. '" } }'
)
else
log.error('s3: bucket creation failed — ' .. (result.stderr or 'unknown error'))
log.error('S3: bucket creation failed — ' .. (result.stderr or 'unknown error'))
end
end
@ -120,13 +120,13 @@ function M.auth(args)
if not input or input == '' then
local s3cfg = get_config()
if s3cfg and s3cfg.profile then
log.info('s3: current profile: ' .. s3cfg.profile)
log.info('S3: current profile: ' .. s3cfg.profile)
else
log.info('s3: no profile configured (using default)')
log.info('S3: no profile configured (using default)')
end
return
end
log.info('s3: set profile in your config: sync = { s3 = { profile = "' .. input .. '" } }')
log.info('S3: set profile in your config: sync = { s3 = { profile = "' .. input .. '" } }')
end)
return
end
@ -138,9 +138,9 @@ function M.auth(args)
if result.code == 0 then
local ok, data = pcall(vim.json.decode, result.stdout or '')
if ok and data then
log.info('s3: authenticated as ' .. (data.Arn or data.Account or 'unknown'))
log.info('S3: authenticated as ' .. (data.Arn or data.Account or 'unknown'))
else
log.info('s3: credentials valid')
log.info('S3: credentials valid')
end
local s3cfg = get_config()
if not s3cfg or not s3cfg.bucket then
@ -149,21 +149,21 @@ function M.auth(args)
else
local stderr = result.stderr or ''
if stderr:find('SSO') or stderr:find('sso') then
log.info('s3: SSO session expired — running login...')
log.info('S3: SSO session expired — running login...')
local login_cmd = base_cmd()
vim.list_extend(login_cmd, { 'sso', 'login' })
local login_result = util.system(login_cmd, { text = true })
if login_result.code == 0 then
log.info('s3: SSO login successful')
log.info('S3: SSO login successful')
else
log.error('s3: SSO login failed — ' .. (login_result.stderr or ''))
log.error('S3: SSO login failed — ' .. (login_result.stderr or ''))
end
elseif
stderr:find('Unable to locate credentials') or stderr:find('NoCredentialProviders')
then
log.error('s3: no AWS credentials configured. See :h pending-s3')
log.error('S3: no AWS credentials configured. See :h pending-s3')
else
log.error('s3: ' .. stderr)
log.error('S3: ' .. stderr)
end
end
end)
@ -176,10 +176,10 @@ end
function M.push()
util.async(function()
util.with_guard('s3', function()
util.with_guard('S3', function()
local s3cfg = get_config()
if not s3cfg or not s3cfg.bucket then
log.error('s3: bucket is required. Set sync.s3.bucket in config.')
log.error('S3: bucket is required. Set sync.s3.bucket in config.')
return
end
local key = s3cfg.key or 'pending.json'
@ -198,7 +198,7 @@ function M.push()
local f = io.open(s.path, 'r')
if not f then
log.error('s3: failed to read store file')
log.error('S3: failed to read store file')
return
end
local content = f:read('*a')
@ -206,7 +206,7 @@ function M.push()
local tf = io.open(tmpfile, 'w')
if not tf then
log.error('s3: failed to create temp file')
log.error('S3: failed to create temp file')
return
end
tf:write(content)
@ -218,22 +218,22 @@ function M.push()
os.remove(tmpfile)
if result.code ~= 0 then
log.error('s3: push failed — ' .. (result.stderr or 'unknown error'))
log.error('S3: push failed — ' .. (result.stderr or 'unknown error'))
return
end
util.finish(s)
log.info('s3: push uploaded to s3://' .. s3cfg.bucket .. '/' .. key)
log.info('S3: push uploaded to s3://' .. s3cfg.bucket .. '/' .. key)
end)
end)
end
function M.pull()
util.async(function()
util.with_guard('s3', function()
util.with_guard('S3', function()
local s3cfg = get_config()
if not s3cfg or not s3cfg.bucket then
log.error('s3: bucket is required. Set sync.s3.bucket in config.')
log.error('S3: bucket is required. Set sync.s3.bucket in config.')
return
end
local key = s3cfg.key or 'pending.json'
@ -245,7 +245,7 @@ function M.pull()
if result.code ~= 0 then
os.remove(tmpfile)
log.error('s3: pull failed — ' .. (result.stderr or 'unknown error'))
log.error('S3: pull failed — ' .. (result.stderr or 'unknown error'))
return
end
@ -256,7 +256,7 @@ function M.pull()
end)
if not load_ok then
os.remove(tmpfile)
log.error('s3: pull failed — could not parse remote store')
log.error('S3: pull failed — could not parse remote store')
return
end
@ -318,7 +318,7 @@ function M.pull()
os.remove(tmpfile)
util.finish(s)
log.info('s3: pull ' .. util.fmt_counts({
log.info('S3: pull ' .. util.fmt_counts({
{ created, 'added' },
{ updated, 'updated' },
{ unchanged, 'unchanged' },
@ -329,10 +329,10 @@ end
function M.sync()
util.async(function()
util.with_guard('s3', function()
util.with_guard('S3', function()
local s3cfg = get_config()
if not s3cfg or not s3cfg.bucket then
log.error('s3: bucket is required. Set sync.s3.bucket in config.')
log.error('S3: bucket is required. Set sync.s3.bucket in config.')
return
end
local key = s3cfg.key or 'pending.json'
@ -414,7 +414,7 @@ function M.sync()
local f = io.open(s.path, 'r')
if not f then
log.error('s3: sync failed — could not read store file')
log.error('S3: sync failed — could not read store file')
return
end
local content = f:read('*a')
@ -423,7 +423,7 @@ function M.sync()
local push_tmpfile = vim.fn.tempname() .. '.json'
local tf = io.open(push_tmpfile, 'w')
if not tf then
log.error('s3: sync failed — could not create temp file')
log.error('S3: sync failed — could not create temp file')
return
end
tf:write(content)
@ -435,13 +435,13 @@ function M.sync()
os.remove(push_tmpfile)
if push_result.code ~= 0 then
log.error('s3: sync push failed — ' .. (push_result.stderr or 'unknown error'))
log.error('S3: sync push failed — ' .. (push_result.stderr or 'unknown error'))
util.finish(s)
return
end
util.finish(s)
log.info('s3: sync ' .. util.fmt_counts({
log.info('S3: sync ' .. util.fmt_counts({
{ created, 'added' },
{ updated, 'updated' },
}) .. ' | push uploaded')