可观测性

带脱敏的日志、诊断、可选的崩溃上报与分析。

本模板附带四层可观测性,全部按"默认安全"接线:带自动脱敏的日志、用于错误报告的 诊断数据、一个可选加入的崩溃上报插槽,以及一个可选加入的分析插槽。除非你完成 配置并且用户选择加入,否则没有任何东西离开设备。

日志

lib/main/logger.ts 封装了 electron-log。文件传输以 info 记录,控制台传输以 debug 记录,日志文件上限为 5 MB。startCatching 还会把 未捕获的主进程错误引流到可选的崩溃上报器。

writeLog 写日志,它会为每一行标注来源:

import { writeLog } from '@/lib/main/logger'

writeLog({ level: 'warn', message: 'Retry scheduled', context: { attempt: 2 }, source: 'main' })

渲染进程的日志经由 app-log Conveyor 通道转发,落入同一个文件并标注 [renderer] ——而且它们的 context 在进入时会被脱敏(见下文)。日志文件位置遵循 electron-log 的默认值:

操作系统路径
macOS~/Library/Logs/<AppName>/main.log
Windows%USERPROFILE%\AppData\Roaming\<AppName>\logs\main.log
Linux~/.config/<AppName>/logs/main.log

应用内的日志页面(app/routes/LogsPage.tsxlogs Conveyor 领域)会显示 解析出的路径和一个"打开日志文件夹"按钮(logs-open-folder),这样提交报告的 用户无需了解操作系统惯例也能找到文件。

脱敏

lib/main/log-redact.ts 是一个卖点:它会把秘密从任何将被记录、放入诊断或发往 崩溃上报器的内容中擦除。redactSensitive 会遍历字符串、对象、数组与 Error (防循环),并替换命中项:

模式命中
敏感passwordsecrettokenapikey / api_keyauthcookiesessioncredentialpin → 值变为 [redacted]
敏感上述同类术语的 key: value / key=value 键值对。
Bearer 令牌bearer <token>bearer [redacted]
URL 中的凭据https://user:pass@hosthttps://[redacted]@host

它被应用在秘密可能泄露的边界处:渲染进程的日志 context(app-log handler 中的 redactContext)、诊断数据,以及崩溃上报器的 beforeSend。这意味着日志行里的 一个漏网令牌、或诊断字段里的一个签名 URL,都会在被持久化或传输之前被剥除。

诊断

lib/main/diagnostics.ts 汇集一份构建与运行时元数据:应用名/版本/提交/构建时间、 Electron/Chromium/Node/V8 版本、操作系统平台/发行版/架构,以及日志路径。整份数据 在跨越 IPC 之前都会经过 redactSensitive,因此任何日后开始携带秘密的字段都会被 防御性地剥除。

关于页面通过 app-get-diagnostics 读取它,并提供一个"复制诊断信息"按钮—— 用户可以把这段(已脱敏的)确切文本粘贴到错误报告里。

崩溃上报(可选加入插槽)

错误上报是一个可选加入插槽,在两件事同时成立前保持熄灭:配置了 DSN 用户已选择加入。lib/main/error-reporting.tsErrorReportingService)集成了 可选的 @sentry/electron

  • DSN 来自 MAIN_VITE_SENTRY_DSN(主进程构建变量)或 SENTRY_DSN 运行时 环境变量。没有 DSN → 服务处于惰性状态。
  • 同意settings.errorReportingOptIn(默认关闭,在高级设置标签页切换)。 若它为关闭,initialize()report() 都会直接返回。
  • Sentry SDK 通过一个受保护的动态 require 加载,因此若这个可选依赖未安装, 服务会记录一条警告并保持熄灭,而不是崩溃。
  • sendDefaultPii: false 以及一个运行 redactSensitivebeforeSend 让被 捕获的事件保持已擦除。

主进程崩溃(经由日志器的 startCatching)与渲染进程错误(经由 app-report-renderer-error 通道转发到 reportRendererError)都会流入同一个 插槽。

产品分析(可选加入插槽)

app/services/analytics.ts 是第二个刻意做薄的可选加入插槽——与错误插槽相互独立。 默认不附带任何分析提供方;买家把它指向自己的采集器。除非以下两点同时成立, 否则它是彻底的空操作:

  1. 构建时设置了 VITE_ANALYTICS_ENDPOINTanalyticsConfig.configured),且
  2. 用户选择加入(settings.analyticsOptIn,默认关闭)。

启用后,track() / page() 会以"发后不理"的方式向该端点发一个 JSON POST (可携带一个可选的 VITE_ANALYTICS_WRITE_KEY bearer 令牌,keepalive: true)。 事件只携带调用方传入的内容外加一个本地生成的匿名 id——绝不包含 Supabase 会话、 JWT、邮箱或文件路径。网络失败会被吞掉,因此分析绝不会干扰应用。

两个可选加入插槽都默认关闭并以熄灭状态出厂。开启它们是一个刻意且有记录的动作 ——先设置环境变量/DSN,再尊重用户在高级标签页的同意。参见 环境变量

渲染进程错误体验

两个 React 错误边界外加一个带主题的错误路由,让渲染进程的失败不至于变成一个 空白窗口:

  • RouterErrorBoundaryapp/app.tsx)捕获路由树内的错误,并可通过导航恢复。
  • ErrorBoundaryapp/renderer.tsx)是包裹整个应用的最后兜底。
  • ErrorPage/error)是为路由错误显示的带主题界面。

渲染进程错误同样会被记录,并(在插槽开启时)被上报,因此一次崩溃既对用户可见, 也为你所捕获。

相关页面

On this page