sobey-monitor-sdk 1.1.7 → 1.1.9
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/dist/index.cjs.js +115 -13
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.d.ts +19 -1
- package/dist/index.esm.js +115 -13
- package/dist/index.esm.js.map +1 -1
- package/dist/index.umd.js +115 -13
- package/dist/index.umd.js.map +1 -1
- package/dist/types/index.d.ts +19 -1
- package/package.json +1 -1
package/dist/index.umd.js
CHANGED
|
@@ -737,11 +737,12 @@
|
|
|
737
737
|
};
|
|
738
738
|
// 添加到面包屑
|
|
739
739
|
context.addBreadcrumb({
|
|
740
|
-
type: '
|
|
740
|
+
type: 'resource',
|
|
741
741
|
category: 'resource_error',
|
|
742
742
|
data: {
|
|
743
743
|
tagName,
|
|
744
|
-
resourceUrl,
|
|
744
|
+
url: resourceUrl,
|
|
745
|
+
error: `Failed to load ${tagName}`,
|
|
745
746
|
},
|
|
746
747
|
});
|
|
747
748
|
reporter.reportError(errorData);
|
|
@@ -776,6 +777,79 @@
|
|
|
776
777
|
return false;
|
|
777
778
|
return url.includes(cfg.dsn);
|
|
778
779
|
}
|
|
780
|
+
/**
|
|
781
|
+
* 获取嵌套对象的字段值
|
|
782
|
+
* @param obj 对象
|
|
783
|
+
* @param path 字段路径,如 "status" 或 "data.code"
|
|
784
|
+
*/
|
|
785
|
+
function getNestedValue(obj, path) {
|
|
786
|
+
if (!obj || typeof obj !== 'object')
|
|
787
|
+
return undefined;
|
|
788
|
+
const keys = path.split('.');
|
|
789
|
+
let value = obj;
|
|
790
|
+
for (const key of keys) {
|
|
791
|
+
if (value === null || value === undefined)
|
|
792
|
+
return undefined;
|
|
793
|
+
value = value[key];
|
|
794
|
+
}
|
|
795
|
+
return value;
|
|
796
|
+
}
|
|
797
|
+
/**
|
|
798
|
+
* 检查单条规则是否匹配
|
|
799
|
+
*/
|
|
800
|
+
function matchRule(data, rule) {
|
|
801
|
+
const value = getNestedValue(data, rule.field);
|
|
802
|
+
switch (rule.operator) {
|
|
803
|
+
case 'exists':
|
|
804
|
+
return value !== undefined && value !== null;
|
|
805
|
+
case 'eq':
|
|
806
|
+
return value === rule.value;
|
|
807
|
+
case 'ne':
|
|
808
|
+
return value !== rule.value;
|
|
809
|
+
case 'gt':
|
|
810
|
+
return typeof value === 'number' && typeof rule.value === 'number' && value > rule.value;
|
|
811
|
+
case 'gte':
|
|
812
|
+
return typeof value === 'number' && typeof rule.value === 'number' && value >= rule.value;
|
|
813
|
+
case 'lt':
|
|
814
|
+
return typeof value === 'number' && typeof rule.value === 'number' && value < rule.value;
|
|
815
|
+
case 'lte':
|
|
816
|
+
return typeof value === 'number' && typeof rule.value === 'number' && value <= rule.value;
|
|
817
|
+
default:
|
|
818
|
+
return false;
|
|
819
|
+
}
|
|
820
|
+
}
|
|
821
|
+
/**
|
|
822
|
+
* 检测业务错误
|
|
823
|
+
* @param responseBody 响应体字符串
|
|
824
|
+
* @returns 是否为业务错误
|
|
825
|
+
*/
|
|
826
|
+
function detectBusinessError(responseBody) {
|
|
827
|
+
if (!responseBody)
|
|
828
|
+
return false;
|
|
829
|
+
if (!config.isInitialized())
|
|
830
|
+
return false;
|
|
831
|
+
const cfg = config.get();
|
|
832
|
+
const rules = cfg.error?.businessErrorRules;
|
|
833
|
+
if (!rules || rules.length === 0)
|
|
834
|
+
return false;
|
|
835
|
+
try {
|
|
836
|
+
const data = JSON.parse(responseBody);
|
|
837
|
+
// 任一规则匹配时返回 true
|
|
838
|
+
for (const rule of rules) {
|
|
839
|
+
if (matchRule(data, rule)) {
|
|
840
|
+
if (cfg.debug) {
|
|
841
|
+
console.log('[Monitor] Business error detected by rule:', rule, 'data:', data);
|
|
842
|
+
}
|
|
843
|
+
return true;
|
|
844
|
+
}
|
|
845
|
+
}
|
|
846
|
+
return false;
|
|
847
|
+
}
|
|
848
|
+
catch {
|
|
849
|
+
// JSON 解析失败,不是业务错误
|
|
850
|
+
return false;
|
|
851
|
+
}
|
|
852
|
+
}
|
|
779
853
|
function interceptXHR() {
|
|
780
854
|
XMLHttpRequest.prototype.open = function (method, url, async = true, username, password) {
|
|
781
855
|
const urlStr = url.toString();
|
|
@@ -827,6 +901,8 @@
|
|
|
827
901
|
},
|
|
828
902
|
});
|
|
829
903
|
}
|
|
904
|
+
const responseBody = this.responseText?.substring(0, 1000);
|
|
905
|
+
// HTTP 错误或业务错误
|
|
830
906
|
if (status === 0 || status >= 400) {
|
|
831
907
|
reportHttpError({
|
|
832
908
|
method: monitorData.method,
|
|
@@ -834,9 +910,20 @@
|
|
|
834
910
|
status,
|
|
835
911
|
duration,
|
|
836
912
|
requestBody: monitorData.requestBody,
|
|
837
|
-
responseBody
|
|
913
|
+
responseBody,
|
|
838
914
|
});
|
|
839
915
|
}
|
|
916
|
+
else if (status >= 200 && status < 300 && detectBusinessError(responseBody)) {
|
|
917
|
+
// HTTP 200 但检测到业务错误
|
|
918
|
+
reportHttpError({
|
|
919
|
+
method: monitorData.method,
|
|
920
|
+
url: monitorData.url,
|
|
921
|
+
status,
|
|
922
|
+
duration,
|
|
923
|
+
requestBody: monitorData.requestBody,
|
|
924
|
+
responseBody,
|
|
925
|
+
}, true);
|
|
926
|
+
}
|
|
840
927
|
});
|
|
841
928
|
return originalXHRSend.call(this, body);
|
|
842
929
|
};
|
|
@@ -878,15 +965,16 @@
|
|
|
878
965
|
},
|
|
879
966
|
});
|
|
880
967
|
}
|
|
968
|
+
// 克隆响应以读取 body(无论成功与否都需要,用于业务错误检测)
|
|
969
|
+
const cloned = response.clone();
|
|
970
|
+
let responseBody;
|
|
971
|
+
try {
|
|
972
|
+
responseBody = await cloned.text();
|
|
973
|
+
responseBody = responseBody.substring(0, 1000);
|
|
974
|
+
}
|
|
975
|
+
catch { }
|
|
881
976
|
if (!response.ok) {
|
|
882
|
-
//
|
|
883
|
-
const cloned = response.clone();
|
|
884
|
-
let responseBody;
|
|
885
|
-
try {
|
|
886
|
-
responseBody = await cloned.text();
|
|
887
|
-
responseBody = responseBody.substring(0, 1000);
|
|
888
|
-
}
|
|
889
|
-
catch { }
|
|
977
|
+
// HTTP 错误
|
|
890
978
|
reportHttpError({
|
|
891
979
|
method,
|
|
892
980
|
url,
|
|
@@ -896,6 +984,17 @@
|
|
|
896
984
|
responseBody,
|
|
897
985
|
});
|
|
898
986
|
}
|
|
987
|
+
else if (detectBusinessError(responseBody)) {
|
|
988
|
+
// HTTP 200 但检测到业务错误
|
|
989
|
+
reportHttpError({
|
|
990
|
+
method,
|
|
991
|
+
url,
|
|
992
|
+
status,
|
|
993
|
+
duration,
|
|
994
|
+
requestBody,
|
|
995
|
+
responseBody,
|
|
996
|
+
}, true);
|
|
997
|
+
}
|
|
899
998
|
return response;
|
|
900
999
|
}
|
|
901
1000
|
catch (error) {
|
|
@@ -931,10 +1030,13 @@
|
|
|
931
1030
|
/**
|
|
932
1031
|
* 上报 HTTP 错误
|
|
933
1032
|
*/
|
|
934
|
-
function reportHttpError(httpInfo) {
|
|
1033
|
+
function reportHttpError(httpInfo, isBusinessError = false) {
|
|
1034
|
+
const message = isBusinessError
|
|
1035
|
+
? `Business Error ${httpInfo.method} ${httpInfo.url}`
|
|
1036
|
+
: `HTTP ${httpInfo.status} ${httpInfo.method} ${httpInfo.url}`;
|
|
935
1037
|
const errorData = {
|
|
936
1038
|
type: 'http_error',
|
|
937
|
-
message
|
|
1039
|
+
message,
|
|
938
1040
|
httpInfo,
|
|
939
1041
|
};
|
|
940
1042
|
reporter.reportError(errorData);
|