sobey-monitor-sdk 1.0.5 → 1.0.7
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 +2 -0
- package/dist/index.cjs.js +76 -38
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.d.ts +10 -0
- package/dist/index.esm.js +76 -38
- package/dist/index.esm.js.map +1 -1
- package/dist/index.umd.js +76 -38
- package/dist/index.umd.js.map +1 -1
- package/dist/types/index.d.ts +10 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -119,6 +119,8 @@ ReactDOM.render(
|
|
|
119
119
|
| `sampling.error` | number | 1 | 错误采样率 (0-1) |
|
|
120
120
|
| `sampling.performance` | number | 1 | 性能采样率 (0-1) |
|
|
121
121
|
| `sampling.behavior` | number | 1 | 行为采样率 (0-1) |
|
|
122
|
+
| `behavior.maxBreadcrumbs` | number | 20 | 行为回溯最大记录数 |
|
|
123
|
+
| `behavior.recordRequestBreadcrumb` | 'all' \| 'error' \| 'none' | 'error' | 网络请求记录模式:'all' 记录所有、'error' 记录非 2xx 响应(重定向、4xx、5xx、网络错误)、'none' 不记录 |
|
|
122
124
|
| `report.maxBufferSize` | number | 10 | 缓冲区最大数量 |
|
|
123
125
|
| `report.flushInterval` | number | 5000 | 上报间隔 (ms) |
|
|
124
126
|
|
package/dist/index.cjs.js
CHANGED
|
@@ -6,6 +6,7 @@ Object.defineProperty(exports, '__esModule', { value: true });
|
|
|
6
6
|
* 默认配置
|
|
7
7
|
*/
|
|
8
8
|
const DEFAULT_CONFIG = {
|
|
9
|
+
enabled: true,
|
|
9
10
|
debug: false,
|
|
10
11
|
sampling: {
|
|
11
12
|
error: 1,
|
|
@@ -36,6 +37,7 @@ const DEFAULT_CONFIG = {
|
|
|
36
37
|
click: true,
|
|
37
38
|
route: true,
|
|
38
39
|
maxBreadcrumbs: 20,
|
|
40
|
+
recordRequestBreadcrumb: 'error',
|
|
39
41
|
},
|
|
40
42
|
};
|
|
41
43
|
/**
|
|
@@ -447,6 +449,13 @@ class Reporter {
|
|
|
447
449
|
*/
|
|
448
450
|
send(data) {
|
|
449
451
|
const cfg = config.get();
|
|
452
|
+
// 全局开关检查:如果 enabled 为 false,则不上报
|
|
453
|
+
if (cfg.enabled === false) {
|
|
454
|
+
if (cfg.debug) {
|
|
455
|
+
console.log('[Monitor] SDK disabled, skip report:', data.type || 'unknown');
|
|
456
|
+
}
|
|
457
|
+
return;
|
|
458
|
+
}
|
|
450
459
|
if (cfg.debug) {
|
|
451
460
|
console.log('[Monitor] Report:', data);
|
|
452
461
|
}
|
|
@@ -662,18 +671,26 @@ function interceptXHR() {
|
|
|
662
671
|
return;
|
|
663
672
|
const duration = Date.now() - monitorData.startTime;
|
|
664
673
|
const status = this.status;
|
|
665
|
-
//
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
674
|
+
// 根据配置决定是否添加到面包屑
|
|
675
|
+
const cfg = config.get();
|
|
676
|
+
const recordMode = cfg.behavior?.recordRequestBreadcrumb || 'error';
|
|
677
|
+
// 重定向(3xx)始终记录,不受配置控制
|
|
678
|
+
const isRedirect = status >= 300 && status < 400;
|
|
679
|
+
// 其他异常情况(0-网络错误、4xx-客户端错误、5xx-服务端错误)根据配置控制
|
|
680
|
+
const isError = status === 0 || status < 200 || status >= 400;
|
|
681
|
+
const shouldRecord = isRedirect || recordMode === 'all' || (recordMode === 'error' && isError);
|
|
682
|
+
if (shouldRecord) {
|
|
683
|
+
context.addBreadcrumb({
|
|
684
|
+
type: 'request',
|
|
685
|
+
category: 'xhr',
|
|
686
|
+
data: {
|
|
687
|
+
method: monitorData.method,
|
|
688
|
+
url: monitorData.url,
|
|
689
|
+
status,
|
|
690
|
+
duration,
|
|
691
|
+
},
|
|
692
|
+
});
|
|
693
|
+
}
|
|
677
694
|
if (status === 0 || status >= 400) {
|
|
678
695
|
reportHttpError({
|
|
679
696
|
method: monitorData.method,
|
|
@@ -705,18 +722,26 @@ function interceptFetch() {
|
|
|
705
722
|
const response = await originalFetch.call(window, input, init);
|
|
706
723
|
const duration = Date.now() - startTime;
|
|
707
724
|
const status = response.status;
|
|
708
|
-
//
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
725
|
+
// 根据配置决定是否添加到面包屑
|
|
726
|
+
const cfg = config.get();
|
|
727
|
+
const recordMode = cfg.behavior?.recordRequestBreadcrumb || 'error';
|
|
728
|
+
// 重定向(3xx)始终记录,不受配置控制
|
|
729
|
+
const isRedirect = status >= 300 && status < 400;
|
|
730
|
+
// 其他异常情况根据配置控制
|
|
731
|
+
const isError = status < 200 || status >= 400;
|
|
732
|
+
const shouldRecord = isRedirect || recordMode === 'all' || (recordMode === 'error' && isError);
|
|
733
|
+
if (shouldRecord) {
|
|
734
|
+
context.addBreadcrumb({
|
|
735
|
+
type: 'request',
|
|
736
|
+
category: 'fetch',
|
|
737
|
+
data: {
|
|
738
|
+
method,
|
|
739
|
+
url,
|
|
740
|
+
status,
|
|
741
|
+
duration,
|
|
742
|
+
},
|
|
743
|
+
});
|
|
744
|
+
}
|
|
720
745
|
if (!response.ok) {
|
|
721
746
|
// 克隆响应以读取 body
|
|
722
747
|
const cloned = response.clone();
|
|
@@ -739,18 +764,23 @@ function interceptFetch() {
|
|
|
739
764
|
}
|
|
740
765
|
catch (error) {
|
|
741
766
|
const duration = Date.now() - startTime;
|
|
742
|
-
//
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
767
|
+
// 网络错误时根据配置决定是否添加到面包屑
|
|
768
|
+
const cfg = config.get();
|
|
769
|
+
const recordMode = cfg.behavior?.recordRequestBreadcrumb || 'error';
|
|
770
|
+
// 网络错误属于 error,当模式为 'all' 或 'error' 时都记录
|
|
771
|
+
if (recordMode !== 'none') {
|
|
772
|
+
context.addBreadcrumb({
|
|
773
|
+
type: 'request',
|
|
774
|
+
category: 'fetch',
|
|
775
|
+
data: {
|
|
776
|
+
method,
|
|
777
|
+
url,
|
|
778
|
+
status: 0,
|
|
779
|
+
duration,
|
|
780
|
+
error: error.message,
|
|
781
|
+
},
|
|
782
|
+
});
|
|
783
|
+
}
|
|
754
784
|
reportHttpError({
|
|
755
785
|
method,
|
|
756
786
|
url,
|
|
@@ -1079,10 +1109,14 @@ function installClickTracker() {
|
|
|
1079
1109
|
function extractClickData(element, event) {
|
|
1080
1110
|
const tagName = element.tagName.toLowerCase();
|
|
1081
1111
|
const rect = element.getBoundingClientRect();
|
|
1112
|
+
// SVG 元素的 className 是 SVGAnimatedString 对象,需要特殊处理
|
|
1113
|
+
const classNameStr = typeof element.className === 'string'
|
|
1114
|
+
? element.className
|
|
1115
|
+
: element.className?.baseVal || '';
|
|
1082
1116
|
return {
|
|
1083
1117
|
tagName,
|
|
1084
1118
|
id: element.id || undefined,
|
|
1085
|
-
className:
|
|
1119
|
+
className: classNameStr || undefined,
|
|
1086
1120
|
text: getElementText(element),
|
|
1087
1121
|
path: getElementPath(element),
|
|
1088
1122
|
// 鼠标坐标
|
|
@@ -1120,7 +1154,11 @@ function getElementPath(element) {
|
|
|
1120
1154
|
selector += `#${current.id}`;
|
|
1121
1155
|
}
|
|
1122
1156
|
else if (current.className) {
|
|
1123
|
-
|
|
1157
|
+
// SVG 元素的 className 是 SVGAnimatedString 对象,需要特殊处理
|
|
1158
|
+
const classNameStr = typeof current.className === 'string'
|
|
1159
|
+
? current.className
|
|
1160
|
+
: current.className?.baseVal || '';
|
|
1161
|
+
const classes = classNameStr.split(' ').filter(Boolean).slice(0, 2);
|
|
1124
1162
|
if (classes.length) {
|
|
1125
1163
|
selector += `.${classes.join('.')}`;
|
|
1126
1164
|
}
|