Skip to content

远程配置 ​

lens 的白名单、采样率、错误分级、熔断等都不写在代码里,而是托管在 CDN 上的一份 JSON(configUrl)。运营 / 数据团队改完上传 CDN 即生效,无需发版。

ts
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,超时即降级
缓存 TTL24 小时超龄缓存弃用,避免远端长期故障时永用陈旧配置
识别的 version1、2v2 为终态;v1 仅版本号兼容解析

fail-open 与 killSwitch 是两回事

fail-open 是「配置拿不到时不放弃上报」的容错策略——CDN 挂了也不丢数据。 killSwitch 是配置里的显式熔断开关——true 时 SDK 完全不上报,用于线上紧急止血。两者方向相反,别混淆。

坏字段丢弃、不抛错

解析容错:只有 version 缺失/不识别、或 killSwitch 不是布尔,才判定整份配置非法走降级;其余字段坏值就丢弃该字段、走该字段的缺省,不会因为某个可选字段写错而拖垮整份配置。

配置 schema(v2) ​

完整字段如下(* 为必填)。除 version / killSwitch / 白名单外都可省略:

jsonc
{
  "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 *numberschema 版本;SDK 只信任已识别版本(1 / 2),否则整份降级必填。当前应填 2;其它值整份配置降级
killSwitch *boolean全局熔断,true 时 L4 入口统一闸断、完全不上报必填。日常填 false;必须是布尔,写字符串 "false" 会判整份非法
utm.utmSourcestring[]渠道白名单;SDK 把 URL 的 utm_source 转小写后比对。空数组 = fail-open 放行全部值必须全小写;数组里混入非字符串会丢弃整个字段(等同空数组放行全部)
breadcrumb.maxnumber面包屑(错误前操作链)条数上限,默认 10必须为正数(小数向下取整,非正 / 非数丢弃走默认)
control.pollstring聚合上报池轮询间隔 ms填字符串形式的毫秒数如 "5000";非法值回内置默认
control.performancestring性能整体采样率,'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.errorLevelsRecord<错误子类, 规则[]>远端错误分级规则(见下);优先级 remote > local > 默认子类 key 限 js/promise/resource/white-screen/api/ssr;规则结构见下节
error.filterErrorFilterConfig错误前置过滤,命中即整条丢弃(见下)各子字段为正则字符串数组;非法正则 fail-open 跳过该项
identity.ratestring身份上报采样率,默认 '10' 全量'1'–'10' 的字符串;远程下调仅作止血用途
track.ratestringtrack 自定义事件采样率'1'–'10' 的字符串
track.trackGraynumber对登录用户的比例开关[0,1] 之间的数字(如 0.5),非有限数丢弃
track.userIdstring[]定向采集白名单["*"] 匹配全部;否则填具体 user_id 列表
performance.slowResourceMsnumber慢资源阈值 ms,duration 达阈值的资源上报为慢资源。远端优先于插件本地选项 PerformancePluginOptions.slowResourceMs,两者都缺省走内置默认 1000正数(小数向下取整,非正丢弃回本地/默认)
performance.resourceTimeRecord<资源组, string[]>慢资源黑名单,命中即排除key 限 API/CSS/IFRAME/IMG/JS/VIDEO,值为 URL 正则数组;坏组丢弃、好组保留
performance.stalePageRefreshobject长时间后台恢复刷新,消费方为 PerformancePlugin缺失或非法时整体关闭;enabled 必须为 true 才开启,thresholdMs 为 30000~86400000 的整数,routeMode 仅 allowlist/denylist,routes 为 pathname glob 字符串数组
performance.stalePageRefresh.onHideobjecthide 后台延迟刷新子路径,消费方为 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(归因落地)。
jsonc
// 只降采样性能事件到 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
jsmessage fileName stack href
promisemessage stack href
resourcemessage tagName url href
apimessage url href
ssrmessage stack url href
white-screen无——规则永不命中,只落默认级 major

operator 取值与语义:

operator语义说明
=字符串全等value 会 String() 后比对
contains子串包含大小写敏感
match正则测试value 作为正则源串;非法正则不命中
> < >= <=数值比较字段值与 value 都 Number(),任一非有限数不命中

示例:

jsonc
"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 / 浏览器扩展脚本)同一环节,早于指纹、会话上限和全局限流。

示例:

jsonc
"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%
userIdtrack() 事件缺省 / 空数组 / 含 '*' = 全放行;非空且无 '*' 时,只有 user_id 命中名单的登录用户参与,未登录用户一条不采
trackGraytrack() 事件、仅登录用户[0,1] 数字;按 device_id 分桶确定性命中(同设备稳定)。未登录用户不受影响、始终放行

三道门是串联的:userId 白名单 → trackGray 比例 → rate 采样,全过才上报。

示例:

jsonc
// 日常全量
"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覆盖场景
APIxmlhttprequest fetchXHR / fetch 请求
CSSlink css样式表及其内的 url() 引用
IFRAMEiframe内嵌框架
IMGimg image图片(含 SVG <image>)
JSscript脚本
VIDEOvideo视频

匹配规则:

  • value 是 URL 正则源串数组,对资源完整 URL 做 .test();非法正则静默跳过、不影响其余项;空数组 / 未配的组不排除任何。
  • 不在上表的 initiatorType(如 beacon、other)不受黑名单影响,一律正常上报。
  • SDK 自身的上报接口 URL 有内置自排除(防「上报请求又被当慢资源上报」的反馈环),无需在这里配置。
  • slowResourceMs 优先级:远端 > 插件本地选项 PerformancePluginOptions.slowResourceMs > 内置默认 1000,运营可免发版调阈值。

示例:

jsonc
"resourceTime": {
  // 打点像素、埋点 gif 不算慢资源
  "IMG": ["\\.gif(\\?|$)", "analytics\\.example\\.com"],

  // 轮询 / 长连接类接口天然耗时长,排除
  "API": ["/heartbeat", "/poll", "^https://push\\.example\\.com/"],

  // 第三方视频源不受我们控制,不上报
  "VIDEO": ["cdn\\.thirdparty\\.com"],

  // 第三方客服 iframe
  "IFRAME": ["chat-widget"]
}

常见踩坑 ​

  1. 采样率都是字符串:control.performance / track.rate / identity.rate 要写 "5" 不是 5,写成数字会被丢弃走默认。
  2. **trackGray 是数字**:与上一条相反,写 0.5 不是 "0.5"。
  3. JSON 里正则要双反斜杠转义:\.gif$ 要写成 "\\.gif$"。
  4. **limitDomain 是白名单**(不匹配即丢),其余 filter 子字段是黑名单(匹配即丢),方向相反。
  5. 白名单空数组 ≠ 不上报:utm.utmSource: [] 是 fail-open 放行全部;想停止上报用 killSwitch: true。
  6. 必填字段只有两个:version 和 killSwitch 写错才会整份降级;其余字段坏值只丢该字段,不会拖垮整份配置。
  7. track.rate 只管 track() 自定义事件:click / expo 埋点不受它控制,要降它们只能用 control.custom 坐标级规则。
  8. track.userId 填了具体 id 就把未登录用户全关了:非空名单(且无 '*')时匿名流量一条不采,排障完记得改回 ["*"]。

运营常见操作 ​

新增投放渠道——往白名单加一项:

diff
- "utm": { "utmSource": ["baidu", "google"] }
+ "utm": { "utmSource": ["baidu", "google", "bytedance"] }

线上紧急熔断——怀疑上报有问题,先止血(几分钟 CDN 生效):

diff
- "killSwitch": false
+ "killSwitch": true

下调性能采样——压低上报量:

diff
- "control": { "performance": "10" }
+ "control": { "performance": "1" }

CDN 部署建议

响应头建议 Cache-Control: max-age=300, public(5 分钟),权衡命中率与生效速度;配置 CORS 允许业务域 GET。SDK 拉取时用 credentials: 'omit',不带 cookie。

下一步 ​

基于 MIT 协议发布(内部使用)