Univer 遥测服务接入指南:基于 @univerjs/telemetry 的ITelemetryService接口实现与注册
【免费下载链接】univerUniver is a full-stack framework for creating and editing spreadsheets / word processor / presentation on both web and server.项目地址: https://gitcode.com/GitHub_Trending/un/univer
@univerjs/telemetry是 Univer 生态中专用于定义遥测(Telemetry)服务契约的基础包,它本身不包含任何采集逻辑,而是为 Univer 各功能包提供统一的「事件上报接口」,由应用侧自行实现并注册。本文以该包的 README.md 为骨架,结合 telemetry.service.ts 的接口源码、sheet.render-controller.ts 的真实消费示例以及 Univer 的依赖注入(DI)机制,完整讲解如何安装、实现、注册并使用这一接口,从而在不侵入源码的前提下采集渲染性能、用户行为等诊断数据。
包概览:一个纯接口包
| 包名 | UMD 全局变量 | CSS | Locales | Facade 入口 |
|---|---|---|---|---|
@univerjs/telemetry | UniverTelemetry | 无 | 无 | 无 |
从 package.json 可以确认它的定位:
- 当前版本为
1.0.0-beta.2,许可证为 Apache-2.0; - 运行时依赖仅有
@univerjs/core(用于createIdentifier等 DI 基础设施),除此之外不依赖任何 UI、渲染或业务模块; keywords为univer / telemetry / analytics / events / service,是典型的「纯类型 + 接口」声明包;- 构建产物同时提供
lib/es/index.js(ESM)与lib/cjs/index.js(CJS),并带有lib/types/index.d.ts类型声明,可被现代打包器与 Node.js 环境直接引用。
整个包的源码结构非常精简,只有两个文件:
- src/index.ts:唯一入口,
export * from './services/telemetry.service'; - src/services/telemetry.service.ts:
ITelemetryService接口与标识符的全部定义。
包不提供 CSS、语言包(Locales)和 Facade 入口,因为它完全不涉及 UI 渲染——它只负责「把事件从 Univer 内部送到你的上报管道」。
安装与版本一致性
pnpm add @univerjs/telemetry # 或 npm install @univerjs/telemetry安装后应保持所有@univerjs/*包处于同一版本,这是 Univer 官方对 monorepo 发布包的一贯要求——不同包之间通过workspace:*约束内部依赖(见 package.json 的dependencies字段),版本不一致会导致 DI 标识符或类型在编译期/运行期错位。
接口定义:ITelemetryService的九个方法
包的核心资产是ITelemetryService接口,定义于 telemetry.service.ts。它通过createIdentifier<ITelemetryService>('telemetry.service')生成 DI 标识符,在 Univer 的依赖注入体系中作为「抽象服务」被其他包消费。接口共声明九个方法,覆盖了遥测的典型生命周期:
| 方法 | 签名 | 用途 |
|---|---|---|
debug | debug: () => void | 开启调试模式,便于联调时输出遥测日志 |
init | init: (options?: object) => void | 初始化遥测服务,如初始化 SDK、传入上报配置 |
identify | identify: (id: string, params?: object) => void | 标识当前用户,id为用户唯一标识,可附带params自定义属性 |
reset | reset(): void | 重置当前用户会话(如用户登出) |
capture | capture: (eventName: string, params?: object) => void | 记录一个具名事件,params为该事件的附加字段 |
startTime | startTime: (functionName: string) => void | 以函数名为键启动计时器 |
endTime | endTime: (functionName: string) => void | 结束对应计时器 |
trackPerformance | trackPerformance: (params: { duration: number; functionName: string; [prop: string]: unknown }) => void | 上报一段耗时指标,duration与functionName为必填,其余字段开放扩展 |
onPageView | onPageView: (url: string) => void | 上报页面浏览事件 |
几个值得注意的设计细节:
- 方法与属性混用:
init/identify/capture/startTime/endTime/trackPerformance/onPageView是箭头函数属性(method: () => void),而debug同样为属性式;reset则是普通方法(reset(): void)。实现时两种写法皆可,语义上reset更强调「可被解构调用」。 - 宽松的载荷类型:除
trackPerformance对duration(毫秒数)和functionName有明确要求外,其余方法的附加参数均为object或开放索引的unknown,意味着你可以携带任意自定义字段,无需为每种事件预定义强类型。 - 接口即契约:该接口刻意保持精简,没有任何与具体采集厂商(如 Sentry、PostHog、自研埋点)绑定的字段,便于按需适配。
注册服务:利用 Univer 的依赖覆盖(override)机制
@univerjs/telemetry本身不注册任何默认实现——它在 Univer 的默认注入器中并不存在。这带来一个关键特性:Univer 各功能包对它的注入全部采用「可选注入」(见下文),因此你不注册它也完全不影响功能;一旦注册,遥测能力即刻生效。
推荐的注册方式是利用Univer构造配置中的override字段。在 univer.ts 中,IUniverConfig声明了override?: DependencyOverride,其语义在 plugin-override.ts 中定义:按[标识符, { useClass: 实现类 }]的元组覆盖默认依赖,若第二个元素为null则移除原依赖。因此注册遥测实现的标准写法如下:
import { Univer } from '@univerjs/core'; import { ITelemetryService } from '@univerjs/telemetry'; import { MyTelemetryService } from './my-telemetry-service'; const univer = new Univer({ // 其余配置…… override: [ [ITelemetryService, { useClass: MyTelemetryService }], ], });mergeOverrideWithDependencies会遍历 Univer 核心的默认依赖列表,凡是标识符命中的条目一律替换为你提供的实现(见 plugin-override.ts 的实现逻辑)。对于在@univerjs/telemetry中通过createIdentifier创建的标识符,这一覆盖机制完全适用。
如果你的实现需要访问 Univer 的注入器(例如读取IConfigService),也可以通过univer.__getInjector()拿到注入器后调用injector.add([ITelemetryService, { useClass: MyTelemetryService }])完成注册——这是 univer.ts 暴露的内部 API,测试代码与 Facade(见 f-univer.ts)均采用同样方式获取注入器。
消费实践:sheets-ui 如何上报渲染耗时
为了理解该接口的实际价值,可以看一个真实的消费方示例:SheetRenderController 是电子表格渲染控制器,它在构造函数中通过装饰器进行可选注入:
@Optional(ITelemetryService) private readonly _telemetryService?: ITelemetryService关键点在于@Optional——即使应用没有注册任何遥测实现,控制器也不会因依赖缺失而崩溃;而在注册后,_telemetryService便可用。这解释了为什么@univerjs/telemetry能作为「可选增强」横跨整个生态:注册即生效,不注册零成本。
该控制器的上报逻辑位于 _captureRenderMetric,流程清晰展示了遥测接口的典型用法:
- 采集:订阅渲染引擎的
_afterRenderMetric$与endFrame$,逐帧收集FPS、elapsedTime、frameTime以及各渲染扩展(键名以SHEET_EXTENSION_PREFIX开头)的耗时; - 聚合:攒够
FRAME_STACK_THRESHOLD(值为 60)帧后,对数组型字段求和,再对每个数值字段计算max / min / avg,并保留两位小数; - 上报:拼装包含
sheetId、unitId、elapsedTimeToStart及汇总统计的telemetryData,调用:
this._telemetryService?.capture('sheet_render_cost', telemetryData);也就是说,只要注册了ITelemetryService实现,Univer 的表格渲染器就会自动以约 60 帧为一批,通过capture事件'sheet_render_cost'上报渲染性能摘要。这为线上性能监控(如 FPS 分布、单帧耗时)提供了开箱即用的数据源,无需改动任何业务源码。
一个最小实现示例
基于上述契约,一个极简的「控制台遥测」实现大致如下:
import { ITelemetryService } from '@univerjs/telemetry'; export class ConsoleTelemetryService implements ITelemetryService { debug(): void { // 在 debug 模式下输出详细信息 } init(_options?: object): void { // 初始化上报 SDK(如设置采集地址、采样率) } identify(id: string, params?: object): void { console.log('[telemetry] identify', id, params); } reset(): void { console.log('[telemetry] reset user'); } capture(eventName: string, params?: object): void { console.log('[telemetry] capture', eventName, params); } startTime(functionName: string): void { performance.mark(`${functionName}:start`); } endTime(functionName: string): void { performance.measure(functionName, `${functionName}:start`, `${functionName}:end`); } trackPerformance(params: { duration: number; functionName: string; [prop: string]: unknown }): void { console.log('[telemetry] performance', params); } onPageView(url: string): void { console.log('[telemetry] pageView', url); } }将ConsoleTelemetryService通过上文override方式注册后,打开任意包含电子表格的页面,即可在控制台观察到sheet_render_cost事件及其携带的帧统计字段——这是验证整条链路是否打通的最快方式。
注意事项
- 接口的必实现性:
ITelemetryService是一个普通 TypeScript 接口而非抽象类,所有九个成员都需要实现类完整提供,否则会在编译期报错;若用as any绕过类型检查,运行期调用缺失方法时会抛出TypeError。 - 可选注入的广泛性:包括 sheets-ui 渲染控制器在内的多个 Univer 包都以
@Optional(ITelemetryService)方式注入该服务,因此实现类应做好「应用可能在任何时机调用任意方法」的防御式设计。 - 标识符来源:
ITelemetryService既是类型也是值——作为标识符,它由createIdentifier('telemetry.service')生成(见 telemetry.service.ts),该工具由@univerjs/core从@wendellhu/redi重新导出(见 di.ts),这意味着你在自定义插件中同样可以按此模式定义自己的遥测扩展标识符。
小结
@univerjs/telemetry用不到一百行代码,为 Univer 建立了一条「定义契约 → 应用实现 → 可选注入 → 自动上报」的完整遥测通道:包本身只提供ITelemetryService接口与 DI 标识符,应用侧通过override配置注入任意实现,而 Univer 各功能包(如电子表格渲染器)在内部以@Optional方式消费,自动上报sheet_render_cost等诊断事件。对需要精细化运营与性能监控的 Univer 应用而言,接入它仅需「一个实现类 + 一行 override 配置」,是成本最低、侵入性最小的遥测方案。
【免费下载链接】univerUniver is a full-stack framework for creating and editing spreadsheets / word processor / presentation on both web and server.项目地址: https://gitcode.com/GitHub_Trending/un/univer
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考