@webex/internal-plugin-metrics 3.0.0 → 3.1.0-next.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/call-diagnostic/call-diagnostic-metrics-latencies.js +90 -14
- package/dist/call-diagnostic/call-diagnostic-metrics-latencies.js.map +1 -1
- package/dist/call-diagnostic/call-diagnostic-metrics.js +60 -38
- package/dist/call-diagnostic/call-diagnostic-metrics.js.map +1 -1
- package/dist/call-diagnostic/call-diagnostic-metrics.util.js +10 -3
- package/dist/call-diagnostic/call-diagnostic-metrics.util.js.map +1 -1
- package/dist/client-metrics-prelogin-batcher.js +32 -0
- package/dist/client-metrics-prelogin-batcher.js.map +1 -0
- package/dist/index.js +0 -1
- package/dist/index.js.map +1 -1
- package/dist/metrics.js +10 -25
- package/dist/metrics.js.map +1 -1
- package/dist/metrics.types.js.map +1 -1
- package/dist/new-metrics.js +5 -4
- package/dist/new-metrics.js.map +1 -1
- package/dist/prelogin-metrics-batcher.js +1 -1
- package/dist/prelogin-metrics-batcher.js.map +1 -1
- package/dist/types/call-diagnostic/call-diagnostic-metrics-latencies.d.ts +41 -8
- package/dist/types/call-diagnostic/call-diagnostic-metrics.d.ts +17 -12
- package/dist/types/client-metrics-prelogin-batcher.d.ts +2 -0
- package/dist/types/index.d.ts +2 -3
- package/dist/types/metrics.types.d.ts +3 -1
- package/package.json +12 -13
- package/src/call-diagnostic/call-diagnostic-metrics-latencies.ts +89 -13
- package/src/call-diagnostic/call-diagnostic-metrics.ts +35 -8
- package/src/call-diagnostic/call-diagnostic-metrics.util.ts +17 -3
- package/src/client-metrics-prelogin-batcher.ts +26 -0
- package/src/index.ts +2 -2
- package/src/metrics.js +8 -23
- package/src/metrics.types.ts +12 -1
- package/src/new-metrics.ts +2 -2
- package/src/prelogin-metrics-batcher.ts +1 -1
- package/test/unit/spec/call-diagnostic/call-diagnostic-metrics-batcher.ts +25 -15
- package/test/unit/spec/call-diagnostic/call-diagnostic-metrics-latencies.ts +199 -1
- package/test/unit/spec/call-diagnostic/call-diagnostic-metrics.ts +155 -41
- package/test/unit/spec/call-diagnostic/call-diagnostic-metrics.util.ts +28 -7
- package/test/unit/spec/client-metrics-prelogin-batcher.ts +54 -0
- package/test/unit/spec/metrics.js +9 -31
- package/test/unit/spec/new-metrics.ts +29 -31
- package/test/unit/spec/prelogin-metrics-batcher.ts +13 -10
|
@@ -31,6 +31,7 @@ export default class CallDiagnosticLatencies extends WebexPlugin {
|
|
|
31
31
|
*/
|
|
32
32
|
public clearTimestamps() {
|
|
33
33
|
this.latencyTimestamps.clear();
|
|
34
|
+
this.precomputedLatencies.clear();
|
|
34
35
|
}
|
|
35
36
|
|
|
36
37
|
/**
|
|
@@ -57,7 +58,8 @@ export default class CallDiagnosticLatencies extends WebexPlugin {
|
|
|
57
58
|
/**
|
|
58
59
|
* Store timestamp value
|
|
59
60
|
* @param key - key
|
|
60
|
-
* @param value -value
|
|
61
|
+
* @param value - value
|
|
62
|
+
* @param options - store options
|
|
61
63
|
* @throws
|
|
62
64
|
* @returns
|
|
63
65
|
*/
|
|
@@ -92,12 +94,33 @@ export default class CallDiagnosticLatencies extends WebexPlugin {
|
|
|
92
94
|
/**
|
|
93
95
|
* Store precomputed latency value
|
|
94
96
|
* @param key - key
|
|
95
|
-
* @param value -value
|
|
97
|
+
* @param value - value
|
|
98
|
+
* @param accumulate - when it is true, it overwrites existing value with sum of the current value and the new measurement otherwise just store the new measurement
|
|
96
99
|
* @throws
|
|
97
100
|
* @returns
|
|
98
101
|
*/
|
|
99
|
-
public saveLatency(key: PreComputedLatencies, value: number) {
|
|
100
|
-
this.precomputedLatencies.
|
|
102
|
+
public saveLatency(key: PreComputedLatencies, value: number, accumulate = false) {
|
|
103
|
+
const existingValue = accumulate ? this.precomputedLatencies.get(key) || 0 : 0;
|
|
104
|
+
this.precomputedLatencies.set(key, value + existingValue);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Measure latency for a request
|
|
109
|
+
* @param callback - callback for which you would like to measure latency
|
|
110
|
+
* @param key - key
|
|
111
|
+
* @param accumulate - when it is true, it overwrites existing value with sum of the current value and the new measurement otherwise just store the new measurement
|
|
112
|
+
* @returns
|
|
113
|
+
*/
|
|
114
|
+
public measureLatency(
|
|
115
|
+
callback: () => Promise<unknown>,
|
|
116
|
+
key: PreComputedLatencies,
|
|
117
|
+
accumulate = false
|
|
118
|
+
) {
|
|
119
|
+
const start = performance.now();
|
|
120
|
+
|
|
121
|
+
return callback().finally(() => {
|
|
122
|
+
this.saveLatency(key, performance.now() - start, accumulate);
|
|
123
|
+
});
|
|
101
124
|
}
|
|
102
125
|
|
|
103
126
|
/**
|
|
@@ -158,6 +181,16 @@ export default class CallDiagnosticLatencies extends WebexPlugin {
|
|
|
158
181
|
);
|
|
159
182
|
}
|
|
160
183
|
|
|
184
|
+
/**
|
|
185
|
+
* getU2CTime
|
|
186
|
+
* @returns - latency
|
|
187
|
+
*/
|
|
188
|
+
public getU2CTime() {
|
|
189
|
+
const u2cLatency = this.precomputedLatencies.get('internal.get.u2c.time');
|
|
190
|
+
|
|
191
|
+
return u2cLatency ? Math.floor(u2cLatency) : undefined;
|
|
192
|
+
}
|
|
193
|
+
|
|
161
194
|
/**
|
|
162
195
|
* Device Register Time
|
|
163
196
|
* @returns - latency
|
|
@@ -188,15 +221,6 @@ export default class CallDiagnosticLatencies extends WebexPlugin {
|
|
|
188
221
|
return this.getDiffBetweenTimestamps('client.locus.join.request', 'client.locus.join.response');
|
|
189
222
|
}
|
|
190
223
|
|
|
191
|
-
/**
|
|
192
|
-
* Locus Join Response Sent Received
|
|
193
|
-
* @returns - latency
|
|
194
|
-
*/
|
|
195
|
-
public getJoinRespSentReceived() {
|
|
196
|
-
// TODO: not clear SPARK-440554
|
|
197
|
-
return undefined;
|
|
198
|
-
}
|
|
199
|
-
|
|
200
224
|
/**
|
|
201
225
|
* Time taken to do turn discovery
|
|
202
226
|
* @returns - latency
|
|
@@ -419,6 +443,15 @@ export default class CallDiagnosticLatencies extends WebexPlugin {
|
|
|
419
443
|
return this.getDiffBetweenTimestamps('client.locus.join.response', 'client.media.rx.start');
|
|
420
444
|
}
|
|
421
445
|
|
|
446
|
+
/**
|
|
447
|
+
* Total latency for all get cluster request.
|
|
448
|
+
*/
|
|
449
|
+
public getReachabilityClustersReqResp() {
|
|
450
|
+
const reachablityClusterReqResp = this.precomputedLatencies.get('internal.get.cluster.time');
|
|
451
|
+
|
|
452
|
+
return reachablityClusterReqResp ? Math.floor(reachablityClusterReqResp) : undefined;
|
|
453
|
+
}
|
|
454
|
+
|
|
422
455
|
/**
|
|
423
456
|
* Audio setup delay transmit
|
|
424
457
|
*/
|
|
@@ -432,4 +465,47 @@ export default class CallDiagnosticLatencies extends WebexPlugin {
|
|
|
432
465
|
public getVideoJoinRespTxStart() {
|
|
433
466
|
return this.getDiffBetweenTimestamps('client.locus.join.response', 'client.media.tx.start');
|
|
434
467
|
}
|
|
468
|
+
|
|
469
|
+
/**
|
|
470
|
+
* Total latency for all exchange ci token.
|
|
471
|
+
*/
|
|
472
|
+
public getExchangeCITokenJMT() {
|
|
473
|
+
const exchangeCITokenJMT = this.precomputedLatencies.get('internal.exchange.ci.token.time');
|
|
474
|
+
|
|
475
|
+
return exchangeCITokenJMT ? Math.floor(exchangeCITokenJMT) : undefined;
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
/**
|
|
479
|
+
* Total latency for all refresh captcha requests.
|
|
480
|
+
*/
|
|
481
|
+
public getRefreshCaptchaReqResp() {
|
|
482
|
+
const refreshCaptchaReqResp = this.precomputedLatencies.get('internal.refresh.captcha.time');
|
|
483
|
+
|
|
484
|
+
return refreshCaptchaReqResp ? Math.floor(refreshCaptchaReqResp) : undefined;
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
/**
|
|
488
|
+
* Get the latency for downloading intelligence models.
|
|
489
|
+
* @returns - latency
|
|
490
|
+
*/
|
|
491
|
+
public getDownloadIntelligenceModelsReqResp() {
|
|
492
|
+
const downloadIntelligenceModelsReqResp = this.precomputedLatencies.get(
|
|
493
|
+
'internal.api.fetch.intelligence.models'
|
|
494
|
+
);
|
|
495
|
+
|
|
496
|
+
return downloadIntelligenceModelsReqResp
|
|
497
|
+
? Math.floor(downloadIntelligenceModelsReqResp)
|
|
498
|
+
: undefined;
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
/**
|
|
502
|
+
* Get the total latency for all other app API requests.
|
|
503
|
+
* Excludes meeting info, because it's measured separately.
|
|
504
|
+
* @returns - latency
|
|
505
|
+
*/
|
|
506
|
+
public getOtherAppApiReqResp() {
|
|
507
|
+
const otherAppApiJMT = this.precomputedLatencies.get('internal.other.app.api.time');
|
|
508
|
+
|
|
509
|
+
return otherAppApiJMT > 0 ? Math.floor(otherAppApiJMT) : undefined;
|
|
510
|
+
}
|
|
435
511
|
}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
/* eslint-disable @typescript-eslint/no-unused-vars */
|
|
2
2
|
/* eslint-disable class-methods-use-this */
|
|
3
3
|
/* eslint-disable valid-jsdoc */
|
|
4
|
-
import {getOSNameInternal} from '@webex/internal-plugin-metrics';
|
|
5
4
|
import {BrowserDetection, getBrowserSerial} from '@webex/common';
|
|
6
5
|
import uuid from 'uuid';
|
|
7
6
|
import {merge} from 'lodash';
|
|
8
7
|
import {StatelessWebexPlugin} from '@webex/webex-core';
|
|
8
|
+
import {getOSNameInternal} from '../metrics';
|
|
9
9
|
|
|
10
10
|
import {
|
|
11
11
|
anonymizeIPAddress,
|
|
@@ -39,6 +39,7 @@ import {
|
|
|
39
39
|
ClientInfo,
|
|
40
40
|
ClientEventPayloadError,
|
|
41
41
|
ClientSubServiceType,
|
|
42
|
+
BrowserLaunchMethodType,
|
|
42
43
|
} from '../metrics.types';
|
|
43
44
|
import CallDiagnosticEventsBatcher from './call-diagnostic-metrics-batcher';
|
|
44
45
|
import PreLoginMetricsBatcher from '../prelogin-metrics-batcher';
|
|
@@ -65,6 +66,7 @@ type GetOriginOptions = {
|
|
|
65
66
|
subClientType: SubClientType;
|
|
66
67
|
networkType?: NetworkType;
|
|
67
68
|
clientLaunchMethod?: ClientLaunchMethodType;
|
|
69
|
+
browserLaunchMethod?: BrowserLaunchMethodType;
|
|
68
70
|
environment?: EnvironmentType;
|
|
69
71
|
newEnvironment?: NewEnvironmentType;
|
|
70
72
|
};
|
|
@@ -91,6 +93,8 @@ export default class CallDiagnosticMetrics extends StatelessWebexPlugin {
|
|
|
91
93
|
|
|
92
94
|
private logger: any; // to avoid adding @ts-ignore everywhere
|
|
93
95
|
private hasLoggedBrowserSerial: boolean;
|
|
96
|
+
private device: any;
|
|
97
|
+
|
|
94
98
|
// the default validator before piping an event to the batcher
|
|
95
99
|
// this function can be overridden by the user
|
|
96
100
|
public validator: (options: {
|
|
@@ -258,6 +262,10 @@ export default class CallDiagnosticMetrics extends StatelessWebexPlugin {
|
|
|
258
262
|
origin.clientInfo.clientLaunchMethod = options.clientLaunchMethod;
|
|
259
263
|
}
|
|
260
264
|
|
|
265
|
+
if (options?.browserLaunchMethod) {
|
|
266
|
+
origin.clientInfo.browserLaunchMethod = options.browserLaunchMethod;
|
|
267
|
+
}
|
|
268
|
+
|
|
261
269
|
return origin;
|
|
262
270
|
}
|
|
263
271
|
|
|
@@ -289,15 +297,20 @@ export default class CallDiagnosticMetrics extends StatelessWebexPlugin {
|
|
|
289
297
|
if (correlationId) {
|
|
290
298
|
identifiers.correlationId = correlationId;
|
|
291
299
|
}
|
|
292
|
-
|
|
293
|
-
if (this.
|
|
294
|
-
|
|
295
|
-
const {
|
|
296
|
-
|
|
297
|
-
identifiers.
|
|
298
|
-
identifiers.
|
|
300
|
+
|
|
301
|
+
if (this.device) {
|
|
302
|
+
const {device} = this;
|
|
303
|
+
const {installationId} = device?.config || {};
|
|
304
|
+
|
|
305
|
+
identifiers.userId = device?.userId || preLoginId;
|
|
306
|
+
identifiers.deviceId = device?.url;
|
|
307
|
+
identifiers.orgId = device?.orgId;
|
|
299
308
|
// @ts-ignore
|
|
300
309
|
identifiers.locusUrl = this.webex.internal.services.get('locus');
|
|
310
|
+
|
|
311
|
+
if (installationId) {
|
|
312
|
+
identifiers.machineId = installationId;
|
|
313
|
+
}
|
|
301
314
|
}
|
|
302
315
|
|
|
303
316
|
if (meeting?.locusInfo?.fullState) {
|
|
@@ -441,6 +454,7 @@ export default class CallDiagnosticMetrics extends StatelessWebexPlugin {
|
|
|
441
454
|
webClientDomain: window.location.hostname,
|
|
442
455
|
},
|
|
443
456
|
intervals: payload.intervals,
|
|
457
|
+
callingServiceType: 'LOCUS',
|
|
444
458
|
sourceMetadata: {
|
|
445
459
|
applicationSoftwareType: CLIENT_NAME,
|
|
446
460
|
// @ts-ignore
|
|
@@ -607,6 +621,7 @@ export default class CallDiagnosticMetrics extends StatelessWebexPlugin {
|
|
|
607
621
|
return this.getErrorPayloadForClientErrorCode({
|
|
608
622
|
clientErrorCode: UNKNOWN_ERROR,
|
|
609
623
|
serviceErrorCode: UNKNOWN_ERROR,
|
|
624
|
+
payloadOverrides: rawError.payloadOverrides,
|
|
610
625
|
rawErrorMessage,
|
|
611
626
|
httpStatusCode,
|
|
612
627
|
});
|
|
@@ -909,4 +924,16 @@ export default class CallDiagnosticMetrics extends StatelessWebexPlugin {
|
|
|
909
924
|
|
|
910
925
|
return clientErrorPayload?.category === 'expected';
|
|
911
926
|
}
|
|
927
|
+
|
|
928
|
+
/**
|
|
929
|
+
* This method is used to set the device information by internal-plugin-device
|
|
930
|
+
* @param {device} object The webex.internal.device object
|
|
931
|
+
* @returns {undefined}
|
|
932
|
+
*/
|
|
933
|
+
public setDeviceInfo(device: any): void {
|
|
934
|
+
// This was created to fix the circular dependency between internal-plugin-device and internal-plugin-metrics
|
|
935
|
+
this.logger.log('CallDiagnosticMetrics: @setDeviceInfo called', device);
|
|
936
|
+
|
|
937
|
+
this.device = device;
|
|
938
|
+
}
|
|
912
939
|
}
|
|
@@ -244,22 +244,29 @@ export const prepareDiagnosticMetricItem = (webex: any, item: any) => {
|
|
|
244
244
|
case 'client.webexapp.launched':
|
|
245
245
|
joinTimes.downloadTime = cdl.getDownloadTimeJMT();
|
|
246
246
|
break;
|
|
247
|
+
case 'client.login.end':
|
|
248
|
+
joinTimes.otherAppApiReqResp = cdl.getOtherAppApiReqResp();
|
|
249
|
+
joinTimes.exchangeCITokenJMT = cdl.getExchangeCITokenJMT();
|
|
250
|
+
break;
|
|
247
251
|
case 'client.interstitial-window.launched':
|
|
248
252
|
joinTimes.meetingInfoReqResp = cdl.getMeetingInfoReqResp();
|
|
249
253
|
joinTimes.clickToInterstitial = cdl.getClickToInterstitial();
|
|
254
|
+
joinTimes.refreshCaptchaServiceReqResp = cdl.getRefreshCaptchaReqResp();
|
|
255
|
+
joinTimes.downloadIntelligenceModelsReqResp = cdl.getDownloadIntelligenceModelsReqResp();
|
|
250
256
|
break;
|
|
251
257
|
|
|
252
258
|
case 'client.call.initiated':
|
|
253
259
|
joinTimes.meetingInfoReqResp = cdl.getMeetingInfoReqResp();
|
|
254
260
|
joinTimes.showInterstitialTime = cdl.getShowInterstitialTime();
|
|
255
261
|
joinTimes.registerWDMDeviceJMT = cdl.getRegisterWDMDeviceJMT();
|
|
262
|
+
joinTimes.getU2CTime = cdl.getU2CTime();
|
|
263
|
+
joinTimes.getReachabilityClustersReqResp = cdl.getReachabilityClustersReqResp();
|
|
256
264
|
break;
|
|
257
265
|
|
|
258
266
|
case 'client.locus.join.response':
|
|
259
267
|
joinTimes.meetingInfoReqResp = cdl.getMeetingInfoReqResp();
|
|
260
268
|
joinTimes.callInitJoinReq = cdl.getCallInitJoinReq();
|
|
261
269
|
joinTimes.joinReqResp = cdl.getJoinReqResp();
|
|
262
|
-
joinTimes.joinReqSentReceived = cdl.getJoinRespSentReceived();
|
|
263
270
|
joinTimes.pageJmt = cdl.getPageJMT();
|
|
264
271
|
joinTimes.clickToInterstitial = cdl.getClickToInterstitial();
|
|
265
272
|
joinTimes.interstitialToJoinOK = cdl.getInterstitialToJoinOK();
|
|
@@ -376,11 +383,18 @@ export const generateClientErrorCodeForIceFailure = ({
|
|
|
376
383
|
errorCode = MISSING_ROAP_ANSWER_CLIENT_CODE;
|
|
377
384
|
}
|
|
378
385
|
|
|
379
|
-
if (
|
|
386
|
+
if (
|
|
387
|
+
signalingState === 'stable' &&
|
|
388
|
+
(iceConnectionState === 'connected' || iceConnectionState === 'disconnected')
|
|
389
|
+
) {
|
|
380
390
|
errorCode = DTLS_HANDSHAKE_FAILED_CLIENT_CODE;
|
|
381
391
|
}
|
|
382
392
|
|
|
383
|
-
if (
|
|
393
|
+
if (
|
|
394
|
+
signalingState !== 'have-local-offer' &&
|
|
395
|
+
iceConnectionState !== 'connected' &&
|
|
396
|
+
iceConnectionState !== 'disconnected'
|
|
397
|
+
) {
|
|
384
398
|
if (turnServerUsed) {
|
|
385
399
|
errorCode = ICE_FAILED_WITH_TURN_TLS_CLIENT_CODE;
|
|
386
400
|
} else {
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import PreLoginMetricsBatcher from './prelogin-metrics-batcher';
|
|
2
|
+
|
|
3
|
+
const ClientMetricsPreloginBatcher = PreLoginMetricsBatcher.extend({
|
|
4
|
+
namespace: 'Metrics',
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Prepare item
|
|
8
|
+
* @param {any} item
|
|
9
|
+
* @returns {Promise<any>}
|
|
10
|
+
*/
|
|
11
|
+
prepareItem(item) {
|
|
12
|
+
// Add more defaults to payload when the clientmetrics endpoint evolves to support richer payloads
|
|
13
|
+
return Promise.resolve(item);
|
|
14
|
+
},
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Prepare request, add time sensitive date etc.
|
|
18
|
+
* @param {any[]} queue
|
|
19
|
+
* @returns {Promise<any[]>}
|
|
20
|
+
*/
|
|
21
|
+
prepareRequest(queue) {
|
|
22
|
+
return Promise.resolve(queue);
|
|
23
|
+
},
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
export default ClientMetricsPreloginBatcher;
|
package/src/index.ts
CHANGED
|
@@ -2,8 +2,6 @@
|
|
|
2
2
|
* Copyright (c) 2015-2020 Cisco Systems, Inc. See LICENSE file.
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
import '@webex/internal-plugin-device';
|
|
6
|
-
|
|
7
5
|
import {registerInternalPlugin} from '@webex/webex-core';
|
|
8
6
|
|
|
9
7
|
import Metrics from './metrics';
|
|
@@ -18,6 +16,7 @@ import {
|
|
|
18
16
|
SubmitInternalEvent,
|
|
19
17
|
SubmitOperationalEvent,
|
|
20
18
|
SubmitMQE,
|
|
19
|
+
PreComputedLatencies,
|
|
21
20
|
} from './metrics.types';
|
|
22
21
|
import * as CALL_DIAGNOSTIC_CONFIG from './call-diagnostic/config';
|
|
23
22
|
import * as CallDiagnosticUtils from './call-diagnostic/call-diagnostic-metrics.util';
|
|
@@ -51,4 +50,5 @@ export type {
|
|
|
51
50
|
SubmitInternalEvent,
|
|
52
51
|
SubmitMQE,
|
|
53
52
|
SubmitOperationalEvent,
|
|
53
|
+
PreComputedLatencies,
|
|
54
54
|
};
|
package/src/metrics.js
CHANGED
|
@@ -10,6 +10,7 @@ import {OS_NAME, OSMap, CLIENT_NAME} from './config';
|
|
|
10
10
|
|
|
11
11
|
import Batcher from './batcher';
|
|
12
12
|
import ClientMetricsBatcher from './client-metrics-batcher';
|
|
13
|
+
import ClientMetricsPreloginBatcher from './client-metrics-prelogin-batcher';
|
|
13
14
|
|
|
14
15
|
const {getOSName, getOSVersion, getBrowserName, getBrowserVersion} = BrowserDetection();
|
|
15
16
|
|
|
@@ -37,6 +38,7 @@ const Metrics = WebexPlugin.extend({
|
|
|
37
38
|
children: {
|
|
38
39
|
batcher: Batcher,
|
|
39
40
|
clientMetricsBatcher: ClientMetricsBatcher,
|
|
41
|
+
clientMetricsPreloginBatcher: ClientMetricsPreloginBatcher,
|
|
40
42
|
},
|
|
41
43
|
|
|
42
44
|
namespace: 'Metrics',
|
|
@@ -56,11 +58,14 @@ const Metrics = WebexPlugin.extend({
|
|
|
56
58
|
throw Error('Missing behavioral metric name. Please provide one');
|
|
57
59
|
}
|
|
58
60
|
const payload = {metricName: eventName};
|
|
61
|
+
// @ts-ignore
|
|
62
|
+
const providedClientVersion = this.webex.meetings?.config?.metrics?.clientVersion;
|
|
59
63
|
|
|
60
64
|
payload.tags = {
|
|
61
65
|
...props.tags,
|
|
62
66
|
browser: getBrowserName(),
|
|
63
67
|
os: getOSNameInternal(),
|
|
68
|
+
appVersion: providedClientVersion,
|
|
64
69
|
|
|
65
70
|
// Node does not like this so we need to check if it exists or not
|
|
66
71
|
// eslint-disable-next-line no-undef
|
|
@@ -114,14 +119,9 @@ const Metrics = WebexPlugin.extend({
|
|
|
114
119
|
const payload = this.getClientMetricsPayload(eventName, props);
|
|
115
120
|
|
|
116
121
|
if (preLoginId) {
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
// Do not batch these because pre-login events occur during onboarding, so we will be partially blind
|
|
122
|
-
// to users' progress through the reg flow if we wait to persist pre-login metrics for people who drop off because
|
|
123
|
-
// their metrics will not post from a queue flush in time
|
|
124
|
-
return this.postPreLoginMetric(_payload, preLoginId);
|
|
122
|
+
this.clientMetricsPreloginBatcher.savePreLoginId(preLoginId);
|
|
123
|
+
|
|
124
|
+
return this.clientMetricsPreloginBatcher.request(payload);
|
|
125
125
|
}
|
|
126
126
|
|
|
127
127
|
return this.clientMetricsBatcher.request(payload);
|
|
@@ -146,21 +146,6 @@ const Metrics = WebexPlugin.extend({
|
|
|
146
146
|
},
|
|
147
147
|
});
|
|
148
148
|
},
|
|
149
|
-
|
|
150
|
-
postPreLoginMetric(payload, preLoginId) {
|
|
151
|
-
return this.webex.credentials.getClientToken().then((token) =>
|
|
152
|
-
this.request({
|
|
153
|
-
method: 'POST',
|
|
154
|
-
api: 'metrics',
|
|
155
|
-
resource: 'clientmetrics-prelogin',
|
|
156
|
-
headers: {
|
|
157
|
-
authorization: token.toString(),
|
|
158
|
-
'x-prelogin-userid': preLoginId,
|
|
159
|
-
},
|
|
160
|
-
body: payload,
|
|
161
|
-
})
|
|
162
|
-
);
|
|
163
|
-
},
|
|
164
149
|
});
|
|
165
150
|
|
|
166
151
|
export default Metrics;
|
package/src/metrics.types.ts
CHANGED
|
@@ -16,6 +16,10 @@ export type ClientLaunchMethodType = NonNullable<
|
|
|
16
16
|
RawEvent['origin']['clientInfo']
|
|
17
17
|
>['clientLaunchMethod'];
|
|
18
18
|
|
|
19
|
+
export type BrowserLaunchMethodType = NonNullable<
|
|
20
|
+
RawEvent['origin']['clientInfo']
|
|
21
|
+
>['browserLaunchMethod'];
|
|
22
|
+
|
|
19
23
|
export type SubmitClientEventOptions = {
|
|
20
24
|
meetingId?: string;
|
|
21
25
|
mediaConnections?: any[];
|
|
@@ -25,6 +29,7 @@ export type SubmitClientEventOptions = {
|
|
|
25
29
|
environment?: EnvironmentType;
|
|
26
30
|
newEnvironmentType?: NewEnvironmentType;
|
|
27
31
|
clientLaunchMethod?: ClientLaunchMethodType;
|
|
32
|
+
browserLaunchMethod?: BrowserLaunchMethodType;
|
|
28
33
|
webexConferenceIdStr?: string;
|
|
29
34
|
globalMeetingId?: string;
|
|
30
35
|
};
|
|
@@ -164,5 +169,11 @@ export type BuildClientEventFetchRequestOptions = (args: {
|
|
|
164
169
|
export type PreComputedLatencies =
|
|
165
170
|
| 'internal.client.pageJMT'
|
|
166
171
|
| 'internal.download.time'
|
|
172
|
+
| 'internal.get.cluster.time'
|
|
167
173
|
| 'internal.click.to.interstitial'
|
|
168
|
-
| 'internal.
|
|
174
|
+
| 'internal.refresh.captcha.time'
|
|
175
|
+
| 'internal.exchange.ci.token.time'
|
|
176
|
+
| 'internal.get.u2c.time'
|
|
177
|
+
| 'internal.call.init.join.req'
|
|
178
|
+
| 'internal.other.app.api.time'
|
|
179
|
+
| 'internal.api.fetch.intelligence.models';
|
package/src/new-metrics.ts
CHANGED
|
@@ -43,6 +43,8 @@ class Metrics extends WebexPlugin {
|
|
|
43
43
|
constructor(...args) {
|
|
44
44
|
super(...args);
|
|
45
45
|
|
|
46
|
+
// @ts-ignore
|
|
47
|
+
this.callDiagnosticLatencies = new CallDiagnosticLatencies({}, {parent: this.webex});
|
|
46
48
|
this.onReady();
|
|
47
49
|
}
|
|
48
50
|
|
|
@@ -54,8 +56,6 @@ class Metrics extends WebexPlugin {
|
|
|
54
56
|
this.webex.once('ready', () => {
|
|
55
57
|
// @ts-ignore
|
|
56
58
|
this.callDiagnosticMetrics = new CallDiagnosticMetrics({}, {parent: this.webex});
|
|
57
|
-
// @ts-ignore
|
|
58
|
-
this.callDiagnosticLatencies = new CallDiagnosticLatencies({}, {parent: this.webex});
|
|
59
59
|
});
|
|
60
60
|
}
|
|
61
61
|
|
|
@@ -48,7 +48,7 @@ const PreLoginMetricsBatcher = Batcher.extend({
|
|
|
48
48
|
* @returns {Promise<any>}
|
|
49
49
|
*/
|
|
50
50
|
submitHttpRequest(payload: any) {
|
|
51
|
-
const batchId = uniqueId('prelogin-
|
|
51
|
+
const batchId = uniqueId('prelogin-batch-');
|
|
52
52
|
if (this.preLoginId === undefined) {
|
|
53
53
|
this.webex.logger.error(
|
|
54
54
|
PRE_LOGIN_METRICS_IDENTIFIER,
|
|
@@ -103,6 +103,12 @@ describe('plugin-metrics', () => {
|
|
|
103
103
|
webex.internal.newMetrics.callDiagnosticLatencies.getClickToInterstitial = sinon
|
|
104
104
|
.stub()
|
|
105
105
|
.returns(10);
|
|
106
|
+
webex.internal.newMetrics.callDiagnosticLatencies.getRefreshCaptchaReqResp = sinon
|
|
107
|
+
.stub()
|
|
108
|
+
.returns(10);
|
|
109
|
+
webex.internal.newMetrics.callDiagnosticLatencies.getDownloadIntelligenceModelsReqResp =
|
|
110
|
+
sinon.stub().returns(42);
|
|
111
|
+
|
|
106
112
|
const promise = webex.internal.newMetrics.callDiagnosticMetrics.submitToCallDiagnostics(
|
|
107
113
|
//@ts-ignore
|
|
108
114
|
{event: {name: 'client.interstitial-window.launched'}}
|
|
@@ -119,6 +125,8 @@ describe('plugin-metrics', () => {
|
|
|
119
125
|
joinTimes: {
|
|
120
126
|
clickToInterstitial: 10,
|
|
121
127
|
meetingInfoReqResp: 10,
|
|
128
|
+
refreshCaptchaServiceReqResp: 10,
|
|
129
|
+
downloadIntelligenceModelsReqResp: 42,
|
|
122
130
|
},
|
|
123
131
|
});
|
|
124
132
|
assert.lengthOf(
|
|
@@ -131,6 +139,12 @@ describe('plugin-metrics', () => {
|
|
|
131
139
|
webex.internal.newMetrics.callDiagnosticLatencies.getDiffBetweenTimestamps = sinon
|
|
132
140
|
.stub()
|
|
133
141
|
.returns(10);
|
|
142
|
+
webex.internal.newMetrics.callDiagnosticLatencies.getU2CTime = sinon
|
|
143
|
+
.stub()
|
|
144
|
+
.returns(20);
|
|
145
|
+
webex.internal.newMetrics.callDiagnosticLatencies.getReachabilityClustersReqResp = sinon
|
|
146
|
+
.stub()
|
|
147
|
+
.returns(10);
|
|
134
148
|
const promise = webex.internal.newMetrics.callDiagnosticMetrics.submitToCallDiagnostics(
|
|
135
149
|
//@ts-ignore
|
|
136
150
|
{event: {name: 'client.call.initiated'}}
|
|
@@ -147,6 +161,8 @@ describe('plugin-metrics', () => {
|
|
|
147
161
|
meetingInfoReqResp: 10,
|
|
148
162
|
registerWDMDeviceJMT: 10,
|
|
149
163
|
showInterstitialTime: 10,
|
|
164
|
+
getU2CTime: 20,
|
|
165
|
+
getReachabilityClustersReqResp: 10
|
|
150
166
|
},
|
|
151
167
|
});
|
|
152
168
|
assert.lengthOf(
|
|
@@ -159,9 +175,6 @@ describe('plugin-metrics', () => {
|
|
|
159
175
|
webex.internal.newMetrics.callDiagnosticLatencies.getDiffBetweenTimestamps = sinon
|
|
160
176
|
.stub()
|
|
161
177
|
.returns(10);
|
|
162
|
-
webex.internal.newMetrics.callDiagnosticLatencies.getJoinRespSentReceived = sinon
|
|
163
|
-
.stub()
|
|
164
|
-
.returns(20);
|
|
165
178
|
webex.internal.newMetrics.callDiagnosticLatencies.getPageJMT = sinon.stub().returns(30);
|
|
166
179
|
webex.internal.newMetrics.callDiagnosticLatencies.getClientJMT = sinon.stub().returns(5);
|
|
167
180
|
webex.internal.newMetrics.callDiagnosticLatencies.getClickToInterstitial = sinon
|
|
@@ -191,7 +204,6 @@ describe('plugin-metrics', () => {
|
|
|
191
204
|
clickToInterstitial: 10,
|
|
192
205
|
interstitialToJoinOK: 10,
|
|
193
206
|
joinReqResp: 10,
|
|
194
|
-
joinReqSentReceived: 20,
|
|
195
207
|
meetingInfoReqResp: 10,
|
|
196
208
|
pageJmt: 30,
|
|
197
209
|
totalJmt: 20,
|
|
@@ -357,9 +369,8 @@ describe('plugin-metrics', () => {
|
|
|
357
369
|
});
|
|
358
370
|
});
|
|
359
371
|
|
|
360
|
-
//TODO: The following two skipped tests needs investigation: https://jira-eng-gpk2.cisco.com/jira/browse/SPARK-485382
|
|
361
372
|
describe('when the request fails', () => {
|
|
362
|
-
it
|
|
373
|
+
it('does not clear the queue', async () => {
|
|
363
374
|
// avoid setting .sent timestamp
|
|
364
375
|
webex.internal.newMetrics.callDiagnosticMetrics.callDiagnosticEventsBatcher.prepareRequest =
|
|
365
376
|
(q) => Promise.resolve(q);
|
|
@@ -385,18 +396,17 @@ describe('plugin-metrics', () => {
|
|
|
385
396
|
error = e;
|
|
386
397
|
});
|
|
387
398
|
|
|
388
|
-
// This is horrific, but stubbing lodash is proving difficult
|
|
389
|
-
const expectedBatchId = parseInt(uniqueId()) - 1;
|
|
390
|
-
|
|
391
399
|
// check that promise was rejected with the original error of the webex.request
|
|
392
400
|
assert.deepEqual(err, error);
|
|
393
401
|
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
402
|
+
const calls = webex.logger.error.getCalls();
|
|
403
|
+
assert.deepEqual(calls[0].args[0], 'call-diagnostic-events -> ');
|
|
404
|
+
// This is horrific, but stubbing lodash is proving difficult
|
|
405
|
+
assert.match(
|
|
406
|
+
calls[0].args[1],
|
|
407
|
+
/CallDiagnosticEventsBatcher: @submitHttpRequest#ca-batch-\d{0,}\. Request failed:/
|
|
399
408
|
);
|
|
409
|
+
assert.deepEqual(calls[0].args[2], `error: formattedError`);
|
|
400
410
|
assert.lengthOf(
|
|
401
411
|
webex.internal.newMetrics.callDiagnosticMetrics.callDiagnosticEventsBatcher.queue,
|
|
402
412
|
0
|
|
@@ -406,7 +416,7 @@ describe('plugin-metrics', () => {
|
|
|
406
416
|
});
|
|
407
417
|
|
|
408
418
|
describe('prepareItem', () => {
|
|
409
|
-
it
|
|
419
|
+
it('calls prepareDiagnosticMetricItem correctly', async () => {
|
|
410
420
|
// avoid setting .sent timestamp
|
|
411
421
|
webex.internal.newMetrics.callDiagnosticMetrics.callDiagnosticEventsBatcher.prepareRequest =
|
|
412
422
|
(q) => Promise.resolve(q);
|