@arms/rum-reactnative 0.0.2-bate.1 → 0.0.2-bate.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 +22 -20
- package/package.json +6 -7
- package/RumSdkReactnative.podspec +0 -21
- package/android/build.gradle +0 -77
- package/android/gradle.properties +0 -5
- package/android/src/main/AndroidManifest.xml +0 -2
- package/android/src/main/java/com/rumsdkreactnative/RumSdkReactnativeModule.kt +0 -23
- package/android/src/main/java/com/rumsdkreactnative/RumSdkReactnativePackage.kt +0 -33
- package/ios/RumSdkReactnative.h +0 -5
- package/ios/RumSdkReactnative.mm +0 -18
- package/src/collector/action/index.ts +0 -67
- package/src/collector/exception/index.ts +0 -158
- package/src/collector/resource/api.ts +0 -379
- package/src/collector/view/perf.ts +0 -77
- package/src/collector/view/pv.ts +0 -73
- package/src/index.ts +0 -4
- package/src/plugin.ts +0 -41
- package/src/processor/default-processor.ts +0 -22
- package/src/processor/session-processor.ts +0 -23
- package/src/reporter/index.ts +0 -67
- package/src/shell.ts +0 -81
- package/src/types/client.ts +0 -32
- package/src/types/index.ts +0 -159
- package/src/utils/api.ts +0 -119
- package/src/utils/base.ts +0 -92
- package/src/utils/platform.ts +0 -107
- package/src/utils/session.ts +0 -168
- package/src/utils/url.ts +0 -53
- package/src/utils/view.ts +0 -93
|
@@ -1,379 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
find,
|
|
3
|
-
generateGUID,
|
|
4
|
-
generateSpanId,
|
|
5
|
-
generateTraceId,
|
|
6
|
-
ICollector,
|
|
7
|
-
IContext,
|
|
8
|
-
isString,
|
|
9
|
-
interceptFunction,
|
|
10
|
-
restoreFunction,
|
|
11
|
-
isFunction,
|
|
12
|
-
ITracingHeaders,
|
|
13
|
-
makeTracingHeaders,
|
|
14
|
-
matchList,
|
|
15
|
-
parseTracingOptions,
|
|
16
|
-
performDraw,
|
|
17
|
-
RumEvent,
|
|
18
|
-
RumEventType,
|
|
19
|
-
RumResourceEvent,
|
|
20
|
-
ResourceStatus,
|
|
21
|
-
TraceOption,
|
|
22
|
-
urlMatch,
|
|
23
|
-
ITracingOption,
|
|
24
|
-
PropagatorType,
|
|
25
|
-
} from '@arms/rum-core';
|
|
26
|
-
import { getCurrentTime } from '../../utils/base';
|
|
27
|
-
import { IRNConfig } from '../../types/client';
|
|
28
|
-
import {
|
|
29
|
-
ApiType,
|
|
30
|
-
IApiAttr,
|
|
31
|
-
IApiCache,
|
|
32
|
-
reviseApiAttr,
|
|
33
|
-
getResourceName,
|
|
34
|
-
getResourceSuccessByCode,
|
|
35
|
-
} from '../../utils/api';
|
|
36
|
-
import { RumSession } from '../../utils/session';
|
|
37
|
-
|
|
38
|
-
declare global {
|
|
39
|
-
interface XMLHttpRequest {
|
|
40
|
-
apiAttr: IApiAttr;
|
|
41
|
-
apiCache: IApiCache;
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
export default class ApiCollector implements ICollector {
|
|
46
|
-
name = 'api-collector';
|
|
47
|
-
|
|
48
|
-
private ctx?: IContext;
|
|
49
|
-
private sendEvent?: (payload: RumEvent) => void;
|
|
50
|
-
private originFetch: unknown;
|
|
51
|
-
|
|
52
|
-
setup(ctx: IContext, sendEvent: (payload: RumEvent) => void) {
|
|
53
|
-
const collectors = ctx.getConfig().collectors || {};
|
|
54
|
-
if (!collectors.api) {
|
|
55
|
-
return;
|
|
56
|
-
}
|
|
57
|
-
this.sendEvent = sendEvent;
|
|
58
|
-
this.ctx = ctx;
|
|
59
|
-
// this.perfObserver();
|
|
60
|
-
this.hackXhr();
|
|
61
|
-
// this.hackFetch();
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
injectTracing(
|
|
65
|
-
apiAttr: IApiAttr,
|
|
66
|
-
inject: (tracingHeaders: ITracingHeaders) => void
|
|
67
|
-
) {
|
|
68
|
-
const {
|
|
69
|
-
tracing = false,
|
|
70
|
-
pid,
|
|
71
|
-
version = '1.0.0',
|
|
72
|
-
} = (this.ctx as IContext).getConfig();
|
|
73
|
-
const {
|
|
74
|
-
enable,
|
|
75
|
-
sample,
|
|
76
|
-
propagatorTypes,
|
|
77
|
-
allowedUrls,
|
|
78
|
-
tracestate,
|
|
79
|
-
baggage = false,
|
|
80
|
-
} = parseTracingOptions(tracing as ITracingOption);
|
|
81
|
-
if (!enable) return;
|
|
82
|
-
// @ts-ignore
|
|
83
|
-
const traceOption = find(allowedUrls, (traceOption: TraceOption) =>
|
|
84
|
-
matchList([traceOption.match], apiAttr.url || '')
|
|
85
|
-
) as TraceOption;
|
|
86
|
-
if (!traceOption) return;
|
|
87
|
-
let pTypes = traceOption.propagatorTypes;
|
|
88
|
-
if (pTypes.length === 0) {
|
|
89
|
-
pTypes = propagatorTypes as PropagatorType[];
|
|
90
|
-
}
|
|
91
|
-
// skywalking
|
|
92
|
-
let isSw8 = false;
|
|
93
|
-
if (pTypes.indexOf('sw8') > -1) {
|
|
94
|
-
pTypes = ['sw8'];
|
|
95
|
-
isSw8 = true;
|
|
96
|
-
}
|
|
97
|
-
const session = (this.ctx as IContext).session;
|
|
98
|
-
const traceId = isSw8 ? generateGUID() : generateTraceId();
|
|
99
|
-
const spanId = isSw8 ? generateGUID() : generateSpanId();
|
|
100
|
-
const sampled = performDraw(sample as number);
|
|
101
|
-
const uid = session.getUserId();
|
|
102
|
-
const sid = session.getSessionId();
|
|
103
|
-
const traceContext = tracestate
|
|
104
|
-
? `rum=v2&browser&${pid}&${sid}&${uid}`
|
|
105
|
-
: undefined;
|
|
106
|
-
const baggageContext = baggage
|
|
107
|
-
? `rum=v2,appType=browser,pid=${pid},sid=${sid},uid=${uid}`
|
|
108
|
-
: undefined;
|
|
109
|
-
|
|
110
|
-
const tracingHeaders = makeTracingHeaders(
|
|
111
|
-
traceId,
|
|
112
|
-
spanId,
|
|
113
|
-
sampled,
|
|
114
|
-
pTypes,
|
|
115
|
-
{
|
|
116
|
-
tracestate: traceContext,
|
|
117
|
-
baggage: baggageContext,
|
|
118
|
-
appId: pid,
|
|
119
|
-
appVersion: version,
|
|
120
|
-
viewName: apiAttr.view?.name,
|
|
121
|
-
// host: location.host
|
|
122
|
-
}
|
|
123
|
-
);
|
|
124
|
-
if (sampled) {
|
|
125
|
-
apiAttr.trace_id = traceId;
|
|
126
|
-
apiAttr.trace_data = JSON.stringify({
|
|
127
|
-
spanId,
|
|
128
|
-
sample,
|
|
129
|
-
sampled,
|
|
130
|
-
headers: tracingHeaders,
|
|
131
|
-
});
|
|
132
|
-
}
|
|
133
|
-
inject(tracingHeaders);
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
hackXhr() {
|
|
137
|
-
const oldXHRProto = XMLHttpRequest.prototype;
|
|
138
|
-
const self = this;
|
|
139
|
-
interceptFunction(
|
|
140
|
-
oldXHRProto,
|
|
141
|
-
'open',
|
|
142
|
-
function (
|
|
143
|
-
this: XMLHttpRequest,
|
|
144
|
-
method: string,
|
|
145
|
-
url: string | URL,
|
|
146
|
-
async?: boolean,
|
|
147
|
-
user?: string,
|
|
148
|
-
password?: string
|
|
149
|
-
) {
|
|
150
|
-
const filters = (self.ctx as IContext).getConfig().filters || {};
|
|
151
|
-
const urlStr = String(url);
|
|
152
|
-
const methodStr = method.toUpperCase();
|
|
153
|
-
// chrome 对 URL 的最大长度为 8182 个字符
|
|
154
|
-
if (
|
|
155
|
-
urlMatch(urlStr, filters.resource) ||
|
|
156
|
-
methodStr === 'HEAD' ||
|
|
157
|
-
urlStr.length > 8182
|
|
158
|
-
)
|
|
159
|
-
return;
|
|
160
|
-
this.apiCache = {
|
|
161
|
-
type: ApiType.XHR,
|
|
162
|
-
method,
|
|
163
|
-
url,
|
|
164
|
-
async,
|
|
165
|
-
user,
|
|
166
|
-
password,
|
|
167
|
-
headers: {},
|
|
168
|
-
};
|
|
169
|
-
const baseRumEvent = (
|
|
170
|
-
(self.ctx as IContext).session as RumSession
|
|
171
|
-
).getBaseEvent();
|
|
172
|
-
this.apiAttr = {
|
|
173
|
-
...baseRumEvent,
|
|
174
|
-
url: urlStr,
|
|
175
|
-
method: methodStr,
|
|
176
|
-
} as IApiAttr;
|
|
177
|
-
},
|
|
178
|
-
true
|
|
179
|
-
);
|
|
180
|
-
interceptFunction(
|
|
181
|
-
oldXHRProto,
|
|
182
|
-
'setRequestHeader',
|
|
183
|
-
function (this: XMLHttpRequest, header: string, value: string) {
|
|
184
|
-
if (!this.apiCache) return;
|
|
185
|
-
this.apiCache.headers = {
|
|
186
|
-
...this.apiCache.headers,
|
|
187
|
-
[header]: value,
|
|
188
|
-
};
|
|
189
|
-
},
|
|
190
|
-
true
|
|
191
|
-
);
|
|
192
|
-
interceptFunction(
|
|
193
|
-
oldXHRProto,
|
|
194
|
-
'send',
|
|
195
|
-
function (this: XMLHttpRequest, body: any) {
|
|
196
|
-
if (!this.apiAttr || !this.apiCache) return;
|
|
197
|
-
let apiAttr = this.apiAttr;
|
|
198
|
-
this.apiCache.data = body;
|
|
199
|
-
self.injectTracing(this.apiAttr, (tracingHeaders) => {
|
|
200
|
-
Object.keys(tracingHeaders).forEach((key) => {
|
|
201
|
-
tracingHeaders[key] && this.setRequestHeader(key, tracingHeaders[key])
|
|
202
|
-
});
|
|
203
|
-
});
|
|
204
|
-
this.addEventListener('loadend', async () => {
|
|
205
|
-
const { status, statusText, response } = this;
|
|
206
|
-
const { evaluateApi } = (self.ctx as IContext).getConfig() as IRNConfig;
|
|
207
|
-
if (!this.apiAttr) return;
|
|
208
|
-
apiAttr.status_code = status;
|
|
209
|
-
apiAttr.message = statusText;
|
|
210
|
-
const entry = {
|
|
211
|
-
name: this.apiAttr.url,
|
|
212
|
-
entryType: ApiType.XHR,
|
|
213
|
-
duration: getCurrentTime() - apiAttr.timestamp,
|
|
214
|
-
};
|
|
215
|
-
if (isFunction(evaluateApi)) {
|
|
216
|
-
try {
|
|
217
|
-
let error: Error | undefined;
|
|
218
|
-
if (apiAttr.success === ResourceStatus.Failed) {
|
|
219
|
-
error = new Error(ApiType.XHR + ' error');
|
|
220
|
-
}
|
|
221
|
-
const attrs = await evaluateApi?.(
|
|
222
|
-
this.apiCache,
|
|
223
|
-
response,
|
|
224
|
-
error,
|
|
225
|
-
this
|
|
226
|
-
);
|
|
227
|
-
this.apiAttr = apiAttr = {
|
|
228
|
-
...apiAttr,
|
|
229
|
-
...reviseApiAttr(attrs as IApiAttr),
|
|
230
|
-
};
|
|
231
|
-
} catch (e) {
|
|
232
|
-
//
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
self.sendAPI(apiAttr, entry);
|
|
236
|
-
});
|
|
237
|
-
this.addEventListener('error', () => {
|
|
238
|
-
this.apiAttr && (this.apiAttr.success = ResourceStatus.Failed);
|
|
239
|
-
});
|
|
240
|
-
},
|
|
241
|
-
true
|
|
242
|
-
);
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
hackFetch() {
|
|
246
|
-
const self = this;
|
|
247
|
-
const originFetch = (this.originFetch = globalThis.fetch);
|
|
248
|
-
const filters = (this.ctx as IContext).getConfig().filters || {};
|
|
249
|
-
globalThis.fetch = function (
|
|
250
|
-
input: Request | URL | string,
|
|
251
|
-
init: RequestInit = {}
|
|
252
|
-
) {
|
|
253
|
-
const isReq = input instanceof Request;
|
|
254
|
-
const urlStr = isReq
|
|
255
|
-
? input.url
|
|
256
|
-
: isString(input)
|
|
257
|
-
? input
|
|
258
|
-
: input.toString();
|
|
259
|
-
let method = init.method;
|
|
260
|
-
let headers = init.headers;
|
|
261
|
-
if (isReq) {
|
|
262
|
-
!method && (method = input.method);
|
|
263
|
-
!headers && (headers = input.headers);
|
|
264
|
-
}
|
|
265
|
-
method = method ? method.toUpperCase() : 'GET';
|
|
266
|
-
if (!headers) {
|
|
267
|
-
init.headers = headers = new Headers();
|
|
268
|
-
}
|
|
269
|
-
if (
|
|
270
|
-
urlMatch(urlStr, filters.resource) ||
|
|
271
|
-
method === 'HEAD' ||
|
|
272
|
-
init?.mode === 'no-cors' ||
|
|
273
|
-
urlStr.length > 8182
|
|
274
|
-
) {
|
|
275
|
-
return originFetch.call(global, input, init);
|
|
276
|
-
}
|
|
277
|
-
const baseRumEvent = ((self.ctx as IContext).session as RumSession).getBaseEvent();
|
|
278
|
-
let apiAttr = {
|
|
279
|
-
...baseRumEvent,
|
|
280
|
-
url: urlStr,
|
|
281
|
-
type: ApiType.FETCH,
|
|
282
|
-
method,
|
|
283
|
-
} as IApiAttr;
|
|
284
|
-
let apiResp: Response;
|
|
285
|
-
let apiError: Error;
|
|
286
|
-
|
|
287
|
-
self.injectTracing(apiAttr, (tracingHeaders) => {
|
|
288
|
-
Object.keys(tracingHeaders).forEach((key) => {
|
|
289
|
-
if(!headers) return;
|
|
290
|
-
if (headers instanceof Headers) {
|
|
291
|
-
tracingHeaders[key] && headers.set(key, tracingHeaders[key]);
|
|
292
|
-
} else {
|
|
293
|
-
// @ts-ignore
|
|
294
|
-
headers[key] = tracingHeaders[key];
|
|
295
|
-
}
|
|
296
|
-
});
|
|
297
|
-
});
|
|
298
|
-
|
|
299
|
-
async function fetchFinally() {
|
|
300
|
-
const { evaluateApi } = (self.ctx as IContext).getConfig() as IRNConfig;
|
|
301
|
-
const entry = {
|
|
302
|
-
name: apiAttr.url,
|
|
303
|
-
entryType: ApiType.FETCH,
|
|
304
|
-
duration: getCurrentTime() - apiAttr.timestamp,
|
|
305
|
-
};
|
|
306
|
-
if (isFunction(evaluateApi)) {
|
|
307
|
-
try {
|
|
308
|
-
const attrs = await evaluateApi?.(
|
|
309
|
-
{ url: input, ...init },
|
|
310
|
-
apiResp,
|
|
311
|
-
apiError
|
|
312
|
-
);
|
|
313
|
-
apiAttr = { ...apiAttr, ...reviseApiAttr(attrs as IApiAttr) };
|
|
314
|
-
} catch (e) {
|
|
315
|
-
//
|
|
316
|
-
}
|
|
317
|
-
}
|
|
318
|
-
self.sendAPI(apiAttr, entry);
|
|
319
|
-
}
|
|
320
|
-
|
|
321
|
-
return originFetch
|
|
322
|
-
.call(globalThis, input, init)
|
|
323
|
-
.then((response: Response) => {
|
|
324
|
-
// @ts-ignore
|
|
325
|
-
if (response || isFunction(response.clone)) {
|
|
326
|
-
apiResp = response.clone();
|
|
327
|
-
const { status, statusText } = apiResp;
|
|
328
|
-
apiAttr.status_code = status;
|
|
329
|
-
apiAttr.message = statusText;
|
|
330
|
-
fetchFinally().then();
|
|
331
|
-
}
|
|
332
|
-
return response;
|
|
333
|
-
})
|
|
334
|
-
.catch((error: Error) => {
|
|
335
|
-
apiError = error;
|
|
336
|
-
apiAttr.message = String(error);
|
|
337
|
-
apiAttr.success = ResourceStatus.Failed;
|
|
338
|
-
fetchFinally().then();
|
|
339
|
-
throw error;
|
|
340
|
-
});
|
|
341
|
-
};
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
sendAPI(apiAttr: IApiAttr, entry: any) {
|
|
345
|
-
const { parseResourceName } = (this.ctx as IContext).getConfig() as IRNConfig;
|
|
346
|
-
const { url, status_code, view } = apiAttr;
|
|
347
|
-
const success = getResourceSuccessByCode(status_code as string);
|
|
348
|
-
const measures = {
|
|
349
|
-
duration: entry.duration,
|
|
350
|
-
};
|
|
351
|
-
const event: RumResourceEvent = {
|
|
352
|
-
event_type: RumEventType.RESOURCE,
|
|
353
|
-
url,
|
|
354
|
-
name: getResourceName(url || '', parseResourceName),
|
|
355
|
-
success,
|
|
356
|
-
type: entry.initiatorType || entry.entryType,
|
|
357
|
-
...apiAttr,
|
|
358
|
-
timing_data: JSON.stringify(entry),
|
|
359
|
-
// Measure
|
|
360
|
-
...measures,
|
|
361
|
-
view,
|
|
362
|
-
};
|
|
363
|
-
|
|
364
|
-
this.sendEvent?.(event);
|
|
365
|
-
}
|
|
366
|
-
|
|
367
|
-
destroy() {
|
|
368
|
-
this.sendEvent = () => {};
|
|
369
|
-
// 恢复XHR
|
|
370
|
-
const oldXHRProto = XMLHttpRequest.prototype;
|
|
371
|
-
restoreFunction(oldXHRProto, 'open');
|
|
372
|
-
restoreFunction(oldXHRProto, 'setRequestHeader');
|
|
373
|
-
restoreFunction(oldXHRProto, 'send');
|
|
374
|
-
// 恢复 fetch
|
|
375
|
-
if (this.originFetch) {
|
|
376
|
-
globalThis.fetch = this.originFetch as any;
|
|
377
|
-
}
|
|
378
|
-
}
|
|
379
|
-
}
|
|
@@ -1,77 +0,0 @@
|
|
|
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
|
-
// }
|
package/src/collector/view/pv.ts
DELETED
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
import { ICollector, IContext, isFunction, IViewData, RumEvent, RumEventType, RumViewEvent } from '@arms/rum-core';
|
|
2
|
-
import { IRNConfig, IPage } from "../../types/client";
|
|
3
|
-
import { addNavigateListener, removeNavigateListener } from "../../utils/view";
|
|
4
|
-
import { Route } from "../../types";
|
|
5
|
-
|
|
6
|
-
export default class PvCollector implements ICollector {
|
|
7
|
-
name = 'pv-collector';
|
|
8
|
-
ctx?: IContext;
|
|
9
|
-
sendEvent?: (payload: RumEvent) => void;
|
|
10
|
-
|
|
11
|
-
private prevPage?: IPage;
|
|
12
|
-
|
|
13
|
-
private pageMap: { [key: string]: IPage } = {};
|
|
14
|
-
|
|
15
|
-
setup(ctx: IContext, sendEvent: (payload: RumEvent) => void) {
|
|
16
|
-
this.ctx = ctx;
|
|
17
|
-
this.sendEvent = sendEvent;
|
|
18
|
-
addNavigateListener(this.onChange)
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
onChange = (route: Route<any>) => {
|
|
22
|
-
// {"name":"index","path":"/","key":"index-SB2hXmOGNdpiLskG5sXwj"}
|
|
23
|
-
// {"name":"__root","key":"__root-jPbNqG7-HaM-OUx_FcCUw"}
|
|
24
|
-
const {key, name, path, params} = route;
|
|
25
|
-
const page: IPage = {name, path, id: key, params};
|
|
26
|
-
if (name === "__root" || !('path' in page)) return;
|
|
27
|
-
this.sendPv(page);
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
sendPv = (page: IPage) => {
|
|
31
|
-
const prevPage = this.prevPage;
|
|
32
|
-
const ctx = this.ctx as IContext;
|
|
33
|
-
if (page.id === prevPage?.id) {
|
|
34
|
-
// 路由没有发生变化,不发送
|
|
35
|
-
return;
|
|
36
|
-
}
|
|
37
|
-
page.name = this.getViewName(page.path as string, page);
|
|
38
|
-
|
|
39
|
-
if (prevPage && prevPage.id in this.pageMap) {
|
|
40
|
-
delete this.pageMap[prevPage.id];
|
|
41
|
-
ctx.removeView(prevPage.id)
|
|
42
|
-
}
|
|
43
|
-
this.prevPage = page;
|
|
44
|
-
|
|
45
|
-
ctx.addView(page as IViewData);
|
|
46
|
-
|
|
47
|
-
// 路由回退情况下已经上报
|
|
48
|
-
if(page.id in this.pageMap) {
|
|
49
|
-
return;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
this.pageMap[page.id] = page;
|
|
53
|
-
this.sendEvent?.({
|
|
54
|
-
event_type: RumEventType.VIEW,
|
|
55
|
-
type: 'pv',
|
|
56
|
-
loading_type: 'initial_load',
|
|
57
|
-
...page,
|
|
58
|
-
} as RumViewEvent);
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
private getViewName(url: string, page: IPage): string | undefined {
|
|
62
|
-
let { parseViewName } = this.ctx?.getConfig() as IRNConfig;
|
|
63
|
-
let name = page.name;
|
|
64
|
-
if (parseViewName && isFunction(parseViewName)) {
|
|
65
|
-
name = parseViewName(url, page) || name;
|
|
66
|
-
}
|
|
67
|
-
return name
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
destroy() {
|
|
71
|
-
removeNavigateListener(this.onChange);
|
|
72
|
-
}
|
|
73
|
-
}
|
package/src/index.ts
DELETED
package/src/plugin.ts
DELETED
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
import { NativeModules, NativeEventEmitter } from 'react-native';
|
|
2
|
-
import { isString } from "@arms/rum-core";
|
|
3
|
-
import { IRNConfig } from "./types/client";
|
|
4
|
-
import { VERSION } from "./utils/platform";
|
|
5
|
-
import armsRum from './shell';
|
|
6
|
-
|
|
7
|
-
const RumSdkModule = NativeModules.RumSdkModule;
|
|
8
|
-
|
|
9
|
-
function initRum(config: IRNConfig) {
|
|
10
|
-
armsRum.init({
|
|
11
|
-
...config,
|
|
12
|
-
beforeReport(bundle): any {
|
|
13
|
-
RumSdkModule.sendEvent(JSON.stringify(bundle));
|
|
14
|
-
return null
|
|
15
|
-
}
|
|
16
|
-
})
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
if (RumSdkModule) {
|
|
20
|
-
const eventEmitter = new NativeEventEmitter(RumSdkModule);
|
|
21
|
-
eventEmitter.addListener('rumNativeEvent', (config: IRNConfig) => {
|
|
22
|
-
if (isString(config)) {
|
|
23
|
-
try {
|
|
24
|
-
config = JSON.parse(config);
|
|
25
|
-
} catch (e) {
|
|
26
|
-
console.warn('getConfig error', e);
|
|
27
|
-
return
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
if (!config.pid) {
|
|
31
|
-
config.pid = `react-native@${VERSION}`;
|
|
32
|
-
}
|
|
33
|
-
if (!config.endpoint) {
|
|
34
|
-
config.endpoint = `http://127.0.0.1/?version=${VERSION}`;
|
|
35
|
-
}
|
|
36
|
-
initRum(config);
|
|
37
|
-
});
|
|
38
|
-
RumSdkModule?.getConfig?.();
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
export default armsRum
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import { IContext, IProcessor, IViewData, RumEvent } from '@arms/rum-core';
|
|
2
|
-
import { getCurrentTime } from '../utils/base';
|
|
3
|
-
import { getCurView } from '../utils/view';
|
|
4
|
-
|
|
5
|
-
export default class DefaultProcessor implements IProcessor {
|
|
6
|
-
name = 'default-processor';
|
|
7
|
-
|
|
8
|
-
process(ctx: IContext) {
|
|
9
|
-
const event = ctx.getRumEvent();
|
|
10
|
-
const view = getCurView(ctx) as IViewData;
|
|
11
|
-
const session_id = ctx.session.getSessionId();
|
|
12
|
-
const event_id = ctx.session.getEventId();
|
|
13
|
-
const rumEvent: RumEvent = {
|
|
14
|
-
timestamp: getCurrentTime(),
|
|
15
|
-
session_id,
|
|
16
|
-
event_id,
|
|
17
|
-
view,
|
|
18
|
-
...event,
|
|
19
|
-
};
|
|
20
|
-
return rumEvent;
|
|
21
|
-
}
|
|
22
|
-
}
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import { debounce, IContext, IProcessor, ONE_SECOND } from '@arms/rum-core';
|
|
2
|
-
|
|
3
|
-
export default class SessionProcessor implements IProcessor {
|
|
4
|
-
name = 'session-processor';
|
|
5
|
-
|
|
6
|
-
ctx?: IContext;
|
|
7
|
-
|
|
8
|
-
setup(ctx: IContext) {
|
|
9
|
-
this.ctx = ctx;
|
|
10
|
-
this.update = debounce(this.update, ONE_SECOND);
|
|
11
|
-
// sdk.onTouchStart(this.update)
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
update = (e?: Event) => {
|
|
15
|
-
if (e && !e.isTrusted) return;
|
|
16
|
-
this.ctx?.session.updateSession();
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
process(ctx: IContext) {
|
|
20
|
-
this.update();
|
|
21
|
-
return ctx.getRumEvent();
|
|
22
|
-
}
|
|
23
|
-
}
|
package/src/reporter/index.ts
DELETED
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
IContext,
|
|
3
|
-
IReporter,
|
|
4
|
-
Reporter,
|
|
5
|
-
RumEventBundle,
|
|
6
|
-
} from '@arms/rum-core';
|
|
7
|
-
import { fixAttrs } from '../utils/platform';
|
|
8
|
-
// @ts-ignore
|
|
9
|
-
import { AppState, NativeEventSubscription } from 'react-native';
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* rn-app reporter
|
|
13
|
-
*/
|
|
14
|
-
class RNReporter extends Reporter implements IReporter {
|
|
15
|
-
name = 'rn-reporter';
|
|
16
|
-
|
|
17
|
-
private appStateListener?: NativeEventSubscription;
|
|
18
|
-
|
|
19
|
-
constructor() {
|
|
20
|
-
super();
|
|
21
|
-
// 离开之前 flushEventQueue
|
|
22
|
-
try {
|
|
23
|
-
this.appStateListener = AppState.addEventListener('change', this.onAppStateChanged);
|
|
24
|
-
} catch (error) {
|
|
25
|
-
//
|
|
26
|
-
console.info(error)
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
init(ctx: IContext) {
|
|
31
|
-
this.ctx = ctx;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
onAppStateChanged(nextAppState: string) {
|
|
35
|
-
if (nextAppState === 'background') {
|
|
36
|
-
// 执行后台操作:暂停动画、保存数据、停止网络请求等
|
|
37
|
-
this.flushEventQueue();
|
|
38
|
-
}
|
|
39
|
-
// else if (nextAppState === 'active') {
|
|
40
|
-
// console.warn('RUM:应用回到前台');
|
|
41
|
-
// }
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
request(ctx: IContext, bundle: RumEventBundle) {
|
|
45
|
-
const batchedEvents = fixAttrs(bundle);
|
|
46
|
-
const config = ctx.getConfig();
|
|
47
|
-
fetch(config.endpoint, {
|
|
48
|
-
method: 'POST',
|
|
49
|
-
headers: {
|
|
50
|
-
'Content-Type': 'text/plain',
|
|
51
|
-
},
|
|
52
|
-
body: JSON.stringify(batchedEvents)
|
|
53
|
-
}).then((_res) => {
|
|
54
|
-
//
|
|
55
|
-
}).catch(this.catchHandle)
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
catchHandle = (err: any) => {
|
|
59
|
-
console.warn('[rum] sendRequest fail', err);
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
destroy() {
|
|
63
|
-
this.appStateListener?.remove();
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
export default RNReporter;
|