@webex/internal-plugin-metrics 3.0.0-next.9 → 3.1.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.
- package/dist/call-diagnostic/call-diagnostic-metrics-latencies.js +33 -9
- package/dist/call-diagnostic/call-diagnostic-metrics-latencies.js.map +1 -1
- package/dist/call-diagnostic/call-diagnostic-metrics.util.js +4 -2
- 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/metrics.js +6 -25
- package/dist/metrics.js.map +1 -1
- package/dist/metrics.types.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 +18 -7
- package/dist/types/call-diagnostic/call-diagnostic-metrics.d.ts +2 -2
- package/dist/types/client-metrics-prelogin-batcher.d.ts +2 -0
- package/dist/types/metrics.types.d.ts +1 -1
- package/package.json +12 -12
- package/src/call-diagnostic/call-diagnostic-metrics-latencies.ts +36 -10
- package/src/call-diagnostic/call-diagnostic-metrics.util.ts +11 -2
- package/src/client-metrics-prelogin-batcher.ts +26 -0
- package/src/metrics.js +5 -23
- package/src/metrics.types.ts +3 -1
- package/src/prelogin-metrics-batcher.ts +1 -1
- package/test/unit/spec/call-diagnostic/call-diagnostic-metrics-batcher.ts +9 -1
- package/test/unit/spec/call-diagnostic/call-diagnostic-metrics-latencies.ts +47 -22
- package/test/unit/spec/call-diagnostic/call-diagnostic-metrics.ts +54 -23
- package/test/unit/spec/call-diagnostic/call-diagnostic-metrics.util.ts +27 -13
- package/test/unit/spec/client-metrics-prelogin-batcher.ts +54 -0
- package/test/unit/spec/metrics.js +1 -31
- package/test/unit/spec/prelogin-metrics-batcher.ts +5 -3
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["_lodash","require","_batcher","_interopRequireDefault","_callDiagnosticMetrics","_utils","PRE_LOGIN_METRICS_IDENTIFIER","PreLoginMetricsBatcher","Batcher","extend","namespace","preLoginId","undefined","savePreLoginId","prepareItem","item","_promise","default","resolve","prepareDiagnosticMetricItem","webex","prepareRequest","queue","forEach","eventPayload","originTime","sent","Date","toISOString","submitHttpRequest","payload","_this","batchId","uniqueId","logger","error","concat","reject","Error","request","method","service","resource","headers","authorization","body","metrics","waitForServiceTimeout","config","then","res","log","catch","err","generateCommonErrorMetadata","_default","exports"],"sources":["prelogin-metrics-batcher.ts"],"sourcesContent":["import {uniqueId} from 'lodash';\nimport Batcher from './batcher';\nimport {prepareDiagnosticMetricItem} from './call-diagnostic/call-diagnostic-metrics.util';\nimport {generateCommonErrorMetadata} from './utils';\n\nconst PRE_LOGIN_METRICS_IDENTIFIER = 'Pre Login Metrics -->';\n\nconst PreLoginMetricsBatcher = Batcher.extend({\n namespace: 'Metrics',\n preLoginId: undefined,\n\n /**\n * Save the pre-login ID.\n * @param {string} preLoginId The pre-login ID to be saved.\n * @returns {void}\n */\n savePreLoginId(preLoginId) {\n this.preLoginId = preLoginId;\n },\n\n /**\n * Prepare item\n * @param {any} item\n * @returns {Promise<any>}\n */\n prepareItem(item) {\n return Promise.resolve(prepareDiagnosticMetricItem(this.webex, item));\n },\n\n /**\n * Prepare request, add time sensitive date etc.\n * @param {any[]} queue\n * @returns {Promise<any[]>}\n */\n prepareRequest(queue) {\n // Add sent timestamp\n queue.forEach((item) => {\n item.eventPayload.originTime = item.eventPayload.originTime || {};\n item.eventPayload.originTime.sent = new Date().toISOString();\n });\n\n return Promise.resolve(queue);\n },\n\n /**\n *\n * @param {any} payload\n * @returns {Promise<any>}\n */\n submitHttpRequest(payload: any) {\n const batchId = uniqueId('prelogin-
|
|
1
|
+
{"version":3,"names":["_lodash","require","_batcher","_interopRequireDefault","_callDiagnosticMetrics","_utils","PRE_LOGIN_METRICS_IDENTIFIER","PreLoginMetricsBatcher","Batcher","extend","namespace","preLoginId","undefined","savePreLoginId","prepareItem","item","_promise","default","resolve","prepareDiagnosticMetricItem","webex","prepareRequest","queue","forEach","eventPayload","originTime","sent","Date","toISOString","submitHttpRequest","payload","_this","batchId","uniqueId","logger","error","concat","reject","Error","request","method","service","resource","headers","authorization","body","metrics","waitForServiceTimeout","config","then","res","log","catch","err","generateCommonErrorMetadata","_default","exports"],"sources":["prelogin-metrics-batcher.ts"],"sourcesContent":["import {uniqueId} from 'lodash';\nimport Batcher from './batcher';\nimport {prepareDiagnosticMetricItem} from './call-diagnostic/call-diagnostic-metrics.util';\nimport {generateCommonErrorMetadata} from './utils';\n\nconst PRE_LOGIN_METRICS_IDENTIFIER = 'Pre Login Metrics -->';\n\nconst PreLoginMetricsBatcher = Batcher.extend({\n namespace: 'Metrics',\n preLoginId: undefined,\n\n /**\n * Save the pre-login ID.\n * @param {string} preLoginId The pre-login ID to be saved.\n * @returns {void}\n */\n savePreLoginId(preLoginId) {\n this.preLoginId = preLoginId;\n },\n\n /**\n * Prepare item\n * @param {any} item\n * @returns {Promise<any>}\n */\n prepareItem(item) {\n return Promise.resolve(prepareDiagnosticMetricItem(this.webex, item));\n },\n\n /**\n * Prepare request, add time sensitive date etc.\n * @param {any[]} queue\n * @returns {Promise<any[]>}\n */\n prepareRequest(queue) {\n // Add sent timestamp\n queue.forEach((item) => {\n item.eventPayload.originTime = item.eventPayload.originTime || {};\n item.eventPayload.originTime.sent = new Date().toISOString();\n });\n\n return Promise.resolve(queue);\n },\n\n /**\n *\n * @param {any} payload\n * @returns {Promise<any>}\n */\n submitHttpRequest(payload: any) {\n const batchId = uniqueId('prelogin-batch-');\n if (this.preLoginId === undefined) {\n this.webex.logger.error(\n PRE_LOGIN_METRICS_IDENTIFIER,\n `PreLoginMetricsBatcher: @submitHttpRequest#${batchId}. PreLoginId is not set.`\n );\n\n return Promise.reject(new Error('PreLoginId is not set.'));\n }\n\n return this.webex\n .request({\n method: 'POST',\n service: 'metrics',\n resource: 'clientmetrics-prelogin',\n headers: {\n authorization: false,\n 'x-prelogin-userid': this.preLoginId,\n },\n body: {\n metrics: payload,\n },\n waitForServiceTimeout: this.webex.config.metrics.waitForServiceTimeout,\n })\n .then((res) => {\n this.webex.logger.log(\n PRE_LOGIN_METRICS_IDENTIFIER,\n `PreLoginMetricsBatcher: @submitHttpRequest#${batchId}. Request successful.`\n );\n\n return res;\n })\n .catch((err) => {\n this.webex.logger.error(\n PRE_LOGIN_METRICS_IDENTIFIER,\n `PreLoginMetricsBatcher: @submitHttpRequest#${batchId}. Request failed:`,\n `error: ${generateCommonErrorMetadata(err)}`\n );\n\n return Promise.reject(err);\n });\n },\n});\n\nexport default PreLoginMetricsBatcher;\n"],"mappings":"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"}
|
|
@@ -30,7 +30,8 @@ export default class CallDiagnosticLatencies extends WebexPlugin {
|
|
|
30
30
|
/**
|
|
31
31
|
* Store timestamp value
|
|
32
32
|
* @param key - key
|
|
33
|
-
* @param value -value
|
|
33
|
+
* @param value - value
|
|
34
|
+
* @param options - store options
|
|
34
35
|
* @throws
|
|
35
36
|
* @returns
|
|
36
37
|
*/
|
|
@@ -45,19 +46,19 @@ export default class CallDiagnosticLatencies extends WebexPlugin {
|
|
|
45
46
|
* Store precomputed latency value
|
|
46
47
|
* @param key - key
|
|
47
48
|
* @param value - value
|
|
48
|
-
* @param
|
|
49
|
+
* @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
|
|
49
50
|
* @throws
|
|
50
51
|
* @returns
|
|
51
52
|
*/
|
|
52
|
-
saveLatency(key: PreComputedLatencies, value: number,
|
|
53
|
+
saveLatency(key: PreComputedLatencies, value: number, accumulate?: boolean): void;
|
|
53
54
|
/**
|
|
54
55
|
* Measure latency for a request
|
|
55
|
-
* @param key - key
|
|
56
56
|
* @param callback - callback for which you would like to measure latency
|
|
57
|
-
* @param
|
|
57
|
+
* @param key - key
|
|
58
|
+
* @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
|
|
58
59
|
* @returns
|
|
59
60
|
*/
|
|
60
|
-
measureLatency(callback: () => Promise<
|
|
61
|
+
measureLatency(callback: () => Promise<unknown>, key: PreComputedLatencies, accumulate?: boolean): Promise<unknown>;
|
|
61
62
|
/**
|
|
62
63
|
* Store only the first timestamp value for the given key
|
|
63
64
|
* @param key - key
|
|
@@ -202,6 +203,10 @@ export default class CallDiagnosticLatencies extends WebexPlugin {
|
|
|
202
203
|
* Video setup delay receive
|
|
203
204
|
*/
|
|
204
205
|
getVideoJoinRespRxStart(): number;
|
|
206
|
+
/**
|
|
207
|
+
* Total latency for all get cluster request.
|
|
208
|
+
*/
|
|
209
|
+
getReachabilityClustersReqResp(): number;
|
|
205
210
|
/**
|
|
206
211
|
* Audio setup delay transmit
|
|
207
212
|
*/
|
|
@@ -219,8 +224,14 @@ export default class CallDiagnosticLatencies extends WebexPlugin {
|
|
|
219
224
|
*/
|
|
220
225
|
getRefreshCaptchaReqResp(): number;
|
|
221
226
|
/**
|
|
222
|
-
*
|
|
227
|
+
* Get the latency for downloading intelligence models.
|
|
228
|
+
* @returns - latency
|
|
229
|
+
*/
|
|
230
|
+
getDownloadIntelligenceModelsReqResp(): number;
|
|
231
|
+
/**
|
|
232
|
+
* Get the total latency for all other app API requests.
|
|
223
233
|
* Excludes meeting info, because it's measured separately.
|
|
234
|
+
* @returns - latency
|
|
224
235
|
*/
|
|
225
236
|
getOtherAppApiReqResp(): number;
|
|
226
237
|
}
|
|
@@ -76,7 +76,7 @@ export default class CallDiagnosticMetrics extends StatelessWebexPlugin {
|
|
|
76
76
|
environment?: string;
|
|
77
77
|
newEnvironment?: string;
|
|
78
78
|
clientInfo?: {
|
|
79
|
-
os?: "
|
|
79
|
+
os?: "other" | "chrome" | "windows" | "mac" | "ios" | "android" | "linux" | "android-x64" | "android-arm64" | "uwp-arm64";
|
|
80
80
|
osVersion?: string;
|
|
81
81
|
localIP?: string;
|
|
82
82
|
gatewayIP?: string;
|
|
@@ -335,7 +335,7 @@ export default class CallDiagnosticMetrics extends StatelessWebexPlugin {
|
|
|
335
335
|
*/
|
|
336
336
|
generateClientEventErrorPayload(rawError: any): {
|
|
337
337
|
fatal: boolean;
|
|
338
|
-
category: "
|
|
338
|
+
category: "signaling" | "media" | "network" | "other" | "expected";
|
|
339
339
|
errorDescription?: string;
|
|
340
340
|
errorCode?: number;
|
|
341
341
|
errorCodeStr?: string;
|
|
@@ -104,4 +104,4 @@ export type BuildClientEventFetchRequestOptions = (args: {
|
|
|
104
104
|
payload?: RecursivePartial<ClientEvent['payload']>;
|
|
105
105
|
options?: SubmitClientEventOptions;
|
|
106
106
|
}) => Promise<any>;
|
|
107
|
-
export type PreComputedLatencies = 'internal.client.pageJMT' | 'internal.download.time' | 'internal.click.to.interstitial' | 'internal.refresh.captcha.time' | 'internal.exchange.ci.token.time' | 'internal.get.u2c.time' | 'internal.call.init.join.req' | 'internal.other.app.api.time';
|
|
107
|
+
export type PreComputedLatencies = 'internal.client.pageJMT' | 'internal.download.time' | 'internal.get.cluster.time' | 'internal.click.to.interstitial' | 'internal.refresh.captcha.time' | 'internal.exchange.ci.token.time' | 'internal.get.u2c.time' | 'internal.call.init.join.req' | 'internal.other.app.api.time' | 'internal.api.fetch.intelligence.models';
|
package/package.json
CHANGED
|
@@ -26,23 +26,23 @@
|
|
|
26
26
|
"@webex/eslint-config-legacy": "0.0.0",
|
|
27
27
|
"@webex/jest-config-legacy": "0.0.0",
|
|
28
28
|
"@webex/legacy-tools": "0.0.0",
|
|
29
|
-
"@webex/test-helper-chai": "3.
|
|
30
|
-
"@webex/test-helper-mocha": "3.
|
|
31
|
-
"@webex/test-helper-mock-webex": "3.
|
|
32
|
-
"@webex/test-helper-test-users": "3.
|
|
29
|
+
"@webex/test-helper-chai": "3.1.0",
|
|
30
|
+
"@webex/test-helper-mocha": "3.1.0",
|
|
31
|
+
"@webex/test-helper-mock-webex": "3.1.0",
|
|
32
|
+
"@webex/test-helper-test-users": "3.1.0",
|
|
33
33
|
"eslint": "^8.24.0",
|
|
34
34
|
"prettier": "^2.7.1",
|
|
35
35
|
"sinon": "^9.2.4"
|
|
36
36
|
},
|
|
37
37
|
"dependencies": {
|
|
38
|
-
"@webex/common": "3.
|
|
39
|
-
"@webex/common-timers": "3.
|
|
38
|
+
"@webex/common": "3.1.0",
|
|
39
|
+
"@webex/common-timers": "3.1.0",
|
|
40
40
|
"@webex/event-dictionary-ts": "^1.0.1406",
|
|
41
|
-
"@webex/internal-plugin-device": "3.
|
|
42
|
-
"@webex/internal-plugin-metrics": "3.
|
|
43
|
-
"@webex/test-helper-chai": "3.
|
|
44
|
-
"@webex/test-helper-mock-webex": "3.
|
|
45
|
-
"@webex/webex-core": "3.
|
|
41
|
+
"@webex/internal-plugin-device": "3.1.0",
|
|
42
|
+
"@webex/internal-plugin-metrics": "3.1.0",
|
|
43
|
+
"@webex/test-helper-chai": "3.1.0",
|
|
44
|
+
"@webex/test-helper-mock-webex": "3.1.0",
|
|
45
|
+
"@webex/webex-core": "3.1.0",
|
|
46
46
|
"ip-anonymize": "^0.1.0",
|
|
47
47
|
"lodash": "^4.17.21",
|
|
48
48
|
"uuid": "^3.3.2"
|
|
@@ -55,5 +55,5 @@
|
|
|
55
55
|
"test:style": "eslint ./src/**/*.*",
|
|
56
56
|
"test:unit": "webex-legacy-tools test --unit --runner mocha"
|
|
57
57
|
},
|
|
58
|
-
"version": "3.
|
|
58
|
+
"version": "3.1.0"
|
|
59
59
|
}
|
|
@@ -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
|
*/
|
|
@@ -93,31 +95,31 @@ export default class CallDiagnosticLatencies extends WebexPlugin {
|
|
|
93
95
|
* Store precomputed latency value
|
|
94
96
|
* @param key - key
|
|
95
97
|
* @param value - value
|
|
96
|
-
* @param
|
|
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
|
|
97
99
|
* @throws
|
|
98
100
|
* @returns
|
|
99
101
|
*/
|
|
100
|
-
public saveLatency(key: PreComputedLatencies, value: number,
|
|
101
|
-
const existingValue =
|
|
102
|
+
public saveLatency(key: PreComputedLatencies, value: number, accumulate = false) {
|
|
103
|
+
const existingValue = accumulate ? this.precomputedLatencies.get(key) || 0 : 0;
|
|
102
104
|
this.precomputedLatencies.set(key, value + existingValue);
|
|
103
105
|
}
|
|
104
106
|
|
|
105
107
|
/**
|
|
106
108
|
* Measure latency for a request
|
|
107
|
-
* @param key - key
|
|
108
109
|
* @param callback - callback for which you would like to measure latency
|
|
109
|
-
* @param
|
|
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
|
|
110
112
|
* @returns
|
|
111
113
|
*/
|
|
112
114
|
public measureLatency(
|
|
113
|
-
callback: () => Promise<
|
|
115
|
+
callback: () => Promise<unknown>,
|
|
114
116
|
key: PreComputedLatencies,
|
|
115
|
-
|
|
117
|
+
accumulate = false
|
|
116
118
|
) {
|
|
117
119
|
const start = performance.now();
|
|
118
120
|
|
|
119
121
|
return callback().finally(() => {
|
|
120
|
-
this.saveLatency(key, performance.now() - start,
|
|
122
|
+
this.saveLatency(key, performance.now() - start, accumulate);
|
|
121
123
|
});
|
|
122
124
|
}
|
|
123
125
|
|
|
@@ -441,6 +443,15 @@ export default class CallDiagnosticLatencies extends WebexPlugin {
|
|
|
441
443
|
return this.getDiffBetweenTimestamps('client.locus.join.response', 'client.media.rx.start');
|
|
442
444
|
}
|
|
443
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
|
+
|
|
444
455
|
/**
|
|
445
456
|
* Audio setup delay transmit
|
|
446
457
|
*/
|
|
@@ -474,8 +485,23 @@ export default class CallDiagnosticLatencies extends WebexPlugin {
|
|
|
474
485
|
}
|
|
475
486
|
|
|
476
487
|
/**
|
|
477
|
-
*
|
|
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.
|
|
478
503
|
* Excludes meeting info, because it's measured separately.
|
|
504
|
+
* @returns - latency
|
|
479
505
|
*/
|
|
480
506
|
public getOtherAppApiReqResp() {
|
|
481
507
|
const otherAppApiJMT = this.precomputedLatencies.get('internal.other.app.api.time');
|
|
@@ -252,6 +252,7 @@ export const prepareDiagnosticMetricItem = (webex: any, item: any) => {
|
|
|
252
252
|
joinTimes.meetingInfoReqResp = cdl.getMeetingInfoReqResp();
|
|
253
253
|
joinTimes.clickToInterstitial = cdl.getClickToInterstitial();
|
|
254
254
|
joinTimes.refreshCaptchaServiceReqResp = cdl.getRefreshCaptchaReqResp();
|
|
255
|
+
joinTimes.downloadIntelligenceModelsReqResp = cdl.getDownloadIntelligenceModelsReqResp();
|
|
255
256
|
break;
|
|
256
257
|
|
|
257
258
|
case 'client.call.initiated':
|
|
@@ -259,6 +260,7 @@ export const prepareDiagnosticMetricItem = (webex: any, item: any) => {
|
|
|
259
260
|
joinTimes.showInterstitialTime = cdl.getShowInterstitialTime();
|
|
260
261
|
joinTimes.registerWDMDeviceJMT = cdl.getRegisterWDMDeviceJMT();
|
|
261
262
|
joinTimes.getU2CTime = cdl.getU2CTime();
|
|
263
|
+
joinTimes.getReachabilityClustersReqResp = cdl.getReachabilityClustersReqResp();
|
|
262
264
|
break;
|
|
263
265
|
|
|
264
266
|
case 'client.locus.join.response':
|
|
@@ -381,11 +383,18 @@ export const generateClientErrorCodeForIceFailure = ({
|
|
|
381
383
|
errorCode = MISSING_ROAP_ANSWER_CLIENT_CODE;
|
|
382
384
|
}
|
|
383
385
|
|
|
384
|
-
if (
|
|
386
|
+
if (
|
|
387
|
+
signalingState === 'stable' &&
|
|
388
|
+
(iceConnectionState === 'connected' || iceConnectionState === 'disconnected')
|
|
389
|
+
) {
|
|
385
390
|
errorCode = DTLS_HANDSHAKE_FAILED_CLIENT_CODE;
|
|
386
391
|
}
|
|
387
392
|
|
|
388
|
-
if (
|
|
393
|
+
if (
|
|
394
|
+
signalingState !== 'have-local-offer' &&
|
|
395
|
+
iceConnectionState !== 'connected' &&
|
|
396
|
+
iceConnectionState !== 'disconnected'
|
|
397
|
+
) {
|
|
389
398
|
if (turnServerUsed) {
|
|
390
399
|
errorCode = ICE_FAILED_WITH_TURN_TLS_CLIENT_CODE;
|
|
391
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/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',
|
|
@@ -117,14 +119,9 @@ const Metrics = WebexPlugin.extend({
|
|
|
117
119
|
const payload = this.getClientMetricsPayload(eventName, props);
|
|
118
120
|
|
|
119
121
|
if (preLoginId) {
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
// Do not batch these because pre-login events occur during onboarding, so we will be partially blind
|
|
125
|
-
// to users' progress through the reg flow if we wait to persist pre-login metrics for people who drop off because
|
|
126
|
-
// their metrics will not post from a queue flush in time
|
|
127
|
-
return this.postPreLoginMetric(_payload, preLoginId);
|
|
122
|
+
this.clientMetricsPreloginBatcher.savePreLoginId(preLoginId);
|
|
123
|
+
|
|
124
|
+
return this.clientMetricsPreloginBatcher.request(payload);
|
|
128
125
|
}
|
|
129
126
|
|
|
130
127
|
return this.clientMetricsBatcher.request(payload);
|
|
@@ -149,21 +146,6 @@ const Metrics = WebexPlugin.extend({
|
|
|
149
146
|
},
|
|
150
147
|
});
|
|
151
148
|
},
|
|
152
|
-
|
|
153
|
-
postPreLoginMetric(payload, preLoginId) {
|
|
154
|
-
return this.webex.credentials.getClientToken().then((token) =>
|
|
155
|
-
this.request({
|
|
156
|
-
method: 'POST',
|
|
157
|
-
api: 'metrics',
|
|
158
|
-
resource: 'clientmetrics-prelogin',
|
|
159
|
-
headers: {
|
|
160
|
-
authorization: token.toString(),
|
|
161
|
-
'x-prelogin-userid': preLoginId,
|
|
162
|
-
},
|
|
163
|
-
body: payload,
|
|
164
|
-
})
|
|
165
|
-
);
|
|
166
|
-
},
|
|
167
149
|
});
|
|
168
150
|
|
|
169
151
|
export default Metrics;
|
package/src/metrics.types.ts
CHANGED
|
@@ -169,9 +169,11 @@ export type BuildClientEventFetchRequestOptions = (args: {
|
|
|
169
169
|
export type PreComputedLatencies =
|
|
170
170
|
| 'internal.client.pageJMT'
|
|
171
171
|
| 'internal.download.time'
|
|
172
|
+
| 'internal.get.cluster.time'
|
|
172
173
|
| 'internal.click.to.interstitial'
|
|
173
174
|
| 'internal.refresh.captcha.time'
|
|
174
175
|
| 'internal.exchange.ci.token.time'
|
|
175
176
|
| 'internal.get.u2c.time'
|
|
176
177
|
| 'internal.call.init.join.req'
|
|
177
|
-
| 'internal.other.app.api.time'
|
|
178
|
+
| 'internal.other.app.api.time'
|
|
179
|
+
| 'internal.api.fetch.intelligence.models';
|
|
@@ -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,
|
|
@@ -106,6 +106,9 @@ describe('plugin-metrics', () => {
|
|
|
106
106
|
webex.internal.newMetrics.callDiagnosticLatencies.getRefreshCaptchaReqResp = sinon
|
|
107
107
|
.stub()
|
|
108
108
|
.returns(10);
|
|
109
|
+
webex.internal.newMetrics.callDiagnosticLatencies.getDownloadIntelligenceModelsReqResp =
|
|
110
|
+
sinon.stub().returns(42);
|
|
111
|
+
|
|
109
112
|
const promise = webex.internal.newMetrics.callDiagnosticMetrics.submitToCallDiagnostics(
|
|
110
113
|
//@ts-ignore
|
|
111
114
|
{event: {name: 'client.interstitial-window.launched'}}
|
|
@@ -123,6 +126,7 @@ describe('plugin-metrics', () => {
|
|
|
123
126
|
clickToInterstitial: 10,
|
|
124
127
|
meetingInfoReqResp: 10,
|
|
125
128
|
refreshCaptchaServiceReqResp: 10,
|
|
129
|
+
downloadIntelligenceModelsReqResp: 42,
|
|
126
130
|
},
|
|
127
131
|
});
|
|
128
132
|
assert.lengthOf(
|
|
@@ -138,6 +142,9 @@ describe('plugin-metrics', () => {
|
|
|
138
142
|
webex.internal.newMetrics.callDiagnosticLatencies.getU2CTime = sinon
|
|
139
143
|
.stub()
|
|
140
144
|
.returns(20);
|
|
145
|
+
webex.internal.newMetrics.callDiagnosticLatencies.getReachabilityClustersReqResp = sinon
|
|
146
|
+
.stub()
|
|
147
|
+
.returns(10);
|
|
141
148
|
const promise = webex.internal.newMetrics.callDiagnosticMetrics.submitToCallDiagnostics(
|
|
142
149
|
//@ts-ignore
|
|
143
150
|
{event: {name: 'client.call.initiated'}}
|
|
@@ -154,7 +161,8 @@ describe('plugin-metrics', () => {
|
|
|
154
161
|
meetingInfoReqResp: 10,
|
|
155
162
|
registerWDMDeviceJMT: 10,
|
|
156
163
|
showInterstitialTime: 10,
|
|
157
|
-
getU2CTime: 20
|
|
164
|
+
getU2CTime: 20,
|
|
165
|
+
getReachabilityClustersReqResp: 10
|
|
158
166
|
},
|
|
159
167
|
});
|
|
160
168
|
assert.lengthOf(
|
|
@@ -51,29 +51,29 @@ describe('internal-plugin-metrics', () => {
|
|
|
51
51
|
assert.deepEqual(cdl.precomputedLatencies.get('internal.client.pageJMT'), 20);
|
|
52
52
|
});
|
|
53
53
|
|
|
54
|
-
it('should overwrite latency when
|
|
54
|
+
it('should overwrite latency when accumulate is false', () => {
|
|
55
55
|
assert.deepEqual(cdl.precomputedLatencies.size, 0);
|
|
56
|
-
cdl.saveLatency('internal.client.pageJMT', 10,
|
|
56
|
+
cdl.saveLatency('internal.client.pageJMT', 10, false);
|
|
57
57
|
assert.deepEqual(cdl.precomputedLatencies.size, 1);
|
|
58
58
|
assert.deepEqual(cdl.precomputedLatencies.get('internal.client.pageJMT'), 10);
|
|
59
|
-
cdl.saveLatency('internal.client.pageJMT', 20,
|
|
59
|
+
cdl.saveLatency('internal.client.pageJMT', 20, false);
|
|
60
60
|
assert.deepEqual(cdl.precomputedLatencies.size, 1);
|
|
61
61
|
assert.deepEqual(cdl.precomputedLatencies.get('internal.client.pageJMT'), 20);
|
|
62
62
|
});
|
|
63
63
|
|
|
64
|
-
it('should save latency correctly when
|
|
64
|
+
it('should save latency correctly when accumulate is true', () => {
|
|
65
65
|
assert.deepEqual(cdl.precomputedLatencies.size, 0);
|
|
66
|
-
cdl.saveLatency('internal.client.pageJMT', 10,
|
|
66
|
+
cdl.saveLatency('internal.client.pageJMT', 10, true);
|
|
67
67
|
assert.deepEqual(cdl.precomputedLatencies.size, 1);
|
|
68
68
|
assert.deepEqual(cdl.precomputedLatencies.get('internal.client.pageJMT'), 10);
|
|
69
69
|
});
|
|
70
70
|
|
|
71
|
-
it('should save latency correctly when
|
|
71
|
+
it('should save latency correctly when accumulate is true and there is existing value', () => {
|
|
72
72
|
assert.deepEqual(cdl.precomputedLatencies.size, 0);
|
|
73
73
|
cdl.saveLatency('internal.client.pageJMT', 10);
|
|
74
74
|
assert.deepEqual(cdl.precomputedLatencies.size, 1);
|
|
75
75
|
assert.deepEqual(cdl.precomputedLatencies.get('internal.client.pageJMT'), 10);
|
|
76
|
-
cdl.saveLatency('internal.client.pageJMT', 10,
|
|
76
|
+
cdl.saveLatency('internal.client.pageJMT', 10, true);
|
|
77
77
|
assert.deepEqual(cdl.precomputedLatencies.size, 1);
|
|
78
78
|
assert.deepEqual(cdl.precomputedLatencies.get('internal.client.pageJMT'), 20);
|
|
79
79
|
});
|
|
@@ -108,8 +108,13 @@ describe('internal-plugin-metrics', () => {
|
|
|
108
108
|
cdl.saveTimestamp({key: 'client.alert.displayed'});
|
|
109
109
|
cdl.saveTimestamp({key: 'client.alert.removed'});
|
|
110
110
|
assert.deepEqual(cdl.latencyTimestamps.size, 2);
|
|
111
|
+
cdl.saveLatency('internal.api.fetch.intelligence.models', 42);
|
|
112
|
+
assert.deepEqual(cdl.precomputedLatencies.size, 1);
|
|
113
|
+
|
|
111
114
|
cdl.clearTimestamps();
|
|
115
|
+
|
|
112
116
|
assert.deepEqual(cdl.latencyTimestamps.size, 0);
|
|
117
|
+
assert.deepEqual(cdl.precomputedLatencies.size, 0);
|
|
113
118
|
});
|
|
114
119
|
|
|
115
120
|
it('should calculate diff between timestamps correctly', () => {
|
|
@@ -145,9 +150,9 @@ describe('internal-plugin-metrics', () => {
|
|
|
145
150
|
let clock;
|
|
146
151
|
let saveLatencySpy;
|
|
147
152
|
|
|
148
|
-
beforeEach(() => {
|
|
149
|
-
clock = sinon.useFakeTimers();
|
|
150
|
-
|
|
153
|
+
beforeEach(() => {
|
|
154
|
+
clock = sinon.useFakeTimers();
|
|
155
|
+
|
|
151
156
|
saveLatencySpy = sinon.stub(cdl, 'saveLatency');
|
|
152
157
|
});
|
|
153
158
|
|
|
@@ -155,54 +160,56 @@ describe('internal-plugin-metrics', () => {
|
|
|
155
160
|
clock.restore();
|
|
156
161
|
sinon.restore();
|
|
157
162
|
});
|
|
158
|
-
|
|
159
|
-
it('checks measureLatency with
|
|
163
|
+
|
|
164
|
+
it('checks measureLatency with accumulate false', async () => {
|
|
160
165
|
const key = 'internal.client.pageJMT';
|
|
161
|
-
const
|
|
166
|
+
const accumulate = false;
|
|
167
|
+
|
|
162
168
|
const callbackStub = sinon.stub().callsFake(() => {
|
|
163
169
|
clock.tick(50);
|
|
164
170
|
return Promise.resolve('test');
|
|
165
171
|
});
|
|
166
172
|
|
|
167
|
-
|
|
173
|
+
// accumulate should be false by default
|
|
174
|
+
const promise = cdl.measureLatency(callbackStub, 'internal.client.pageJMT');
|
|
168
175
|
|
|
169
176
|
const resolvedValue = await promise;
|
|
170
177
|
assert.deepEqual(resolvedValue, 'test');
|
|
171
178
|
assert.calledOnceWithExactly(callbackStub);
|
|
172
|
-
assert.calledOnceWithExactly(saveLatencySpy, key, 50,
|
|
179
|
+
assert.calledOnceWithExactly(saveLatencySpy, key, 50, accumulate);
|
|
173
180
|
});
|
|
174
181
|
|
|
175
|
-
it('checks measureLatency with
|
|
182
|
+
it('checks measureLatency with accumulate true', async () => {
|
|
176
183
|
const key = 'internal.download.time';
|
|
177
|
-
const
|
|
184
|
+
const accumulate = true;
|
|
178
185
|
const callbackStub = sinon.stub().callsFake(() => {
|
|
179
186
|
clock.tick(20);
|
|
180
187
|
return Promise.resolve('test123');
|
|
181
188
|
});
|
|
182
189
|
|
|
183
|
-
const promise = cdl.measureLatency(callbackStub, 'internal.download.time',
|
|
190
|
+
const promise = cdl.measureLatency(callbackStub, 'internal.download.time', accumulate);
|
|
184
191
|
|
|
185
192
|
const resolvedValue = await promise;
|
|
186
193
|
assert.deepEqual(resolvedValue, 'test123');
|
|
187
194
|
assert.calledOnceWithExactly(callbackStub);
|
|
188
|
-
assert.calledOnceWithExactly(saveLatencySpy, key, 20,
|
|
195
|
+
assert.calledOnceWithExactly(saveLatencySpy, key, 20, accumulate);
|
|
189
196
|
});
|
|
190
197
|
|
|
191
198
|
it('checks measureLatency when callBack rejects', async () => {
|
|
192
199
|
const key = 'internal.client.pageJMT';
|
|
193
|
-
const
|
|
200
|
+
const accumulate = false;
|
|
194
201
|
const error = new Error('some error');
|
|
195
202
|
const callbackStub = sinon.stub().callsFake(() => {
|
|
196
203
|
clock.tick(50);
|
|
197
204
|
return Promise.reject(error);
|
|
198
205
|
});
|
|
199
206
|
|
|
200
|
-
const promise = cdl.measureLatency(callbackStub, 'internal.client.pageJMT',
|
|
207
|
+
const promise = cdl.measureLatency(callbackStub, 'internal.client.pageJMT', accumulate);
|
|
201
208
|
|
|
202
209
|
const rejectedValue = await assert.isRejected(promise);
|
|
203
210
|
assert.deepEqual(rejectedValue, error);
|
|
204
211
|
assert.calledOnceWithExactly(callbackStub);
|
|
205
|
-
assert.calledOnceWithExactly(saveLatencySpy, key, 50,
|
|
212
|
+
assert.calledOnceWithExactly(saveLatencySpy, key, 50, accumulate);
|
|
206
213
|
});
|
|
207
214
|
});
|
|
208
215
|
|
|
@@ -224,6 +231,24 @@ describe('internal-plugin-metrics', () => {
|
|
|
224
231
|
});
|
|
225
232
|
});
|
|
226
233
|
|
|
234
|
+
describe('getReachabilityClustersReqResp', () => {
|
|
235
|
+
it('returns undefined when no precomputed value available', () => {
|
|
236
|
+
assert.deepEqual(cdl.getReachabilityClustersReqResp(), undefined);
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
it('returns the correct value', () => {
|
|
240
|
+
cdl.saveLatency('internal.get.cluster.time', 123);
|
|
241
|
+
|
|
242
|
+
assert.deepEqual(cdl.getReachabilityClustersReqResp(), 123);
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
it('returns the correct whole number', () => {
|
|
246
|
+
cdl.saveLatency('internal.get.cluster.time', 321.44);
|
|
247
|
+
|
|
248
|
+
assert.deepEqual(cdl.getReachabilityClustersReqResp(), 321);
|
|
249
|
+
});
|
|
250
|
+
});
|
|
251
|
+
|
|
227
252
|
describe('getExchangeCITokenJMT', () => {
|
|
228
253
|
it('returns undefined when no precomputed value available', () => {
|
|
229
254
|
assert.deepEqual(cdl.getExchangeCITokenJMT(), undefined);
|