@nstc-sdk/star-sdk
v1.0.0
Published
Front-end monitoring SDK
Downloads
26
Maintainers
Readme
Star SDK
轻量级前端监控埋点 SDK,支持 JS 错误监控、页面性能采集、用户行为追踪、白屏检测等功能。
特性
- TypeScript 编写 — 完整的类型支持
- 插件架构 — 支持自定义插件扩展
- 批量上报 — 自动批量合并,减少请求数
- 离线重试 — 使用 localStorage 持久化队列
- 三级降级上报 — sendBeacon > fetch > Image Beacon
- 会话追踪 — 自动管理 session ID
- 用户行为轨迹 — 记录点击、导航等行为
- 白屏检测 — MutationObserver 监控 DOM 渲染
- 数据脱敏 — 自动过滤敏感字段
- 完整清理 — destroy() 方法清理所有资源
安装
npm install star-sdk或使用 CDN:
<script src="dist/index.global.js"></script>快速开始
import { Star } from 'star-sdk';
// 初始化
const star = new Star({
pid: 'your-project-id', // 项目 ID(必填)
reportUrl: 'https://your-server.com/report', // 上报地址(必填)
ucid: 'user-id', // 用户 ID(可选)
version: '1.0.0', // 版本号
isTest: true, // 测试模式
});
// 发送错误
star.notify('PaymentFailed', '/api/pay', { http_code: 500 });
// 发送行为
star.behavior('click', 'Submit Button', '/form');
// 发送事件
star.logger('page_view', { page: '/home' });
// SPA 卸载时清理
onUnmounted(() => star.destroy());API 文档
构造函数
new Star(config: StarConfig): Star配置项
| 配置项 | 类型 | 默认值 | 说明 |
|--------|------|--------|------|
| pid | string | 必填 | 项目 ID |
| reportUrl | string | 必填 | 上报服务器地址 |
| uuid | string | 自动生成 | 设备唯一 ID |
| ucid | string | '' | 用户唯一 ID |
| isTest | boolean | false | 是否为测试数据 |
| version | string | '1.0.0' | 应用版本号 |
| sampleRate | number | 1 | 采样率 (0-1) |
| batchMaxSize | number | 10 | 批量上报阈值 |
| batchMaxWait | number | 5000 | 批量等待时间 (ms) |
| maxRetries | number | 3 | 最大重试次数 |
| getPageType | function | 自动生成 | 页面类型解析函数 |
| record.js_error | boolean | true | 是否采集 JS 错误 |
| record.performance | boolean | true | 是否采集性能数据 |
| record.time_on_page | boolean | true | 是否采集在线时长 |
| collectBreadcrumbs | boolean | true | 是否采集用户行为轨迹 |
| collectResourceTiming | boolean | false | 是否采集资源耗时 |
| maxBreadcrumbs | number | 20 | 最大行为轨迹条数 |
| beforeSend | function | - | 发送前钩子 |
| afterSend | function | - | 发送后钩子 |
实例方法
notify(errorName, url, extraInfo?)
上报自定义错误。
star.notify('PaymentFailed', '/api/pay', { http_code: 500, during_ms: 3000 });error(code, detail?, extra?)
发送 error 类型日志 (codes 1-9999)。
star.error(1, { url: '/api/data', http_code: 500 }, {});product(code, detail?, extra?)
发送 product 类型日志 (codes 10000-19999)。
star.product(10001, { duration_ms: 5000 }, {});info(code, detail?, extra?)
发送 info 类型日志 (codes 20000-29999)。
star.info(20001, { action: 'search', keyword: 'test' }, {});log(type, code, detail?, extra?)
通用日志方法。
star.log('error', 8, { error_name: 'CustomError' }, {});
star.log('product', 10002, { code: 'click', name: 'Button' }, {});behavior(code, name, url?)
上报用户行为事件。
star.behavior('click_submit', 'Submit Button', '/form');logger(name, props?, extra?)
通用事件追踪。
star.logger('page_exposure', { module: 'recommend', position: 3 }, { extra: 'data' });detect(target?, notifyConfig?, observerConfig?, callback?)
白屏检测,监控 DOM 是否正常渲染。
// 基础用法
star.detect(
document.getElementById('app'), // 监控目标
{ errorName: 'WhiteScreen', url: '/home' }, // 错误配置
{ childList: true, subtree: true }, // MutationObserver 配置
(hasContent) => { console.log(hasContent ? '渲染正常' : '白屏'); } // 回调
);addBreadcrumb(entry)
添加用户行为轨迹。
star.addBreadcrumb({
category: 'custom',
message: '用户提交表单',
timestamp: Date.now(),
data: { formId: 'contact-form' },
});getBreadcrumbs()
获取当前所有行为轨迹。
const breadcrumbs = star.getBreadcrumbs();use(plugin)
注册自定义插件。
import { Star, type StarPlugin } from 'star-sdk';
const myPlugin: StarPlugin = {
name: 'my-plugin',
setup(ctx) {
ctx.bus.on('before-send', (payload) => {
console.log('发送前:', payload);
return payload; // 返回 null 可丢弃
});
},
teardown() {
// 清理资源
},
};
star.use(myPlugin);destroy()
完整清理所有资源。
onUnmounted(() => {
star.destroy();
});getConfig()
获取当前配置(只读)。
const config = star.getConfig();getSession()
获取会话信息。
const session = star.getSession();
// { id: 'abc123', startedAt: 1699999999999, pageViews: 3, lastActivity: 1699999999999 }生命周期钩子
beforeSend
在数据发送前调用,可修改或丢弃数据。
const star = new Star({
pid: 'test',
reportUrl: 'https://example.com/report',
beforeSend: (payload) => {
// 丢弃测试环境的错误
if (payload.type === 'error' && payload.detail?.desc?.includes('test')) {
return null;
}
// 添加额外字段
payload.extra = { ...payload.extra, environment: 'production' };
return payload;
},
});afterSend
在数据发送后调用,可用于日志记录。
const star = new Star({
pid: 'test',
reportUrl: 'https://example.com/report',
afterSend: (payload, success) => {
if (!success) {
console.error('上报失败:', payload);
}
},
});错误类型码
| 类型 | 范围 | 说明 |
|------|------|------|
| error | 1-9999 | JS 运行时错误、资源加载错误等 |
| product | 10000-19999 | 业务行为数据 |
| info | 20000-29999 | 信息类数据 |
| perf | 20001-20999 | 性能指标 |
| event | 30001+ | 自定义事件 |
JS 错误类型
| 类型码 | 名称 | 说明 | |--------|------|------| | 1 | RUNTIME | JS 运行时错误 | | 2 | SCRIPT | 脚本加载失败 | | 3 | STYLE | 样式加载失败 | | 4 | IMAGE | 图片加载失败 | | 5 | AUDIO | 音频加载失败 | | 6 | VIDEO | 视频加载失败 | | 7 | CONSOLE | console.error 捕获 | | 8 | TRY_CATCH | try-catch 捕获 |
插件开发
StarPlugin 接口
interface StarPlugin {
name: string; // 插件名称(唯一)
setup(ctx: StarContext): void; // 初始化时调用
teardown(): void; // 销毁时调用
}StarContext 接口
interface StarContext {
readonly config: Readonly<ResolvedConfig>; // 只读配置
report(payload: Omit<ReportPayload, 'common'>): void; // 上报数据
reportError(errorLog: ErrorLog): void; // 上报错误
notify(errorName: string, url: string, extraInfo?: Record<string, unknown>): void;
addBreadcrumb(entry: BreadcrumbEntry): void;
getBreadcrumbs(): ReadonlyArray<BreadcrumbEntry>;
readonly bus: EventBus; // 事件总线
readonly session: SessionManager; // 会话管理
debug(...args: unknown[]): void; // 调试日志
}EventBus 事件
type EventMap = {
'before-send': (payload: ReportPayload) => ReportPayload | null;
'after-send': (payload: ReportPayload, success: boolean) => void;
'on-error': (error: ErrorLog) => void;
'session-update': (session: SessionInfo) => void;
};示例:自定义性能插件
import type { StarPlugin, StarContext } from 'star-sdk';
export class CustomPerformancePlugin implements StarPlugin {
name = 'custom-performance';
private ctx!: StarContext;
setup(ctx: StarContext): void {
this.ctx = ctx;
window.addEventListener('load', () => {
this.ctx.report({
type: 'perf',
code: 20010,
detail: {
customMetric: this.measureSomething(),
},
extra: {},
});
});
}
teardown(): void {
// 清理资源
}
private measureSomething(): number {
return performance.now();
}
}
// 使用
star.use(new CustomPerformancePlugin());工具函数
tryWrap / tryWrapIgnore / tryWrapArgs
安全包装函数,自动捕获异常。
import { tryWrap, tryWrapIgnore, tryWrapArgs } from 'star-sdk';
// 包装函数,返回结果和错误
const safeFn = tryWrap((data: string) => JSON.parse(data));
const { result, error } = safeFn('invalid json');
// 忽略错误,返回 undefined
const safeParse = tryWrapIgnore(JSON.parse);
const result = safeParse('invalid json'); // undefined
// 包装函数参数
const wrappedFn = tryWrapArgs(someFunction);debounce / throttle
防抖和节流函数。
import { debounce, throttle } from 'star-sdk';
// 防抖
const debouncedFn = debounce(() => {
star.behavior('scroll', 'End of Page');
}, 500);
// 节流
const throttledFn = throttle(() => {
star.behavior('scroll', 'Scrolling');
}, 200);其他工具
import {
getUUID, // 生成 UUID
hash, // 字符串哈希
parseDomain, // 解析域名
safeStringify, // 安全 JSON 序列化
truncate, // 字符串截断
noop, // 空函数
clog, // 红色控制台日志
getDeviceId, // 获取设备 ID
} from 'star-sdk';上报数据格式
单条数据
{
"type": "error",
"code": 1,
"detail": {
"desc": "Uncaught TypeError: Cannot read property",
"stack": "at foo (https://example.com/app.js:10:5)"
},
"extra": {},
"common": {
"pid": "project-id",
"uuid": "device-uuid",
"ucid": "user-id",
"timestamp": 1699999999999,
"sdk_version": "1.0.0",
"page_type": "example.com/detail",
"session_id": "session-123"
}
}批量上报
批量数据通过 POST JSON 发送,请求体为数组格式:
[
{ "type": "error", "code": 1, ... },
{ "type": "product", "code": 10001, ... }
]服务端接入
服务端需要接收 POST 请求,Content-Type 为 application/json。
Node.js 示例:
const http = require('http');
const server = http.createServer((req, res) => {
if (req.method === 'POST' && req.url === '/report') {
let body = '';
req.on('data', chunk => body += chunk);
req.on('end', () => {
const data = JSON.parse(body);
console.log('收到上报数据:', data);
res.end('ok');
});
}
});
server.listen(3000);浏览器兼容
- Chrome 49+
- Firefox 44+
- Safari 10+
- Edge 79+
不支持 IE。
