@arms/rum-electron
v0.0.3
Published
ARMS RUM SDK for Electron (monitoring layer; implementation pending)
Downloads
268
Readme
@arms/rum-electron
阿里云 ARMS 用户体验监控 Electron SDK。一次主进程 init() 即覆盖主进程与渲染进程:自动采集异常、原生崩溃、HTTP/tRPC、应用启动指标、页面 PV、性能、Web Vitals 等数据,由主进程统一上报。
核心特性
- 零配置自动注入:主进程
init()后,所有BrowserWindow自动注入 Browser SDK 与 IPC Bridge,渲染进程零改造 - 统一上报通道:渲染进程事件经
arms:rum-bridgeIPC 通道回流至主进程,由主进程统一组织与上报 - 主进程监控全覆盖:
- 未捕获异常、未处理 Promise 拒绝、
console.error拦截 - 原生崩溃(集成 WASM
minidump-processor,解析.dmp获取完整堆栈与模块) - 应用启动指标(
app ready耗时、进程数、主进程 CPU/内存) globalThis.fetch全局 patch,自动产出type='api'资源事件- tRPC server 端 procedure 调用(
type='rpc'),通过armsRum.instrumentTRPC()一行接入
- 未捕获异常、未处理 Promise 拒绝、
- 渲染进程自动注入:PV、性能、Web Vitals、白屏、API、长任务等
- 分布式链路追踪:内置
tracing配置,支持 W3C tracecontext / B3 / B3 multi / Jaeger / SW8;主进程 fetch 与 tRPC procedure 共享同一份决策 - 远程配置:支持 ARMS 控制台下发配置,动态调整采样率、采集器开关等
安装
npm install @arms/rum-electron| 依赖 | 版本要求 | 说明 |
|------|----------|------|
| electron | >= 28.0.0 | peerDependency(optional),由项目自行安装 |
| @trpc/server | * | 仅在使用 instrumentTRPC() 时由业务侧安装(optional peer) |
需要 Electron 28+ 是因为 SDK 使用
session.registerPreloadScript()(v28 新增),低版本会自动回退到session.setPreloads()。
快速接入
1. 主进程顶层 import 并 init()
SDK 必须在 app.ready 之前被 import——src/index.ts 顶层会调用 protocol.registerSchemesAsPrivileged() 注册 rum-event 协议(占位用,预留给后续降级通道,不影响功能)。
// main/index.ts —— 文件顶部
import armsRum from '@arms/rum-electron';
import { app } from 'electron';
armsRum.init({
endpoint: '<your-endpoint>', // 控制台「用户体验监控 > 应用列表」创建应用后获取
env: 'prod', // 'prod' | 'gray' | 'pre' | 'daily' | 'local'
version: '1.0.0',
});
app.whenReady().then(() => {
// 创建 BrowserWindow 等
});2. 渲染进程零改造
默认 autoInject: true:SDK 监听 web-contents-created,在每个 BrowserWindow 的 dom-ready 时机注入 Browser SDK 脚本与 IPC Bridge。渲染进程既不需要 import SDK,也不需要修改 preload。
3.(可选)验证数据
armsRum.init({
endpoint: '<your-endpoint>',
beforeReport(bundle) {
console.log('[RUM]', bundle);
return bundle; // 返回 undefined 不会丢弃;若需丢弃请显式处理
},
});4.(可选)自定义 partition
BrowserWindow 使用了自定义 partition(如 'persist:main')时,必须显式声明,否则该 partition 下的窗口不会注入 IPC Bridge:
// 方式一:init 时声明(单 partition 推荐)
await armsRum.init({
endpoint: '<your-endpoint>',
partition: 'persist:main',
});
// 方式二:init 之后动态注册(多 partition 场景)
await armsRum.init({ endpoint: '<your-endpoint>' });
await armsRum.registerSession('persist:other');5.(可选)启用 tRPC 监控
主进程使用 tRPC 定义 server router 时(如 electron-trpc),用 armsRum.instrumentTRPC() 包一层 t,所有 procedure 自动带监控 middleware:
import { initTRPC } from '@trpc/server';
import armsRum from '@arms/rum-electron';
const t = armsRum.instrumentTRPC(initTRPC.create());
export const appRouter = t.router({
greeting: t.procedure.input(...).query(...),
});详见 docs/接入tRPC监控.md。
主进程作为 tRPC client 调用云端 HTTP 服务时无需额外接入:底层 fetch 会被
ApiCollector自动采集为type='api'事件。
配置一览
init(config) 接收 IElectronConfig,继承自 @arms/rum-core 的 IConfiguration。下表为常用字段,完整版见 docs/Electron SDK配置参考.md。
基础
| 字段 | 类型 | 必填 | 默认值 | 说明 |
|------|------|------|--------|------|
| endpoint | string | 是 | — | ARMS 数据上报地址 |
| enable | boolean | 否 | true | 关闭后所有采集器与上报均不工作 |
| env | 'prod' \| 'gray' \| 'pre' \| 'daily' \| 'local' \| string | 否 | — | 应用环境标识 |
| version | string | 否 | — | 应用版本号 |
| app | object | 否 | — | 应用扩展信息(name / channel / framework 等) |
| user | object | 否 | — | 用户信息(id / name / tags) |
Electron 专属
| 字段 | 类型 | 默认值 | 说明 |
|------|------|--------|------|
| autoInject | boolean | true | 是否自动向 BrowserWindow 注入 Browser SDK |
| partition | string | — | 自定义 session partition;与 BrowserWindow.webPreferences.partition 对应 |
| spaMode | false \| true \| 'auto' \| 'hash' \| 'history' | false | SPA 路由追踪模式 |
| tracing | boolean \| ITracingOption | — | 分布式链路追踪(主进程 fetch + tRPC procedure 共用) |
| evaluateApi | (request, response, error?) => Promise<IApiBaseAttr> | — | 自定义 API/RPC payload 解析,返回值经 reviseApiAttr 裁剪后合并 |
| parseViewName | (url: string) => string | — | 自定义页面 name 解析(兜底用 SpaMode 解析 URL) |
| parseResourceName | (url: string) => string | — | 自定义资源 name 解析;默认取 URL pathname |
| beforeReport | (bundle) => any | — | 上报前回调,可改写 bundle |
| browserCollectors | Record<string, boolean \| ICollectorConfig> | 全部启用 | 渲染进程 Browser SDK 采集器开关(仅 autoInject 模式生效) |
| properties | Record<string, number \| string> | — | 全局自定义属性,附加到所有上报事件 |
主进程采集器(collectors)
armsRum.init({
endpoint: '<your-endpoint>',
collectors: {
crash: false, // 关闭崩溃采集
consoleError: false, // 关闭 console.error 拦截
api: {
enable: true,
filters: [/\.internal\.example\.com/], // 命中即不上报
},
rpc: {
enable: true,
filters: [/^internal\./], // 按 procedure path 跳过
},
},
});| 采集器 | 默认 | 说明 |
|--------|------|------|
| jsError | true | 主进程未捕获异常 + 未处理 Promise 拒绝 |
| consoleError | true | console.error 拦截上报 |
| crash | true | 原生崩溃采集(依赖 crashReporter) |
| application | true | 应用启动指标 |
| api | true | 主进程 globalThis.fetch patch(type='api') |
| rpc | true | tRPC server middleware(配合 instrumentTRPC,type='rpc') |
渲染进程采集器(browserCollectors)
autoInject: true 时控制注入到渲染进程的 Browser SDK 采集器:
| 采集器 | 说明 |
|--------|------|
| perf | 页面加载性能 |
| webvitals | Web Vitals(LCP / FID / CLS) |
| exception | 未捕获异常 + Promise 拒绝 |
| whiteScreen | 白屏检测 |
| api | XHR / Fetch HTTP 请求 |
| staticResource | 静态资源加载 |
| click / action | 用户交互 |
| longTask | 长任务(>50ms) |
armsRum.init({
endpoint: '<your-endpoint>',
browserCollectors: {
longTask: false,
whiteScreen: false,
api: { enable: true },
},
});链路追踪(tracing)
armsRum.init({
endpoint: '<your-endpoint>',
tracing: {
enable: true,
sample: 10, // 10% 采样(取值 0–100)
propagatorTypes: ['tracecontext', 'b3'],
allowedUrls: [/^https:\/\/api\.example\.com/], // 仅向白名单注入追踪头
},
});| 字段 | 类型 | 说明 |
|------|------|------|
| enable | boolean | 是否启用链路追踪 |
| sample | number | 采样率,取值 0–100(默认 100) |
| propagatorTypes | Array<'tracecontext' \| 'b3' \| 'b3multi' \| 'jaeger' \| 'sw8'> | 传播协议 |
| allowedUrls | Array<MatchOption \| TraceOption> | 命中规则的 URL/path 才会注入追踪头;未配置时默认全量命中 |
| tracestate / baggage | boolean | 是否携带 W3C tracestate / baggage |
主进程 fetch(ApiCollector)与 tRPC procedure(RpcCollector)共用同一份 tracing 决策,自动在 outbound 请求注入 traceparent 等头。
evaluateApi:把 payload 写入 snapshots
evaluateApi 用于把请求/响应内容写入事件。SDK 不会自动采集 payload——业务侧按需提取并经返回值 snapshots 上报,SDK 自动经 reviseApiAttr 裁剪至 5KB:
armsRum.init({
endpoint: '<your-endpoint>',
async evaluateApi(request, response, error) {
const snapshot: Record<string, unknown> = {};
if (request && typeof request === 'object' && 'input' in request) {
snapshot.input = (request as { input?: unknown }).input;
}
if (response && typeof response === 'object' && 'data' in response) {
snapshot.output = (response as { data?: unknown }).data;
}
return {
success: error ? 0 : 1,
snapshots: JSON.stringify(snapshot),
};
},
});字段约定:
snapshots留给 SDK /evaluateApi写采集元数据,properties保留给用户业务标签。回调有 50ms 超时硬限,超时后回退到原始事件。
运行时 API
// 修改单个字段
armsRum.setConfig('enable', false);
// 批量修改
armsRum.setConfig({ env: 'staging', version: '1.1.0' });
// 读取当前完整配置
const config = armsRum.getConfig();
// 为额外的 partition 注册 preload(init 之后调用)
await armsRum.registerSession('persist:other');
// 一行接入 tRPC server 监控(需 @trpc/server)
const t = armsRum.instrumentTRPC(initTRPC.create());注意事项
init()必须在app.ready之前调用,且 SDK 模块本身必须更早被import——src/index.ts顶层调用protocol.registerSchemesAsPrivileged(),错过ready之前的窗口会导致协议注册失败并触发 Electron 警告。- Electron 版本
>= 28:SDK 优先使用session.registerPreloadScript()(v28 新增),低版本自动降级到session.setPreloads()。 - 不要覆盖 SDK 注册的 preload:若应用层调用
session.setPreloads()覆盖全部 preload,渲染进程事件将无法回流。建议使用追加方式。 autoInject: true模式下禁止在渲染进程手动import '@arms/rum-electron/browser':会导致重复初始化与事件双采。- 自定义 partition 必须显式声明:未声明的 partition 下的窗口里
window.ArmsEventBridge为undefined,RUM 数据无法上报。 evaluateApi内禁止同步阻塞:回调有 50ms 超时硬限,超时后回退到原始事件不抛错。- tRPC 监控仅采 server 端:主进程作为 tRPC client 调用云端 HTTP 时由
ApiCollector在 fetch 层自动采集为type='api',不需要再包 link。
