@zhaogyna/browser
v1.0.1
Published
Browser platform layer for Monitor SDK
Downloads
387
Readme
@zhaogyna/browser
浏览器环境核心监控包,提供完整的错误采集、HTTP 拦截、面包屑、分布式追踪、会话管理等能力。
安装
npm install @zhaogyna/browser快速开始
import { init } from '@zhaogyna/browser'
init({
dsn: 'https://monitor.example.com/api/envelope',
release: '1.0.0',
environment: 'production',
sampleRate: 1,
tracesSampleRate: 0.2,
})初始化后 SDK 自动:
- 捕获全局 JS 错误与未处理 Promise 异常
- 拦截 Fetch / XHR 请求并注入 W3C Trace Context 链路头
- 采集用户行为面包屑(点击、导航、控制台、输入)
- 去重相似错误(5s 窗口)和重复埋点(1s 窗口)
完整配置项
import { init } from '@zhaogyna/browser'
init({
// ===== 必填 =====
dsn: 'https://monitor.example.com/api/envelope',
// ===== 采样 =====
sampleRate: 1, // 错误采样率(0~1,默认 1)
tracesSampleRate: 0.2, // 链路追踪采样率(0~1,默认 0)
tracesSampler: (ctx) => { // 动态链路采样函数(优先于 tracesSampleRate)
if (ctx.transactionContext?.name?.startsWith('/api/')) return 1
return 0.1
},
trackSampleRate: 1, // Track 事件采样率(0~1,默认 1)
replaysSessionSampleRate: 0.1, // 会话回放-会话级采样率(0~1,默认 0)
replaysOnErrorSampleRate: 1.0, // 会话回放-错误触发采样率(0~1,默认 0)
// ===== 环境 =====
release: '1.0.0', // 应用版本号(用于 SourceMap 关联)
environment: 'production', // 环境标识
initialScope: { // 初始作用域
user: { id: 'user-123', email: '[email protected]' },
tags: { env: 'prod' },
extra: { plan: 'premium' },
level: 'info',
},
// ===== 钩子 =====
beforeSend: (event, hint) => { // 事件发送前,返回 null 丢弃
if (event.tags?.ignore) return null
return event
},
beforeSendTransaction: (event, hint) => event,
beforeBreadcrumb: (breadcrumb, hint) => { // 面包屑添加前
if (breadcrumb.category === 'console') return null
return breadcrumb
},
beforeTrack: (trackEvent) => { // Track 事件发送前
trackEvent.properties = { ...trackEvent.properties, timestamp: Date.now() }
return trackEvent
},
// ===== 过滤 =====
ignoreErrors: [
'ResizeObserver loop limit exceeded',
/NetworkError/,
],
denyUrls: [
/analytics\.google\.com/,
/doubleclick\.net/,
],
allowUrls: [
/myapp\.example\.com/,
/cdn\.myapp\.com/,
],
// ===== 序列化 =====
normalizeDepth: 3,
normalizeMaxSize: 1000,
normalizeMaxStringLength: 250,
// ===== 传输 =====
transport: (options) => new FetchTransport(options),
tunnel: 'https://monitor.example.com/tunnel',
sendClientReports: true,
maxQueueSize: 30,
// ===== 集成 =====
integrations: [],
defaultIntegrations: true,
enableTracing: true,
// ===== 栈追踪 =====
attachStacktrace: true,
maxStackFrames: 50,
// ===== 采集 =====
sendCookies: false,
collectModules: false,
maxBreadcrumbs: 100,
// ===== 埋点 =====
maxTrackPerSecond: 10,
maxTrackProperties: 20,
exposureBatchSize: 10,
exposureBatchInterval: 3000,
clickDebounceMs: 300,
trackDedupeInterval: 1000,
minStayDuration: 1000,
stripTrackKeys: ['token', 'secret'],
stripUrlParams: ['access_token', 'password'],
// ===== 调试 =====
debug: false,
logLevel: 'warn',
})常用 API
事件上报
import { captureException, captureMessage, track } from '@zhaogyna/browser'
// 捕获异常
captureException(new Error('something broke'))
// 捕获异常 + 一次性 Scope
captureException(err, (scope) => {
scope.setTag('section', 'payment')
scope.setExtra('orderId', 'ORD-123')
})
// 捕获消息
captureMessage('Something happened', 'warning')
// 自定义埋点
track('purchase_complete', { product: 'iPhone', price: 999 })上下文
import {
setUser, setTag, setTags, setExtra, setExtras,
setLevel, setTransaction, setFingerprint,
addBreadcrumb, clearBreadcrumbs,
} from '@zhaogyna/browser'
setUser({ id: 'user-123', email: '[email protected]', username: 'john' })
setTag('feature', 'checkout')
setTags({ env: 'prod', region: 'cn-north' })
setExtra('cartSize', 5)
setExtras({ plan: 'premium', trial: false })
setLevel('warning')
setTransaction('CheckoutFlow')
setFingerprint(['my-error-group'])
addBreadcrumb({ category: 'ui', message: 'Clicked checkout', level: 'info', timestamp: Date.now() })
clearBreadcrumbs()分布式追踪
import { startSpan } from '@zhaogyna/browser'
const span = startSpan('api/fetch-orders')
try {
const orders = await fetchOrders()
span.setStatus('ok')
span.setData('orderCount', orders.length)
} catch (err) {
span.setStatus('internal_error')
captureException(err)
} finally {
span.finish()
}漏斗分析
import { startFunnel, trackFunnelStep, endFunnel } from '@zhaogyna/browser'
startFunnel('checkout_funnel')
trackFunnelStep('checkout_funnel', 'view_cart', { itemCount: 3 })
trackFunnelStep('checkout_funnel', 'enter_payment', { method: 'alipay' })
trackFunnelStep('checkout_funnel', 'complete_payment', { amount: 999 })
endFunnel('checkout_funnel')多实例 / 微前端
import { createClient, getActiveClients, findClientForUrl } from '@zhaogyna/browser'
const client = createClient({ dsn: '...', release: '[email protected]' })
// client.captureException(err)
// client.flush()
const clients = getActiveClients()
const matched = findClientForUrl('/sub-app/dashboard')生命周期
import { on, flush, close } from '@zhaogyna/browser'
const unsubscribe = on('beforeFlush', (event) => console.log('flush:', event))
flush()
close()
unsubscribe()作用域隔离
import { withScope, captureException } from '@zhaogyna/browser'
withScope((scope) => {
scope.setTag('temp', 'value')
captureException(err) // 只附加到本次上报
})动态添加集成
import { addIntegration, lazyLoadIntegration } from '@zhaogyna/browser'
addIntegration(someIntegration())
// 按需加载
const replay = lazyLoadIntegration(
() => import('@zhaogyna/browser/sessionReplay'),
'sessionReplay'
)
addIntegration(replay)集成 (Integrations)
默认集成(自动加载,共 10 个)
| 集成 | 说明 |
|------|------|
| inboundFilter | 根据 ignoreErrors / denyUrls / allowUrls 过滤事件 |
| functionToString | 保留猴子补丁前原生函数的 toString() 输出,teardown 时恢复 |
| tryCatchWrapper | 包裹 setTimeout / setInterval / rAF / addEventListener,嵌套 WeakMap 保证 removeEventListener 兼容 |
| globalErrorHandler | window.onerror + unhandledrejection,区分资源/JS 错误,Error.cause 递归解析(max 5) |
| breadcrumbCollector | 点击(捕获阶段)、路由变化、控制台、输入面包屑,支持 beforeBreadcrumb |
| httpInterceptor | Fetch + XHR 猴子补丁,注入 W3C traceparent 头,SDK 请求自动跳过,5xx 自动上报 |
| dedupe | 5s 窗口错误去重,指纹 = hash(message + 栈帧) |
| trackDedupe | 1s 窗口埋点去重,指纹 = event_name + hash(properties) |
| httpContext | 附加浏览器/OS/设备上下文 + HTTP 上下文(url, referrer, ua, debugIds) |
| browserSessionIntegration | visibilitychange 驱动会话管理:hidden > 5min 或 session > 1hr 触发新会话 |
可选集成(需手动添加,共 8 个)
| 集成 | 说明 | 相关配置项 |
|------|------|-----------|
| performanceVitals() | Web Vitals:TTFB/FCP/LCP/CLS/INP,支持 bfcache 恢复 | 无 |
| longTaskObserver() | 长任务监控:优先 LoAF API,降级 Long Tasks API,>50ms | 无 |
| resourceObserver() | 资源加载失败:script/link/img/video/audio/font | 无 |
| pageViewTracker() | PV 自动采集:URL 去重,首次带 load_time | 无 |
| clickTracker() | 声明式点击埋点:data-monitor / data-monitor-props | clickDebounceMs |
| exposureTracker() | 元素曝光检测:IntersectionObserver(50% + 500ms),批量上报 | exposureBatchSize / exposureBatchInterval |
| stayTracker() | 页面停留时长 | minStayDuration |
| sessionReplay() | 会话回放:MutationObserver 增量快照,隐私脱敏 | replaysSessionSampleRate / replaysOnErrorSampleRate |
启用可选集成:
import {
init,
performanceVitals,
pageViewTracker,
clickTracker,
exposureTracker,
stayTracker,
sessionReplay,
longTaskObserver,
resourceObserver,
} from '@zhaogyna/browser'
init({
dsn: 'https://monitor.example.com/api/envelope',
integrations: [
performanceVitals(),
pageViewTracker(),
clickTracker(),
exposureTracker(),
stayTracker(),
longTaskObserver(),
resourceObserver(),
sessionReplay(),
],
replaysSessionSampleRate: 0.1,
replaysOnErrorSampleRate: 1.0,
clickDebounceMs: 300,
exposureBatchSize: 10,
exposureBatchInterval: 3000,
minStayDuration: 1000,
})声明式埋点
点击埋点
在元素上添加 data-monitor 和 data-monitor-props:
<button data-monitor="buy_click" data-monitor-props='{"product":"iPhone","price":999}'>
立即购买
</button>自动附加元素信息:__element、__element_id、__element_class、__element_text(截断 100 字符)、__element_xpath
曝光埋点
在元素上添加 data-monitor-exposure 和 data-monitor-exposure-props:
<div data-monitor-exposure="banner_view" data-monitor-exposure-props='{"position":"top","campaign":"summer"}'>
<img src="banner.jpg" />
</div>隐私遮盖(会话回放)
<input type="password" />
<input type="credit-card" />
<div data-monitor-mask>敏感文本内容</div>传输层
FetchTransport
默认传输方式,使用 fetch POST 发送。
- 支持 gzip 压缩(
CompressionStreamAPI) - 5xx 自动重试(3 次,1s/2s/4s 退避)
- 429 存入 OfflineCache 稍后重传
- 通过
X-Monitor-SDK: true头跳过自身拦截 - 支持
tunnel代理 - 请求体 > 64KB 时 console.warn
BeaconTransport
页面卸载时自动降级为 navigator.sendBeacon。
- 使用 Blob 设置 Content-Type
- 认证通过
monitor_key查询参数(sendBeacon 不支持自定义头)
离线缓存
- 基于 IndexedDB,内存降级兜底
- 最多 1000 条,FIFO 淘汰
- 网络恢复时自动重传
浏览器信息
SDK 自动采集并附加到事件上下文:
getBrowserInfo()— 浏览器名称/版本(优先userAgentDataAPI,降级 UA 解析)getOsInfo()— 操作系统getDeviceInfo()— 设备品牌/型号getCurrentUrl()/getReferrer()/getTitle()
Trace 传播
W3C Trace Context 标准:
import { generateTraceparentHeader, injectTraceHeaders, parseTraceparentHeader } from '@zhaogyna/browser'
// 生成 traceparent 头
const header = generateTraceparentHeader(traceId, spanId, sampled)
// '00-{traceId}-{spanId}-{traceFlags}'
// 注入到请求头
const headers = injectTraceHeaders({ 'Content-Type': 'application/json' }, traceId, spanId, sampled)
// 解析 traceparent 头
const { traceId, spanId, parentSampled } = parseTraceparentHeader(header)tracestate 支持 vendor 前缀:monitor=sid:{span_id}
License
MIT
