@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.
- package/dist/call-diagnostic/call-diagnostic-metrics-latencies.js +49 -0
- package/dist/call-diagnostic/call-diagnostic-metrics-latencies.js.map +1 -1
- package/dist/call-diagnostic/call-diagnostic-metrics.js +301 -81
- package/dist/call-diagnostic/call-diagnostic-metrics.js.map +1 -1
- package/dist/call-diagnostic/call-diagnostic-metrics.util.js +6 -0
- package/dist/call-diagnostic/call-diagnostic-metrics.util.js.map +1 -1
- package/dist/call-diagnostic/config.js +32 -3
- package/dist/call-diagnostic/config.js.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/metrics.js +1 -1
- package/dist/metrics.types.js.map +1 -1
- package/dist/new-metrics.js +58 -5
- package/dist/new-metrics.js.map +1 -1
- package/dist/types/call-diagnostic/call-diagnostic-metrics-latencies.d.ts +15 -0
- package/dist/types/call-diagnostic/call-diagnostic-metrics.d.ts +154 -24
- package/dist/types/call-diagnostic/config.d.ts +14 -0
- package/dist/types/index.d.ts +2 -2
- package/dist/types/metrics.types.d.ts +28 -7
- package/dist/types/new-metrics.d.ts +28 -4
- package/package.json +12 -12
- package/src/call-diagnostic/call-diagnostic-metrics-latencies.ts +58 -0
- package/src/call-diagnostic/call-diagnostic-metrics.ts +294 -66
- package/src/call-diagnostic/call-diagnostic-metrics.util.ts +6 -0
- package/src/call-diagnostic/config.ts +31 -0
- package/src/index.ts +4 -0
- package/src/metrics.types.ts +36 -6
- package/src/new-metrics.ts +73 -5
- package/test/unit/spec/call-diagnostic/call-diagnostic-metrics-batcher.ts +20 -1
- package/test/unit/spec/call-diagnostic/call-diagnostic-metrics-latencies.ts +167 -0
- package/test/unit/spec/call-diagnostic/call-diagnostic-metrics.ts +1054 -153
- package/test/unit/spec/call-diagnostic/call-diagnostic-metrics.util.ts +6 -0
- package/test/unit/spec/new-metrics.ts +94 -5
- package/test/unit/spec/prelogin-metrics-batcher.ts +1 -0
- package/dist/call-diagnostic-events-batcher.js +0 -59
- package/dist/call-diagnostic-events-batcher.js.map +0 -1
|
@@ -41,6 +41,9 @@ import {
|
|
|
41
41
|
ClientSubServiceType,
|
|
42
42
|
BrowserLaunchMethodType,
|
|
43
43
|
DelayedClientEvent,
|
|
44
|
+
DelayedClientFeatureEvent,
|
|
45
|
+
FeatureEvent,
|
|
46
|
+
ClientFeatureEventPayload,
|
|
44
47
|
} from '../metrics.types';
|
|
45
48
|
import CallDiagnosticEventsBatcher from './call-diagnostic-metrics-batcher';
|
|
46
49
|
import PreLoginMetricsBatcher from '../prelogin-metrics-batcher';
|
|
@@ -58,6 +61,8 @@ import {
|
|
|
58
61
|
AUTHENTICATION_FAILED_CODE,
|
|
59
62
|
WEBEX_SUB_SERVICE_TYPES,
|
|
60
63
|
SDP_OFFER_CREATION_ERROR_MAP,
|
|
64
|
+
CALL_FEATURE_LOG_IDENTIFIER,
|
|
65
|
+
CALL_FEATURE_EVENT_FAILED_TO_SEND,
|
|
61
66
|
} from './config';
|
|
62
67
|
|
|
63
68
|
const {getOSVersion, getBrowserName, getBrowserVersion} = BrowserDetection();
|
|
@@ -97,6 +102,9 @@ export default class CallDiagnosticMetrics extends StatelessWebexPlugin {
|
|
|
97
102
|
private hasLoggedBrowserSerial: boolean;
|
|
98
103
|
private device: any;
|
|
99
104
|
private delayedClientEvents: DelayedClientEvent[] = [];
|
|
105
|
+
private delayedClientFeatureEvents: DelayedClientFeatureEvent[] = [];
|
|
106
|
+
private eventErrorCache: WeakMap<any, any> = new WeakMap();
|
|
107
|
+
private isMercuryConnected = false;
|
|
100
108
|
|
|
101
109
|
// the default validator before piping an event to the batcher
|
|
102
110
|
// this function can be overridden by the user
|
|
@@ -149,6 +157,16 @@ export default class CallDiagnosticMetrics extends StatelessWebexPlugin {
|
|
|
149
157
|
return undefined;
|
|
150
158
|
}
|
|
151
159
|
|
|
160
|
+
/**
|
|
161
|
+
* Sets mercury connected status for event data object in CA events
|
|
162
|
+
* @public
|
|
163
|
+
* @param status - boolean value indicating mercury connection status
|
|
164
|
+
* @return {void}
|
|
165
|
+
*/
|
|
166
|
+
public setMercuryConnectedStatus(status: boolean): void {
|
|
167
|
+
this.isMercuryConnected = status;
|
|
168
|
+
}
|
|
169
|
+
|
|
152
170
|
/**
|
|
153
171
|
* Returns meeting's subServiceType
|
|
154
172
|
* @param meeting
|
|
@@ -166,23 +184,17 @@ export default class CallDiagnosticMetrics extends StatelessWebexPlugin {
|
|
|
166
184
|
if (meetingInfo?.webexScheduled && !meetingInfo?.enableEvent && !meetingInfo?.pmr) {
|
|
167
185
|
return WEBEX_SUB_SERVICE_TYPES.SCHEDULED_MEETING;
|
|
168
186
|
}
|
|
169
|
-
|
|
170
|
-
if
|
|
171
|
-
|
|
172
|
-
meetingInfo?.
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
) {
|
|
176
|
-
return WEBEX_SUB_SERVICE_TYPES.WEBINAR;
|
|
187
|
+
|
|
188
|
+
// if ConvergedArchitecture enable and isConvergedWebinarWebcast -- then webcast
|
|
189
|
+
if (meetingInfo?.enableConvergedArchitecture && meetingInfo?.enableEvent) {
|
|
190
|
+
return meetingInfo?.isConvergedWebinarWebcast
|
|
191
|
+
? WEBEX_SUB_SERVICE_TYPES.WEBCAST
|
|
192
|
+
: WEBEX_SUB_SERVICE_TYPES.WEBINAR;
|
|
177
193
|
}
|
|
178
|
-
|
|
179
|
-
if
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
!meetingInfo?.pmr &&
|
|
183
|
-
meetingInfo?.isConvergedWebinarWebcast
|
|
184
|
-
) {
|
|
185
|
-
return WEBEX_SUB_SERVICE_TYPES.WEBCAST;
|
|
194
|
+
|
|
195
|
+
// if Scheduled, enable event, not pmr - then Webinar
|
|
196
|
+
if (meetingInfo?.webexScheduled && meetingInfo?.enableEvent && !meetingInfo?.pmr) {
|
|
197
|
+
return WEBEX_SUB_SERVICE_TYPES.WEBINAR;
|
|
186
198
|
}
|
|
187
199
|
}
|
|
188
200
|
|
|
@@ -421,12 +433,97 @@ export default class CallDiagnosticMetrics extends StatelessWebexPlugin {
|
|
|
421
433
|
}
|
|
422
434
|
|
|
423
435
|
/**
|
|
424
|
-
*
|
|
436
|
+
* Create feature event
|
|
437
|
+
* @param name
|
|
438
|
+
* @param payload
|
|
439
|
+
* @param options
|
|
440
|
+
* @returns
|
|
441
|
+
*/
|
|
442
|
+
private prepareClientFeatureEvent({
|
|
443
|
+
name,
|
|
444
|
+
payload,
|
|
445
|
+
options,
|
|
446
|
+
}: {
|
|
447
|
+
name: FeatureEvent['name'];
|
|
448
|
+
payload?: ClientFeatureEventPayload;
|
|
449
|
+
options?: SubmitClientEventOptions;
|
|
450
|
+
}) {
|
|
451
|
+
const {meetingId, correlationId} = options;
|
|
452
|
+
let featureEventObject: FeatureEvent['payload'];
|
|
453
|
+
|
|
454
|
+
// events that will most likely happen in join phase
|
|
455
|
+
if (meetingId) {
|
|
456
|
+
featureEventObject = this.createFeatureEventObjectInMeeting({name, options});
|
|
457
|
+
} else {
|
|
458
|
+
throw new Error('Not implemented');
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
// merge any new properties, or override existing ones
|
|
462
|
+
featureEventObject = merge(featureEventObject, payload);
|
|
463
|
+
|
|
464
|
+
// append client event data to the call diagnostic event
|
|
465
|
+
const featureEvent = this.prepareDiagnosticEvent(featureEventObject, options);
|
|
466
|
+
|
|
467
|
+
return featureEvent;
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
/**
|
|
425
471
|
* Submit Feature Event
|
|
472
|
+
* submit to business_ucf
|
|
426
473
|
* @returns
|
|
427
474
|
*/
|
|
428
|
-
public submitFeatureEvent(
|
|
429
|
-
|
|
475
|
+
public submitFeatureEvent({
|
|
476
|
+
name,
|
|
477
|
+
payload,
|
|
478
|
+
options,
|
|
479
|
+
delaySubmitEvent,
|
|
480
|
+
}: {
|
|
481
|
+
name: FeatureEvent['name'];
|
|
482
|
+
payload?: ClientFeatureEventPayload;
|
|
483
|
+
options?: SubmitClientEventOptions;
|
|
484
|
+
delaySubmitEvent?: boolean;
|
|
485
|
+
}) {
|
|
486
|
+
if (delaySubmitEvent) {
|
|
487
|
+
// Preserve the time when the event was triggered if delaying the submission to Call Features
|
|
488
|
+
const delayedOptions = {
|
|
489
|
+
...options,
|
|
490
|
+
triggeredTime: new Date().toISOString(),
|
|
491
|
+
};
|
|
492
|
+
|
|
493
|
+
this.delayedClientFeatureEvents.push({
|
|
494
|
+
name,
|
|
495
|
+
payload,
|
|
496
|
+
options: delayedOptions,
|
|
497
|
+
});
|
|
498
|
+
|
|
499
|
+
return Promise.resolve();
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
this.logger.log(
|
|
503
|
+
CALL_FEATURE_LOG_IDENTIFIER,
|
|
504
|
+
'CallFeatureMetrics: @submitFeatureEvent. Submit Client Feature Event CA event.',
|
|
505
|
+
`name: ${name}`
|
|
506
|
+
);
|
|
507
|
+
const featureEvent = this.prepareClientFeatureEvent({name, payload, options});
|
|
508
|
+
|
|
509
|
+
this.validator({type: 'ce', event: featureEvent});
|
|
510
|
+
|
|
511
|
+
return this.submitToCallFeatures(featureEvent);
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
/**
|
|
515
|
+
* Submit Feature Event
|
|
516
|
+
* type is business
|
|
517
|
+
* @param event
|
|
518
|
+
*/
|
|
519
|
+
submitToCallFeatures(event: Event): Promise<any> {
|
|
520
|
+
// build metrics-a event type
|
|
521
|
+
const finalEvent = {
|
|
522
|
+
eventPayload: event,
|
|
523
|
+
type: ['business'],
|
|
524
|
+
};
|
|
525
|
+
|
|
526
|
+
return this.callDiagnosticEventsBatcher.request(finalEvent);
|
|
430
527
|
}
|
|
431
528
|
|
|
432
529
|
/**
|
|
@@ -561,16 +658,31 @@ export default class CallDiagnosticMetrics extends StatelessWebexPlugin {
|
|
|
561
658
|
return undefined;
|
|
562
659
|
}
|
|
563
660
|
|
|
661
|
+
/**
|
|
662
|
+
* Clear the error cache
|
|
663
|
+
*/
|
|
664
|
+
clearErrorCache() {
|
|
665
|
+
this.eventErrorCache = new WeakMap();
|
|
666
|
+
}
|
|
667
|
+
|
|
564
668
|
/**
|
|
565
669
|
* Generate error payload for Client Event
|
|
566
670
|
* @param rawError
|
|
567
671
|
*/
|
|
568
672
|
generateClientEventErrorPayload(rawError: any) {
|
|
673
|
+
const cachedError = this.eventErrorCache.get(rawError);
|
|
674
|
+
|
|
675
|
+
if (cachedError) {
|
|
676
|
+
return [cachedError, true];
|
|
677
|
+
}
|
|
678
|
+
|
|
569
679
|
const rawErrorMessage = rawError.message;
|
|
570
680
|
const httpStatusCode = rawError.statusCode;
|
|
681
|
+
let payload;
|
|
682
|
+
|
|
571
683
|
if (rawError.name) {
|
|
572
684
|
if (isBrowserMediaErrorName(rawError.name)) {
|
|
573
|
-
|
|
685
|
+
payload = this.getErrorPayloadForClientErrorCode({
|
|
574
686
|
serviceErrorCode: undefined,
|
|
575
687
|
clientErrorCode: BROWSER_MEDIA_ERROR_NAME_TO_CLIENT_ERROR_CODES_MAP[rawError.name],
|
|
576
688
|
serviceErrorName: rawError.name,
|
|
@@ -580,11 +692,11 @@ export default class CallDiagnosticMetrics extends StatelessWebexPlugin {
|
|
|
580
692
|
}
|
|
581
693
|
}
|
|
582
694
|
|
|
583
|
-
if (isSdpOfferCreationError(rawError)) {
|
|
695
|
+
if (isSdpOfferCreationError(rawError) && !payload) {
|
|
584
696
|
// error code is 30005, but that's not specific enough. we also need to check error.cause.type
|
|
585
697
|
const causeType = rawError.cause?.type;
|
|
586
698
|
|
|
587
|
-
|
|
699
|
+
payload = this.getErrorPayloadForClientErrorCode({
|
|
588
700
|
serviceErrorCode: undefined,
|
|
589
701
|
clientErrorCode:
|
|
590
702
|
SDP_OFFER_CREATION_ERROR_MAP[causeType] || SDP_OFFER_CREATION_ERROR_MAP.GENERAL,
|
|
@@ -602,8 +714,8 @@ export default class CallDiagnosticMetrics extends StatelessWebexPlugin {
|
|
|
602
714
|
|
|
603
715
|
if (serviceErrorCode) {
|
|
604
716
|
const clientErrorCode = SERVICE_ERROR_CODES_TO_CLIENT_ERROR_CODES_MAP[serviceErrorCode];
|
|
605
|
-
if (clientErrorCode) {
|
|
606
|
-
|
|
717
|
+
if (clientErrorCode && !payload) {
|
|
718
|
+
payload = this.getErrorPayloadForClientErrorCode({
|
|
607
719
|
clientErrorCode,
|
|
608
720
|
serviceErrorCode,
|
|
609
721
|
rawErrorMessage,
|
|
@@ -612,8 +724,8 @@ export default class CallDiagnosticMetrics extends StatelessWebexPlugin {
|
|
|
612
724
|
}
|
|
613
725
|
|
|
614
726
|
// by default, if it is locus error, return new locus err
|
|
615
|
-
if (isLocusServiceErrorCode(serviceErrorCode)) {
|
|
616
|
-
|
|
727
|
+
if (isLocusServiceErrorCode(serviceErrorCode) && !payload) {
|
|
728
|
+
payload = this.getErrorPayloadForClientErrorCode({
|
|
617
729
|
clientErrorCode: NEW_LOCUS_ERROR_CLIENT_CODE,
|
|
618
730
|
serviceErrorCode,
|
|
619
731
|
rawErrorMessage,
|
|
@@ -622,8 +734,8 @@ export default class CallDiagnosticMetrics extends StatelessWebexPlugin {
|
|
|
622
734
|
}
|
|
623
735
|
}
|
|
624
736
|
|
|
625
|
-
if (isMeetingInfoServiceError(rawError)) {
|
|
626
|
-
|
|
737
|
+
if (isMeetingInfoServiceError(rawError) && !payload) {
|
|
738
|
+
payload = this.getErrorPayloadForClientErrorCode({
|
|
627
739
|
clientErrorCode: MEETING_INFO_LOOKUP_ERROR_CLIENT_CODE,
|
|
628
740
|
serviceErrorCode,
|
|
629
741
|
rawErrorMessage,
|
|
@@ -631,8 +743,8 @@ export default class CallDiagnosticMetrics extends StatelessWebexPlugin {
|
|
|
631
743
|
});
|
|
632
744
|
}
|
|
633
745
|
|
|
634
|
-
if (isNetworkError(rawError)) {
|
|
635
|
-
|
|
746
|
+
if (isNetworkError(rawError) && !payload) {
|
|
747
|
+
payload = this.getErrorPayloadForClientErrorCode({
|
|
636
748
|
clientErrorCode: NETWORK_ERROR,
|
|
637
749
|
serviceErrorCode,
|
|
638
750
|
payloadOverrides: rawError.payloadOverrides,
|
|
@@ -641,8 +753,8 @@ export default class CallDiagnosticMetrics extends StatelessWebexPlugin {
|
|
|
641
753
|
});
|
|
642
754
|
}
|
|
643
755
|
|
|
644
|
-
if (isUnauthorizedError(rawError)) {
|
|
645
|
-
|
|
756
|
+
if (isUnauthorizedError(rawError) && !payload) {
|
|
757
|
+
payload = this.getErrorPayloadForClientErrorCode({
|
|
646
758
|
clientErrorCode: AUTHENTICATION_FAILED_CODE,
|
|
647
759
|
serviceErrorCode,
|
|
648
760
|
payloadOverrides: rawError.payloadOverrides,
|
|
@@ -651,32 +763,39 @@ export default class CallDiagnosticMetrics extends StatelessWebexPlugin {
|
|
|
651
763
|
});
|
|
652
764
|
}
|
|
653
765
|
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
766
|
+
if (!payload) {
|
|
767
|
+
// otherwise return unkown error but passing serviceErrorCode and serviceErrorName so that we know the issue
|
|
768
|
+
payload = this.getErrorPayloadForClientErrorCode({
|
|
769
|
+
clientErrorCode: UNKNOWN_ERROR,
|
|
770
|
+
serviceErrorCode: serviceErrorCode || UNKNOWN_ERROR,
|
|
771
|
+
serviceErrorName: rawError?.name,
|
|
772
|
+
payloadOverrides: rawError.payloadOverrides,
|
|
773
|
+
rawErrorMessage,
|
|
774
|
+
httpStatusCode,
|
|
775
|
+
});
|
|
776
|
+
}
|
|
777
|
+
|
|
778
|
+
// cache the payload for future use
|
|
779
|
+
this.eventErrorCache.set(rawError, payload);
|
|
780
|
+
|
|
781
|
+
return [payload, false];
|
|
663
782
|
}
|
|
664
783
|
|
|
665
784
|
/**
|
|
666
|
-
* Create
|
|
667
|
-
* @param
|
|
668
|
-
* @param
|
|
669
|
-
* @param
|
|
785
|
+
* Create common object for in meeting events
|
|
786
|
+
* @param name
|
|
787
|
+
* @param options
|
|
788
|
+
* @param eventType - 'client' | 'feature'
|
|
670
789
|
* @returns object
|
|
671
790
|
*/
|
|
672
|
-
private
|
|
791
|
+
private createCommonEventObjectInMeeting({
|
|
673
792
|
name,
|
|
674
793
|
options,
|
|
675
|
-
|
|
794
|
+
eventType = 'client',
|
|
676
795
|
}: {
|
|
677
|
-
name:
|
|
796
|
+
name: string;
|
|
678
797
|
options?: SubmitClientEventOptions;
|
|
679
|
-
|
|
798
|
+
eventType?: 'client' | 'feature';
|
|
680
799
|
}) {
|
|
681
800
|
const {
|
|
682
801
|
meetingId,
|
|
@@ -691,16 +810,21 @@ export default class CallDiagnosticMetrics extends StatelessWebexPlugin {
|
|
|
691
810
|
|
|
692
811
|
if (!meeting) {
|
|
693
812
|
console.warn(
|
|
694
|
-
'Attempt to send
|
|
813
|
+
'Attempt to send common event but no meeting was found...',
|
|
695
814
|
`name: ${name}, meetingId: ${meetingId}`
|
|
696
815
|
);
|
|
697
816
|
// @ts-ignore
|
|
698
|
-
this.webex.internal.metrics.submitClientMetrics(
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
817
|
+
this.webex.internal.metrics.submitClientMetrics(
|
|
818
|
+
eventType === 'feature'
|
|
819
|
+
? CALL_FEATURE_EVENT_FAILED_TO_SEND
|
|
820
|
+
: CALL_DIAGNOSTIC_EVENT_FAILED_TO_SEND,
|
|
821
|
+
{
|
|
822
|
+
fields: {
|
|
823
|
+
meetingId,
|
|
824
|
+
name,
|
|
825
|
+
},
|
|
826
|
+
}
|
|
827
|
+
);
|
|
704
828
|
|
|
705
829
|
return undefined;
|
|
706
830
|
}
|
|
@@ -714,12 +838,11 @@ export default class CallDiagnosticMetrics extends StatelessWebexPlugin {
|
|
|
714
838
|
sessionCorrelationId,
|
|
715
839
|
});
|
|
716
840
|
|
|
717
|
-
// create
|
|
718
|
-
const
|
|
841
|
+
// create common event object structur
|
|
842
|
+
const commonEventObject = {
|
|
719
843
|
name,
|
|
720
844
|
canProceed: true,
|
|
721
845
|
identifiers,
|
|
722
|
-
errors,
|
|
723
846
|
eventData: {
|
|
724
847
|
webClientDomain: window.location.hostname,
|
|
725
848
|
},
|
|
@@ -731,6 +854,8 @@ export default class CallDiagnosticMetrics extends StatelessWebexPlugin {
|
|
|
731
854
|
isConvergedArchitectureEnabled: this.getIsConvergedArchitectureEnabled({
|
|
732
855
|
meetingId,
|
|
733
856
|
}),
|
|
857
|
+
...(meeting.userNameInput && {userNameInput: meeting.userNameInput}),
|
|
858
|
+
...(meeting.emailInput && {emailInput: meeting.emailInput}),
|
|
734
859
|
webexSubServiceType: this.getSubServiceType(meeting),
|
|
735
860
|
// @ts-ignore
|
|
736
861
|
webClientPreload: this.webex.meetings?.config?.metrics?.webClientPreload,
|
|
@@ -738,14 +863,80 @@ export default class CallDiagnosticMetrics extends StatelessWebexPlugin {
|
|
|
738
863
|
|
|
739
864
|
const joinFlowVersion = options.joinFlowVersion ?? meeting.callStateForMetrics?.joinFlowVersion;
|
|
740
865
|
if (joinFlowVersion) {
|
|
741
|
-
|
|
866
|
+
// @ts-ignore
|
|
867
|
+
commonEventObject.joinFlowVersion = joinFlowVersion;
|
|
868
|
+
}
|
|
869
|
+
const meetingJoinedTime = meeting.isoLocalClientMeetingJoinTime;
|
|
870
|
+
if (meetingJoinedTime) {
|
|
871
|
+
// @ts-ignore
|
|
872
|
+
commonEventObject.meetingJoinedTime = meetingJoinedTime;
|
|
742
873
|
}
|
|
743
874
|
|
|
744
875
|
if (options.meetingJoinPhase) {
|
|
745
|
-
|
|
876
|
+
// @ts-ignore
|
|
877
|
+
commonEventObject.meetingJoinPhase = options.meetingJoinPhase;
|
|
746
878
|
}
|
|
747
879
|
|
|
748
|
-
return
|
|
880
|
+
return commonEventObject;
|
|
881
|
+
}
|
|
882
|
+
|
|
883
|
+
/**
|
|
884
|
+
* Create client event object for in meeting events
|
|
885
|
+
* @param arg - create args
|
|
886
|
+
* @param arg.event - event key
|
|
887
|
+
* @param arg.options - options
|
|
888
|
+
* @returns object
|
|
889
|
+
*/
|
|
890
|
+
private createClientEventObjectInMeeting({
|
|
891
|
+
name,
|
|
892
|
+
options,
|
|
893
|
+
errors,
|
|
894
|
+
}: {
|
|
895
|
+
name: ClientEvent['name'];
|
|
896
|
+
options?: SubmitClientEventOptions;
|
|
897
|
+
errors?: ClientEventPayloadError;
|
|
898
|
+
}) {
|
|
899
|
+
const commonObject = this.createCommonEventObjectInMeeting({
|
|
900
|
+
name,
|
|
901
|
+
options,
|
|
902
|
+
eventType: 'client',
|
|
903
|
+
});
|
|
904
|
+
if (!commonObject) return undefined;
|
|
905
|
+
|
|
906
|
+
return {
|
|
907
|
+
...commonObject,
|
|
908
|
+
errors,
|
|
909
|
+
eventData: {
|
|
910
|
+
...commonObject.eventData,
|
|
911
|
+
isMercuryConnected: this.isMercuryConnected,
|
|
912
|
+
},
|
|
913
|
+
} as ClientEvent['payload'];
|
|
914
|
+
}
|
|
915
|
+
|
|
916
|
+
/**
|
|
917
|
+
* Create feature event object for in meeting function event
|
|
918
|
+
* @param name
|
|
919
|
+
* @param options
|
|
920
|
+
* @returns object
|
|
921
|
+
*/
|
|
922
|
+
private createFeatureEventObjectInMeeting({
|
|
923
|
+
name,
|
|
924
|
+
options,
|
|
925
|
+
}: {
|
|
926
|
+
name: FeatureEvent['name'];
|
|
927
|
+
options?: SubmitClientEventOptions;
|
|
928
|
+
}) {
|
|
929
|
+
const commonObject = this.createCommonEventObjectInMeeting({
|
|
930
|
+
name,
|
|
931
|
+
options,
|
|
932
|
+
eventType: 'feature',
|
|
933
|
+
});
|
|
934
|
+
if (!commonObject) return undefined;
|
|
935
|
+
|
|
936
|
+
return {
|
|
937
|
+
...commonObject,
|
|
938
|
+
key: 'UcfFeatureUsage',
|
|
939
|
+
} as FeatureEvent['payload'];
|
|
749
940
|
}
|
|
750
941
|
|
|
751
942
|
/**
|
|
@@ -784,6 +975,7 @@ export default class CallDiagnosticMetrics extends StatelessWebexPlugin {
|
|
|
784
975
|
identifiers,
|
|
785
976
|
eventData: {
|
|
786
977
|
webClientDomain: window.location.hostname,
|
|
978
|
+
isMercuryConnected: this.isMercuryConnected,
|
|
787
979
|
},
|
|
788
980
|
loginType: this.getCurLoginType(),
|
|
789
981
|
// @ts-ignore
|
|
@@ -798,6 +990,14 @@ export default class CallDiagnosticMetrics extends StatelessWebexPlugin {
|
|
|
798
990
|
clientEventObject.meetingJoinPhase = options.meetingJoinPhase;
|
|
799
991
|
}
|
|
800
992
|
|
|
993
|
+
if (options.userNameInput) {
|
|
994
|
+
clientEventObject.userNameInput = options.userNameInput;
|
|
995
|
+
}
|
|
996
|
+
|
|
997
|
+
if (options.emailInput) {
|
|
998
|
+
clientEventObject.emailInput = options.emailInput;
|
|
999
|
+
}
|
|
1000
|
+
|
|
801
1001
|
return clientEventObject;
|
|
802
1002
|
}
|
|
803
1003
|
|
|
@@ -826,14 +1026,14 @@ export default class CallDiagnosticMetrics extends StatelessWebexPlugin {
|
|
|
826
1026
|
const errors: ClientEventPayloadError = [];
|
|
827
1027
|
|
|
828
1028
|
if (rawError) {
|
|
829
|
-
const generatedError = this.generateClientEventErrorPayload(rawError);
|
|
1029
|
+
const [generatedError, cached] = this.generateClientEventErrorPayload(rawError);
|
|
830
1030
|
if (generatedError) {
|
|
831
1031
|
errors.push(generatedError);
|
|
832
1032
|
}
|
|
833
1033
|
this.logger.log(
|
|
834
1034
|
CALL_DIAGNOSTIC_LOG_IDENTIFIER,
|
|
835
1035
|
'CallDiagnosticMetrics: @prepareClientEvent. Generated errors:',
|
|
836
|
-
`generatedError: ${JSON.stringify(generatedError)}`
|
|
1036
|
+
`generatedError (cached: ${cached}): ${JSON.stringify(generatedError)}`
|
|
837
1037
|
);
|
|
838
1038
|
}
|
|
839
1039
|
|
|
@@ -911,7 +1111,7 @@ export default class CallDiagnosticMetrics extends StatelessWebexPlugin {
|
|
|
911
1111
|
/**
|
|
912
1112
|
* Submit Delayed Client Event CA events. Clears delayedClientEvents array after submission.
|
|
913
1113
|
*/
|
|
914
|
-
public submitDelayedClientEvents() {
|
|
1114
|
+
public submitDelayedClientEvents(overrides?: Partial<DelayedClientEvent['options']>) {
|
|
915
1115
|
this.logger.log(
|
|
916
1116
|
CALL_DIAGNOSTIC_LOG_IDENTIFIER,
|
|
917
1117
|
'CallDiagnosticMetrics: @submitDelayedClientEvents. Submitting delayed client events.'
|
|
@@ -922,7 +1122,10 @@ export default class CallDiagnosticMetrics extends StatelessWebexPlugin {
|
|
|
922
1122
|
}
|
|
923
1123
|
|
|
924
1124
|
const promises = this.delayedClientEvents.map((delayedSubmitClientEventParams) => {
|
|
925
|
-
|
|
1125
|
+
const {name, payload, options} = delayedSubmitClientEventParams;
|
|
1126
|
+
const optionsWithOverrides: DelayedClientEvent['options'] = {...options, ...overrides};
|
|
1127
|
+
|
|
1128
|
+
return this.submitClientEvent({name, payload, options: optionsWithOverrides});
|
|
926
1129
|
});
|
|
927
1130
|
|
|
928
1131
|
this.delayedClientEvents = [];
|
|
@@ -930,6 +1133,31 @@ export default class CallDiagnosticMetrics extends StatelessWebexPlugin {
|
|
|
930
1133
|
return Promise.all(promises);
|
|
931
1134
|
}
|
|
932
1135
|
|
|
1136
|
+
/**
|
|
1137
|
+
* Submit Delayed feature Event CA events. Clears submitDelayedClientFeatureEvents array after submission.
|
|
1138
|
+
*/
|
|
1139
|
+
public submitDelayedClientFeatureEvents(overrides?: Partial<DelayedClientEvent['options']>) {
|
|
1140
|
+
this.logger.log(
|
|
1141
|
+
CALL_FEATURE_LOG_IDENTIFIER,
|
|
1142
|
+
'CallDiagnosticMetrics: @submitDelayedClientFeatureEvents. Submitting delayed feature events.'
|
|
1143
|
+
);
|
|
1144
|
+
|
|
1145
|
+
if (this.delayedClientFeatureEvents.length === 0) {
|
|
1146
|
+
return Promise.resolve();
|
|
1147
|
+
}
|
|
1148
|
+
|
|
1149
|
+
const promises = this.delayedClientFeatureEvents.map((delayedSubmitClientEventParams) => {
|
|
1150
|
+
const {name, payload, options} = delayedSubmitClientEventParams;
|
|
1151
|
+
const optionsWithOverrides: DelayedClientEvent['options'] = {...options, ...overrides};
|
|
1152
|
+
|
|
1153
|
+
return this.submitFeatureEvent({name, payload, options: optionsWithOverrides});
|
|
1154
|
+
});
|
|
1155
|
+
|
|
1156
|
+
this.delayedClientFeatureEvents = [];
|
|
1157
|
+
|
|
1158
|
+
return Promise.all(promises);
|
|
1159
|
+
}
|
|
1160
|
+
|
|
933
1161
|
/**
|
|
934
1162
|
* Prepare the event and send the request to metrics-a service.
|
|
935
1163
|
* @param event
|
|
@@ -257,6 +257,7 @@ export const prepareDiagnosticMetricItem = (webex: any, item: any) => {
|
|
|
257
257
|
switch (eventName) {
|
|
258
258
|
case 'client.webexapp.launched':
|
|
259
259
|
joinTimes.downloadTime = cdl.getDownloadTimeJMT();
|
|
260
|
+
joinTimes.pageJmt = cdl.getPageJMT();
|
|
260
261
|
break;
|
|
261
262
|
case 'client.login.end':
|
|
262
263
|
joinTimes.otherAppApiReqResp = cdl.getOtherAppApiReqResp();
|
|
@@ -267,6 +268,7 @@ export const prepareDiagnosticMetricItem = (webex: any, item: any) => {
|
|
|
267
268
|
joinTimes.clickToInterstitial = cdl.getClickToInterstitial();
|
|
268
269
|
joinTimes.refreshCaptchaServiceReqResp = cdl.getRefreshCaptchaReqResp();
|
|
269
270
|
joinTimes.downloadIntelligenceModelsReqResp = cdl.getDownloadIntelligenceModelsReqResp();
|
|
271
|
+
joinTimes.clickToInterstitialWithUserDelay = cdl.getClickToInterstitialWithUserDelay();
|
|
270
272
|
break;
|
|
271
273
|
|
|
272
274
|
case 'client.call.initiated':
|
|
@@ -287,6 +289,8 @@ export const prepareDiagnosticMetricItem = (webex: any, item: any) => {
|
|
|
287
289
|
joinTimes.totalJmt = cdl.getTotalJMT();
|
|
288
290
|
joinTimes.clientJmt = cdl.getClientJMT();
|
|
289
291
|
joinTimes.downloadTime = cdl.getDownloadTimeJMT();
|
|
292
|
+
joinTimes.clickToInterstitialWithUserDelay = cdl.getClickToInterstitialWithUserDelay();
|
|
293
|
+
joinTimes.totalJMTWithUserDelay = cdl.getTotalJMTWithUserDelay();
|
|
290
294
|
break;
|
|
291
295
|
|
|
292
296
|
case 'client.ice.end':
|
|
@@ -307,6 +311,8 @@ export const prepareDiagnosticMetricItem = (webex: any, item: any) => {
|
|
|
307
311
|
joinTimes.interstitialToMediaOKJMT = cdl.getInterstitialToMediaOKJMT();
|
|
308
312
|
joinTimes.callInitMediaEngineReady = cdl.getCallInitMediaEngineReady();
|
|
309
313
|
joinTimes.stayLobbyTime = cdl.getStayLobbyTime();
|
|
314
|
+
joinTimes.totalMediaJMTWithUserDelay = cdl.getTotalMediaJMTWithUserDelay();
|
|
315
|
+
joinTimes.totalJMTWithUserDelay = cdl.getTotalJMTWithUserDelay();
|
|
310
316
|
break;
|
|
311
317
|
|
|
312
318
|
case 'client.media.tx.start':
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
import {ClientEventError, ClientSubServiceType} from '../metrics.types';
|
|
6
6
|
|
|
7
7
|
export const CALL_DIAGNOSTIC_LOG_IDENTIFIER = 'call-diagnostic-events -> ';
|
|
8
|
+
export const CALL_FEATURE_LOG_IDENTIFIER = 'call-diagnostic-events-feature -> ';
|
|
8
9
|
|
|
9
10
|
export const AUTHENTICATION_FAILED_CODE = 1010;
|
|
10
11
|
export const NETWORK_ERROR = 1026;
|
|
@@ -133,6 +134,7 @@ export const ERROR_DESCRIPTIONS = {
|
|
|
133
134
|
SDP_OFFER_CREATION_ERROR: 'SdpOfferCreationError',
|
|
134
135
|
SDP_OFFER_CREATION_ERROR_MISSING_CODEC: 'SdpOfferCreationErrorMissingCodec',
|
|
135
136
|
WDM_RESTRICTED_REGION: 'WdmRestrictedRegion',
|
|
137
|
+
USER_NOT_ALLOWED_JOIN_WEBINAR: 'UserNotAllowedJoinWebinar',
|
|
136
138
|
};
|
|
137
139
|
|
|
138
140
|
export const SERVICE_ERROR_CODES_TO_CLIENT_ERROR_CODES_MAP = {
|
|
@@ -151,6 +153,10 @@ export const SERVICE_ERROR_CODES_TO_CLIENT_ERROR_CODES_MAP = {
|
|
|
151
153
|
403004: 4005,
|
|
152
154
|
// Wrong password. Meeting is not allow to access since password error
|
|
153
155
|
403028: 4005,
|
|
156
|
+
// meeting is not allow to access since require panelist password
|
|
157
|
+
403025: 4005,
|
|
158
|
+
// wrong password. Meeting is not allow to access since panelist password error
|
|
159
|
+
403125: 4005,
|
|
154
160
|
// Wrong or expired permission. Meeting is not allow to access since permissionToken error or expire
|
|
155
161
|
403032: 4005,
|
|
156
162
|
// Meeting is required login for current user
|
|
@@ -202,6 +208,24 @@ export const SERVICE_ERROR_CODES_TO_CLIENT_ERROR_CODES_MAP = {
|
|
|
202
208
|
423013: 4005,
|
|
203
209
|
// Too many requests access
|
|
204
210
|
429005: 4100,
|
|
211
|
+
// Webinar: Meeting registration is required
|
|
212
|
+
403021: 4104,
|
|
213
|
+
// Webinar: Meeting registration is still pending
|
|
214
|
+
403022: 4104,
|
|
215
|
+
// Webinar: Meeting registration have been rejected
|
|
216
|
+
403024: 4104,
|
|
217
|
+
// Webinar: Registration ID verified failure
|
|
218
|
+
403137: 4104,
|
|
219
|
+
// Webinar: Registration ID input too many time,please input captcha code
|
|
220
|
+
423007: 4104,
|
|
221
|
+
// Webinar: Need to join meeting via webcast
|
|
222
|
+
403026: 4104,
|
|
223
|
+
// Webinar: Meeting join required registration ID
|
|
224
|
+
403037: 4104,
|
|
225
|
+
// Not reach JBH, can't join meeting
|
|
226
|
+
403003: 4101,
|
|
227
|
+
// Attendee email is required
|
|
228
|
+
403030: 4101,
|
|
205
229
|
|
|
206
230
|
// ---- Locus ------
|
|
207
231
|
// FREE_USER_MAX_PARTICIPANTS_EXCEEDED
|
|
@@ -666,6 +690,11 @@ export const CLIENT_ERROR_CODE_TO_ERROR_PAYLOAD: Record<number, Partial<ClientEv
|
|
|
666
690
|
category: 'expected',
|
|
667
691
|
fatal: true,
|
|
668
692
|
},
|
|
693
|
+
4104: {
|
|
694
|
+
errorDescription: ERROR_DESCRIPTIONS.USER_NOT_ALLOWED_JOIN_WEBINAR,
|
|
695
|
+
category: 'expected',
|
|
696
|
+
fatal: true,
|
|
697
|
+
},
|
|
669
698
|
2729: {
|
|
670
699
|
errorDescription: ERROR_DESCRIPTIONS.NO_MEDIA_FOUND,
|
|
671
700
|
category: 'expected',
|
|
@@ -710,3 +739,5 @@ export const CLIENT_ERROR_CODE_TO_ERROR_PAYLOAD: Record<number, Partial<ClientEv
|
|
|
710
739
|
};
|
|
711
740
|
|
|
712
741
|
export const CALL_DIAGNOSTIC_EVENT_FAILED_TO_SEND = 'js_sdk_call_diagnostic_event_failed_to_send';
|
|
742
|
+
|
|
743
|
+
export const CALL_FEATURE_EVENT_FAILED_TO_SEND = 'js_sdk_call_feature_event_failed_to_send';
|
package/src/index.ts
CHANGED
|
@@ -15,8 +15,10 @@ import {
|
|
|
15
15
|
SubmitClientEvent,
|
|
16
16
|
SubmitInternalEvent,
|
|
17
17
|
SubmitOperationalEvent,
|
|
18
|
+
SubmitBusinessEvent,
|
|
18
19
|
SubmitMQE,
|
|
19
20
|
PreComputedLatencies,
|
|
21
|
+
SubmitFeatureEvent,
|
|
20
22
|
} from './metrics.types';
|
|
21
23
|
import * as CALL_DIAGNOSTIC_CONFIG from './call-diagnostic/config';
|
|
22
24
|
import * as CallDiagnosticUtils from './call-diagnostic/call-diagnostic-metrics.util';
|
|
@@ -58,5 +60,7 @@ export type {
|
|
|
58
60
|
SubmitInternalEvent,
|
|
59
61
|
SubmitMQE,
|
|
60
62
|
SubmitOperationalEvent,
|
|
63
|
+
SubmitBusinessEvent,
|
|
61
64
|
PreComputedLatencies,
|
|
65
|
+
SubmitFeatureEvent,
|
|
62
66
|
};
|