monitor-track 1.14.0 → 1.15.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.
@@ -0,0 +1,277 @@
1
+ import { __awaiter } from '../_virtual/_tslib.js';
2
+ import { Config } from '../config/index.js';
3
+ import { getReport } from '../config/global.js';
4
+ import { getUid } from '../utils/index.js';
5
+
6
+ let reconnectAndSendTimeout, websocketHeartBeatInterval, ws, userId = '';
7
+ let remoteDebugEnable = false;
8
+ let targetPlatform = '';
9
+ let targetUserId = '';
10
+ const originConsole = Object.assign({}, console);
11
+ const formatConsole = () => {
12
+ if (remoteDebugEnable)
13
+ return;
14
+ remoteDebugEnable = true;
15
+ window.console = Object.assign({}, originConsole);
16
+ const arr = ['debug', 'log', 'info', 'warn', 'error'];
17
+ arr.forEach((item) => {
18
+ //@ts-ignore
19
+ window.console[item] = function (...args) {
20
+ //@ts-ignore
21
+ originConsole[item](...args);
22
+ const data = {
23
+ origin: 'console',
24
+ level: item,
25
+ userId,
26
+ time: new Date().toLocaleString(),
27
+ page: location.href,
28
+ content: '',
29
+ targetPlatform,
30
+ targetUserId,
31
+ };
32
+ try {
33
+ const content = JSON.stringify(args);
34
+ data.content = content;
35
+ }
36
+ catch (err) {
37
+ data.content = 'console内容解析错误: ' + err.stack || err.message || err.toString();
38
+ }
39
+ const msg = {
40
+ type: WEBSOCKET_TYPE.DEBUG_INFO_UPLOAD,
41
+ userId,
42
+ platform: 'monitor-track-sdk',
43
+ data,
44
+ };
45
+ wsSendFunc(msg);
46
+ };
47
+ });
48
+ };
49
+ const resetConsole = () => {
50
+ window.console = originConsole;
51
+ remoteDebugEnable = false;
52
+ };
53
+ const uploadRequest = (requestInfo) => {
54
+ // console.log('monitor-track-sdk: uploadRequest remoteDebugEnable', remoteDebugEnable);
55
+ if (remoteDebugEnable) {
56
+ const data = {
57
+ origin: 'request',
58
+ userId,
59
+ time: new Date().toLocaleString(),
60
+ page: location.href,
61
+ content: requestInfo,
62
+ targetPlatform,
63
+ targetUserId,
64
+ };
65
+ const msg = {
66
+ type: WEBSOCKET_TYPE.DEBUG_INFO_UPLOAD,
67
+ userId,
68
+ platform: 'monitor-track-sdk',
69
+ data,
70
+ };
71
+ // console.log('monitor-track-sdk: request-upload sent');
72
+ wsSendFunc(msg);
73
+ }
74
+ };
75
+ function enableOnlinePersonsFunc() {
76
+ initWebsocket();
77
+ }
78
+ const WEBSOCKET_TYPE = {
79
+ TRY_CONNECT: 'try-connect',
80
+ CHECK_CONNECT: 'check-connect',
81
+ PING: 'ping',
82
+ PONG: 'pong',
83
+ REPLY_SERVER_HEART_BEAT: 'reply-server-heart-beat',
84
+ SOCKET_HEART_BEAT: 'socket-heart-beat',
85
+ RESPONSE_DATE: 'response-date',
86
+ REMOTE_DEBUG_ENABLE: 'remote-debug-enable',
87
+ DEBUG_INFO_UPLOAD: 'debug-info-upload',
88
+ REPlY_MESSAGE: 'reply-message',
89
+ };
90
+ let mounted = false;
91
+ const initWebsocket = () => {
92
+ if (window.WebSocket) {
93
+ userId = localStorage.getItem('username') || getUid();
94
+ closeWebsocket('');
95
+ websocketHeartBeatInterval = setInterval(reconnectAndSend, 30000);
96
+ const isLocal = Config.reportUrl.includes('http://');
97
+ ws = new WebSocket(`ws${isLocal ? '' : 's'}://${Config.reportUrl.replace(isLocal ? 'http://' : 'https://', '').replace('/s/r', '')}?type=monitor-dsk`);
98
+ ws.onopen = () => openWS();
99
+ ws.onmessage = (data) => incomingMessage(data);
100
+ ws.onerror = () => {
101
+ ws.close(1000);
102
+ if (websocketHeartBeatInterval)
103
+ clearInterval(websocketHeartBeatInterval);
104
+ websocketHeartBeatInterval = setInterval(reconnectAndSend, 10000);
105
+ };
106
+ ws.onclose = () => {
107
+ ws.close(1000);
108
+ if (websocketHeartBeatInterval)
109
+ clearInterval(websocketHeartBeatInterval);
110
+ websocketHeartBeatInterval = setInterval(reconnectAndSend, 10000);
111
+ };
112
+ if (!mounted) {
113
+ reconnectNetwork();
114
+ mounted = true;
115
+ }
116
+ }
117
+ };
118
+ const openWS = () => {
119
+ const data = getReport();
120
+ const { page, projectID, host, pageTitle } = data;
121
+ const msg = {
122
+ type: WEBSOCKET_TYPE.TRY_CONNECT,
123
+ userId,
124
+ platform: 'monitor-track-sdk',
125
+ data: {
126
+ p: page,
127
+ pid: projectID,
128
+ host,
129
+ pt: pageTitle,
130
+ platform: 'web',
131
+ },
132
+ };
133
+ wsSendFunc(msg);
134
+ };
135
+ const reconnectAndSend = () => {
136
+ try {
137
+ if (ws.readyState !== 1) {
138
+ reconnectSocket();
139
+ }
140
+ else {
141
+ const msg = {
142
+ type: WEBSOCKET_TYPE.CHECK_CONNECT,
143
+ userId,
144
+ data: WEBSOCKET_TYPE.PING,
145
+ date: Date.now(),
146
+ };
147
+ wsSendFunc(msg, 'reconnectAndSend');
148
+ // 20秒超时,如果收不到服务端pong响应则表示服务端已主动断开连接,此时需客户端重新开启websocket连接
149
+ reconnectAndSendTimeout = setTimeout(() => {
150
+ reconnectSocket();
151
+ }, 20000);
152
+ }
153
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
154
+ }
155
+ catch (_err) {
156
+ // console.error('monitor-track-sdk: reconnectAndSend err', err);
157
+ }
158
+ };
159
+ const closeWebsocket = (info) => {
160
+ if (ws) {
161
+ ws.onopen = null;
162
+ ws.onmessage = null;
163
+ ws.onerror = null;
164
+ ws.onclose = null;
165
+ if (ws.readyState === WebSocket.OPEN || ws.readyState === WebSocket.CONNECTING) {
166
+ ws.close(1000, info);
167
+ }
168
+ //@ts-ignore
169
+ ws = null; // 释放引用
170
+ }
171
+ if (websocketHeartBeatInterval)
172
+ clearInterval(websocketHeartBeatInterval);
173
+ };
174
+ const reconnectSocket = () => {
175
+ // console.warn('monitor-track-sdk: 正在重新建立websocket连接...');
176
+ initWebsocket();
177
+ };
178
+ const incomingMessage = (e) => __awaiter(void 0, void 0, void 0, function* () {
179
+ let data = {};
180
+ try {
181
+ data = JSON.parse(e.data);
182
+ // console.info('incomingMessage data', data);
183
+ switch (data.type) {
184
+ case WEBSOCKET_TYPE.PONG:
185
+ // console.info('monitor-track-sdk: incomingMessage 响应客户端的心跳: ping => pong');
186
+ clearTimeout(reconnectAndSendTimeout);
187
+ break;
188
+ case WEBSOCKET_TYPE.SOCKET_HEART_BEAT: {
189
+ // console.info('monitor-track-sdk: incomingMessage 响应服务端的心跳: heart beat => ', new Date().toLocaleString());
190
+ const msg = {
191
+ type: WEBSOCKET_TYPE.CHECK_CONNECT,
192
+ userId,
193
+ data: WEBSOCKET_TYPE.REPLY_SERVER_HEART_BEAT,
194
+ date: Date.now(),
195
+ };
196
+ wsSendFunc(msg, 'socket-heart-beat reply-server-heart-beat');
197
+ break;
198
+ }
199
+ case WEBSOCKET_TYPE.RESPONSE_DATE:
200
+ // console.info(`monitor-track-sdk: incomingMessage WS connected, Roundtrip time: ${Date.now() - data.data} ms`);
201
+ break;
202
+ case WEBSOCKET_TYPE.REMOTE_DEBUG_ENABLE: {
203
+ // console.log('monitor-track-sdk REMOTE_DEBUG_ENABLE data.data', data.data);
204
+ const { enable, platform, userId } = data.data;
205
+ if (enable && platform && userId) {
206
+ targetPlatform = platform;
207
+ targetUserId = userId;
208
+ formatConsole();
209
+ }
210
+ else {
211
+ resetConsole();
212
+ }
213
+ break;
214
+ }
215
+ case WEBSOCKET_TYPE.REPlY_MESSAGE: {
216
+ // eslint-disable-next-line no-console
217
+ console.info('incomingMessage REPlY_MESSAGE, data: ', data.data);
218
+ break;
219
+ }
220
+ default:
221
+ // console.error('incomingMessage default error', data);
222
+ break;
223
+ }
224
+ }
225
+ catch (err) {
226
+ // eslint-disable-next-line no-console
227
+ console.error('monitor-track-sdk incomingMessage JSON.parse', err);
228
+ }
229
+ });
230
+ const wsSendFunc = (msg, _info) => {
231
+ if (ws.readyState === 1) {
232
+ msg.platform = 'monitor-track-sdk';
233
+ const message = JSON.stringify(msg);
234
+ ws.send(message);
235
+ }
236
+ else {
237
+ // console.warn('monitor-track-sdk: window.ws.readyState === 1 info', info);
238
+ reconnectSocket();
239
+ }
240
+ };
241
+ const reconnectNetwork = () => {
242
+ let networkFlag = false;
243
+ let debounceTimeout = null;
244
+ document.addEventListener('offline', function () {
245
+ // 断开网络
246
+ try {
247
+ // console.info('monitor-track-sdk: 客户端网络已断开,正在关闭websocket');
248
+ ws.close(1000);
249
+ networkFlag = true;
250
+ debounceTimeout = setTimeout(() => {
251
+ // console.warn('monitor-track-sdk: reconnectNetwork offline 无法访问网络');
252
+ // message.error('无法访问网络');
253
+ }, 5000);
254
+ }
255
+ catch (err) {
256
+ // console.error('monitor-track-sdk: addEventListener offline after setTimeout', err);
257
+ }
258
+ }, false);
259
+ document.addEventListener('online', function () {
260
+ // 连接到网络
261
+ try {
262
+ if (networkFlag === true) {
263
+ clearTimeout(debounceTimeout);
264
+ // console.info('monitor-track-sdk: addEventListener reconnectNetwork online');
265
+ // message.success('网络已恢复');
266
+ networkFlag = false;
267
+ // console.warn('monitor-track-sdk: addEventListener online websocket 正在重新建立连接...');
268
+ initWebsocket();
269
+ }
270
+ }
271
+ catch (err) {
272
+ // console.error('monitor-track-sdk: document.addEventListener online', err);
273
+ }
274
+ }, false);
275
+ };
276
+
277
+ export { WEBSOCKET_TYPE, closeWebsocket, enableOnlinePersonsFunc, uploadRequest };
package/esm/index.d.ts CHANGED
@@ -22,11 +22,6 @@ export default class Track {
22
22
  * @description 页面将要关闭
23
23
  */
24
24
  addListenUnload(): void;
25
- /**
26
- * 忽略的url
27
- * @param urls
28
- */
29
- ignoreUrl(urls: string[]): boolean;
30
25
  /**
31
26
  * @description 销毁监听器
32
27
  */
package/esm/index.js CHANGED
@@ -1,9 +1,11 @@
1
1
  import { Config, setConfig } from './config/index.js';
2
- import { initReport, recordXMLHttpRequestLog, hackFetch } from './config/global.js';
2
+ import { initReport } from './config/global.js';
3
+ import { recordXMLHttpRequest, recordFetch } from './config/request.js';
3
4
  import { monitorTrackSessionId } from './constant.js';
4
5
  import { handlePageLag, _history, handleHistoryChange } from './handlers/pv.js';
5
6
  import { enableRecordFunc, handleError } from './handlers/error.js';
6
7
  import { handleClick, handleBlur, handleScroll } from './handlers/user-activity.js';
8
+ import { enableOnlinePersonsFunc, closeWebsocket } from './handlers/websocket.js';
7
9
  import { initWindowObjectFunction, on, off, visualTrackFunc, handleLocationChange } from './utils/index.js';
8
10
 
9
11
  class Track {
@@ -29,7 +31,6 @@ class Track {
29
31
  };
30
32
  }
31
33
  init(config) {
32
- var _a;
33
34
  // 是否开启日志收集
34
35
  if (!config || !config.enable) {
35
36
  return;
@@ -46,19 +47,17 @@ class Track {
46
47
  console.warn('缺少上报地址!');
47
48
  return;
48
49
  }
49
- if (this.ignoreUrl(((_a = config === null || config === void 0 ? void 0 : config.ignore) === null || _a === void 0 ? void 0 : _a.urls) || [])) {
50
- return;
51
- }
52
50
  setConfig(config);
53
51
  initReport();
54
- recordXMLHttpRequestLog(config.XMLHttpRequestTimeout);
55
- hackFetch(config.XMLHttpRequestTimeout);
52
+ recordXMLHttpRequest(config.XMLHttpRequestTimeout || 2500);
53
+ recordFetch(config.XMLHttpRequestTimeout || 2500);
56
54
  Config.spa && this.addListenRouterChange();
57
55
  Config.enableBehavior && this.addListenUserActivity();
58
56
  Config.enableError && this.addListenJSUncaught();
59
57
  Config.enableVisualTrack && this.visualTrack();
60
58
  Config.enableLagTrack && this.listenPageLag();
61
59
  Config.enableRecord && enableRecordFunc();
60
+ Config.enableOnlinePersons && enableOnlinePersonsFunc();
62
61
  this.addListenUnload();
63
62
  initWindowObjectFunction();
64
63
  }
@@ -98,14 +97,6 @@ class Track {
98
97
  this.destroy();
99
98
  });
100
99
  }
101
- /**
102
- * 忽略的url
103
- * @param urls
104
- */
105
- ignoreUrl(urls) {
106
- const someUrl = urls.some((url) => location.href.includes(url));
107
- return someUrl;
108
- }
109
100
  /**
110
101
  * @description 销毁监听器
111
102
  */
@@ -128,6 +119,7 @@ class Track {
128
119
  this.lagTimer && clearInterval(this.lagTimer);
129
120
  (_a = this.observer) === null || _a === void 0 ? void 0 : _a.disconnect();
130
121
  sessionStorage.removeItem(monitorTrackSessionId);
122
+ closeWebsocket('destroy');
131
123
  }
132
124
  }
133
125
 
@@ -1,3 +1,3 @@
1
- var version = "1.14.0";
1
+ var version = "1.15.0";
2
2
 
3
3
  export { version };
package/esm/reporter.d.ts CHANGED
@@ -184,6 +184,8 @@ export declare const reportMap: {
184
184
  detail: string;
185
185
  /** 上报时带上的请求参数 */
186
186
  requestData: string;
187
+ /** 上报时带上的响应结果 */
188
+ responseBody: string;
187
189
  /** 上报时带上的请求方法 */
188
190
  method: string;
189
191
  };
package/esm/reporter.js CHANGED
@@ -188,6 +188,8 @@ const reportMap = {
188
188
  detail: 'de',
189
189
  /** 上报时带上的请求参数 */
190
190
  requestData: 'rD',
191
+ /** 上报时带上的响应结果 */
192
+ responseBody: 'rB',
191
193
  /** 上报时带上的请求方法 */
192
194
  method: 'rM',
193
195
  },
@@ -316,6 +318,10 @@ function reportFunc(data) {
316
318
  // 上报
317
319
  function report(data) {
318
320
  return new Promise((res) => {
321
+ var _a;
322
+ if ((((_a = Config.ignore) === null || _a === void 0 ? void 0 : _a.urls) || []).some((url) => location.href.includes(url))) {
323
+ return;
324
+ }
319
325
  //在帧的空闲时间上报
320
326
  const dataCopy = JSON.parse(JSON.stringify(data));
321
327
  if (typeof window.requestIdleCallback === 'function') {
@@ -45,6 +45,8 @@ export interface IConfig {
45
45
  lagTimeout?: number;
46
46
  /** 是否启用页面录制 */
47
47
  enableRecord: boolean;
48
+ /** 启用在线人数上报 */
49
+ enableOnlinePersons?: boolean;
48
50
  }
49
51
  type IParams = {
50
52
  name: string;
@@ -48,7 +48,8 @@ export interface IReport extends INavigator {
48
48
  statusText: string;
49
49
  reason: 'slow' | 'failed' | string;
50
50
  detail: string;
51
- requestData: string;
51
+ requestData: string | null;
52
+ responseBody: string | null;
52
53
  method: string;
53
54
  } | null;
54
55
  vD?: {