@arms/rum-reactnative 0.1.3-beta.4 → 0.1.4-beta.1

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.
Files changed (84) hide show
  1. package/README.md +7 -1
  2. package/RumSdkReactnative.podspec +3 -1
  3. package/android/src/main/java/com/rumsdkreactnative/RumSdkReactnativeModule.kt +31 -0
  4. package/docs/ReactNative SDK/351/205/215/347/275/256/345/217/202/350/200/203.md" +25 -0
  5. package/docs/SDK /347/211/210/346/234/254/350/257/264/346/230/216.md" +14 -0
  6. package/ios/RumAppStateRecorder.h +69 -0
  7. package/ios/RumAppStateRecorder.mm +547 -0
  8. package/ios/RumCrashReporter.h +32 -0
  9. package/ios/RumCrashReporter.mm +156 -33
  10. package/ios/RumSdkReactnative.mm +81 -1
  11. package/lib/commonjs/NativeRumSdkReactnative.js +1 -54
  12. package/lib/commonjs/collector/action/index.js +1 -108
  13. package/lib/commonjs/collector/exception/crash.js +1 -148
  14. package/lib/commonjs/collector/exception/index.js +1 -238
  15. package/lib/commonjs/collector/exception/oom.js +1 -0
  16. package/lib/commonjs/collector/index.js +1 -42
  17. package/lib/commonjs/collector/resource/api.js +1 -292
  18. package/lib/commonjs/collector/view/perf.js +1 -79
  19. package/lib/commonjs/collector/view/pv.js +1 -88
  20. package/lib/commonjs/expoConfigPlugin.js +1 -37
  21. package/lib/commonjs/index.js +1 -29
  22. package/lib/commonjs/plugin.js +1 -47
  23. package/lib/commonjs/processor/default-processor.js +1 -27
  24. package/lib/commonjs/processor/session-processor.js +1 -47
  25. package/lib/commonjs/reporter/index.js +1 -148
  26. package/lib/commonjs/reporter/monitor-reporter.js +1 -43
  27. package/lib/commonjs/shell.js +1 -91
  28. package/lib/commonjs/types/client.js +1 -6
  29. package/lib/commonjs/types/crash.js +1 -37
  30. package/lib/commonjs/types/index.js +1 -2
  31. package/lib/commonjs/types/oom.js +1 -0
  32. package/lib/commonjs/utils/action.js +1 -305
  33. package/lib/commonjs/utils/api.js +1 -84
  34. package/lib/commonjs/utils/base.js +1 -95
  35. package/lib/commonjs/utils/crash.js +1 -149
  36. package/lib/commonjs/utils/platform.js +1 -162
  37. package/lib/commonjs/utils/session.js +1 -158
  38. package/lib/commonjs/utils/url.js +1 -59
  39. package/lib/commonjs/utils/view.js +1 -93
  40. package/lib/module/NativeRumSdkReactnative.js +1 -51
  41. package/lib/module/collector/action/index.js +1 -103
  42. package/lib/module/collector/exception/crash.js +1 -143
  43. package/lib/module/collector/exception/index.js +1 -233
  44. package/lib/module/collector/exception/oom.js +1 -0
  45. package/lib/module/collector/index.js +1 -8
  46. package/lib/module/collector/resource/api.js +1 -287
  47. package/lib/module/collector/view/perf.js +1 -79
  48. package/lib/module/collector/view/pv.js +1 -83
  49. package/lib/module/expoConfigPlugin.js +1 -33
  50. package/lib/module/index.js +1 -7
  51. package/lib/module/plugin.js +1 -42
  52. package/lib/module/processor/default-processor.js +1 -22
  53. package/lib/module/processor/session-processor.js +1 -42
  54. package/lib/module/reporter/index.js +1 -144
  55. package/lib/module/reporter/monitor-reporter.js +1 -38
  56. package/lib/module/shell.js +1 -84
  57. package/lib/module/types/client.js +1 -4
  58. package/lib/module/types/crash.js +1 -33
  59. package/lib/module/types/index.js +1 -2
  60. package/lib/module/types/oom.js +1 -0
  61. package/lib/module/utils/action.js +1 -299
  62. package/lib/module/utils/api.js +1 -76
  63. package/lib/module/utils/base.js +1 -90
  64. package/lib/module/utils/crash.js +1 -144
  65. package/lib/module/utils/platform.js +1 -150
  66. package/lib/module/utils/session.js +1 -154
  67. package/lib/module/utils/url.js +1 -54
  68. package/lib/module/utils/view.js +1 -88
  69. package/lib/typescript/commonjs/src/NativeRumSdkReactnative.d.ts +10 -0
  70. package/lib/typescript/commonjs/src/collector/exception/oom.d.ts +34 -0
  71. package/lib/typescript/commonjs/src/collector/index.d.ts +1 -0
  72. package/lib/typescript/commonjs/src/shell.d.ts +1 -1
  73. package/lib/typescript/commonjs/src/types/client.d.ts +27 -0
  74. package/lib/typescript/commonjs/src/types/oom.d.ts +58 -0
  75. package/lib/typescript/commonjs/src/utils/crash.d.ts +13 -0
  76. package/lib/typescript/module/src/NativeRumSdkReactnative.d.ts +10 -0
  77. package/lib/typescript/module/src/collector/exception/oom.d.ts +34 -0
  78. package/lib/typescript/module/src/collector/index.d.ts +1 -0
  79. package/lib/typescript/module/src/shell.d.ts +1 -1
  80. package/lib/typescript/module/src/types/client.d.ts +27 -0
  81. package/lib/typescript/module/src/types/oom.d.ts +58 -0
  82. package/lib/typescript/module/src/utils/crash.d.ts +13 -0
  83. package/package.json +1 -2
  84. package/src/NativeRumSdkReactnative.ts +18 -0
@@ -1,238 +1 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.default = void 0;
7
- var _rumCore = require("@arms/rum-core");
8
- class ExceptionCollector {
9
- name = 'exception-collector';
10
- installed = false;
11
- /** fatal 去重保护:防止连续 fatal error 重复上报 */
12
- handlingFatal = false;
13
- /** 防止 errorHandle 内部 console.error 形成循环 */
14
- inErrorHandle = false;
15
- origin = {
16
- consoleError: console.error,
17
- originalOnError: null,
18
- originalOnUnhandledRejection: null
19
- };
20
- setup(ctx, sendEvent) {
21
- this.ctx = ctx;
22
- this.sendEvent = sendEvent;
23
- this.hackOrigin();
24
- }
25
- hackOrigin() {
26
- // 防止重复安装覆盖 originalOnError
27
- if (this.installed) return;
28
- this.installed = true;
29
- const self = this;
30
- const {
31
- collectors = {}
32
- } = this.ctx.getConfig();
33
- if (collectors.jsError !== false) {
34
- if (ErrorUtils) {
35
- this.origin.originalOnError = ErrorUtils.getGlobalHandler?.();
36
- ErrorUtils.setGlobalHandler(this.onError);
37
- }
38
- // Promise rejection: 优先 Hermes,JSC 兜底
39
- if (HermesInternal?.enablePromiseRejectionTracker && HermesInternal?.hasPromise?.()) {
40
- HermesInternal.enablePromiseRejectionTracker({
41
- allRejections: true,
42
- onUnhandled: this.onUnhandled
43
- });
44
- } else {
45
- // JSC / 其他引擎:监听 unhandledrejection 事件
46
- this.setupJSCPromiseRejection();
47
- }
48
- }
49
- if (collectors.consoleError !== false) {
50
- (0, _rumCore.interceptFunction)(console, 'error', function (error) {
51
- if (self.inErrorHandle) return; // 防止循环
52
- self.errorHandle(error, 'console.error');
53
- });
54
- }
55
- }
56
-
57
- /** JSC 引擎 Promise rejection 兜底方案 */
58
- setupJSCPromiseRejection() {
59
- try {
60
- if (typeof globalThis !== 'undefined') {
61
- const self = this;
62
- this.origin.originalOnUnhandledRejection = globalThis.onunhandledrejection || null;
63
- globalThis.onunhandledrejection = function (event) {
64
- if (event?.reason) {
65
- self.errorHandle(event.reason, 'onUnhandled');
66
- }
67
- if (typeof self.origin.originalOnUnhandledRejection === 'function') {
68
- self.origin.originalOnUnhandledRejection.call(this, event);
69
- }
70
- };
71
- }
72
- } catch {
73
- // JSC 不支持时不影响主流程
74
- }
75
- }
76
- onError = (e, isFatal) => {
77
- // fatal 去重保护:防止连续 fatal error 重复上报或死循环
78
- if (isFatal) {
79
- if (this.handlingFatal) return;
80
- this.handlingFatal = true;
81
- }
82
-
83
- // 先采集(确保数据不丢)
84
- this.errorHandle(e, 'onError');
85
-
86
- // fatal error:确保事件落盘后再终止进程
87
- if (isFatal && this.ctx) {
88
- try {
89
- const reporter = this.ctx.reporter;
90
- if (reporter && typeof reporter.flush === 'function') {
91
- // 使用超时兜底,避免永久阻塞
92
- Promise.race([reporter.flush(), new Promise(resolve => setTimeout(resolve, 2000))]).finally(() => {
93
- if (this.origin.originalOnError) {
94
- this.origin.originalOnError(e, isFatal);
95
- }
96
- });
97
- return;
98
- }
99
- } catch {
100
- // ignore flush error
101
- }
102
- }
103
-
104
- // 非 fatal 或 flush 不可用时直接链式调用
105
- if (this.origin.originalOnError) {
106
- this.origin.originalOnError(e, isFatal);
107
- }
108
- if (!isFatal) {
109
- this.handlingFatal = false;
110
- }
111
- };
112
- onUnhandled = (_id, error) => {
113
- this.errorHandle(error, 'onUnhandled');
114
- };
115
- errorHandle = (error, source = '') => {
116
- if (this.inErrorHandle) return; // 防止循环
117
- if (error == null) return; // null/undefined 直接跳过
118
-
119
- this.inErrorHandle = true;
120
- try {
121
- let name = '';
122
- let message = '';
123
- let file = '';
124
- let stack = '';
125
- let line = 0;
126
- let column = 0;
127
- if (error instanceof Object) {
128
- name = String(error.name || error.constructor?.name || 'Error');
129
- message = String(error.message || '');
130
- file = String(error.filename || error.fileName || '');
131
- // stack 可能在 error.stack 或 error.componentStack(React 渲染错误)
132
- stack = String(error.stack || '');
133
- if (!stack && error.componentStack) {
134
- stack = String(error.componentStack);
135
- }
136
- line = Number(error.lineno || error.lineNumber || 0);
137
- column = Number(error.colno || error.columnNumber || 0);
138
- } else if (typeof error === 'string') {
139
- stack = error;
140
- const err = this.getErrorByStack(error);
141
- if (err) {
142
- name = err.name || 'Error';
143
- message = err.message || '';
144
- } else {
145
- name = 'Error';
146
- message = error.substring(0, 200);
147
- }
148
- } else if (typeof error === 'number' || typeof error === 'boolean') {
149
- name = 'Error';
150
- message = String(error);
151
- }
152
- if (!name || !message && !stack || this.errorFilter(error)) {
153
- return;
154
- }
155
- if (this.ctx && this.sendEvent) {
156
- const baseRumEvent = this.ctx.session.getBaseEvent();
157
- const normalizedSource = source === 'console.error' ? 'console' : 'event';
158
- this.sendEvent({
159
- ...baseRumEvent,
160
- event_type: _rumCore.RumEventType.EXCEPTION,
161
- source: normalizedSource,
162
- type: 'error',
163
- name,
164
- message,
165
- file,
166
- stack,
167
- line,
168
- column,
169
- times: 1
170
- });
171
- }
172
- } finally {
173
- this.inErrorHandle = false;
174
- }
175
- };
176
-
177
- /**
178
- * 根据stack获取Error信息
179
- * TODO: 增加基于Stack解析filename和lineNumber的能力
180
- * @param stack
181
- * @returns
182
- */
183
- getErrorByStack(stack = '') {
184
- const res = stack.split('\n');
185
- const prefix = 'at ';
186
- if (res.length < 2) return;
187
- for (let i = 1; i < res.length; i++) {
188
- const str = res[i] || '';
189
- if (str.trim().startsWith(prefix)) {
190
- const line = res[i - 1] || '';
191
- const index = line.indexOf(': ');
192
- return {
193
- name: line.substring(0, index),
194
- message: line.substring(index + 2)
195
- };
196
- }
197
- }
198
- return;
199
- }
200
- errorFilter(err) {
201
- let {
202
- exception: filters
203
- } = this.ctx.getConfig().filters || {};
204
- if (!filters) {
205
- return false;
206
- }
207
- if (!(0, _rumCore.isArray)(filters)) {
208
- filters = [filters];
209
- }
210
- return (0, _rumCore.matchList)(filters, err.name, true, err) || (0, _rumCore.matchList)(filters, err.message, true, err) || (0, _rumCore.matchList)(filters, err.stack || '', true, err);
211
- }
212
- destroy() {
213
- if (!this.installed) return;
214
- // 恢复 console.error
215
- if (this.origin.consoleError) {
216
- console.error = this.origin.consoleError;
217
- }
218
- // 恢复 ErrorUtils.setGlobalHandler
219
- if (ErrorUtils && this.origin.originalOnError) {
220
- try {
221
- ErrorUtils.setGlobalHandler(this.origin.originalOnError);
222
- } catch {
223
- // ignore
224
- }
225
- }
226
- // 恢复 onunhandledrejection
227
- if (typeof globalThis !== 'undefined' && this.origin.originalOnUnhandledRejection !== null) {
228
- try {
229
- globalThis.onunhandledrejection = this.origin.originalOnUnhandledRejection;
230
- } catch {
231
- // ignore
232
- }
233
- }
234
- this.installed = false;
235
- }
236
- }
237
- exports.default = ExceptionCollector;
238
- //# sourceMappingURL=index.js.map
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.default=void 0;var _rumCore=require("@arms/rum-core");class ExceptionCollector{name="exception-collector";installed=!1;handlingFatal=!1;inErrorHandle=!1;origin={consoleError:console.error,originalOnError:null,originalOnUnhandledRejection:null};setup(r,e){this.ctx=r,this.sendEvent=e,this.hackOrigin()}hackOrigin(){if(this.installed)return;this.installed=!0;const r=this,{collectors:e={}}=this.ctx.getConfig();!1!==e.jsError&&(ErrorUtils&&(this.origin.originalOnError=ErrorUtils.getGlobalHandler?.(),ErrorUtils.setGlobalHandler(this.onError)),HermesInternal?.enablePromiseRejectionTracker&&HermesInternal?.hasPromise?.()?HermesInternal.enablePromiseRejectionTracker({allRejections:!0,onUnhandled:this.onUnhandled}):this.setupJSCPromiseRejection()),!1!==e.consoleError&&(0,_rumCore.interceptFunction)(console,"error",function(e){r.inErrorHandle||r.errorHandle(e,"console.error")})}setupJSCPromiseRejection(){try{if("undefined"!=typeof globalThis){const r=this;this.origin.originalOnUnhandledRejection=globalThis.onunhandledrejection||null,globalThis.onunhandledrejection=function(e){e?.reason&&r.errorHandle(e.reason,"onUnhandled"),"function"==typeof r.origin.originalOnUnhandledRejection&&r.origin.originalOnUnhandledRejection.call(this,e)}}}catch{}}onError=(r,e)=>{if(e){if(this.handlingFatal)return;this.handlingFatal=!0}if(this.errorHandle(r,"onError"),e&&this.ctx)try{const n=this.ctx.reporter;if(n&&"function"==typeof n.flush)return void Promise.race([n.flush(),new Promise(r=>setTimeout(r,2e3))]).finally(()=>{this.origin.originalOnError&&this.origin.originalOnError(r,e)})}catch{}this.origin.originalOnError&&this.origin.originalOnError(r,e),e||(this.handlingFatal=!1)};onUnhandled=(r,e)=>{this.errorHandle(e,"onUnhandled")};errorHandle=(r,e="")=>{if(!this.inErrorHandle&&null!=r){this.inErrorHandle=!0;try{let n="",i="",o="",t="",s=0,l=0;if(r instanceof Object)n=String(r.name||r.constructor?.name||"Error"),i=String(r.message||""),o=String(r.filename||r.fileName||""),t=String(r.stack||""),!t&&r.componentStack&&(t=String(r.componentStack)),s=Number(r.lineno||r.lineNumber||0),l=Number(r.colno||r.columnNumber||0);else if("string"==typeof r){t=r;const e=this.getErrorByStack(r);e?(n=e.name||"Error",i=e.message||""):(n="Error",i=r.substring(0,200))}else"number"!=typeof r&&"boolean"!=typeof r||(n="Error",i=String(r));if(!n||!i&&!t||this.errorFilter(r))return;if(this.ctx&&this.sendEvent){const r=this.ctx.session.getBaseEvent(),a="console.error"===e?"console":"event";this.sendEvent({...r,event_type:_rumCore.RumEventType.EXCEPTION,source:a,type:"error",name:n,message:i,file:o,stack:t,line:s,column:l,times:1})}}finally{this.inErrorHandle=!1}}};getErrorByStack(r=""){const e=r.split("\n");if(!(e.length<2))for(let r=1;r<e.length;r++){if((e[r]||"").trim().startsWith("at ")){const n=e[r-1]||"",i=n.indexOf(": ");return{name:n.substring(0,i),message:n.substring(i+2)}}}}errorFilter(r){let{exception:e}=this.ctx.getConfig().filters||{};return!!e&&((0,_rumCore.isArray)(e)||(e=[e]),(0,_rumCore.matchList)(e,r.name,!0,r)||(0,_rumCore.matchList)(e,r.message,!0,r)||(0,_rumCore.matchList)(e,r.stack||"",!0,r))}destroy(){if(this.installed){if(this.origin.consoleError&&(console.error=this.origin.consoleError),ErrorUtils&&this.origin.originalOnError)try{ErrorUtils.setGlobalHandler(this.origin.originalOnError)}catch{}if("undefined"!=typeof globalThis&&null!==this.origin.originalOnUnhandledRejection)try{globalThis.onunhandledrejection=this.origin.originalOnUnhandledRejection}catch{}this.installed=!1}}}exports.default=ExceptionCollector;
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.default=void 0;var _rumCore=require("@arms/rum-core"),_NativeRumSdkReactnative=_interopRequireDefault(require("../../NativeRumSdkReactnative")),_crash=require("../../types/crash"),_crash2=require("../../utils/crash");function _interopRequireDefault(e){return e&&e.__esModule?e:{default:e}}class OomCollector{name="oom-collector";initialized=!1;pendingAckIds=new Set;setup(e,t){const{collectors:r={}}=e.getConfig();if(!0===r.oom){this.ctx=e,this.sendEvent=t;try{_NativeRumSdkReactnative.default.updateCollectorsConfig(JSON.stringify({oom:!0}))}catch{}e.emitter.on(_crash.CRASH_CONTEXT_EVENT,this.onCrashContextChange),e.emitter.on(_crash.CRASH_REPORT_ACK_EVENT,this.onCrashReportAck),this.processPendingOomReports().catch(e=>{_rumCore.logger.error("oom-collector","Failed to process OOM reports",e)})}}async processPendingOomReports(){if(this.initialized)return;this.initialized=!0;const e=await(0,_crash2.safeNativeCall)(()=>_NativeRumSdkReactnative.default.getPendingOomReports(),"getPendingOomReports");if(!e)return;let t=[];try{t=JSON.parse(e)||[]}catch(e){return void _rumCore.logger.error("oom-collector","Failed to parse OOM reports JSON",e)}if(Array.isArray(t)&&0!==t.length)for(const e of t)try{const t=(0,_crash2.convertOomToRumEvent)(e),r=e.oom_id;if(r){try{const e=JSON.parse(t.snapshots);e[_crash.CRASH_ID_FIELD]=r,t.snapshots=JSON.stringify(e)}catch{t[_crash.CRASH_ID_FIELD]=r}this.pendingAckIds.add(r)}this.sendEvent?.(t,{immediate:!0})}catch(e){_rumCore.logger.warn("oom-collector","Failed to convert OOM report",e)}}onCrashContextChange=e=>{try{_NativeRumSdkReactnative.default.updateCrashContext(JSON.stringify(e))}catch{}};onCrashReportAck=e=>{if(!e||!Array.isArray(e.crashIds)||0===e.crashIds.length)return;const t=e.crashIds.filter(e=>this.pendingAckIds.has(e));if(0!==t.length)if(e.success)(0,_crash2.safeNativeCall)(()=>_NativeRumSdkReactnative.default.clearOomReports(JSON.stringify(t)),"clearOomReports").finally(()=>{for(const e of t)this.pendingAckIds.delete(e)});else for(const e of t)this.pendingAckIds.delete(e)};destroy(){this.ctx?.emitter.off(_crash.CRASH_CONTEXT_EVENT,this.onCrashContextChange),this.ctx?.emitter.off(_crash.CRASH_REPORT_ACK_EVENT,this.onCrashReportAck),this.pendingAckIds.clear(),this.sendEvent=void 0}}exports.default=OomCollector;
@@ -1,42 +1 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- Object.defineProperty(exports, "ActionCollector", {
7
- enumerable: true,
8
- get: function () {
9
- return _index2.default;
10
- }
11
- });
12
- Object.defineProperty(exports, "ApiCollector", {
13
- enumerable: true,
14
- get: function () {
15
- return _api.default;
16
- }
17
- });
18
- Object.defineProperty(exports, "CrashCollector", {
19
- enumerable: true,
20
- get: function () {
21
- return _crash.default;
22
- }
23
- });
24
- Object.defineProperty(exports, "ExceptionCollector", {
25
- enumerable: true,
26
- get: function () {
27
- return _index.default;
28
- }
29
- });
30
- Object.defineProperty(exports, "PvCollector", {
31
- enumerable: true,
32
- get: function () {
33
- return _pv.default;
34
- }
35
- });
36
- var _pv = _interopRequireDefault(require("./view/pv"));
37
- var _index = _interopRequireDefault(require("./exception/index"));
38
- var _crash = _interopRequireDefault(require("./exception/crash"));
39
- var _api = _interopRequireDefault(require("./resource/api"));
40
- var _index2 = _interopRequireDefault(require("./action/index"));
41
- function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
42
- //# sourceMappingURL=index.js.map
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),Object.defineProperty(exports,"ActionCollector",{enumerable:!0,get:function(){return _index2.default}}),Object.defineProperty(exports,"ApiCollector",{enumerable:!0,get:function(){return _api.default}}),Object.defineProperty(exports,"CrashCollector",{enumerable:!0,get:function(){return _crash.default}}),Object.defineProperty(exports,"ExceptionCollector",{enumerable:!0,get:function(){return _index.default}}),Object.defineProperty(exports,"OomCollector",{enumerable:!0,get:function(){return _oom.default}}),Object.defineProperty(exports,"PvCollector",{enumerable:!0,get:function(){return _pv.default}});var _pv=_interopRequireDefault(require("./view/pv")),_index=_interopRequireDefault(require("./exception/index")),_crash=_interopRequireDefault(require("./exception/crash")),_oom=_interopRequireDefault(require("./exception/oom")),_api=_interopRequireDefault(require("./resource/api")),_index2=_interopRequireDefault(require("./action/index"));function _interopRequireDefault(e){return e&&e.__esModule?e:{default:e}}
@@ -1,292 +1 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.default = void 0;
7
- var _rumCore = require("@arms/rum-core");
8
- var _base = require("../../utils/base");
9
- var _api = require("../../utils/api");
10
- class ApiCollector {
11
- name = 'api-collector';
12
- setup(ctx, sendEvent) {
13
- const collectors = ctx.getConfig().collectors || {};
14
- if (collectors.api === false) {
15
- return;
16
- }
17
- this.sendEvent = sendEvent;
18
- this.ctx = ctx;
19
- // this.perfObserver();
20
- this.hackXhr();
21
- // this.hackFetch();
22
- }
23
- injectTracing(apiAttr, inject) {
24
- const {
25
- tracing = false,
26
- pid,
27
- version = '1.0.0'
28
- } = this.ctx.getConfig();
29
- const {
30
- enable,
31
- sample,
32
- propagatorTypes,
33
- allowedUrls,
34
- tracestate,
35
- baggage = false
36
- } = (0, _rumCore.parseTracingOptions)(tracing);
37
- if (!enable) return;
38
- // @ts-ignore
39
- const resolvedTraceOption = (0, _rumCore.find)(allowedUrls, item => (0, _rumCore.matchList)([item.match], apiAttr.url || ''));
40
- if (!resolvedTraceOption) return;
41
- let pTypes = resolvedTraceOption.propagatorTypes;
42
- if (pTypes && pTypes.length === 0) {
43
- pTypes = propagatorTypes;
44
- }
45
- // skywalking
46
- let isSw8 = false;
47
- if (pTypes && pTypes.indexOf('sw8') > -1) {
48
- pTypes = ['sw8'];
49
- isSw8 = true;
50
- }
51
- const session = this.ctx.session;
52
- const traceId = isSw8 ? (0, _rumCore.generateGUID)() : (0, _rumCore.generateTraceId)();
53
- const spanId = isSw8 ? (0, _rumCore.generateGUID)() : (0, _rumCore.generateSpanId)();
54
- const sampled = (0, _rumCore.performDraw)(sample);
55
- const uid = session.getUserId();
56
- const sid = session.getSessionId();
57
- const traceContext = tracestate ? `rum=v2&browser&${pid}&${sid}&${uid}` : undefined;
58
- const baggageContext = baggage ? `rum=v2,appType=browser,pid=${pid},sid=${sid},uid=${uid}` : undefined;
59
- const tracingHeaders = (0, _rumCore.makeTracingHeaders)(traceId, spanId, sampled, pTypes || [], {
60
- tracestate: traceContext,
61
- baggage: baggageContext,
62
- appId: pid,
63
- appVersion: version,
64
- viewName: apiAttr.view?.name
65
- // host: location.host
66
- });
67
- if (sampled) {
68
- apiAttr.trace_id = traceId;
69
- apiAttr.trace_data = JSON.stringify({
70
- spanId,
71
- sample,
72
- sampled,
73
- headers: tracingHeaders
74
- });
75
- }
76
- inject(tracingHeaders);
77
- }
78
- hackXhr() {
79
- const oldXHRProto = XMLHttpRequest.prototype;
80
- const that = this;
81
- (0, _rumCore.interceptFunction)(oldXHRProto, 'open', function (method, url, async, user, password) {
82
- const filters = that.ctx.getConfig().filters || {};
83
- const urlStr = String(url);
84
- const methodStr = method.toUpperCase();
85
- // chrome 对 URL 的最大长度为 8182 个字符
86
- if ((0, _rumCore.urlMatch)(urlStr, filters.resource) || methodStr === 'HEAD' || urlStr.length > 8182) return;
87
- this.apiCache = {
88
- type: _api.ApiType.XHR,
89
- method,
90
- url,
91
- async,
92
- user,
93
- password,
94
- headers: {}
95
- };
96
- const baseRumEvent = that.ctx.session.getBaseEvent();
97
- this.apiAttr = {
98
- ...baseRumEvent,
99
- url: urlStr,
100
- method: methodStr
101
- };
102
- }, true);
103
- (0, _rumCore.interceptFunction)(oldXHRProto, 'setRequestHeader', function (header, value) {
104
- if (!this.apiCache) return;
105
- this.apiCache.headers = {
106
- ...this.apiCache.headers,
107
- [header]: value
108
- };
109
- }, true);
110
- (0, _rumCore.interceptFunction)(oldXHRProto, 'send', function (body) {
111
- if (!this.apiAttr || !this.apiCache) return;
112
- let apiAttr = this.apiAttr;
113
- this.apiCache.data = body;
114
- that.injectTracing(this.apiAttr, tracingHeaders => {
115
- Object.keys(tracingHeaders).forEach(key => {
116
- tracingHeaders[key] && this.setRequestHeader(key, tracingHeaders[key]);
117
- });
118
- });
119
- this.addEventListener('loadend', async () => {
120
- const {
121
- status,
122
- statusText,
123
- response
124
- } = this;
125
- const {
126
- evaluateApi
127
- } = that.ctx.getConfig();
128
- if (!this.apiAttr) return;
129
- apiAttr.status_code = status;
130
- apiAttr.message = statusText;
131
- const entry = {
132
- name: this.apiAttr.url,
133
- entryType: _api.ApiType.XHR,
134
- duration: (0, _base.getCurrentTime)() - apiAttr.timestamp
135
- };
136
- if ((0, _rumCore.isFunction)(evaluateApi)) {
137
- try {
138
- let error;
139
- if (apiAttr.success === _rumCore.ResourceStatus.Failed) {
140
- error = new Error(_api.ApiType.XHR + ' error');
141
- }
142
- const attrs = await evaluateApi?.(this.apiCache, response, error, this);
143
- this.apiAttr = apiAttr = {
144
- ...apiAttr,
145
- ...(0, _api.reviseApiAttr)(attrs)
146
- };
147
- } catch (e) {
148
- _rumCore.logger.warn('api-collector', 'evaluateApi failed for XHR', e);
149
- }
150
- }
151
- that.sendAPI(apiAttr, entry);
152
- });
153
- this.addEventListener('error', () => {
154
- this.apiAttr && (this.apiAttr.success = _rumCore.ResourceStatus.Failed);
155
- });
156
- this.addEventListener('abort', () => {
157
- if (this.apiAttr) {
158
- this.apiAttr.success = _rumCore.ResourceStatus.Failed;
159
- this.apiAttr.message = 'abort';
160
- }
161
- });
162
- }, true);
163
- }
164
- hackFetch() {
165
- const that = this;
166
- const originFetch = this.originFetch = globalThis.fetch;
167
- const filters = this.ctx.getConfig().filters || {};
168
- globalThis.fetch = function (input, init = {}) {
169
- const isReq = input instanceof Request;
170
- const urlStr = isReq ? input.url : (0, _rumCore.isString)(input) ? input : input.toString();
171
- let method = init.method;
172
- let headers = init.headers;
173
- if (isReq) {
174
- !method && (method = input.method);
175
- !headers && (headers = input.headers);
176
- }
177
- method = method ? method.toUpperCase() : 'GET';
178
- if (!headers) {
179
- init.headers = headers = new Headers();
180
- }
181
- if ((0, _rumCore.urlMatch)(urlStr, filters.resource) || method === 'HEAD' || init?.mode === 'no-cors' || urlStr.length > 8182) {
182
- return originFetch.call(global, input, init);
183
- }
184
- const baseRumEvent = that.ctx.session.getBaseEvent();
185
- let apiAttr = {
186
- ...baseRumEvent,
187
- url: urlStr,
188
- type: _api.ApiType.FETCH,
189
- method
190
- };
191
- let apiResp;
192
- let apiError;
193
- that.injectTracing(apiAttr, tracingHeaders => {
194
- Object.keys(tracingHeaders).forEach(key => {
195
- if (!headers) return;
196
- if (headers instanceof Headers) {
197
- tracingHeaders[key] && headers.set(key, tracingHeaders[key]);
198
- } else {
199
- // @ts-ignore
200
- headers[key] = tracingHeaders[key];
201
- }
202
- });
203
- });
204
- async function fetchFinally() {
205
- const {
206
- evaluateApi
207
- } = that.ctx.getConfig();
208
- const entry = {
209
- name: apiAttr.url,
210
- entryType: _api.ApiType.FETCH,
211
- duration: (0, _base.getCurrentTime)() - apiAttr.timestamp
212
- };
213
- if ((0, _rumCore.isFunction)(evaluateApi)) {
214
- try {
215
- const attrs = await evaluateApi?.({
216
- url: input,
217
- ...init
218
- }, apiResp, apiError);
219
- apiAttr = {
220
- ...apiAttr,
221
- ...(0, _api.reviseApiAttr)(attrs)
222
- };
223
- } catch (e) {
224
- _rumCore.logger.warn('api-collector', 'evaluateApi failed for fetch', e);
225
- }
226
- }
227
- that.sendAPI(apiAttr, entry);
228
- }
229
- return originFetch.call(globalThis, input, init).then(response => {
230
- // @ts-ignore
231
- if (response || (0, _rumCore.isFunction)(response.clone)) {
232
- apiResp = response.clone();
233
- const {
234
- status,
235
- statusText
236
- } = apiResp;
237
- apiAttr.status_code = status;
238
- apiAttr.message = statusText;
239
- fetchFinally().then();
240
- }
241
- return response;
242
- }).catch(error => {
243
- apiError = error;
244
- apiAttr.message = String(error);
245
- apiAttr.success = _rumCore.ResourceStatus.Failed;
246
- fetchFinally().then();
247
- throw error;
248
- });
249
- };
250
- }
251
- sendAPI(apiAttr, entry) {
252
- const {
253
- parseResourceName
254
- } = this.ctx.getConfig();
255
- const {
256
- url,
257
- status_code,
258
- view
259
- } = apiAttr;
260
- const success = (0, _api.getResourceSuccessByCode)(status_code);
261
- const measures = {
262
- duration: entry.duration
263
- };
264
- const event = {
265
- event_type: _rumCore.RumEventType.RESOURCE,
266
- url,
267
- name: (0, _api.getResourceName)(url || '', parseResourceName),
268
- success,
269
- type: entry.initiatorType || entry.entryType,
270
- ...apiAttr,
271
- timing_data: JSON.stringify(entry),
272
- // Measure
273
- ...measures,
274
- view
275
- };
276
- this.sendEvent?.(event);
277
- }
278
- destroy() {
279
- this.sendEvent = () => {};
280
- // 恢复XHR
281
- const oldXHRProto = XMLHttpRequest.prototype;
282
- (0, _rumCore.restoreFunction)(oldXHRProto, 'open');
283
- (0, _rumCore.restoreFunction)(oldXHRProto, 'setRequestHeader');
284
- (0, _rumCore.restoreFunction)(oldXHRProto, 'send');
285
- // 恢复 fetch
286
- if (this.originFetch) {
287
- globalThis.fetch = this.originFetch;
288
- }
289
- }
290
- }
291
- exports.default = ApiCollector;
292
- //# sourceMappingURL=api.js.map
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.default=void 0;var _rumCore=require("@arms/rum-core"),_base=require("../../utils/base"),_api=require("../../utils/api");class ApiCollector{name="api-collector";setup(e,t){!1!==(e.getConfig().collectors||{}).api&&(this.sendEvent=t,this.ctx=e,this.hackXhr())}injectTracing(e,t){const{tracing:r=!1,pid:s,version:i="1.0.0"}=this.ctx.getConfig(),{enable:a,sample:o,propagatorTypes:n,allowedUrls:c,tracestate:u,baggage:p=!1}=(0,_rumCore.parseTracingOptions)(r);if(!a)return;const h=(0,_rumCore.find)(c,t=>(0,_rumCore.matchList)([t.match],e.url||""));if(!h)return;let l=h.propagatorTypes;l&&0===l.length&&(l=n);let d=!1;l&&l.indexOf("sw8")>-1&&(l=["sw8"],d=!0);const g=this.ctx.session,m=d?(0,_rumCore.generateGUID)():(0,_rumCore.generateTraceId)(),C=d?(0,_rumCore.generateGUID)():(0,_rumCore.generateSpanId)(),_=(0,_rumCore.performDraw)(o),f=g.getUserId(),y=g.getSessionId(),A=u?`rum=v2&browser&${s}&${y}&${f}`:void 0,T=p?`rum=v2,appType=browser,pid=${s},sid=${y},uid=${f}`:void 0,v=(0,_rumCore.makeTracingHeaders)(m,C,_,l||[],{tracestate:A,baggage:T,appId:s,appVersion:i,viewName:e.view?.name});_&&(e.trace_id=m,e.trace_data=JSON.stringify({spanId:C,sample:o,sampled:_,headers:v})),t(v)}hackXhr(){const e=XMLHttpRequest.prototype,t=this;(0,_rumCore.interceptFunction)(e,"open",function(e,r,s,i,a){const o=t.ctx.getConfig().filters||{},n=String(r),c=e.toUpperCase();if((0,_rumCore.urlMatch)(n,o.resource)||"HEAD"===c||n.length>8182)return;this.apiCache={type:_api.ApiType.XHR,method:e,url:r,async:s,user:i,password:a,headers:{}};const u=t.ctx.session.getBaseEvent();this.apiAttr={...u,url:n,method:c}},!0),(0,_rumCore.interceptFunction)(e,"setRequestHeader",function(e,t){this.apiCache&&(this.apiCache.headers={...this.apiCache.headers,[e]:t})},!0),(0,_rumCore.interceptFunction)(e,"send",function(e){if(!this.apiAttr||!this.apiCache)return;let r=this.apiAttr;this.apiCache.data=e,t.injectTracing(this.apiAttr,e=>{Object.keys(e).forEach(t=>{e[t]&&this.setRequestHeader(t,e[t])})}),this.addEventListener("loadend",async()=>{const{status:e,statusText:s,response:i}=this,{evaluateApi:a}=t.ctx.getConfig();if(!this.apiAttr)return;r.status_code=e,r.message=s;const o={name:this.apiAttr.url,entryType:_api.ApiType.XHR,duration:(0,_base.getCurrentTime)()-r.timestamp};if((0,_rumCore.isFunction)(a))try{let e;r.success===_rumCore.ResourceStatus.Failed&&(e=new Error(_api.ApiType.XHR+" error"));const t=await(a?.(this.apiCache,i,e,this));this.apiAttr=r={...r,...(0,_api.reviseApiAttr)(t)}}catch(e){_rumCore.logger.warn("api-collector","evaluateApi failed for XHR",e)}t.sendAPI(r,o)}),this.addEventListener("error",()=>{this.apiAttr&&(this.apiAttr.success=_rumCore.ResourceStatus.Failed)}),this.addEventListener("abort",()=>{this.apiAttr&&(this.apiAttr.success=_rumCore.ResourceStatus.Failed,this.apiAttr.message="abort")})},!0)}hackFetch(){const e=this,t=this.originFetch=globalThis.fetch,r=this.ctx.getConfig().filters||{};globalThis.fetch=function(s,i={}){const a=s instanceof Request,o=a?s.url:(0,_rumCore.isString)(s)?s:s.toString();let n=i.method,c=i.headers;if(a&&(!n&&(n=s.method),!c&&(c=s.headers)),n=n?n.toUpperCase():"GET",c||(i.headers=c=new Headers),(0,_rumCore.urlMatch)(o,r.resource)||"HEAD"===n||"no-cors"===i?.mode||o.length>8182)return t.call(global,s,i);let u,p,h={...e.ctx.session.getBaseEvent(),url:o,type:_api.ApiType.FETCH,method:n};async function l(){const{evaluateApi:t}=e.ctx.getConfig(),r={name:h.url,entryType:_api.ApiType.FETCH,duration:(0,_base.getCurrentTime)()-h.timestamp};if((0,_rumCore.isFunction)(t))try{const e=await(t?.({url:s,...i},u,p));h={...h,...(0,_api.reviseApiAttr)(e)}}catch(e){_rumCore.logger.warn("api-collector","evaluateApi failed for fetch",e)}e.sendAPI(h,r)}return e.injectTracing(h,e=>{Object.keys(e).forEach(t=>{c&&(c instanceof Headers?e[t]&&c.set(t,e[t]):c[t]=e[t])})}),t.call(globalThis,s,i).then(e=>{if(e||(0,_rumCore.isFunction)(e.clone)){u=e.clone();const{status:t,statusText:r}=u;h.status_code=t,h.message=r,l().then()}return e}).catch(e=>{throw p=e,h.message=String(e),h.success=_rumCore.ResourceStatus.Failed,l().then(),e})}}sendAPI(e,t){const{parseResourceName:r}=this.ctx.getConfig(),{url:s,status_code:i,view:a}=e,o=(0,_api.getResourceSuccessByCode)(i),n={duration:t.duration},c={event_type:_rumCore.RumEventType.RESOURCE,url:s,name:(0,_api.getResourceName)(s||"",r),success:o,type:t.initiatorType||t.entryType,...e,timing_data:JSON.stringify(t),...n,view:a};this.sendEvent?.(c)}destroy(){this.sendEvent=()=>{};const e=XMLHttpRequest.prototype;(0,_rumCore.restoreFunction)(e,"open"),(0,_rumCore.restoreFunction)(e,"setRequestHeader"),(0,_rumCore.restoreFunction)(e,"send"),this.originFetch&&(globalThis.fetch=this.originFetch)}}exports.default=ApiCollector;
@@ -1,79 +1 @@
1
- // import { ICollector, IContext, isArray, RumEvent } from '@arms/rum-core';
2
- // import { getPerformance } from "../../utils/platform";
3
- // import { getCurView } from "../../utils/view";
4
- //
5
- //
6
- //
7
- //
8
- // export default class PerfCollector implements ICollector {
9
- // name = 'perf-collector';
10
- // ctx: IContext;
11
- // sendEvent: (payload: RumEvent) => void;
12
- // perfObserver: any;
13
- //
14
- // setup(ctx: IContext, sendEvent: (payload: RumEvent) => void) {
15
- // const {collectors = {}} = ctx.getConfig();
16
- // if (collectors.perf === false) {
17
- // return;
18
- // }
19
- // this.ctx = ctx;
20
- // this.sendEvent = sendEvent;
21
- // const performance = getPerformance();
22
- // if (!performance || !performance.createObserver) return;
23
- // this.perfObserver = performance.createObserver(this.observerHandler)
24
- // this.perfObserver.observe({entryTypes: ['launch', 'navigation', 'render', 'paint', 'resource']});
25
- // }
26
- //
27
- // observerHandler = (ev) => {
28
- // const entries = isArray(ev) ? ev : ev.getEntries();
29
- // const perfData = {
30
- // view: getCurView(this.ctx)
31
- // };
32
- // if (Array.isArray(entries) && entries.length > 0) {
33
- // for (let i = 0; i < entries.length; i++) {
34
- // const item = entries[i];
35
- // if (typeof item.duration === 'number') {
36
- // switch (item.name) {
37
- // case 'appLaunch':
38
- // case 'app-click':
39
- // perfData['launch'] = item.duration;
40
- // break;
41
- // case 'firstPaint':
42
- // // case 'first-paint':
43
- // perfData['first-paint'] = item.duration;
44
- // break;
45
- // case 'firstRender':
46
- // perfData['first_render'] = item.duration;
47
- // break;
48
- // case 'firstContentfulPaint':
49
- // // case 'first-contentful-paint':
50
- // perfData['first_contentful_paint'] = item.duration;
51
- // break;
52
- // case 'largestContentfulPaint':
53
- // // case 'largest-contentful-paint':
54
- // perfData['largest_contentful_paint'] = item.duration;
55
- // break;
56
- // case 'resourceTiming':
57
- // case 'resource-timing':
58
- // perfData['timing_data'] = JSON.stringify(item);
59
- // break;
60
- // default:
61
- // break;
62
- // }
63
- // }
64
- // }
65
- // }
66
- //
67
- // if (!Object.keys(perfData).length) return;
68
- // // TODO 处理性能数据
69
- // // console.warn('perf-collector: ', perfData);
70
- // };
71
- //
72
- // destroy() {
73
- // if (this.perfObserver) {
74
- // this.perfObserver.disconnect();
75
- // }
76
- // }
77
- // }
78
- "use strict";
79
- //# sourceMappingURL=perf.js.map
1
+ "use strict";