远程配置
lens 的白名单、采样率、错误分级、熔断等都不写在代码里,而是托管在 CDN 上的一份 JSON(configUrl)。运营 / 数据团队改完上传 CDN 即生效,无需发版。
const trace = new TripoLens({
app: 'shop',
configUrl: 'https://cdn.example.com/trace/whitelist.json', // ← 这份 JSON
endpoint: 'https://gateway.example.com/v2/trace/events',
});加载与降级(fail-open)
init() 会在装配插件前拉取一次配置。这一步有界、永不抛错、永不阻塞 init,失败按三层降级:
拉取远程配置
│ GET configUrl(credentials: omit,3 秒有界超时)
│
├─ 成功且 JSON 合法 ──► 用远程配置,并异步写入本地缓存(带时间戳)
│
└─ 失败 / 超时 / 版本不识别 / 必填字段非法
│ (经 onError 通知,phase: 'config')
├─ 本地缓存命中且未超 24h ──► 用上次成功的缓存版本
└─ 否则 ────────────────────► 用内置默认配置内置默认配置是「最低可用」:killSwitch 关、白名单为空(fail-open:白名单空时上报所有带 utm_source 的访问)。
| 机制 | 值 | 说明 |
|---|---|---|
| 拉取超时 | 3000 ms | 慢 / 挂死的 CDN 不拖死 init,超时即降级 |
| 缓存 TTL | 24 小时 | 超龄缓存弃用,避免远端长期故障时永用陈旧配置 |
| 识别的 version | 1、2 | v2 为终态;v1 仅版本号兼容解析 |
fail-open 与 killSwitch 是两回事
fail-open 是「配置拿不到时不放弃上报」的容错策略——CDN 挂了也不丢数据。 killSwitch 是配置里的显式熔断开关——true 时 SDK 完全不上报,用于线上紧急止血。两者方向相反,别混淆。
坏字段丢弃、不抛错
解析容错:只有 version 缺失/不识别、或 killSwitch 不是布尔,才判定整份配置非法走降级;其余字段坏值就丢弃该字段、走该字段的缺省,不会因为某个可选字段写错而拖垮整份配置。
配置 schema(v2)
完整字段如下(* 为必填)。除 version / killSwitch / 白名单外都可省略:
{
"version": 2, // * SDK 信任的 schema 版本(1 或 2)
"killSwitch": false, // * 全局熔断;true = 完全不上报
"utm": {
"utmSource": ["baidu", "google", "bytedance"]
}, // 渠道白名单(小写)
"breadcrumb": { "max": 10 }, // 面包屑缓冲条数上限(默认 10)当前只有错误上报有携带
"control": { // 上报控制(采样值均为 '1'-'10' 字符串 → 10%-100%,无 '0' 档)
"poll": "5000", // 聚合上报轮询间隔 ms(字符串)
"performance": "1", // 性能整体采样率 '1'-'10' → 0.1-1.0('1'=10% 最低档)
"tech": { "key": "shop.Perf", "val": "5" }, // 技术域坐标级采样;key 仅 <app>.Error / <app>.Perf 两种坐标(后缀大小写敏感),填 "shop" 可前缀通配两者
"custom": { "key": "shop.home", "val": "10" } // 行为域坐标级采样;key 为埋点 TracePath 前缀(另含 <app>.Identity / <app>.Landing)
},
"error": { // 错误监控控制
"errorLevels": { // 远端分级规则,按错误子类分组
"js": [
{
"conditions": [
{ "field": "message", "operator": "contains", "value": "ResizeObserver" }
],
"level": "record"
}
]
},
"filter": { // 远端前置过滤(命中即整条丢弃)
"js": ["^Script error\\.?$"],
"promise": [],
"resource": [],
"api": ["/healthz"],
"ua": ["bot|spider"],
"limitDomain": ["^https://([a-z0-9-]+\\.)?example\\.com/"],
"filterEndJs": false
}
},
"identity": { "rate": "10" }, // 身份上报采样率(默认 '10' 全量;日常勿下调,仅止血用)
"track": { // 自定义 track 事件控制(只管 track(),click/expo 走 control.custom)
"rate": "10", // 采样率 '1'-'10'
"trackGray": 0.5, // 登录用户比例开关 [0,1] 数字;未登录用户不受影响
"userId": ["*"] // 定向采集白名单;'*' 全部;填具体 id 时未登录用户一条不采
},
"performance": { // 性能监控控制
"slowResourceMs": 1000, // 慢资源阈值 ms(远端优先于插件本地选项,缺省回本地默认 1000)
"resourceTime": { // 慢资源黑名单:资源类型组 → URL 正则数组(命中即排除,早于阈值判定)
"IMG": ["\\.gif$"], // 组名限 API/CSS/IFRAME/IMG/JS/VIDEO
"API": ["/heartbeat"]
},
"stalePageRefresh": { // 长时间后台恢复刷新;默认关闭
"enabled": true,
"thresholdMs": 1800000,
"routeMode": "allowlist",
"routes": ["/model/**", "/task/**"],
"onHide": { // hide 后台延迟刷新;缺省即只保留 on-show 路径
"enabled": true,
"delayMs": 180000, // hide 后延迟多久刷新,30000~3600000
"minPageAgeMs": 1800000 // 页龄门槛,60000~86400000
}
}
}
}字段含义与填写规则
| 字段 | 类型 | 含义 / 消费方 | 填写规则 |
|---|---|---|---|
version * | number | schema 版本;SDK 只信任已识别版本(1 / 2),否则整份降级 | 必填。当前应填 2;其它值整份配置降级 |
killSwitch * | boolean | 全局熔断,true 时 L4 入口统一闸断、完全不上报 | 必填。日常填 false;必须是布尔,写字符串 "false" 会判整份非法 |
utm.utmSource | string[] | 渠道白名单;SDK 把 URL 的 utm_source 转小写后比对。空数组 = fail-open 放行全部 | 值必须全小写;数组里混入非字符串会丢弃整个字段(等同空数组放行全部) |
breadcrumb.max | number | 面包屑(错误前操作链)条数上限,默认 10 | 必须为正数(小数向下取整,非正 / 非数丢弃走默认) |
control.poll | string | 聚合上报池轮询间隔 ms | 填字符串形式的毫秒数如 "5000";非法值回内置默认 |
control.performance | string | 性能整体采样率,'1'–'10' 映射 0.1–1.0 | '1'–'10' 的字符串;写成数字会被丢弃 |
control.tech | { key, val } | 技术域(错误 / 性能)坐标级采样:key=TracePath 前缀,val='1'–'10' | key 须为非空字符串(如 "shop.Perf"),val 须为字符串;任一不合规整条规则丢弃 |
control.custom | { key, val } | 行为域坐标级采样,结构同 tech | 同 tech |
error.errorLevels | Record<错误子类, 规则[]> | 远端错误分级规则(见下);优先级 remote > local > 默认 | 子类 key 限 js/promise/resource/white-screen/api/ssr;规则结构见下节 |
error.filter | ErrorFilterConfig | 错误前置过滤,命中即整条丢弃(见下) | 各子字段为正则字符串数组;非法正则 fail-open 跳过该项 |
identity.rate | string | 身份上报采样率,默认 '10' 全量 | '1'–'10' 的字符串;远程下调仅作止血用途 |
track.rate | string | track 自定义事件采样率 | '1'–'10' 的字符串 |
track.trackGray | number | 对登录用户的比例开关 | [0,1] 之间的数字(如 0.5),非有限数丢弃 |
track.userId | string[] | 定向采集白名单 | ["*"] 匹配全部;否则填具体 user_id 列表 |
performance.slowResourceMs | number | 慢资源阈值 ms,duration 达阈值的资源上报为慢资源。远端优先于插件本地选项 PerformancePluginOptions.slowResourceMs,两者都缺省走内置默认 1000 | 正数(小数向下取整,非正丢弃回本地/默认) |
performance.resourceTime | Record<资源组, string[]> | 慢资源黑名单,命中即排除 | key 限 API/CSS/IFRAME/IMG/JS/VIDEO,值为 URL 正则数组;坏组丢弃、好组保留 |
performance.stalePageRefresh | object | 长时间后台恢复刷新,消费方为 PerformancePlugin | 缺失或非法时整体关闭;enabled 必须为 true 才开启,thresholdMs 为 30000~86400000 的整数,routeMode 仅 allowlist/denylist,routes 为 pathname glob 字符串数组 |
performance.stalePageRefresh.onHide | object | hide 后台延迟刷新子路径,消费方为 PerformancePlugin | 缺失或非法时只关该子路径、不影响 on-show;enabled 必须为 true,delayMs 为 30000~3600000 的整数,minPageAgeMs 为 60000~86400000 的整数 |
采样值约定
'1'–'10' 的字符串采样率统一映射为 0.1–1.0(即 '10' = 100% 全量、'5' = 50%)。错误事件无节点级采样率、内置默认 100% 入管线,但 control.tech 坐标级规则可以覆盖(匹配 <app>.Error 即可降采样)——错误的「控量」主要靠下面的 filter 前置过滤与插件内确定性控量,而不是随机丢弃。
control.tech / control.custom —— 坐标级采样可填值
key 是 TracePath 前缀,命中规则为 key 精确相等或 key.* 前缀通配;val 为 '1'–'10' 字符串。每域只能填一条规则(对象、不是数组)。
两域能匹配到的坐标不同:
tech:技术域坐标只有两个固定形态——<app>.Error(所有错误子类)和<app>.Perf(性能)。<app>为init的app归一化小写,但后缀Error/Perf首字母大写、大小写敏感,写成shop.perf匹配不上。custom:行为域坐标即埋点的 TracePath(全小写app.block.detail形态,2–8 段),另含<app>.Identity(身份)与<app>.Landing(归因落地)。
// 只降采样性能事件到 50%
"tech": { "key": "shop.Perf", "val": "5" }
// 只降采样错误事件到 30%(错误默认 100%,这是唯一的错误随机降采样入口)
"tech": { "key": "shop.Error", "val": "3" }
// app 前缀通配:Error 和 Perf 一起降到 10%
"tech": { "key": "shop", "val": "1" }
// 首页区块下所有埋点(shop.home 及 shop.home.*)全量
"custom": { "key": "shop.home", "val": "10" }
// 某个高频按钮点击降到 20%
"custom": { "key": "shop.home.banner_click", "val": "2" }
// 整个 app 的行为域统一降到 50%(含 Identity、Landing)
"custom": { "key": "shop", "val": "5" }优先级:坐标级(tech/custom)> 节点级(control.performance / track.rate / identity.rate)> 内置默认 100%,某级值非法即 fail-open 跳下一级。采样以 device_id 为锚点做确定性判定——同一设备整体留或整体丢,不是逐条随机。
error.errorLevels —— 远端分级规则
按错误子类(js / promise / resource / white-screen / api / ssr)分组,每组是一个规则数组。
匹配规则:
- 一条规则的
conditions全部命中才算命中(AND 语义);conditions为空数组视为不命中(防误伤全量)。 - 组内取第一条命中规则的
level,后面的不再看——特例规则要放在通配规则前面。 - 优先级 remote(远端)> local(插件 options)> 内置默认级;内置默认:
resource→record,其余子类 →major。 - 求值异常(非法正则、字段无值)一律视为不匹配(fail-safe),落到下一条规则或默认级。
field 白名单——每个子类只能读这些字段,越权字段一律不匹配:
| 子类 | 可用 field |
|---|---|
js | message fileName stack href |
promise | message stack href |
resource | message tagName url href |
api | message url href |
ssr | message stack url href |
white-screen | 无——规则永不命中,只落默认级 major |
operator 取值与语义:
| operator | 语义 | 说明 |
|---|---|---|
= | 字符串全等 | value 会 String() 后比对 |
contains | 子串包含 | 大小写敏感 |
match | 正则测试 | value 作为正则源串;非法正则不命中 |
> < >= <= | 数值比较 | 字段值与 value 都 Number(),任一非有限数不命中 |
示例:
"errorLevels": {
"js": [
// ResizeObserver 噪声降为 record(放在前面,特例优先)
{
"conditions": [
{ "field": "message", "operator": "contains", "value": "ResizeObserver" }
],
"level": "record"
},
// 来自 vendor 目录的 js 错误降为 mention(多条件 AND:message 且 fileName 同时命中)
{
"conditions": [
{ "field": "fileName", "operator": "match", "value": "/vendor/" },
{ "field": "message", "operator": "match", "value": "^(TypeError|ReferenceError)" }
],
"level": "mention"
}
],
"api": [
// 特定接口报错升为 major 重点关注
{
"conditions": [
{ "field": "url", "operator": "contains", "value": "/api/checkout" }
],
"level": "major"
}
],
"resource": [
// 关键 CDN 的资源加载失败从默认 record 升为 mention
{
"conditions": [
{ "field": "url", "operator": "match", "value": "cdn\\.example\\.com" },
{ "field": "tagName", "operator": "=", "value": "SCRIPT" }
],
"level": "mention"
}
]
}error.filter —— 前置过滤
命中即整条错误事件丢弃(仅错误域内过滤,不影响其它链路、不触发全局熔断)。正则字符串匹配,非法正则按 fail-open 跳过该项;列表为空 / 字段缺省 = 不过滤。
| 子字段 | 作用 |
|---|---|
js | 正则匹配 js 错误的 message 或 fileName,命中即丢 |
promise | 正则匹配 unhandledrejection 的 message 或 fileName |
resource | 正则匹配资源错误的 url |
api | 正则匹配 api 错误的请求 url 或 message |
ua | 正则匹配 navigator.userAgent,命中即丢(屏蔽爬虫 / 特定客户端) |
limitDomain | 域名白名单:页面 href 不匹配其中任一正则即丢(名单为空则不约束) |
filterEndJs | 为 true 时丢弃 fileName 非 .js 结尾的 js/promise 错误 |
匹配规则:
- 所有列表项都是正则源串(不是通配符),按
new RegExp(p)编译后.test();JSON 里\要写成\\。非法正则 fail-open 跳过该项,不影响列表里其余项。 js/promise/api是任一字段命中任一正则即丢(如js对 message 或 fileName 分别测试);ssr/white-screen没有子类黑名单。ua和limitDomain是全域的——对所有错误子类生效。filterEndJs注意:fileName 缺省也算非.js,会连无栈来源的错误一起丢,开启前想清楚。- 该过滤发生在前置门闸阶段,与内置门闸(页面已卸载 / 视口 ≤100px / 空 message / 浏览器扩展脚本)同一环节,早于指纹、会话上限和全局限流。
示例:
"filter": {
// 跨域脚本的无效报错、第三方 SDK 目录来源的 js 错误
"js": ["^Script error\\.?$", "/third-party-sdk/"],
// 用户取消类 promise 拒绝不算错误
"promise": ["AbortError", "^cancel"],
// 打点像素、统计脚本加载失败不上报
"resource": ["\\.gif(\\?|$)", "analytics\\.example\\.com"],
// 健康检查与轮询接口的失败不上报
"api": ["/healthz", "/heartbeat", "^https://polling\\."],
// 屏蔽爬虫与无头浏览器
"ua": ["bot|spider|crawler", "HeadlessChrome"],
// 白名单:只收自家域名下页面的错误(预发/镜像站不收)
// 注意匹配对象是完整 href(含路径),别用 $ 锚定域名结尾
"limitDomain": ["^https://([a-z0-9-]+\\.)?example\\.com/"],
// 只保留 .js 文件来源的 js/promise 错误(无栈来源也会被丢)
"filterEndJs": false
}identity / track —— 上报门控与采样
identity.rate:身份(device↔user 绑定)事件的节点级采样率,'1'–'10' 字符串,默认 '10' 全量。坐标级规则(control.custom 匹配 <app>.Identity)优先级更高。身份事件是登录归因的基础,远程下调仅作紧急止血,日常保持 '10'。
track 节三个字段分两类——rate 是 L4 管线里的采样,userId / trackGray 是采集侧门控(命中不了直接静默丢弃、根本不产生事件):
| 字段 | 生效范围 | 判定规则 |
|---|---|---|
rate | 仅 track() 自定义事件——click / expo 不受它控制(那两个只认 control.custom 坐标级规则) | '1'–'10' 字符串;优先级 control.custom > track.rate > 默认 100% |
userId | track() 事件 | 缺省 / 空数组 / 含 '*' = 全放行;非空且无 '*' 时,只有 user_id 命中名单的登录用户参与,未登录用户一条不采 |
trackGray | track() 事件、仅登录用户 | [0,1] 数字;按 device_id 分桶确定性命中(同设备稳定)。未登录用户不受影响、始终放行 |
三道门是串联的:userId 白名单 → trackGray 比例 → rate 采样,全过才上报。
示例:
// 日常全量
"track": { "rate": "10", "userId": ["*"] }
// 线上排障:只采集两个指定用户的 track(其他人含未登录全部静默)
"track": { "userId": ["u_1001", "u_1002"] }
// 灰度:登录用户 20% 参与(未登录用户不受 trackGray 影响、仍全量)
"track": { "rate": "10", "trackGray": 0.2, "userId": ["*"] }
// 止血:track 整体降到 10%(click/expo 不受影响,要一起降请用 control.custom)
"track": { "rate": "1" }performance.resourceTime —— 慢资源黑名单
命中即排除该资源、不上报(在耗时阈值判定之前生效)。key 是资源类型组,按 PerformanceResourceTiming.initiatorType 映射:
| 资源组 | 对应 initiatorType | 覆盖场景 |
|---|---|---|
API | xmlhttprequest fetch | XHR / fetch 请求 |
CSS | link css | 样式表及其内的 url() 引用 |
IFRAME | iframe | 内嵌框架 |
IMG | img image | 图片(含 SVG <image>) |
JS | script | 脚本 |
VIDEO | video | 视频 |
匹配规则:
- value 是 URL 正则源串数组,对资源完整 URL 做
.test();非法正则静默跳过、不影响其余项;空数组 / 未配的组不排除任何。 - 不在上表的 initiatorType(如
beacon、other)不受黑名单影响,一律正常上报。 - SDK 自身的上报接口 URL 有内置自排除(防「上报请求又被当慢资源上报」的反馈环),无需在这里配置。
slowResourceMs优先级:远端 > 插件本地选项PerformancePluginOptions.slowResourceMs> 内置默认 1000,运营可免发版调阈值。
示例:
"resourceTime": {
// 打点像素、埋点 gif 不算慢资源
"IMG": ["\\.gif(\\?|$)", "analytics\\.example\\.com"],
// 轮询 / 长连接类接口天然耗时长,排除
"API": ["/heartbeat", "/poll", "^https://push\\.example\\.com/"],
// 第三方视频源不受我们控制,不上报
"VIDEO": ["cdn\\.thirdparty\\.com"],
// 第三方客服 iframe
"IFRAME": ["chat-widget"]
}常见踩坑
- 采样率都是字符串:
control.performance/track.rate/identity.rate要写"5"不是5,写成数字会被丢弃走默认。 **trackGray是数字**:与上一条相反,写0.5不是"0.5"。- JSON 里正则要双反斜杠转义:
\.gif$要写成"\\.gif$"。 **limitDomain是白名单**(不匹配即丢),其余filter子字段是黑名单(匹配即丢),方向相反。- 白名单空数组 ≠ 不上报:
utm.utmSource: []是 fail-open 放行全部;想停止上报用killSwitch: true。 - 必填字段只有两个:
version和killSwitch写错才会整份降级;其余字段坏值只丢该字段,不会拖垮整份配置。 track.rate只管track()自定义事件:click / expo 埋点不受它控制,要降它们只能用control.custom坐标级规则。track.userId填了具体 id 就把未登录用户全关了:非空名单(且无'*')时匿名流量一条不采,排障完记得改回["*"]。
运营常见操作
新增投放渠道——往白名单加一项:
- "utm": { "utmSource": ["baidu", "google"] }
+ "utm": { "utmSource": ["baidu", "google", "bytedance"] }线上紧急熔断——怀疑上报有问题,先止血(几分钟 CDN 生效):
- "killSwitch": false
+ "killSwitch": true下调性能采样——压低上报量:
- "control": { "performance": "10" }
+ "control": { "performance": "1" }CDN 部署建议
响应头建议 Cache-Control: max-age=300, public(5 分钟),权衡命中率与生效速度;配置 CORS 允许业务域 GET。SDK 拉取时用 credentials: 'omit',不带 cookie。