sobey-monitor-sdk 1.0.1 → 1.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +62 -0
- package/dist/frameworks/index.d.ts +7 -0
- package/dist/frameworks/react.d.ts +74 -0
- package/dist/frameworks/vue.d.ts +21 -0
- package/dist/index.cjs.js +259 -15
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.d.ts +99 -4
- package/dist/index.esm.js +257 -16
- package/dist/index.esm.js.map +1 -1
- package/dist/index.umd.js +259 -15
- package/dist/index.umd.js.map +1 -1
- package/dist/reporter/sender.d.ts +2 -0
- package/dist/types/index.d.ts +8 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -44,6 +44,68 @@ monitor.init({
|
|
|
44
44
|
### `monitor.flush()`
|
|
45
45
|
立即上报缓冲区中的数据。
|
|
46
46
|
|
|
47
|
+
## 框架集成
|
|
48
|
+
|
|
49
|
+
### Vue 3
|
|
50
|
+
|
|
51
|
+
使用 `VueMonitorPlugin` 插件,可以捕获 Vue 组件内的渲染错误:
|
|
52
|
+
|
|
53
|
+
```typescript
|
|
54
|
+
import { createApp } from 'vue';
|
|
55
|
+
import App from './App.vue';
|
|
56
|
+
import { VueMonitorPlugin } from 'sobey-monitor-sdk';
|
|
57
|
+
|
|
58
|
+
const app = createApp(App);
|
|
59
|
+
|
|
60
|
+
app.use(VueMonitorPlugin, {
|
|
61
|
+
appId: 'your-app-id',
|
|
62
|
+
dsn: 'http://localhost:3000/api/report',
|
|
63
|
+
debug: true,
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
app.mount('#app');
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### React
|
|
70
|
+
|
|
71
|
+
使用 `createReactErrorBoundary` 创建错误边界组件,包裹根组件以捕获渲染错误:
|
|
72
|
+
|
|
73
|
+
```tsx
|
|
74
|
+
import React from 'react';
|
|
75
|
+
import ReactDOM from 'react-dom';
|
|
76
|
+
import App from './App';
|
|
77
|
+
import { createReactErrorBoundary } from 'sobey-monitor-sdk';
|
|
78
|
+
|
|
79
|
+
// 创建错误边界组件
|
|
80
|
+
const ErrorBoundary = createReactErrorBoundary(React, {
|
|
81
|
+
appId: 'your-app-id',
|
|
82
|
+
dsn: 'http://localhost:3000/api/report',
|
|
83
|
+
debug: true,
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
ReactDOM.render(
|
|
87
|
+
<ErrorBoundary fallback={<h1>页面出错了</h1>}>
|
|
88
|
+
<App />
|
|
89
|
+
</ErrorBoundary>,
|
|
90
|
+
document.getElementById('root')
|
|
91
|
+
);
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
**注意**:框架集成会自动初始化 SDK,无需再手动调用 `monitor.init()`。
|
|
95
|
+
|
|
96
|
+
## 配置项
|
|
97
|
+
|
|
98
|
+
| 配置项 | 类型 | 默认值 | 说明 |
|
|
99
|
+
|--------|------|--------|------|
|
|
100
|
+
| `appId` | string | 必填 | 应用唯一标识 |
|
|
101
|
+
| `dsn` | string | 必填 | 数据上报地址 |
|
|
102
|
+
| `debug` | boolean | false | 调试模式 |
|
|
103
|
+
| `sampling.error` | number | 1 | 错误采样率 (0-1) |
|
|
104
|
+
| `sampling.performance` | number | 1 | 性能采样率 (0-1) |
|
|
105
|
+
| `sampling.behavior` | number | 1 | 行为采样率 (0-1) |
|
|
106
|
+
| `report.maxBufferSize` | number | 10 | 缓冲区最大数量 |
|
|
107
|
+
| `report.flushInterval` | number | 5000 | 上报间隔 (ms) |
|
|
108
|
+
|
|
47
109
|
## 构建
|
|
48
110
|
|
|
49
111
|
```bash
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import type { MonitorConfig } from '../types';
|
|
2
|
+
/**
|
|
3
|
+
* React ErrorBoundary 组件 Props
|
|
4
|
+
*/
|
|
5
|
+
export interface ErrorBoundaryProps {
|
|
6
|
+
/** 发生错误时显示的降级 UI */
|
|
7
|
+
fallback?: any;
|
|
8
|
+
/** 错误回调 */
|
|
9
|
+
onError?: (error: Error, errorInfo: any) => void;
|
|
10
|
+
/** 子组件 */
|
|
11
|
+
children?: any;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* React ErrorBoundary 组件 State
|
|
15
|
+
*/
|
|
16
|
+
export interface ErrorBoundaryState {
|
|
17
|
+
hasError: boolean;
|
|
18
|
+
error: Error | null;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* 创建 React 错误边界组件
|
|
22
|
+
*
|
|
23
|
+
* @param React - React 库引用
|
|
24
|
+
* @param config - SDK 配置
|
|
25
|
+
* @returns ErrorBoundary 组件类
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* ```tsx
|
|
29
|
+
* import React from 'react';
|
|
30
|
+
* import ReactDOM from 'react-dom';
|
|
31
|
+
* import { createReactErrorBoundary } from 'sobey-monitor-sdk';
|
|
32
|
+
*
|
|
33
|
+
* const ErrorBoundary = createReactErrorBoundary(React, {
|
|
34
|
+
* appId: 'your-app-id',
|
|
35
|
+
* dsn: 'http://your-server/api/report',
|
|
36
|
+
* });
|
|
37
|
+
*
|
|
38
|
+
* ReactDOM.render(
|
|
39
|
+
* <ErrorBoundary fallback={<h1>Something went wrong</h1>}>
|
|
40
|
+
* <App />
|
|
41
|
+
* </ErrorBoundary>,
|
|
42
|
+
* document.getElementById('root')
|
|
43
|
+
* );
|
|
44
|
+
* ```
|
|
45
|
+
*/
|
|
46
|
+
export declare function createReactErrorBoundary(React: any, config: MonitorConfig): any;
|
|
47
|
+
/**
|
|
48
|
+
* React Hook: 用于手动上报错误
|
|
49
|
+
*
|
|
50
|
+
* @example
|
|
51
|
+
* ```tsx
|
|
52
|
+
* import { useMonitorError } from 'sobey-monitor-sdk';
|
|
53
|
+
*
|
|
54
|
+
* function MyComponent() {
|
|
55
|
+
* const reportError = useMonitorError();
|
|
56
|
+
*
|
|
57
|
+
* const handleClick = async () => {
|
|
58
|
+
* try {
|
|
59
|
+
* await riskyOperation();
|
|
60
|
+
* } catch (error) {
|
|
61
|
+
* reportError(error, { action: 'riskyOperation' });
|
|
62
|
+
* }
|
|
63
|
+
* };
|
|
64
|
+
*
|
|
65
|
+
* return <button onClick={handleClick}>Click</button>;
|
|
66
|
+
* }
|
|
67
|
+
* ```
|
|
68
|
+
*/
|
|
69
|
+
export declare function createUseMonitorError(React: any): () => any;
|
|
70
|
+
declare const _default: {
|
|
71
|
+
createReactErrorBoundary: typeof createReactErrorBoundary;
|
|
72
|
+
createUseMonitorError: typeof createUseMonitorError;
|
|
73
|
+
};
|
|
74
|
+
export default _default;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { MonitorConfig } from '../types';
|
|
2
|
+
/**
|
|
3
|
+
* Vue 3 错误监控插件
|
|
4
|
+
*
|
|
5
|
+
* @example
|
|
6
|
+
* ```ts
|
|
7
|
+
* import { createApp } from 'vue';
|
|
8
|
+
* import { VueMonitorPlugin } from 'sobey-monitor-sdk';
|
|
9
|
+
*
|
|
10
|
+
* const app = createApp(App);
|
|
11
|
+
* app.use(VueMonitorPlugin, {
|
|
12
|
+
* appId: 'your-app-id',
|
|
13
|
+
* dsn: 'http://your-server/api/report',
|
|
14
|
+
* });
|
|
15
|
+
* app.mount('#app');
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
export declare const VueMonitorPlugin: {
|
|
19
|
+
install(app: any, options: MonitorConfig): void;
|
|
20
|
+
};
|
|
21
|
+
export default VueMonitorPlugin;
|
package/dist/index.cjs.js
CHANGED
|
@@ -231,12 +231,6 @@ function getPageTitle() {
|
|
|
231
231
|
function supportsSendBeacon() {
|
|
232
232
|
return typeof navigator !== 'undefined' && typeof navigator.sendBeacon === 'function';
|
|
233
233
|
}
|
|
234
|
-
/**
|
|
235
|
-
* 判断页面是否即将卸载
|
|
236
|
-
*/
|
|
237
|
-
function isPageHidden() {
|
|
238
|
-
return document.visibilityState === 'hidden';
|
|
239
|
-
}
|
|
240
234
|
|
|
241
235
|
/**
|
|
242
236
|
* 数据发送器
|
|
@@ -277,32 +271,39 @@ class Sender {
|
|
|
277
271
|
}
|
|
278
272
|
/**
|
|
279
273
|
* 执行发送
|
|
274
|
+
* 策略:优先使用 sendBeacon(更可靠),不支持或失败时降级为 fetch
|
|
280
275
|
*/
|
|
281
276
|
doSend(data) {
|
|
282
277
|
const cfg = config.get();
|
|
283
278
|
const dsn = cfg.dsn;
|
|
284
279
|
const payload = JSON.stringify(data);
|
|
285
|
-
//
|
|
286
|
-
if (
|
|
287
|
-
this.sendByBeacon(dsn, payload);
|
|
288
|
-
|
|
280
|
+
// 优先使用 sendBeacon(更可靠、异步、不阻塞页面)
|
|
281
|
+
if (supportsSendBeacon()) {
|
|
282
|
+
const success = this.sendByBeacon(dsn, payload);
|
|
283
|
+
if (success) {
|
|
284
|
+
return;
|
|
285
|
+
}
|
|
286
|
+
// sendBeacon 失败,降级到 fetch
|
|
289
287
|
}
|
|
290
|
-
//
|
|
288
|
+
// 不支持 sendBeacon 或 sendBeacon 失败时,使用 fetch
|
|
291
289
|
this.sendByFetch(dsn, payload);
|
|
292
290
|
}
|
|
293
291
|
/**
|
|
294
292
|
* 使用 sendBeacon 发送
|
|
293
|
+
* 返回 true 表示成功加入队列,false 表示失败需要降级
|
|
295
294
|
*/
|
|
296
295
|
sendByBeacon(url, payload) {
|
|
297
296
|
try {
|
|
298
|
-
|
|
297
|
+
const success = navigator.sendBeacon(url, payload);
|
|
298
|
+
if (!success && config.get().debug) {
|
|
299
|
+
console.warn('[Monitor] sendBeacon returned false, falling back to fetch');
|
|
300
|
+
}
|
|
301
|
+
return success;
|
|
299
302
|
}
|
|
300
303
|
catch (e) {
|
|
301
304
|
if (config.get().debug) {
|
|
302
305
|
console.error('[Monitor] sendBeacon failed:', e);
|
|
303
306
|
}
|
|
304
|
-
// 降级到 fetch
|
|
305
|
-
this.sendByFetch(url, payload);
|
|
306
307
|
return false;
|
|
307
308
|
}
|
|
308
309
|
}
|
|
@@ -618,17 +619,36 @@ function installHttpErrorHandler() {
|
|
|
618
619
|
/**
|
|
619
620
|
* 拦截 XMLHttpRequest
|
|
620
621
|
*/
|
|
622
|
+
/**
|
|
623
|
+
* 检查是否是 SDK 自身的请求
|
|
624
|
+
*/
|
|
625
|
+
function isSdkRequest(url) {
|
|
626
|
+
const cfg = config.get();
|
|
627
|
+
if (!cfg.dsn)
|
|
628
|
+
return false;
|
|
629
|
+
return url.includes(cfg.dsn);
|
|
630
|
+
}
|
|
621
631
|
function interceptXHR() {
|
|
622
632
|
XMLHttpRequest.prototype.open = function (method, url, async = true, username, password) {
|
|
633
|
+
const urlStr = url.toString();
|
|
634
|
+
// 排除 SDK 自身的上报请求
|
|
635
|
+
if (isSdkRequest(urlStr)) {
|
|
636
|
+
this._monitorSkip = true;
|
|
637
|
+
return originalXHROpen.call(this, method, url, async, username, password);
|
|
638
|
+
}
|
|
623
639
|
// 存储请求信息
|
|
624
640
|
this._monitorData = {
|
|
625
641
|
method,
|
|
626
|
-
url:
|
|
642
|
+
url: urlStr,
|
|
627
643
|
startTime: 0,
|
|
628
644
|
};
|
|
629
645
|
return originalXHROpen.call(this, method, url, async, username, password);
|
|
630
646
|
};
|
|
631
647
|
XMLHttpRequest.prototype.send = function (body) {
|
|
648
|
+
// 跳过 SDK 自身的请求
|
|
649
|
+
if (this._monitorSkip) {
|
|
650
|
+
return originalXHRSend.call(this, body);
|
|
651
|
+
}
|
|
632
652
|
const monitorData = this._monitorData;
|
|
633
653
|
if (monitorData) {
|
|
634
654
|
monitorData.startTime = Date.now();
|
|
@@ -671,6 +691,10 @@ function interceptXHR() {
|
|
|
671
691
|
function interceptFetch() {
|
|
672
692
|
window.fetch = async function (input, init) {
|
|
673
693
|
const url = typeof input === 'string' ? input : input instanceof URL ? input.href : input.url;
|
|
694
|
+
// 排除 SDK 自身的上报请求
|
|
695
|
+
if (isSdkRequest(url)) {
|
|
696
|
+
return originalFetch.call(window, input, init);
|
|
697
|
+
}
|
|
674
698
|
const method = init?.method || 'GET';
|
|
675
699
|
const startTime = Date.now();
|
|
676
700
|
const requestBody = typeof init?.body === 'string' ? init.body : undefined;
|
|
@@ -1338,6 +1362,223 @@ function installBehaviorMonitor() {
|
|
|
1338
1362
|
installInputTracker();
|
|
1339
1363
|
}
|
|
1340
1364
|
|
|
1365
|
+
/**
|
|
1366
|
+
* Vue 3 框架集成
|
|
1367
|
+
* 捕获 Vue 组件内的渲染错误
|
|
1368
|
+
*/
|
|
1369
|
+
/**
|
|
1370
|
+
* Vue 3 错误监控插件
|
|
1371
|
+
*
|
|
1372
|
+
* @example
|
|
1373
|
+
* ```ts
|
|
1374
|
+
* import { createApp } from 'vue';
|
|
1375
|
+
* import { VueMonitorPlugin } from 'sobey-monitor-sdk';
|
|
1376
|
+
*
|
|
1377
|
+
* const app = createApp(App);
|
|
1378
|
+
* app.use(VueMonitorPlugin, {
|
|
1379
|
+
* appId: 'your-app-id',
|
|
1380
|
+
* dsn: 'http://your-server/api/report',
|
|
1381
|
+
* });
|
|
1382
|
+
* app.mount('#app');
|
|
1383
|
+
* ```
|
|
1384
|
+
*/
|
|
1385
|
+
const VueMonitorPlugin = {
|
|
1386
|
+
install(app, options) {
|
|
1387
|
+
if (!options || !options.appId || !options.dsn) {
|
|
1388
|
+
console.warn('[Monitor] VueMonitorPlugin requires appId and dsn in options');
|
|
1389
|
+
return;
|
|
1390
|
+
}
|
|
1391
|
+
// 初始化 SDK(如果尚未初始化)
|
|
1392
|
+
try {
|
|
1393
|
+
monitor.init(options);
|
|
1394
|
+
}
|
|
1395
|
+
catch (e) {
|
|
1396
|
+
// SDK 可能已经初始化,忽略错误
|
|
1397
|
+
}
|
|
1398
|
+
// 保存原有的错误处理器
|
|
1399
|
+
const originalErrorHandler = app.config.errorHandler;
|
|
1400
|
+
// 设置 Vue 错误处理器
|
|
1401
|
+
app.config.errorHandler = (err, instance, info) => {
|
|
1402
|
+
// 提取错误信息
|
|
1403
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
1404
|
+
// 获取组件名称
|
|
1405
|
+
let componentName = 'Unknown';
|
|
1406
|
+
if (instance) {
|
|
1407
|
+
componentName = instance.$options?.name ||
|
|
1408
|
+
instance.$.type?.name ||
|
|
1409
|
+
instance.$.type?.__name ||
|
|
1410
|
+
'AnonymousComponent';
|
|
1411
|
+
}
|
|
1412
|
+
// 添加面包屑
|
|
1413
|
+
context.addBreadcrumb({
|
|
1414
|
+
type: 'framework',
|
|
1415
|
+
category: 'vue_error',
|
|
1416
|
+
data: {
|
|
1417
|
+
componentName,
|
|
1418
|
+
info,
|
|
1419
|
+
message: error.message,
|
|
1420
|
+
},
|
|
1421
|
+
});
|
|
1422
|
+
// 上报错误
|
|
1423
|
+
reporter.reportError({
|
|
1424
|
+
type: 'vue_error',
|
|
1425
|
+
message: error.message,
|
|
1426
|
+
stack: error.stack,
|
|
1427
|
+
componentName,
|
|
1428
|
+
lifecycleHook: info,
|
|
1429
|
+
});
|
|
1430
|
+
// 调用原有的错误处理器
|
|
1431
|
+
if (typeof originalErrorHandler === 'function') {
|
|
1432
|
+
originalErrorHandler(err, instance, info);
|
|
1433
|
+
}
|
|
1434
|
+
};
|
|
1435
|
+
// 设置警告处理器(仅在开发模式下)
|
|
1436
|
+
if (options.debug) {
|
|
1437
|
+
const originalWarnHandler = app.config.warnHandler;
|
|
1438
|
+
app.config.warnHandler = (msg, instance, trace) => {
|
|
1439
|
+
// 添加面包屑
|
|
1440
|
+
context.addBreadcrumb({
|
|
1441
|
+
type: 'console',
|
|
1442
|
+
category: 'vue_warning',
|
|
1443
|
+
data: { message: msg },
|
|
1444
|
+
});
|
|
1445
|
+
// 调用原有的警告处理器
|
|
1446
|
+
if (typeof originalWarnHandler === 'function') {
|
|
1447
|
+
originalWarnHandler(msg, instance, trace);
|
|
1448
|
+
}
|
|
1449
|
+
};
|
|
1450
|
+
}
|
|
1451
|
+
if (options.debug) {
|
|
1452
|
+
console.log('[Monitor] Vue plugin installed');
|
|
1453
|
+
}
|
|
1454
|
+
},
|
|
1455
|
+
};
|
|
1456
|
+
|
|
1457
|
+
/**
|
|
1458
|
+
* React 框架集成
|
|
1459
|
+
* 提供 ErrorBoundary 组件捕获渲染错误
|
|
1460
|
+
*/
|
|
1461
|
+
/**
|
|
1462
|
+
* 创建 React 错误边界组件
|
|
1463
|
+
*
|
|
1464
|
+
* @param React - React 库引用
|
|
1465
|
+
* @param config - SDK 配置
|
|
1466
|
+
* @returns ErrorBoundary 组件类
|
|
1467
|
+
*
|
|
1468
|
+
* @example
|
|
1469
|
+
* ```tsx
|
|
1470
|
+
* import React from 'react';
|
|
1471
|
+
* import ReactDOM from 'react-dom';
|
|
1472
|
+
* import { createReactErrorBoundary } from 'sobey-monitor-sdk';
|
|
1473
|
+
*
|
|
1474
|
+
* const ErrorBoundary = createReactErrorBoundary(React, {
|
|
1475
|
+
* appId: 'your-app-id',
|
|
1476
|
+
* dsn: 'http://your-server/api/report',
|
|
1477
|
+
* });
|
|
1478
|
+
*
|
|
1479
|
+
* ReactDOM.render(
|
|
1480
|
+
* <ErrorBoundary fallback={<h1>Something went wrong</h1>}>
|
|
1481
|
+
* <App />
|
|
1482
|
+
* </ErrorBoundary>,
|
|
1483
|
+
* document.getElementById('root')
|
|
1484
|
+
* );
|
|
1485
|
+
* ```
|
|
1486
|
+
*/
|
|
1487
|
+
function createReactErrorBoundary(React, config) {
|
|
1488
|
+
if (!config || !config.appId || !config.dsn) {
|
|
1489
|
+
console.warn('[Monitor] createReactErrorBoundary requires appId and dsn in config');
|
|
1490
|
+
// 返回一个空的组件
|
|
1491
|
+
return class EmptyBoundary extends React.Component {
|
|
1492
|
+
render() {
|
|
1493
|
+
return this.props.children;
|
|
1494
|
+
}
|
|
1495
|
+
};
|
|
1496
|
+
}
|
|
1497
|
+
// 初始化 SDK(如果尚未初始化)
|
|
1498
|
+
try {
|
|
1499
|
+
monitor.init(config);
|
|
1500
|
+
}
|
|
1501
|
+
catch (e) {
|
|
1502
|
+
// SDK 可能已经初始化,忽略错误
|
|
1503
|
+
}
|
|
1504
|
+
/**
|
|
1505
|
+
* React 错误边界组件
|
|
1506
|
+
*/
|
|
1507
|
+
return class ErrorMonitorBoundary extends React.Component {
|
|
1508
|
+
constructor(props) {
|
|
1509
|
+
super(props);
|
|
1510
|
+
this.state = { hasError: false, error: null };
|
|
1511
|
+
}
|
|
1512
|
+
static getDerivedStateFromError(error) {
|
|
1513
|
+
return { hasError: true, error };
|
|
1514
|
+
}
|
|
1515
|
+
componentDidCatch(error, errorInfo) {
|
|
1516
|
+
// 获取组件堆栈
|
|
1517
|
+
const componentStack = errorInfo?.componentStack || '';
|
|
1518
|
+
// 添加面包屑
|
|
1519
|
+
context.addBreadcrumb({
|
|
1520
|
+
type: 'framework',
|
|
1521
|
+
category: 'react_error',
|
|
1522
|
+
data: {
|
|
1523
|
+
message: error.message,
|
|
1524
|
+
componentStack: componentStack.substring(0, 500),
|
|
1525
|
+
},
|
|
1526
|
+
});
|
|
1527
|
+
// 上报错误
|
|
1528
|
+
reporter.reportError({
|
|
1529
|
+
type: 'react_error',
|
|
1530
|
+
message: error.message,
|
|
1531
|
+
stack: error.stack,
|
|
1532
|
+
componentStack,
|
|
1533
|
+
});
|
|
1534
|
+
// 调用自定义错误回调
|
|
1535
|
+
if (typeof this.props.onError === 'function') {
|
|
1536
|
+
this.props.onError(error, errorInfo);
|
|
1537
|
+
}
|
|
1538
|
+
if (config.debug) {
|
|
1539
|
+
console.error('[Monitor] React error caught:', error);
|
|
1540
|
+
console.error('[Monitor] Component stack:', componentStack);
|
|
1541
|
+
}
|
|
1542
|
+
}
|
|
1543
|
+
render() {
|
|
1544
|
+
if (this.state.hasError) {
|
|
1545
|
+
// 显示降级 UI
|
|
1546
|
+
return this.props.fallback || null;
|
|
1547
|
+
}
|
|
1548
|
+
return this.props.children;
|
|
1549
|
+
}
|
|
1550
|
+
};
|
|
1551
|
+
}
|
|
1552
|
+
/**
|
|
1553
|
+
* React Hook: 用于手动上报错误
|
|
1554
|
+
*
|
|
1555
|
+
* @example
|
|
1556
|
+
* ```tsx
|
|
1557
|
+
* import { useMonitorError } from 'sobey-monitor-sdk';
|
|
1558
|
+
*
|
|
1559
|
+
* function MyComponent() {
|
|
1560
|
+
* const reportError = useMonitorError();
|
|
1561
|
+
*
|
|
1562
|
+
* const handleClick = async () => {
|
|
1563
|
+
* try {
|
|
1564
|
+
* await riskyOperation();
|
|
1565
|
+
* } catch (error) {
|
|
1566
|
+
* reportError(error, { action: 'riskyOperation' });
|
|
1567
|
+
* }
|
|
1568
|
+
* };
|
|
1569
|
+
*
|
|
1570
|
+
* return <button onClick={handleClick}>Click</button>;
|
|
1571
|
+
* }
|
|
1572
|
+
* ```
|
|
1573
|
+
*/
|
|
1574
|
+
function createUseMonitorError(React) {
|
|
1575
|
+
return function useMonitorError() {
|
|
1576
|
+
return React.useCallback((error, extra) => {
|
|
1577
|
+
monitor.captureError(error, extra);
|
|
1578
|
+
}, []);
|
|
1579
|
+
};
|
|
1580
|
+
}
|
|
1581
|
+
|
|
1341
1582
|
/**
|
|
1342
1583
|
* 前端监控 SDK
|
|
1343
1584
|
* @description 错误监控、性能监控、行为监控
|
|
@@ -1449,6 +1690,9 @@ class MonitorSDK {
|
|
|
1449
1690
|
// 导出单例
|
|
1450
1691
|
const monitor = new MonitorSDK();
|
|
1451
1692
|
|
|
1693
|
+
exports.VueMonitorPlugin = VueMonitorPlugin;
|
|
1694
|
+
exports.createReactErrorBoundary = createReactErrorBoundary;
|
|
1695
|
+
exports.createUseMonitorError = createUseMonitorError;
|
|
1452
1696
|
exports.default = monitor;
|
|
1453
1697
|
exports.monitor = monitor;
|
|
1454
1698
|
//# sourceMappingURL=index.cjs.js.map
|