@webex/internal-plugin-metrics 3.0.0-beta.196 → 3.0.0-beta.198

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-batcher.js +5 -83
  2. package/dist/call-diagnostic/call-diagnostic-metrics-batcher.js.map +1 -1
  3. package/dist/call-diagnostic/call-diagnostic-metrics.js +76 -3
  4. package/dist/call-diagnostic/call-diagnostic-metrics.js.map +1 -1
  5. package/dist/call-diagnostic/call-diagnostic-metrics.util.js +120 -1
  6. package/dist/call-diagnostic/call-diagnostic-metrics.util.js.map +1 -1
  7. package/dist/call-diagnostic/generated-types-temp/ClientEvent.js.map +1 -1
  8. package/dist/call-diagnostic/generated-types-temp/Event.js.map +1 -1
  9. package/dist/metrics.js +1 -1
  10. package/dist/metrics.types.js.map +1 -1
  11. package/dist/new-metrics.js +64 -0
  12. package/dist/new-metrics.js.map +1 -1
  13. package/dist/types/call-diagnostic/call-diagnostic-metrics.d.ts +24 -0
  14. package/dist/types/call-diagnostic/call-diagnostic-metrics.util.d.ts +21 -0
  15. package/dist/types/call-diagnostic/generated-types-temp/ClientEvent.d.ts +135 -135
  16. package/dist/types/call-diagnostic/generated-types-temp/Event.d.ts +379 -379
  17. package/dist/types/metrics.types.d.ts +5 -0
  18. package/dist/types/new-metrics.d.ts +36 -0
  19. package/package.json +8 -8
  20. package/src/call-diagnostic/call-diagnostic-metrics-batcher.ts +2 -99
  21. package/src/call-diagnostic/call-diagnostic-metrics.ts +64 -2
  22. package/src/call-diagnostic/call-diagnostic-metrics.util.ts +132 -1
  23. package/src/call-diagnostic/generated-types-temp/ClientEvent.ts +1360 -1322
  24. package/src/call-diagnostic/generated-types-temp/Event.ts +3142 -3049
  25. package/src/metrics.types.ts +6 -0
  26. package/src/new-metrics.ts +52 -0
  27. package/test/unit/spec/call-diagnostic/call-diagnostic-metrics.ts +145 -46
  28. package/test/unit/spec/call-diagnostic/call-diagnostic-metrics.util.ts +262 -2
  29. package/test/unit/spec/new-metrics.ts +84 -22
@@ -129,3 +129,9 @@ export type SubmitMQE = (args: {
129
129
  payload: SubmitMQEPayload;
130
130
  options: any;
131
131
  }) => void;
132
+
133
+ export type BuildClientEventFetchRequestOptions = (args: {
134
+ name: ClientEvent['name'];
135
+ payload?: RecursivePartial<ClientEvent['payload']>;
136
+ options: SubmitClientEventOptions;
137
+ }) => Promise<any>;
@@ -17,6 +17,7 @@ import {
17
17
  SubmitClientEventOptions,
18
18
  } from './metrics.types';
19
19
  import CallDiagnosticLatencies from './call-diagnostic/call-diagnostic-metrics-latencies';
20
+ import {setMetricTimings} from './call-diagnostic/call-diagnostic-metrics.util';
20
21
 
21
22
  /**
22
23
  * Metrics plugin to centralize all types of metrics.
@@ -166,6 +167,57 @@ class Metrics extends WebexPlugin {
166
167
 
167
168
  return this.callDiagnosticMetrics.submitClientEvent({name, payload, options});
168
169
  }
170
+
171
+ /**
172
+ * Returns a promise that will resolve to fetch options for submitting a metric.
173
+ *
174
+ * This is to support quickly submitting metrics when the browser/tab is closing.
175
+ * Calling submitClientEvent will not work because there some async steps that will
176
+ * not complete before the browser is closed. Instead, we pre-gather all the
177
+ * information/options needed for the request(s), and then simply and quickly
178
+ * fire the fetch(es) when beforeUnload is triggered.
179
+ *
180
+ * We must use fetch instead of request because fetch has a keepalive option that
181
+ * allows the request it to outlive the page.
182
+ *
183
+ * Note: the timings values will be wrong, but setMetricTimingsAndFetch() will
184
+ * properly adjust them before submitting.
185
+ *
186
+ * @public
187
+ * @param {Object} arg
188
+ * @param {String} arg.name - event name
189
+ * @param {Object} arg.payload - event payload
190
+ * @param {Object} arg.options - other options
191
+ * @returns {Promise} promise that resolves to options to be used with fetch
192
+ */
193
+ public async buildClientEventFetchRequestOptions({
194
+ name,
195
+ payload,
196
+ options,
197
+ }: {
198
+ name: ClientEvent['name'];
199
+ payload?: RecursivePartial<ClientEvent['payload']>;
200
+ options: SubmitClientEventOptions;
201
+ }): Promise<any> {
202
+ return this.callDiagnosticMetrics.buildClientEventFetchRequestOptions({
203
+ name,
204
+ payload,
205
+ options,
206
+ });
207
+ }
208
+
209
+ /**
210
+ * Submits a metric from pre-built request options via the fetch API. Updates
211
+ * the "$timings" and "originTime" values to Date.now() since the existing times
212
+ * were set when the options were built (not submitted).
213
+
214
+ * @param {any} options - the pre-built request options for submitting a metric
215
+ * @returns {Promise} promise that resolves to the response object
216
+ */
217
+ public setMetricTimingsAndFetch(options: any): Promise<any> {
218
+ // @ts-ignore
219
+ return this.webex.setTimingsAndFetch(setMetricTimings(options));
220
+ }
169
221
  }
170
222
 
171
223
  export default Metrics;
@@ -2,6 +2,7 @@ import sinon from 'sinon';
2
2
  import {assert} from '@webex/test-helper-chai';
3
3
 
4
4
  import CallDiagnosticMetrics from '../../../../src/call-diagnostic/call-diagnostic-metrics';
5
+ import CallDiagnosticLatencies from '../../../../src/call-diagnostic/call-diagnostic-metrics-latencies';
5
6
  import * as Utils from '../../../../src/call-diagnostic/call-diagnostic-metrics.util';
6
7
  import {BrowserDetection} from '@webex/common';
7
8
  import {getOSNameInternal} from '@webex/internal-plugin-metrics';
@@ -10,7 +11,10 @@ import uuid from 'uuid';
10
11
  //@ts-ignore
11
12
  global.window = {location: {hostname: 'whatever'}};
12
13
 
13
- const {getOSVersion, getBrowserName, getBrowserVersion} = BrowserDetection();
14
+ const {getOSName, getOSVersion, getBrowserName, getBrowserVersion} = BrowserDetection();
15
+ const userAgent = `webex-js-sdk/test-webex-version client=Cantina; (os=${getOSName()}/${
16
+ getOSVersion().split('.')[0]
17
+ })`;
14
18
 
15
19
  describe('internal-plugin-metrics', () => {
16
20
  describe('CallDiagnosticMetrics', () => {
@@ -42,13 +46,14 @@ describe('internal-plugin-metrics', () => {
42
46
  get: () => 'locus-url',
43
47
  },
44
48
  metrics: {
45
- submitClientMetrics: sinon.stub()
49
+ submitClientMetrics: sinon.stub(),
46
50
  },
51
+ newMetrics: {},
47
52
  device: {
48
53
  userId: 'userId',
49
54
  url: 'deviceUrl',
50
55
  orgId: 'orgId',
51
- }
56
+ },
52
57
  },
53
58
  meetings: {
54
59
  config: {
@@ -61,7 +66,7 @@ describe('internal-plugin-metrics', () => {
61
66
  clientName: 'Cantina',
62
67
  },
63
68
  meetingCollection: {
64
- get: () => fakeMeeting
69
+ get: () => fakeMeeting,
65
70
  },
66
71
  geoHintInfo: {
67
72
  clientAddress: '1.3.4.5',
@@ -69,10 +74,16 @@ describe('internal-plugin-metrics', () => {
69
74
  },
70
75
  },
71
76
  credentials: {
72
- isUnverifiedGuest: false
73
- }
77
+ isUnverifiedGuest: false,
78
+ },
79
+ prepareFetchOptions: sinon.stub().callsFake((opts: any) => ({...opts, foo: 'bar'})),
74
80
  };
75
81
 
82
+ webex.internal.newMetrics.callDiagnosticLatencies = new CallDiagnosticLatencies(
83
+ {},
84
+ {parent: webex}
85
+ );
86
+
76
87
  sinon.createSandbox();
77
88
  sinon.useFakeTimers(now.getTime());
78
89
  cd = new CallDiagnosticMetrics({}, {parent: webex});
@@ -83,7 +94,7 @@ describe('internal-plugin-metrics', () => {
83
94
  sinon.restore();
84
95
  });
85
96
 
86
- describe("#getOrigin", () => {
97
+ describe('#getOrigin', () => {
87
98
  it('should build origin correctly', () => {
88
99
  sinon.stub(Utils, 'anonymizeIPAddress').returns('1.1.1.1');
89
100
 
@@ -107,7 +118,7 @@ describe('internal-plugin-metrics', () => {
107
118
  environment: 'meeting_evn',
108
119
  name: 'endpoint',
109
120
  networkType: 'unknown',
110
- userAgent: 'webex-js-sdk/test-webex-version client=Cantina; (os=linux/5)',
121
+ userAgent,
111
122
  });
112
123
  });
113
124
 
@@ -130,12 +141,12 @@ describe('internal-plugin-metrics', () => {
130
141
  },
131
142
  name: 'endpoint',
132
143
  networkType: 'unknown',
133
- userAgent: 'webex-js-sdk/test-webex-version client=Cantina; (os=linux/5)',
144
+ userAgent,
134
145
  });
135
146
  });
136
- })
147
+ });
137
148
 
138
- describe("#getIdentifiers", () => {
149
+ describe('#getIdentifiers', () => {
139
150
  it('should build identifiers correctly', () => {
140
151
  const res = cd.getIdentifiers({
141
152
  mediaConnections: [
@@ -159,7 +170,7 @@ describe('internal-plugin-metrics', () => {
159
170
 
160
171
  it('should build identifiers correctly given correlationId', () => {
161
172
  const res = cd.getIdentifiers({
162
- correlationId: 'correlationId'
173
+ correlationId: 'correlationId',
163
174
  });
164
175
 
165
176
  assert.deepEqual(res, {
@@ -181,7 +192,7 @@ describe('internal-plugin-metrics', () => {
181
192
  })
182
193
  );
183
194
  });
184
- })
195
+ });
185
196
 
186
197
  it('should prepare diagnostic event successfully', () => {
187
198
  const options = {meetingId: fakeMeeting.id};
@@ -308,7 +319,7 @@ describe('internal-plugin-metrics', () => {
308
319
  sinon.stub(cd, 'getOrigin').returns({origin: 'fake-origin'});
309
320
 
310
321
  const options = {
311
- correlationId: 'correlationId'
322
+ correlationId: 'correlationId',
312
323
  };
313
324
 
314
325
  cd.submitClientEvent({
@@ -405,15 +416,17 @@ describe('internal-plugin-metrics', () => {
405
416
  orgId: 'orgId',
406
417
  userId: 'userId',
407
418
  },
408
- errors: [{
409
- category: 'expected',
410
- errorDescription: 'StartRecordingFailed',
411
- fatal: true,
412
- name: 'other',
413
- shownToUser: false,
414
- serviceErrorCode: 2409005,
415
- errorCode: 4029
416
- }],
419
+ errors: [
420
+ {
421
+ category: 'expected',
422
+ errorDescription: 'StartRecordingFailed',
423
+ fatal: true,
424
+ name: 'other',
425
+ shownToUser: false,
426
+ serviceErrorCode: 2409005,
427
+ errorCode: 4029,
428
+ },
429
+ ],
417
430
  loginType: 'login-ci',
418
431
  name: 'client.alert.displayed',
419
432
  userType: 'host',
@@ -431,7 +444,7 @@ describe('internal-plugin-metrics', () => {
431
444
  });
432
445
  });
433
446
 
434
- it('should include erros in payload if provided via payload', () => {
447
+ it('should include errors in payload if provided via payload', () => {
435
448
  sinon.stub(cd, 'getOrigin').returns({origin: 'fake-origin'});
436
449
  const submitToCallDiagnosticsSpy = sinon.spy(cd, 'submitToCallDiagnostics');
437
450
 
@@ -443,12 +456,14 @@ describe('internal-plugin-metrics', () => {
443
456
  cd.submitClientEvent({
444
457
  name: 'client.alert.displayed',
445
458
  payload: {
446
- errors: [{
447
- name: 'locus.response',
448
- fatal: true,
449
- category: 'signaling',
450
- shownToUser: false,
451
- }]
459
+ errors: [
460
+ {
461
+ name: 'locus.response',
462
+ fatal: true,
463
+ category: 'signaling',
464
+ shownToUser: false,
465
+ },
466
+ ],
452
467
  },
453
468
  options,
454
469
  });
@@ -470,12 +485,14 @@ describe('internal-plugin-metrics', () => {
470
485
  orgId: 'orgId',
471
486
  userId: 'userId',
472
487
  },
473
- errors: [{
474
- name: 'locus.response',
475
- fatal: true,
476
- category: 'signaling',
477
- shownToUser: false,
478
- }],
488
+ errors: [
489
+ {
490
+ name: 'locus.response',
491
+ fatal: true,
492
+ category: 'signaling',
493
+ shownToUser: false,
494
+ },
495
+ ],
479
496
  loginType: 'login-ci',
480
497
  name: 'client.alert.displayed',
481
498
  userType: 'host',
@@ -491,7 +508,7 @@ describe('internal-plugin-metrics', () => {
491
508
  senderCountryCode: 'UK',
492
509
  version: 1,
493
510
  });
494
- })
511
+ });
495
512
 
496
513
  it('should throw if meetingId nor correlationId not provided', () => {
497
514
  assert.throws(() =>
@@ -512,7 +529,7 @@ describe('internal-plugin-metrics', () => {
512
529
  fields: {meetingId: 'meetingId', name: 'client.alert.displayed'},
513
530
  }
514
531
  );
515
- })
532
+ });
516
533
  });
517
534
 
518
535
  it('should send request to call diagnostic batcher', () => {
@@ -528,7 +545,10 @@ describe('internal-plugin-metrics', () => {
528
545
  it('submits the event correctly', () => {
529
546
  const prepareDiagnosticEventSpy = sinon.spy(cd, 'prepareDiagnosticEvent');
530
547
  const submitToCallDiagnosticsSpy = sinon.spy(cd, 'submitToCallDiagnostics');
531
- const getErrorPayloadForClientErrorCodeSpy = sinon.spy(cd, 'getErrorPayloadForClientErrorCode');
548
+ const getErrorPayloadForClientErrorCodeSpy = sinon.spy(
549
+ cd,
550
+ 'getErrorPayloadForClientErrorCode'
551
+ );
532
552
  const getIdentifiersSpy = sinon.spy(cd, 'getIdentifiers');
533
553
  sinon.stub(cd, 'getOrigin').returns({origin: 'fake-origin'});
534
554
  const options = {
@@ -639,11 +659,14 @@ describe('internal-plugin-metrics', () => {
639
659
  fields: {meetingId: 'meetingId', name: 'client.mediaquality.event'},
640
660
  }
641
661
  );
642
- })
662
+ });
643
663
  });
644
664
  describe('#getErrorPayloadForClientErrorCode', () => {
645
665
  it('it should grab the payload for client error code correctly', () => {
646
- const res = cd.getErrorPayloadForClientErrorCode({clientErrorCode: 4008, serviceErrorCode: 10000});
666
+ const res = cd.getErrorPayloadForClientErrorCode({
667
+ clientErrorCode: 4008,
668
+ serviceErrorCode: 10000,
669
+ });
647
670
  assert.deepEqual(res, {
648
671
  category: 'signaling',
649
672
  errorDescription: 'NewLocusError',
@@ -656,7 +679,10 @@ describe('internal-plugin-metrics', () => {
656
679
  });
657
680
 
658
681
  it('it should return undefined if trying to get payload for client error code that doesnt exist', () => {
659
- const res = cd.getErrorPayloadForClientErrorCode({clientErrorCode: 123456, serviceErrorCode: 100000});
682
+ const res = cd.getErrorPayloadForClientErrorCode({
683
+ clientErrorCode: 123456,
684
+ serviceErrorCode: 100000,
685
+ });
660
686
  assert.deepEqual(res, undefined);
661
687
  });
662
688
  });
@@ -671,7 +697,7 @@ describe('internal-plugin-metrics', () => {
671
697
  name: 'other',
672
698
  shownToUser: false,
673
699
  errorCode: 4029,
674
- serviceErrorCode: 2409005
700
+ serviceErrorCode: 2409005,
675
701
  });
676
702
  });
677
703
 
@@ -688,7 +714,6 @@ describe('internal-plugin-metrics', () => {
688
714
  });
689
715
  });
690
716
 
691
-
692
717
  it('should return default meeting info lookup error payload correctly if not locus error', () => {
693
718
  const res = cd.generateClientEventErrorPayload({body: {errorCode: 9400000}});
694
719
  assert.deepEqual(res, {
@@ -716,7 +741,81 @@ describe('internal-plugin-metrics', () => {
716
741
  it('returns unverified guest', () => {
717
742
  webex.credentials.isUnverifiedGuest = true;
718
743
  assert.deepEqual(cd.getCurLoginType(), 'unverified-guest');
719
- })
720
- })
744
+ });
745
+ });
746
+
747
+ describe('#buildClientEventFetchRequestOptions', () => {
748
+ it('returns expected options', async () => {
749
+ const options = {
750
+ meetingId: fakeMeeting.id,
751
+ };
752
+
753
+ const triggered = new Date();
754
+ const fetchOptions = await cd.buildClientEventFetchRequestOptions({
755
+ name: 'client.exit.app',
756
+ payload: {trigger: 'user-interaction', canProceed: false},
757
+ options,
758
+ });
759
+
760
+ assert.deepEqual(fetchOptions, {
761
+ body: {
762
+ metrics: [
763
+ {
764
+ eventPayload: {
765
+ event: {
766
+ canProceed: false,
767
+ eventData: {
768
+ webClientDomain: 'whatever',
769
+ },
770
+ identifiers: {
771
+ correlationId: 'correlationId',
772
+ deviceId: 'deviceUrl',
773
+ locusId: 'url',
774
+ locusStartTime: 'lastActive',
775
+ locusUrl: 'locus/url',
776
+ orgId: 'orgId',
777
+ userId: 'userId',
778
+ },
779
+ loginType: 'login-ci',
780
+ name: 'client.exit.app',
781
+ trigger: 'user-interaction',
782
+ userType: 'host',
783
+ },
784
+ eventId: 'my-fake-id',
785
+ origin: {
786
+ buildType: 'test',
787
+ clientInfo: {
788
+ clientType: 'TEAMS_CLIENT',
789
+ clientVersion: 'webex-js-sdk/webex-version',
790
+ localNetworkPrefix:
791
+ Utils.anonymizeIPAddress(webex.meetings.geoHintInfo?.clientAddress) ||
792
+ undefined,
793
+ os: getOSNameInternal() || 'unknown',
794
+ osVersion: getOSVersion(),
795
+ subClientType: 'WEB_APP',
796
+ },
797
+ environment: 'meeting_evn',
798
+ name: 'endpoint',
799
+ networkType: 'unknown',
800
+ userAgent,
801
+ },
802
+ originTime: {
803
+ sent: 'not_defined_yet',
804
+ triggered: triggered.toISOString(),
805
+ },
806
+ senderCountryCode: webex.meetings.geoHintInfo?.countryCode,
807
+ version: 1,
808
+ },
809
+ type: ['diagnostic-event'],
810
+ },
811
+ ],
812
+ },
813
+ foo: 'bar',
814
+ method: 'POST',
815
+ resource: 'clientmetrics',
816
+ service: 'metrics',
817
+ });
818
+ });
819
+ });
721
820
  });
722
821
  });