可用onDidChangeActiveTextEditor和onDidChangeTextDocument监听编辑行为,结合空闲计时器估算有效工时;上报仅限脱敏后的languageId、durationSec等安全字段,并异步队列重试。

如何用 VSCode 插件监听编辑器活动来估算工时
VSCode 本身不记录“实际工作时间”,但可通过 onDidChangeTextDocument、onDidChangeActiveTextEditor 和 setInterval 组合,近似捕捉「有代码编辑行为的活跃时段」。关键不是精确到秒,而是排除长时间闲置(比如查文档、开会)导致的虚高统计。
实操建议:
- 用
vscode.window.onDidChangeActiveTextEditor捕获切换文件动作,作为「进入工作上下文」信号 - 用
vscode.workspace.onDidChangeTextDocument监听内容变更,重置空闲计时器(比如 60 秒无变更即标记为暂停) - 避免仅靠
onDidChangeTextDocument单独计时——用户粘贴大段代码可能只触发一次事件,但实际耗时几分钟 - 每次「活跃块」结束时,生成一条带
start、end、uri、languageId的记录,暂存内存或本地~/.vscode/worklog.json
上报数据前必须处理的隐私与合规风险
直接上报 document.getText() 或完整文件路径是高危操作:可能泄露公司内部路径结构、项目名、甚至敏感字符串(如 API key 被误写在注释里)。VSCode 插件默认无网络权限,需显式声明 "permissions": ["webview", "http://*"],而审核方会重点检查上报内容。
安全做法:
- 上报字段严格限定为:匿名化
workspaceFolder.name(如"proj-abc123")、languageId、durationSec、lineCount(取document.lineCount,非全文)、charCount(同理) - 绝对禁止上报
document.fileName全路径;可用path.basename(uri.fsPath)+ 哈希脱敏(如crypto.createHash('sha256').update(basename).digest('hex').slice(0,8)) - 首次启用插件时,弹出
vscode.window.showInformationMessage明确告知「仅上报语言类型与编辑时长,不采集代码内容」,并提供开关配置项worklog.enableTelemetry
为什么不能依赖 VSCode 的 debug 或 task 生命周期事件
有人想用 vscode.debug.onDidStartDebugSession 或 vscode.tasks.onDidStartTask 来标记「正式工作开始」,这在多数场景下不可靠:
- 前端开发常全程开着 dev server,
npm run dev启动后就不再触发onDidStartTask,但后续改 CSS、JS 仍属有效工时 - 调试会话(debug session)可能持续数小时,但真正单步调试只占其中 5 分钟;按 session 时长统计会导致严重失真
-
onDidStartTask不触发于手动保存(Ctrl+S)、格式化(Shift+Alt+F)等高频操作,漏掉大量真实编辑行为 - 真正稳定可依赖的只有编辑器焦点(
onDidChangeActiveTextEditor)和文档变更(onDidChangeTextDocument)这两个底层事件
上报失败时的本地缓存与重试策略
网络不可靠是常态。若每次上报都同步等待 HTTP 响应,会卡住 VSCode 主线程,引发「Extension Host Terminated」错误。必须异步 + 持久化 + 退避重试。
具体实现要点:
- 所有上报请求走
vscode.workspace.fs.writeFile先写入本地~/.vscode/worklog-queue/下的 JSONL 文件(每行一条记录),再由独立的setTimeout定时任务批量读取发送 - 发送失败时,把该行重新写回队列文件,并在文件名中加入重试次数标识(如
queue-20240520-2.jsonl),避免无限重试压垮服务端 - 重试间隔采用指数退避:
Math.min(1000 * Math.pow(2, attempt), 30000)(上限 30 秒) - 每天凌晨自动清理 7 天前的队列文件,防止磁盘占满;清理前校验文件大小,超过 10MB 则拆分
最易被忽略的是队列文件的原子写入——务必用 vscode.workspace.fs.writeFile(uri, Buffer.from(jsonLine + '\n', 'utf8')),而非 Node.js 原生 fs.appendFile,否则多实例 VSCode 同时写入会损坏文件。


















