最小化侵入、自动化采集、全链路串联
JS 运行时错误: 通过 window.onerror 拦截。它能获取错误消息、堆栈(Stack Trace)、所在行列号。
Promise 异常: 现代前端的死穴。通过 unhandledrejection 捕获那些没有写 .catch() 的异步调用。
资源加载错误: 捕获图片、CSS、JS 文件的 404 错误。
Vue 错误: 提供专门的 Vue.config.errorHandler 适配器,因为框架内部的错误有时不会冒泡到 window
ajax错误:劫持 XMLHttpRequest 和 fetch,获取状态码获取错误请求
当捕获到错误时push到任务队列中
定量触发:
如果当前 Task 队列中的任务数量超过了阈值(默认通常是 20 条),它会无视一分钟定时器,直接发起 HTTP 请求。
当页面发生“错误风暴”(比如循环报错)时,能迅速清空内存,防止浏览器卡死
定时触发:
setInterval(() => { Task.fireTasks(); }, 60000);用户访问页面只产生了一个微小的资源加载错误,没达到定量阈值,一分钟的延迟保证了数据的相对实时性,又兼顾了性能
卸载触发:
上报逻辑采用 navigator.sendBeacon,普通的ajax 由于页面即将销毁,浏览器会为了节省资源直接**截断(Abort)**这个请求,导致数据发不出去,而navigator.sendBeacon 把数据交给浏览器内核,即便页面关了,内核也会确保在后台发完
if (typeof navigator.sendBeacon === 'function') {
navigator.sendBeacon(
this.url,
new Blob([JSON.stringify(data)], {
type: 'application/json'
})
);
return;
}监控页面的流畅度,量化用户感知到的加载速度
监控内容: 传统的 Navigation Timing(如 DNS、TCP、白屏时间)
页面加载或离开时上报,同样页面离开时上报采用navigator.sendBeacon,并保底降级xhr请求
在 register 阶段通过原型链劫持,接管浏览器所有的通信出口
XMLHttpRequest (XHR)探针会保存原生的 XMLHttpRequest,然后用一个包装类替换它:
sw8请求头包含哪些内容 ${1}-${traceIdStr}-${segmentId}-${index}-${service}-${instance}-${endpoint}-${peer}
| 序号 | 字段变量名 | 含义 | 解析 |
| 1 | 1 (固定值) | Sample (采样标志) | 1 代表该请求需要被采集并上报。如果设为 0,后端 OAP 收到后将丢弃该链路,不存储。 |
| 2 | traceIdStr | Trace ID | 全链路唯一标识。从前端点击到后端微服务 A -> B -> C,这个 ID 永远不变。它是串联整个调用链的“主键”。 |
| 3 | segmentId | Parent Segment ID | 前端段 ID。在 SkyWalking 中,一个服务内的一组操作叫 Segment。这里代表发起请求的“前端这个动作”的 ID。 |
| 4 | index | Span ID | 跨度索引。代表这是当前 Segment 下的第几个操作(通常从 0 开始)。后端根据它来确定请求的先后顺序。 |
| 5 | service | Parent Service | 应用名称。在 register 时配置的 service。后端拓扑图中显示“来源”是谁,全靠它。 |
| 6 | instance | Parent Service Instance | 服务实例。前端通常是浏览器指纹或随机 ID。用于区分是哪个具体用户或设备发出的请求。 |
| 7 | endpoint | Parent Endpoint | 入口路径。记录当前报错或请求发生时,用户正处于哪个页面(pagePath)。 |
| 8 | peer | Peer Address | 目标地址。即接口所在的 Host。后端用来识别这个请求是发往哪个目标集群的。 |
保存引用: 首先把浏览器原生的 window.fetch 保存到一个私有变量中(如 originFetch)。
重写函数: 给 window.fetch 重新赋值一个自定义函数。
注入逻辑: 在这个自定义函数内部:生成 traceId 和 sw8 请求头。将 sw8 塞入请求的 headers 配置中。记录开始时间。执行原生引用: 调用之前保存的 originFetch 真正发出请求。处理响应: 监听 Promise 的 then 和 catch,计算耗时,记录状态码,最后将数据入队。
请求结束时(xhr.onload 或 fetch.then),拿到响应时间、状态码后,才能生成完整的 Segment 数据入队
定时上报:
setInterval(() => {
if (!segments.length) {
return;
}
new Report('SEGMENTS', options.collector).sendByXhr(segments);
segments.splice(0, segments.length);
}, options.traceTimeInterval);卸载触发:
同样采用 navigator.sendBeacon 进行上报
