@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.
Files changed (29) hide show
  1. package/dist/call-diagnostic/call-diagnostic-metrics-latencies.js +33 -9
  2. package/dist/call-diagnostic/call-diagnostic-metrics-latencies.js.map +1 -1
  3. package/dist/call-diagnostic/call-diagnostic-metrics.util.js +4 -2
  4. package/dist/call-diagnostic/call-diagnostic-metrics.util.js.map +1 -1
  5. package/dist/client-metrics-prelogin-batcher.js +32 -0
  6. package/dist/client-metrics-prelogin-batcher.js.map +1 -0
  7. package/dist/metrics.js +6 -25
  8. package/dist/metrics.js.map +1 -1
  9. package/dist/metrics.types.js.map +1 -1
  10. package/dist/prelogin-metrics-batcher.js +1 -1
  11. package/dist/prelogin-metrics-batcher.js.map +1 -1
  12. package/dist/types/call-diagnostic/call-diagnostic-metrics-latencies.d.ts +18 -7
  13. package/dist/types/call-diagnostic/call-diagnostic-metrics.d.ts +2 -2
  14. package/dist/types/client-metrics-prelogin-batcher.d.ts +2 -0
  15. package/dist/types/metrics.types.d.ts +1 -1
  16. package/package.json +12 -12
  17. package/src/call-diagnostic/call-diagnostic-metrics-latencies.ts +36 -10
  18. package/src/call-diagnostic/call-diagnostic-metrics.util.ts +11 -2
  19. package/src/client-metrics-prelogin-batcher.ts +26 -0
  20. package/src/metrics.js +5 -23
  21. package/src/metrics.types.ts +3 -1
  22. package/src/prelogin-metrics-batcher.ts +1 -1
  23. package/test/unit/spec/call-diagnostic/call-diagnostic-metrics-batcher.ts +9 -1
  24. package/test/unit/spec/call-diagnostic/call-diagnostic-metrics-latencies.ts +47 -22
  25. package/test/unit/spec/call-diagnostic/call-diagnostic-metrics.ts +54 -23
  26. package/test/unit/spec/call-diagnostic/call-diagnostic-metrics.util.ts +27 -13
  27. package/test/unit/spec/client-metrics-prelogin-batcher.ts +54 -0
  28. package/test/unit/spec/metrics.js +1 -31
  29. 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-ca-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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"}
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 overwrite - overwrite existing value or add it
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, overwrite?: boolean): void;
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 overwrite - overwite existing value or add to it
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<any>, key: PreComputedLatencies, overwrite?: boolean): Promise<any>;
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
- * Total latency for all other app api requests.
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?: "windows" | "mac" | "ios" | "android" | "chrome" | "linux" | "other" | "android-x64" | "android-arm64" | "uwp-arm64";
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: "other" | "signaling" | "media" | "network" | "expected";
338
+ category: "signaling" | "media" | "network" | "other" | "expected";
339
339
  errorDescription?: string;
340
340
  errorCode?: number;
341
341
  errorCodeStr?: string;
@@ -0,0 +1,2 @@
1
+ declare const ClientMetricsPreloginBatcher: any;
2
+ export default ClientMetricsPreloginBatcher;
@@ -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.0.0-next.9",
30
- "@webex/test-helper-mocha": "3.0.0-next.9",
31
- "@webex/test-helper-mock-webex": "3.0.0-next.9",
32
- "@webex/test-helper-test-users": "3.0.0-next.9",
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.0.0-next.9",
39
- "@webex/common-timers": "3.0.0-next.9",
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.0.0-next.9",
42
- "@webex/internal-plugin-metrics": "3.0.0-next.9",
43
- "@webex/test-helper-chai": "3.0.0-next.9",
44
- "@webex/test-helper-mock-webex": "3.0.0-next.9",
45
- "@webex/webex-core": "3.0.0-next.9",
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.0.0-next.9"
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 overwrite - overwrite existing value or add it
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, overwrite = true) {
101
- const existingValue = overwrite ? 0 : this.precomputedLatencies.get(key) || 0;
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 overwrite - overwite existing value or add to it
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<any>,
115
+ callback: () => Promise<unknown>,
114
116
  key: PreComputedLatencies,
115
- overwrite = false
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, overwrite);
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
- * Total latency for all other app api requests.
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 (signalingState === 'stable' && iceConnectionState === 'connected') {
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 (signalingState !== 'have-local-offer' && iceConnectionState !== 'connected') {
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
- const _payload = {
121
- metrics: [payload],
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;
@@ -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-ca-batch-');
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 overwrite is true', () => {
54
+ it('should overwrite latency when accumulate is false', () => {
55
55
  assert.deepEqual(cdl.precomputedLatencies.size, 0);
56
- cdl.saveLatency('internal.client.pageJMT', 10, true);
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, true);
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 overwrite is false', () => {
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, false);
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 overwrite is false and there is existing value', () => {
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, false);
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 overwrite false', async () => {
163
+
164
+ it('checks measureLatency with accumulate false', async () => {
160
165
  const key = 'internal.client.pageJMT';
161
- const overwrite = false;
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
- const promise = cdl.measureLatency(callbackStub, 'internal.client.pageJMT', overwrite);
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, overwrite)
179
+ assert.calledOnceWithExactly(saveLatencySpy, key, 50, accumulate);
173
180
  });
174
181
 
175
- it('checks measureLatency with overwrite true', async () => {
182
+ it('checks measureLatency with accumulate true', async () => {
176
183
  const key = 'internal.download.time';
177
- const overwrite = true;
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', overwrite);
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, overwrite)
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 overwrite = true;
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', overwrite);
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, overwrite)
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);