@webex/internal-plugin-metrics 3.8.0 → 3.8.1-next.10

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 (35) hide show
  1. package/dist/call-diagnostic/call-diagnostic-metrics-latencies.js +49 -0
  2. package/dist/call-diagnostic/call-diagnostic-metrics-latencies.js.map +1 -1
  3. package/dist/call-diagnostic/call-diagnostic-metrics.js +301 -81
  4. package/dist/call-diagnostic/call-diagnostic-metrics.js.map +1 -1
  5. package/dist/call-diagnostic/call-diagnostic-metrics.util.js +6 -0
  6. package/dist/call-diagnostic/call-diagnostic-metrics.util.js.map +1 -1
  7. package/dist/call-diagnostic/config.js +32 -3
  8. package/dist/call-diagnostic/config.js.map +1 -1
  9. package/dist/index.js.map +1 -1
  10. package/dist/metrics.js +1 -1
  11. package/dist/metrics.types.js.map +1 -1
  12. package/dist/new-metrics.js +58 -5
  13. package/dist/new-metrics.js.map +1 -1
  14. package/dist/types/call-diagnostic/call-diagnostic-metrics-latencies.d.ts +15 -0
  15. package/dist/types/call-diagnostic/call-diagnostic-metrics.d.ts +154 -24
  16. package/dist/types/call-diagnostic/config.d.ts +14 -0
  17. package/dist/types/index.d.ts +2 -2
  18. package/dist/types/metrics.types.d.ts +28 -7
  19. package/dist/types/new-metrics.d.ts +28 -4
  20. package/package.json +12 -12
  21. package/src/call-diagnostic/call-diagnostic-metrics-latencies.ts +58 -0
  22. package/src/call-diagnostic/call-diagnostic-metrics.ts +294 -66
  23. package/src/call-diagnostic/call-diagnostic-metrics.util.ts +6 -0
  24. package/src/call-diagnostic/config.ts +31 -0
  25. package/src/index.ts +4 -0
  26. package/src/metrics.types.ts +36 -6
  27. package/src/new-metrics.ts +73 -5
  28. package/test/unit/spec/call-diagnostic/call-diagnostic-metrics-batcher.ts +20 -1
  29. package/test/unit/spec/call-diagnostic/call-diagnostic-metrics-latencies.ts +167 -0
  30. package/test/unit/spec/call-diagnostic/call-diagnostic-metrics.ts +1054 -153
  31. package/test/unit/spec/call-diagnostic/call-diagnostic-metrics.util.ts +6 -0
  32. package/test/unit/spec/new-metrics.ts +94 -5
  33. package/test/unit/spec/prelogin-metrics-batcher.ts +1 -0
  34. package/dist/call-diagnostic-events-batcher.js +0 -59
  35. package/dist/call-diagnostic-events-batcher.js.map +0 -1
@@ -2,9 +2,12 @@ import {
2
2
  ClientEvent as RawClientEvent,
3
3
  Event as RawEvent,
4
4
  MediaQualityEvent as RawMediaQualityEvent,
5
+ FeatureEvent as RawFeatureEvent,
5
6
  } from '@webex/event-dictionary-ts';
6
7
 
7
- export type Event = Omit<RawEvent, 'event'> & {event: RawClientEvent | RawMediaQualityEvent};
8
+ export type Event = Omit<RawEvent, 'event'> & {
9
+ event: RawClientEvent | RawMediaQualityEvent | RawFeatureEvent;
10
+ };
8
11
 
9
12
  export type ClientEventError = NonNullable<RawClientEvent['errors']>[0];
10
13
 
@@ -16,11 +19,15 @@ export type ClientLaunchMethodType = NonNullable<
16
19
  RawEvent['origin']['clientInfo']
17
20
  >['clientLaunchMethod'];
18
21
 
22
+ export type ClientUserNameInput = NonNullable<RawClientEvent['userNameInput']>;
23
+
24
+ export type ClientEmailInput = NonNullable<RawClientEvent['emailInput']>;
25
+
19
26
  export type BrowserLaunchMethodType = NonNullable<
20
27
  RawEvent['origin']['clientInfo']
21
28
  >['browserLaunchMethod'];
22
29
 
23
- export type MetricEventProduct = 'webex' | 'wxcc_desktop' | 'wxcc_crm';
30
+ export type MetricEventProduct = 'webex' | 'wxcc_desktop' | 'wxcc_crm' | 'wxcc_sdk';
24
31
 
25
32
  export type MetricEventAgent = 'user' | 'browser' | 'system' | 'sdk' | 'redux' | 'service' | 'api';
26
33
 
@@ -129,6 +136,8 @@ export type SubmitClientEventOptions = {
129
136
  joinFlowVersion?: MetricEventJoinFlowVersion;
130
137
  meetingJoinPhase?: MetricEventMeetingJoinPhase;
131
138
  triggeredTime?: string;
139
+ emailInput?: ClientEmailInput;
140
+ userNameInput?: ClientUserNameInput;
132
141
  };
133
142
 
134
143
  export type SubmitMQEOptions = {
@@ -206,10 +215,9 @@ export type BehavioralEvent = TaggedEvent;
206
215
  export type OperationalEvent = TaggedEvent;
207
216
 
208
217
  export interface FeatureEvent {
209
- // TODO: not implemented
210
- name: never;
211
- payload?: never;
212
- options?: never;
218
+ name: RawFeatureEvent['name'];
219
+ payload?: RawFeatureEvent;
220
+ options?: SubmitClientEventOptions;
213
221
  }
214
222
 
215
223
  export interface MediaQualityEvent {
@@ -245,6 +253,8 @@ export type ClientEventPayload = RecursivePartial<ClientEvent['payload']>;
245
253
  export type ClientEventLeaveReason = ClientEvent['payload']['leaveReason'];
246
254
  export type ClientEventPayloadError = ClientEvent['payload']['errors'];
247
255
 
256
+ export type ClientFeatureEventPayload = RecursivePartial<FeatureEvent['payload']>;
257
+
248
258
  export type MediaQualityEventAudioSetupDelayPayload = NonNullable<
249
259
  MediaQualityEvent['payload']
250
260
  >['audioSetupDelay'];
@@ -281,6 +291,13 @@ export type SubmitOperationalEvent = (args: {
281
291
  payload: EventPayload;
282
292
  }) => void;
283
293
 
294
+ export type SubmitBusinessEvent = (args: {
295
+ name: OperationalEvent['metricName'];
296
+ payload: EventPayload;
297
+ metadata?: EventPayload;
298
+ table?: Table;
299
+ }) => void;
300
+
284
301
  export type SubmitMQE = (args: {
285
302
  name: MediaQualityEvent['name'];
286
303
  payload: SubmitMQEPayload;
@@ -298,6 +315,7 @@ export type PreComputedLatencies =
298
315
  | 'internal.download.time'
299
316
  | 'internal.get.cluster.time'
300
317
  | 'internal.click.to.interstitial'
318
+ | 'internal.click.to.interstitial.with.user.delay'
301
319
  | 'internal.refresh.captcha.time'
302
320
  | 'internal.exchange.ci.token.time'
303
321
  | 'internal.get.u2c.time'
@@ -326,3 +344,15 @@ export interface DelayedClientEvent {
326
344
  payload?: RecursivePartial<ClientEvent['payload']>;
327
345
  options?: SubmitClientEventOptions;
328
346
  }
347
+
348
+ export type SubmitFeatureEvent = (args: {
349
+ name: FeatureEvent['name'];
350
+ payload?: RecursivePartial<FeatureEvent['payload']>;
351
+ options?: SubmitClientEventOptions;
352
+ }) => Promise<any>;
353
+
354
+ export interface DelayedClientFeatureEvent {
355
+ name: FeatureEvent['name'];
356
+ payload?: RecursivePartial<FeatureEvent['payload']>;
357
+ options?: SubmitClientEventOptions;
358
+ }
@@ -22,6 +22,8 @@ import {
22
22
  InternalEvent,
23
23
  SubmitClientEventOptions,
24
24
  Table,
25
+ DelayedClientEvent,
26
+ DelayedClientFeatureEvent,
25
27
  } from './metrics.types';
26
28
  import CallDiagnosticLatencies from './call-diagnostic/call-diagnostic-metrics-latencies';
27
29
  import {setMetricTimings} from './call-diagnostic/call-diagnostic-metrics.util';
@@ -50,6 +52,18 @@ class Metrics extends WebexPlugin {
50
52
  */
51
53
  delaySubmitClientEvents = false;
52
54
 
55
+ /**
56
+ * Whether or not to delay the submission of feature events.
57
+ */
58
+ delaySubmitClientFeatureEvents = false;
59
+
60
+ /**
61
+ * Overrides for delayed client events. E.g. if you want to override the correlationId for all delayed client events, you can set this to { correlationId: 'newCorrelationId' }
62
+ */
63
+ delayedClientEventsOverrides: Partial<DelayedClientEvent['options']> = {};
64
+
65
+ delayedClientFeatureEventsOverrides: Partial<DelayedClientFeatureEvent['options']> = {};
66
+
53
67
  /**
54
68
  * Constructor
55
69
  * @param args
@@ -74,6 +88,10 @@ class Metrics extends WebexPlugin {
74
88
  // @ts-ignore
75
89
  this.callDiagnosticMetrics = new CallDiagnosticMetrics({}, {parent: this.webex});
76
90
  this.isReady = true;
91
+ this.setDelaySubmitClientEvents({
92
+ shouldDelay: this.delaySubmitClientEvents,
93
+ overrides: this.delayedClientEventsOverrides,
94
+ });
77
95
  });
78
96
  }
79
97
 
@@ -265,7 +283,25 @@ class Metrics extends WebexPlugin {
265
283
  payload?: RecursivePartial<FeatureEvent['payload']>;
266
284
  options: any;
267
285
  }) {
268
- throw new Error('Not implemented.');
286
+ if (!this.callDiagnosticLatencies || !this.callDiagnosticMetrics) {
287
+ // @ts-ignore
288
+ this.webex.logger.log(
289
+ `NewMetrics: @submitFeatureEvent. Attempted to submit before webex.ready. Event name: ${name}`
290
+ );
291
+
292
+ return Promise.resolve();
293
+ }
294
+ this.callDiagnosticLatencies.saveTimestamp({
295
+ key: name,
296
+ options: {meetingId: options?.meetingId},
297
+ });
298
+
299
+ return this.callDiagnosticMetrics.submitFeatureEvent({
300
+ name,
301
+ payload,
302
+ options,
303
+ delaySubmitEvent: this.delaySubmitClientFeatureEvents,
304
+ });
269
305
  }
270
306
 
271
307
  /**
@@ -404,13 +440,45 @@ class Metrics extends WebexPlugin {
404
440
  * Sets the value of delaySubmitClientEvents. If set to true, client events will be delayed until submitDelayedClientEvents is called. If
405
441
  * set to false, delayed client events will be submitted.
406
442
  *
407
- * @param {boolean} shouldDelay - A boolean value indicating whether to delay the submission of client events.
443
+ * @param {object} options - {shouldDelay: A boolean value indicating whether to delay the submission of client events, overrides: An object containing overrides for the client events}
408
444
  */
409
- public setDelaySubmitClientEvents(shouldDelay: boolean) {
445
+ public setDelaySubmitClientEvents({
446
+ shouldDelay,
447
+ overrides,
448
+ }: {
449
+ shouldDelay: boolean;
450
+ overrides?: Partial<DelayedClientEvent['options']>;
451
+ }) {
410
452
  this.delaySubmitClientEvents = shouldDelay;
453
+ this.delayedClientEventsOverrides = overrides || {};
454
+
455
+ if (this.isReady && !shouldDelay) {
456
+ return this.callDiagnosticMetrics.submitDelayedClientEvents(overrides);
457
+ }
458
+
459
+ return Promise.resolve();
460
+ }
461
+
462
+ /**
463
+ * Sets the value of setDelaySubmitClientFeatureEvents.
464
+ * If set to true, feature events will be delayed until submitDelayedClientFeatureEvents is called.
465
+ * If set to false, delayed feature events will be submitted.
466
+ *
467
+ * @param {object} options - {shouldDelay: A boolean value indicating whether to delay the submission of feature events,
468
+ * overrides: An object containing overrides for the feature events}
469
+ */
470
+ public setDelaySubmitClientFeatureEvents({
471
+ shouldDelay,
472
+ overrides,
473
+ }: {
474
+ shouldDelay: boolean;
475
+ overrides?: Partial<DelayedClientFeatureEvent['options']>;
476
+ }) {
477
+ this.delaySubmitClientFeatureEvents = shouldDelay;
478
+ this.delayedClientFeatureEventsOverrides = overrides || {};
411
479
 
412
- if (!shouldDelay) {
413
- return this.callDiagnosticMetrics.submitDelayedClientEvents();
480
+ if (this.isReady && !shouldDelay) {
481
+ return this.callDiagnosticMetrics.submitDelayedClientFeatureEvents(overrides);
414
482
  }
415
483
 
416
484
  return Promise.resolve();
@@ -108,6 +108,8 @@ describe('plugin-metrics', () => {
108
108
  .returns(10);
109
109
  webex.internal.newMetrics.callDiagnosticLatencies.getDownloadIntelligenceModelsReqResp =
110
110
  sinon.stub().returns(42);
111
+ webex.internal.newMetrics.callDiagnosticLatencies.getClickToInterstitialWithUserDelay =
112
+ sinon.stub().returns(12);
111
113
 
112
114
  const promise = webex.internal.newMetrics.callDiagnosticMetrics.submitToCallDiagnostics(
113
115
  //@ts-ignore
@@ -127,6 +129,7 @@ describe('plugin-metrics', () => {
127
129
  meetingInfoReqResp: 10,
128
130
  refreshCaptchaServiceReqResp: 10,
129
131
  downloadIntelligenceModelsReqResp: 42,
132
+ clickToInterstitialWithUserDelay: 12,
130
133
  },
131
134
  });
132
135
  assert.lengthOf(
@@ -183,9 +186,15 @@ describe('plugin-metrics', () => {
183
186
  webex.internal.newMetrics.callDiagnosticLatencies.getCallInitJoinReq = sinon
184
187
  .stub()
185
188
  .returns(10);
186
- webex.internal.newMetrics.callDiagnosticLatencies.getDownloadTimeJMT = sinon
189
+ webex.internal.newMetrics.callDiagnosticLatencies.getDownloadTimeJMT = sinon
187
190
  .stub()
188
191
  .returns(100);
192
+ webex.internal.newMetrics.callDiagnosticLatencies.getClickToInterstitialWithUserDelay = sinon
193
+ .stub()
194
+ .returns(43);
195
+ webex.internal.newMetrics.callDiagnosticLatencies.getTotalJMTWithUserDelay = sinon
196
+ .stub()
197
+ .returns(64);
189
198
  const promise = webex.internal.newMetrics.callDiagnosticMetrics.submitToCallDiagnostics(
190
199
  //@ts-ignore
191
200
  {event: {name: 'client.locus.join.response'}}
@@ -209,6 +218,8 @@ describe('plugin-metrics', () => {
209
218
  totalJmt: 20,
210
219
  clientJmt: 5,
211
220
  downloadTime: 100,
221
+ clickToInterstitialWithUserDelay: 43,
222
+ totalJMTWithUserDelay: 64,
212
223
  },
213
224
  });
214
225
  assert.lengthOf(
@@ -338,6 +349,12 @@ describe('plugin-metrics', () => {
338
349
  webex.internal.newMetrics.callDiagnosticLatencies.getStayLobbyTime = sinon
339
350
  .stub()
340
351
  .returns(1);
352
+ webex.internal.newMetrics.callDiagnosticLatencies.getTotalMediaJMTWithUserDelay = sinon
353
+ .stub()
354
+ .returns(43);
355
+ webex.internal.newMetrics.callDiagnosticLatencies.getTotalJMTWithUserDelay = sinon
356
+ .stub()
357
+ .returns(64);
341
358
  const promise = webex.internal.newMetrics.callDiagnosticMetrics.submitToCallDiagnostics(
342
359
  //@ts-ignore
343
360
  {event: {name: 'client.media-engine.ready'}}
@@ -356,6 +373,8 @@ describe('plugin-metrics', () => {
356
373
  interstitialToMediaOKJMT: 22,
357
374
  callInitMediaEngineReady: 10,
358
375
  stayLobbyTime: 1,
376
+ totalMediaJMTWithUserDelay: 43,
377
+ totalJMTWithUserDelay: 64,
359
378
  },
360
379
  });
361
380
  assert.lengthOf(
@@ -446,6 +446,36 @@ describe('internal-plugin-metrics', () => {
446
446
  assert.deepEqual(cdl.getClickToInterstitial(), 0);
447
447
  });
448
448
 
449
+ it('calculates getClickToInterstitialWithUserDelay correctly', () => {
450
+ cdl.saveTimestamp({
451
+ key: 'internal.client.meeting.click.joinbutton',
452
+ value: 10,
453
+ });
454
+ cdl.saveTimestamp({
455
+ key: 'internal.client.meeting.interstitial-window.showed',
456
+ value: 20,
457
+ });
458
+ assert.deepEqual(cdl.getClickToInterstitialWithUserDelay(), 10);
459
+ });
460
+
461
+ it('calculates getClickToInterstitialWithUserDelay without join button timestamp', () => {
462
+ cdl.saveLatency('internal.click.to.interstitial.with.user.delay', 5);
463
+ cdl.saveTimestamp({
464
+ key: 'internal.client.meeting.interstitial-window.showed',
465
+ value: 20,
466
+ });
467
+ assert.deepEqual(cdl.getClickToInterstitialWithUserDelay(), 5);
468
+ });
469
+
470
+ it('calculates getClickToInterstitialWithUserDelay without join button timestamp when it is 0', () => {
471
+ cdl.saveLatency('internal.click.to.interstitial.with.user.delay', 0);
472
+ cdl.saveTimestamp({
473
+ key: 'internal.client.meeting.interstitial-window.showed',
474
+ value: 20,
475
+ });
476
+ assert.deepEqual(cdl.getClickToInterstitialWithUserDelay(), 0);
477
+ });
478
+
449
479
  it('calculates getInterstitialToJoinOK correctly', () => {
450
480
  cdl.saveTimestamp({
451
481
  key: 'internal.client.interstitial-window.click.joinbutton',
@@ -554,6 +584,78 @@ describe('internal-plugin-metrics', () => {
554
584
  assert.deepEqual(cdl.getTotalJMT(), undefined);
555
585
  });
556
586
 
587
+ it('calculates getTotalJMTWithUserDelay correctly', () => {
588
+ cdl.saveTimestamp({
589
+ key: 'internal.client.interstitial-window.click.joinbutton',
590
+ value: 5,
591
+ });
592
+ cdl.saveTimestamp({
593
+ key: 'internal.client.meeting.click.joinbutton',
594
+ value: 10,
595
+ });
596
+ cdl.saveTimestamp({
597
+ key: 'internal.client.meeting.interstitial-window.showed',
598
+ value: 20,
599
+ });
600
+ cdl.saveTimestamp({
601
+ key: 'client.locus.join.response',
602
+ value: 40,
603
+ });
604
+ assert.deepEqual(cdl.getTotalJMTWithUserDelay(), 45);
605
+ });
606
+
607
+ it('calculates getTotalJMTWithUserDelay correctly when clickToInterstitialWithUserDelay is 0', () => {
608
+ cdl.saveLatency('internal.click.to.interstitial.with.user.delay', 0);
609
+ cdl.saveTimestamp({
610
+ key: 'internal.client.interstitial-window.click.joinbutton',
611
+ value: 20,
612
+ });
613
+ cdl.saveTimestamp({
614
+ key: 'client.locus.join.response',
615
+ value: 40,
616
+ });
617
+ assert.deepEqual(cdl.getTotalJMTWithUserDelay(), 20);
618
+ });
619
+
620
+ it('calculates getTotalJMTWithUserDelay correctly when interstitialToJoinOk is 0', () => {
621
+ cdl.saveTimestamp({
622
+ key: 'internal.client.interstitial-window.click.joinbutton',
623
+ value: 40,
624
+ });
625
+ cdl.saveLatency('internal.click.to.interstitial.with.user.delay', 12);
626
+ cdl.saveTimestamp({
627
+ key: 'client.locus.join.response',
628
+ value: 40,
629
+ });
630
+ assert.deepEqual(cdl.getTotalJMTWithUserDelay(), 12);
631
+ });
632
+
633
+ it('calculates getTotalJMTWithUserDelay correctly when both clickToInterstitialWithUserDelay and interstitialToJoinOk are 0', () => {
634
+ cdl.saveTimestamp({
635
+ key: 'internal.client.interstitial-window.click.joinbutton',
636
+ value: 40,
637
+ });
638
+ cdl.saveLatency('internal.click.to.interstitial.with.user.delay', 0);
639
+ cdl.saveTimestamp({
640
+ key: 'client.locus.join.response',
641
+ value: 40,
642
+ });
643
+ assert.deepEqual(cdl.getTotalJMTWithUserDelay(), 0);
644
+ });
645
+
646
+ it('calculates getTotalJMTWithUserDelay correctly when both clickToInterstitialWithUserDelay is not a number', () => {
647
+ cdl.saveTimestamp({
648
+ key: 'internal.client.interstitial-window.click.joinbutton',
649
+ value: 40,
650
+ });
651
+ cdl.saveLatency('internal.click.to.interstitial.with.user.delay', 'eleven' as unknown as number);
652
+ cdl.saveTimestamp({
653
+ key: 'client.locus.join.response',
654
+ value: 40,
655
+ });
656
+ assert.deepEqual(cdl.getTotalJMTWithUserDelay(), undefined);
657
+ });
658
+
557
659
  it('calculates getTotalMediaJMT correctly', () => {
558
660
  cdl.saveTimestamp({
559
661
  key: 'internal.client.meeting.click.joinbutton',
@@ -627,6 +729,71 @@ describe('internal-plugin-metrics', () => {
627
729
  assert.deepEqual(cdl.getTotalMediaJMT(), 31);
628
730
  });
629
731
 
732
+ it('calculates getTotalMediaJMTWithUserDelay correctly', () => {
733
+ cdl.saveLatency('internal.click.to.interstitial.with.user.delay', 7);
734
+ cdl.saveTimestamp({
735
+ key: 'internal.client.interstitial-window.click.joinbutton',
736
+ value: 10,
737
+ });
738
+ cdl.saveTimestamp({
739
+ key: 'client.locus.join.request',
740
+ value: 12,
741
+ });
742
+ cdl.saveTimestamp({
743
+ key: 'client.locus.join.response',
744
+ value: 20,
745
+ });
746
+ cdl.saveTimestamp({
747
+ key: 'internal.host.meeting.participant.admitted',
748
+ value: 24,
749
+ });
750
+ cdl.saveTimestamp({
751
+ key: 'client.ice.start',
752
+ value: 30,
753
+ });
754
+ cdl.saveTimestamp({
755
+ key: 'client.ice.end',
756
+ value: 40,
757
+ });
758
+ assert.deepEqual(cdl.getTotalMediaJMTWithUserDelay(), 35);
759
+ });
760
+
761
+ it('calculates getTotalMediaJMTWithUserDelay correctly for guest join', () => {
762
+ cdl.saveTimestamp({
763
+ key: 'internal.client.meeting.click.joinbutton',
764
+ value: 5,
765
+ });
766
+ cdl.saveTimestamp({
767
+ key: 'internal.client.meeting.interstitial-window.showed',
768
+ value: 8,
769
+ });
770
+ cdl.saveTimestamp({
771
+ key: 'internal.client.interstitial-window.click.joinbutton',
772
+ value: 10,
773
+ });
774
+ cdl.saveTimestamp({
775
+ key: 'client.locus.join.request',
776
+ value: 12,
777
+ });
778
+ cdl.saveTimestamp({
779
+ key: 'client.locus.join.response',
780
+ value: 20,
781
+ });
782
+ cdl.saveTimestamp({
783
+ key: 'internal.host.meeting.participant.admitted',
784
+ value: 24,
785
+ });
786
+ cdl.saveTimestamp({
787
+ key: 'client.ice.start',
788
+ value: 30,
789
+ });
790
+ cdl.saveTimestamp({
791
+ key: 'client.ice.end',
792
+ value: 40,
793
+ });
794
+ assert.deepEqual(cdl.getTotalMediaJMTWithUserDelay(), 31);
795
+ });
796
+
630
797
  it('calculates getJoinConfJMT correctly', () => {
631
798
  cdl.saveTimestamp({
632
799
  key: 'client.locus.join.request',