monitor-track 1.10.0

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 (65) hide show
  1. package/CHANGELOG.md +31 -0
  2. package/README.md +101 -0
  3. package/dist/CHANGELOG.md +21 -0
  4. package/dist/README.md +101 -0
  5. package/dist/cjs/config/global.d.ts +17 -0
  6. package/dist/cjs/config/index.d.ts +33 -0
  7. package/dist/cjs/constant.d.ts +2 -0
  8. package/dist/cjs/handlers/error.d.ts +23 -0
  9. package/dist/cjs/handlers/index.d.ts +3 -0
  10. package/dist/cjs/handlers/pv.d.ts +24 -0
  11. package/dist/cjs/handlers/user-activity.d.ts +9 -0
  12. package/dist/cjs/index.d.ts +30 -0
  13. package/dist/cjs/index.js +1485 -0
  14. package/dist/cjs/main.d.ts +1 -0
  15. package/dist/cjs/reporter.d.ts +198 -0
  16. package/dist/cjs/types/config.d.ts +59 -0
  17. package/dist/cjs/types/global.d.ts +70 -0
  18. package/dist/cjs/types/index.d.ts +189 -0
  19. package/dist/cjs/utils/index.d.ts +45 -0
  20. package/dist/esm/_virtual/_tslib.js +26 -0
  21. package/dist/esm/config/global.d.ts +17 -0
  22. package/dist/esm/config/global.js +271 -0
  23. package/dist/esm/config/index.d.ts +33 -0
  24. package/dist/esm/config/index.js +32 -0
  25. package/dist/esm/constant.d.ts +2 -0
  26. package/dist/esm/constant.js +4 -0
  27. package/dist/esm/handlers/error.d.ts +23 -0
  28. package/dist/esm/handlers/error.js +181 -0
  29. package/dist/esm/handlers/index.d.ts +3 -0
  30. package/dist/esm/handlers/pv.d.ts +24 -0
  31. package/dist/esm/handlers/pv.js +99 -0
  32. package/dist/esm/handlers/user-activity.d.ts +9 -0
  33. package/dist/esm/handlers/user-activity.js +66 -0
  34. package/dist/esm/index.d.ts +30 -0
  35. package/dist/esm/index.js +115 -0
  36. package/dist/esm/main.d.ts +1 -0
  37. package/dist/esm/package.json.js +3 -0
  38. package/dist/esm/reporter.d.ts +198 -0
  39. package/dist/esm/reporter.js +359 -0
  40. package/dist/esm/types/config.d.ts +59 -0
  41. package/dist/esm/types/global.d.ts +70 -0
  42. package/dist/esm/types/index.d.ts +189 -0
  43. package/dist/esm/utils/index.d.ts +45 -0
  44. package/dist/esm/utils/index.js +354 -0
  45. package/dist/index.js +1534 -0
  46. package/dist/package.json +41 -0
  47. package/package.json +42 -0
  48. package/rollup.config.js +66 -0
  49. package/scripts/cp.js +11 -0
  50. package/src/config/global.ts +309 -0
  51. package/src/config/index.ts +53 -0
  52. package/src/constant.ts +2 -0
  53. package/src/handlers/error.ts +187 -0
  54. package/src/handlers/index.ts +3 -0
  55. package/src/handlers/pv.ts +124 -0
  56. package/src/handlers/user-activity.ts +69 -0
  57. package/src/index.ts +127 -0
  58. package/src/main.ts +8 -0
  59. package/src/reporter.ts +372 -0
  60. package/src/types/config.ts +58 -0
  61. package/src/types/global.ts +73 -0
  62. package/src/types/index.ts +227 -0
  63. package/src/typing.d.ts +15 -0
  64. package/src/utils/index.ts +371 -0
  65. package/tsconfig.esm.json +14 -0
@@ -0,0 +1,41 @@
1
+ {
2
+ "name": "monitor-track",
3
+ "version": "1.10.0",
4
+ "description": "前端监控及埋点SDK工具javascript版本",
5
+ "main": "cjs/index.js",
6
+ "module": "esm/index.js",
7
+ "types": "esm/index.d.ts",
8
+ "unpkg": "index.js",
9
+ "scripts": {
10
+ "clean": "shx rm -rf ./dist",
11
+ "codecheck": "eslint \"src/**/*.{ts,js}\" && tsc -p ../../tsconfig.json --noEmit",
12
+ "cp": "node ./scripts/cp.js",
13
+ "build:esm": "tsc -p ./tsconfig.esm.json",
14
+ "version": "npm run build",
15
+ "build": "npm run clean && rollup --config && npm run cp"
16
+ },
17
+ "packageInfo": {
18
+ "repoPath": "packages/react"
19
+ },
20
+ "publishConfig": {
21
+ "access": "public",
22
+ "directory": "dist"
23
+ },
24
+ "keywords": [
25
+ "monitor",
26
+ "track"
27
+ ],
28
+ "license": "ISC",
29
+ "sideEffects": false,
30
+ "dependencies": {
31
+ "axios": "^1.2.3",
32
+ "error-stack-parser": "^2.0.6",
33
+ "html2canvas": "^1.4.1",
34
+ "rrweb": "^1.0.4",
35
+ "ua-parser-js": "^0.7.22",
36
+ "uuid": "^8.3.1"
37
+ },
38
+ "devDependencies": {
39
+ "@types/uuid": "^8.3.4"
40
+ }
41
+ }
package/package.json ADDED
@@ -0,0 +1,42 @@
1
+ {
2
+ "name": "monitor-track",
3
+ "version": "1.10.0",
4
+ "description": "前端监控及埋点SDK工具javascript版本",
5
+ "main": "cjs/index.js",
6
+ "module": "esm/index.js",
7
+ "types": "esm/index.d.ts",
8
+ "unpkg": "index.js",
9
+ "scripts": {
10
+ "clean": "shx rm -rf ./dist",
11
+ "codecheck": "eslint \"src/**/*.{ts,js}\" && tsc -p ../../tsconfig.json --noEmit",
12
+ "cp": "node ./scripts/cp.js",
13
+ "build:esm": "tsc -p ./tsconfig.esm.json",
14
+ "version": "npm run build",
15
+ "build": "npm run clean && rollup --config && npm run cp"
16
+ },
17
+ "packageInfo": {
18
+ "repoPath": "packages/react"
19
+ },
20
+ "publishConfig": {
21
+ "access": "public",
22
+ "directory": "dist"
23
+ },
24
+ "keywords": [
25
+ "monitor",
26
+ "track"
27
+ ],
28
+ "license": "ISC",
29
+ "sideEffects": false,
30
+ "dependencies": {
31
+ "axios": "^1.2.3",
32
+ "error-stack-parser": "^2.0.6",
33
+ "html2canvas": "^1.4.1",
34
+ "rrweb": "^1.0.4",
35
+ "ua-parser-js": "^0.7.22",
36
+ "uuid": "^8.3.1"
37
+ },
38
+ "devDependencies": {
39
+ "@types/uuid": "^8.3.4"
40
+ },
41
+ "gitHead": "e6cba26b3c8ebb2dc2c83cdbbb837bbec744cf7e"
42
+ }
@@ -0,0 +1,66 @@
1
+ import typescript from '@rollup/plugin-typescript';
2
+ import typescript2 from 'rollup-plugin-typescript2';
3
+ // import dts from 'rollup-plugin-dts';
4
+ import json from '@rollup/plugin-json';
5
+ import { dependencies as rootDependencies } from '../../package.json';
6
+ import { dependencies } from './package.json';
7
+
8
+ const paths = {
9
+ '@packages': ['../../packages'],
10
+ '@': ['./src'],
11
+ };
12
+
13
+ // eslint-disable-next-line no-console
14
+ // console.log('xxx', [...Object.keys(dependencies)]);
15
+
16
+ export default [
17
+ {
18
+ input: './src/index.ts',
19
+ output: {
20
+ dir: './dist/cjs',
21
+ format: 'cjs',
22
+ },
23
+ plugins: [
24
+ json(),
25
+ typescript2({
26
+ tsconfigOverride: {
27
+ compilerOptions: {
28
+ declaration: true,
29
+ declarationMap: false,
30
+ module: 'ESNext',
31
+ paths,
32
+ },
33
+ },
34
+ tsconfig: './tsconfig.esm.json',
35
+ }),
36
+ ],
37
+ external: [...Object.keys({ ...rootDependencies, dependencies })],
38
+ },
39
+ {
40
+ input: './src/index.ts',
41
+ output: {
42
+ dir: './dist/esm',
43
+ format: 'esm',
44
+ preserveModules: true,
45
+ preserveModulesRoot: 'src',
46
+ },
47
+ plugins: [
48
+ json(),
49
+ typescript2({
50
+ useTsconfigDeclarationDir: false,
51
+ tsconfig: './tsconfig.esm.json',
52
+ }),
53
+ ],
54
+ external: [...Object.keys({ ...rootDependencies, dependencies })],
55
+ },
56
+ {
57
+ input: './src/index.ts',
58
+ output: {
59
+ dir: './dist',
60
+ format: 'iife',
61
+ name: 'ShuyunTrack',
62
+ },
63
+ plugins: [json(), typescript()],
64
+ external: [...Object.keys(dependencies)],
65
+ },
66
+ ];
package/scripts/cp.js ADDED
@@ -0,0 +1,11 @@
1
+ const shell = require('shelljs');
2
+
3
+ shell.cp('-R', 'dist/esm/src/*', 'dist/esm');
4
+ shell.cp('-R', 'dist/cjs/src/*', 'dist/cjs');
5
+
6
+ shell.cp('./README.md', './dist');
7
+ shell.cp('./CHANGELOG.md', './dist');
8
+ shell.cp('./package.json', './dist');
9
+
10
+ shell.rm('-rf', './dist/esm/src');
11
+ shell.rm('-rf', './dist/cjs/src');
@@ -0,0 +1,309 @@
1
+ /*
2
+ * @Author: Mark.Zhang
3
+ * @Date: 2020-10-26 15:40:16
4
+ * @Description 全局配置项
5
+ */
6
+ import { v4 as uuidv4 } from 'uuid';
7
+ import { report } from '../reporter';
8
+ import { getNavigator, getSessionId, getUid, getViewport } from '../utils';
9
+ import { setPVTime, setRouteStack } from '../handlers/pv';
10
+ import { Config } from '.';
11
+ import { version } from '../../package.json';
12
+ import { IReport } from '../types/global';
13
+
14
+ // 上报数据
15
+ let Report: IReport = {
16
+ uuid: '',
17
+ projectID: '',
18
+ host: '',
19
+ originPage: '',
20
+ page: '',
21
+ time: 0,
22
+ browserName: '',
23
+ browserVersion: '',
24
+ engineName: '',
25
+ engineVersion: '',
26
+ language: '',
27
+ navigatorVendor: '',
28
+ connectionType: '2g',
29
+ osName: '',
30
+ osVersion: '',
31
+ type: 'init',
32
+ viewport: '',
33
+ screen: '',
34
+ version: '',
35
+ charset: '',
36
+ pageTitle: '',
37
+ referrer: '',
38
+ pv: null,
39
+ ua: null,
40
+ error: null,
41
+ dpr: 1,
42
+ perf: null,
43
+ vD: undefined,
44
+ manualReport: undefined,
45
+ lifeCycleId: uuidv4(),
46
+ sessionId: getSessionId(),
47
+ };
48
+
49
+ /**
50
+ * @description 初始化上报数据并上报
51
+ */
52
+ export function initReport() {
53
+ if (document.readyState === 'complete') {
54
+ initReportFunc();
55
+ } else {
56
+ // 注意:这里不要使用window.onload,因为一个项目window.onload只能用一次,如果这里用了就会影响宿主项目的功能
57
+ window.addEventListener('load', initReportFunc);
58
+ }
59
+ }
60
+
61
+ function initReportFunc() {
62
+ setRouteStack([location.href, location.href]);
63
+ setPVTime();
64
+ Report = {
65
+ ...getReport(),
66
+ ...{
67
+ page: location.href,
68
+ originPage: location.href,
69
+ type: 'init',
70
+ perf: performance,
71
+ sessionId: getSessionId(),
72
+ lifeCycleId: uuidv4(),
73
+ },
74
+ };
75
+ report(Report);
76
+ }
77
+
78
+ /**
79
+ * @description 设置Report的值
80
+ * @param key Report key
81
+ * @param value Report 值
82
+ */
83
+ export function setReportValue<T extends IReport, K extends keyof T>(key: K, value: T[K]) {
84
+ if (Object.prototype.hasOwnProperty.call(Report, key)) {
85
+ if (['pv', 'ua', 'error', 'request'].includes(key as string)) {
86
+ Report = {
87
+ ...Report,
88
+ ...{
89
+ pv: null,
90
+ ua: null,
91
+ error: null,
92
+ req: null,
93
+ manualReport: undefined,
94
+ perf: null,
95
+ },
96
+ };
97
+ }
98
+ (Report as any)[key] = value;
99
+ }
100
+ }
101
+
102
+ /**
103
+ * @description 获取上报数据
104
+ */
105
+ export function getReport(): IReport {
106
+ const nav = getNavigator();
107
+ const viewport = getViewport();
108
+
109
+ return {
110
+ ...Report,
111
+ ...nav,
112
+ ...{
113
+ version,
114
+ projectID: Config.projectID,
115
+ host: location.host,
116
+ uuid: getUid(),
117
+ viewport,
118
+ screen: `${screen.width} x ${screen.height}`,
119
+ pageTitle: document.title,
120
+ referrer: document.referrer,
121
+ charset: document.charset,
122
+ customPayload: Config.customPayload,
123
+ dpr: window.devicePixelRatio,
124
+ },
125
+ };
126
+ }
127
+
128
+ function ajaxEventTrigger(event: 'ajaxLoadStart' | 'ajaxLoadEnd') {
129
+ const ajaxEvent = new CustomEvent(event, {
130
+ detail: this,
131
+ });
132
+ window.dispatchEvent(ajaxEvent);
133
+ }
134
+
135
+ const OldXHR = window.XMLHttpRequest;
136
+ function newXHR() {
137
+ const realXHR = new OldXHR();
138
+ realXHR.addEventListener(
139
+ 'loadstart',
140
+ function () {
141
+ ajaxEventTrigger.call(this, 'ajaxLoadStart');
142
+ },
143
+ false,
144
+ );
145
+ realXHR.addEventListener(
146
+ 'loadend',
147
+ function () {
148
+ ajaxEventTrigger.call(this, 'ajaxLoadEnd');
149
+ },
150
+ false,
151
+ );
152
+ // 此处的捕获的异常会连日志接口也一起捕获,如果日志上报接口异常了,就会导致死循环了。
153
+ realXHR.onerror = function (e: Error) {
154
+ // eslint-disable-next-line no-console
155
+ console.warn('realXHR.onerror, e', e);
156
+ };
157
+ return realXHR;
158
+ }
159
+
160
+ /**
161
+ * 页面接口请求监控
162
+ */
163
+ const tempUrlInfo: { [k: string]: boolean } = {};
164
+ export const recordXMLHttpRequestLog = (XMLHttpRequestTimeout?: number) => {
165
+ XMLHttpRequestTimeout = typeof XMLHttpRequestTimeout === 'number' ? XMLHttpRequestTimeout : 1000;
166
+ const timeRecordArray: {
167
+ timeStamp: number;
168
+ event: any;
169
+ }[] = [];
170
+ window.__XMLHttpRequest__ = window.XMLHttpRequest;
171
+ window.XMLHttpRequest = newXHR;
172
+ window.addEventListener('ajaxLoadStart', function (e) {
173
+ const tempObj = {
174
+ timeStamp: new Date().getTime(),
175
+ event: e,
176
+ };
177
+ timeRecordArray.push(tempObj);
178
+ });
179
+ window.addEventListener('ajaxLoadEnd', function () {
180
+ const timeRecordArrayCopy = ([] as any).concat(timeRecordArray);
181
+ for (let i = 0; i < timeRecordArrayCopy.length; i++) {
182
+ if (timeRecordArrayCopy[i].event.detail && timeRecordArrayCopy[i].event.detail.status > 0) {
183
+ const currentTime = new Date().getTime();
184
+ const { responseURL, status, statusText, timeStamp } = timeRecordArrayCopy[i].event.detail;
185
+ const previousTime = timeStamp || timeRecordArrayCopy[i].timeStamp;
186
+ const loadTime = currentTime - previousTime;
187
+ const request = {
188
+ requestType: 'xhr',
189
+ responseURL,
190
+ status,
191
+ loadTime,
192
+ statusText,
193
+ reason: '',
194
+ detail: '',
195
+ };
196
+ if (loadTime && loadTime > XMLHttpRequestTimeout!) {
197
+ request.reason = 'slow';
198
+ request.detail = `request is too slow, XMLHttpRequestTimeout: ${XMLHttpRequestTimeout}`;
199
+ } else if (status && status >= 300 && statusText && statusText.toLowerCase() !== 'ok') {
200
+ request.reason = 'failed';
201
+ request.detail = `request is failed, status: ${status}, statusText: ${statusText}`;
202
+ } else {
203
+ // console.log('responseURL', responseURL);
204
+ }
205
+ if (request.reason) {
206
+ if (!tempUrlInfo[responseURL]) {
207
+ tempUrlInfo[responseURL] = true;
208
+ setTimeout(() => {
209
+ delete tempUrlInfo[responseURL];
210
+ }, 10);
211
+ setReportValue<IReport, 'error'>('error', null);
212
+ report({
213
+ ...getReport(),
214
+ ...{
215
+ page: location.href,
216
+ originPage: location.href,
217
+ type: 'request',
218
+ req: request,
219
+ },
220
+ });
221
+ }
222
+ }
223
+ } else {
224
+ //status为0,请求未响应,比如取消请求
225
+ }
226
+ // 当前请求成功后就在数组中移除掉
227
+ timeRecordArray.splice(i, 1);
228
+ }
229
+ });
230
+ };
231
+
232
+ export const hackFetch = (XMLHttpRequestTimeout?: number) => {
233
+ XMLHttpRequestTimeout = typeof XMLHttpRequestTimeout === 'number' ? XMLHttpRequestTimeout : 1000;
234
+ if (typeof window.fetch === 'function') {
235
+ const __fetch__ = window.fetch;
236
+ window.__fetch__ = __fetch__;
237
+ window.fetch = function (t: string, ...args: any[]) {
238
+ const begin = Date.now();
239
+ //禁用数组的扩展运算符,否则portal的生产环境会报Uncaught TypeError: Object(...) is not a function,
240
+ //编译后的__spreadArray函数有问题,而这个函数来自于tslib.具体报错原因不知.
241
+ //其他平台使用数组的扩展运算符没有问题,比如前端监控平台的管理界面
242
+ const params = ([] as any).concat(t).concat(args);
243
+ return __fetch__
244
+ .apply(window, params)
245
+ .then(function (res: any) {
246
+ const response = res.clone();
247
+ const headers = response.headers;
248
+ if (headers && typeof headers.get === 'function') {
249
+ const ct = headers.get('content-type');
250
+ if (ct && !/(text)|(json)/.test(ct)) {
251
+ return res;
252
+ }
253
+ }
254
+ const loadTime = Date.now() - begin;
255
+ response
256
+ .text()
257
+ .then(function (result: []) {
258
+ const { url, status, statusText, ok } = response;
259
+ const request = {
260
+ requestType: 'fetch',
261
+ responseURL: url,
262
+ status,
263
+ loadTime,
264
+ statusText,
265
+ reason: '',
266
+ detail: '',
267
+ };
268
+ if (!ok || status >= 300) {
269
+ request.reason = 'failed';
270
+ request.detail = `request is failed, status: ${status}, statusText: ${statusText}`;
271
+ } else if (loadTime > XMLHttpRequestTimeout!) {
272
+ request.reason = 'slow';
273
+ request.detail = `request is too slow, XMLHttpRequestTimeout: ${XMLHttpRequestTimeout}, result: ${result?.slice(
274
+ 0,
275
+ 500,
276
+ )}`;
277
+ }
278
+ if (request.reason) {
279
+ if (!tempUrlInfo[url]) {
280
+ tempUrlInfo[url] = true;
281
+ setTimeout(() => {
282
+ delete tempUrlInfo[url];
283
+ }, 10);
284
+ setReportValue<IReport, 'error'>('error', null);
285
+ report({
286
+ ...getReport(),
287
+ ...{
288
+ page: location.href,
289
+ originPage: location.href,
290
+ type: 'request',
291
+ req: request,
292
+ },
293
+ });
294
+ }
295
+ }
296
+ })
297
+ .catch((err: Error) => {
298
+ // eslint-disable-next-line no-console
299
+ console.log('hackFetch response.text() err', err);
300
+ });
301
+ return res;
302
+ })
303
+ .catch((err: Error) => {
304
+ // eslint-disable-next-line no-console
305
+ console.log('hackFetch err', err);
306
+ });
307
+ };
308
+ }
309
+ };
@@ -0,0 +1,53 @@
1
+ /*
2
+ * @Author: Mark.Zhang
3
+ * @Description 配置项相关参数及方法
4
+ */
5
+
6
+ import { IConfig } from '../types/config';
7
+
8
+ /** */
9
+ /**
10
+ * @description config配置项默认值
11
+ */
12
+ export const Config: IConfig = {
13
+ reportUrl: '',
14
+ projectID: '',
15
+ maxLength: 1000,
16
+ spa: false,
17
+ hash: false,
18
+ enableBehavior: true,
19
+ enableError: true,
20
+ enableVisualTrack: false,
21
+ ignore: {
22
+ urls: [],
23
+ errors: [],
24
+ apis: [],
25
+ },
26
+ };
27
+
28
+ /**
29
+ * @description 设置config配置项
30
+ * @param config 配置项
31
+ */
32
+ export function setConfig(config: IConfig) {
33
+ Object.assign(Config, config);
34
+ }
35
+
36
+ /**
37
+ * @description 设置config配置项
38
+ * @param config 配置项
39
+ */
40
+ export function setConfigValue<T extends IConfig, K extends keyof T>(key: K, value: T[K]) {
41
+ if ((Config as any)[key]) {
42
+ (Config as any)[key] = value;
43
+ }
44
+ }
45
+
46
+ /**
47
+ * @description 获取通过key值获取配置项value
48
+ * @param key
49
+ * @returns value的值
50
+ */
51
+ export function getConfigValue(key: keyof IConfig) {
52
+ return Config[key];
53
+ }
@@ -0,0 +1,2 @@
1
+ export const shuyunTrackId = 'shuyun-track-id';
2
+ export const shuyunTrackSessionId = 'shuyun-track-session-id';