@webex/internal-plugin-metrics 3.4.0 → 3.5.0-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/behavioral-metrics.js +63 -0
- package/dist/behavioral-metrics.js.map +1 -0
- package/dist/business-metrics.js +169 -0
- package/dist/business-metrics.js.map +1 -0
- package/dist/call-diagnostic/call-diagnostic-metrics-latencies.js +1 -1
- package/dist/call-diagnostic/call-diagnostic-metrics-latencies.js.map +1 -1
- package/dist/call-diagnostic/call-diagnostic-metrics.js +27 -11
- package/dist/call-diagnostic/call-diagnostic-metrics.js.map +1 -1
- package/dist/call-diagnostic/call-diagnostic-metrics.util.js +14 -4
- package/dist/call-diagnostic/call-diagnostic-metrics.util.js.map +1 -1
- package/dist/call-diagnostic/config.js +13 -3
- package/dist/call-diagnostic/config.js.map +1 -1
- package/dist/{behavioral/behavioral-metrics.js → generic-metrics.js} +77 -92
- package/dist/generic-metrics.js.map +1 -0
- package/dist/index.js +22 -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 +124 -24
- package/dist/new-metrics.js.map +1 -1
- package/dist/operational-metrics.js +56 -0
- package/dist/operational-metrics.js.map +1 -0
- package/dist/rtcMetrics/constants.js +11 -0
- package/dist/rtcMetrics/constants.js.map +1 -0
- package/dist/rtcMetrics/index.js +202 -0
- package/dist/rtcMetrics/index.js.map +1 -0
- package/dist/types/behavioral-metrics.d.ts +25 -0
- package/dist/types/business-metrics.d.ts +47 -0
- package/dist/types/call-diagnostic/call-diagnostic-metrics.d.ts +27 -6
- package/dist/types/call-diagnostic/call-diagnostic-metrics.util.d.ts +2 -1
- package/dist/types/call-diagnostic/config.d.ts +3 -0
- package/dist/types/generic-metrics.d.ts +63 -0
- package/dist/types/index.d.ts +5 -2
- package/dist/types/metrics.types.d.ts +27 -14
- package/dist/types/new-metrics.d.ts +42 -9
- package/dist/types/operational-metrics.d.ts +19 -0
- package/dist/types/rtcMetrics/constants.d.ts +4 -0
- package/dist/types/rtcMetrics/index.d.ts +71 -0
- package/package.json +12 -12
- package/src/behavioral-metrics.ts +40 -0
- package/src/business-metrics.ts +118 -0
- package/src/call-diagnostic/call-diagnostic-metrics-latencies.ts +1 -1
- package/src/call-diagnostic/call-diagnostic-metrics.ts +30 -9
- package/src/call-diagnostic/call-diagnostic-metrics.util.ts +17 -4
- package/src/call-diagnostic/config.ts +12 -0
- package/src/generic-metrics.ts +146 -0
- package/src/index.ts +7 -1
- package/src/metrics.types.ts +32 -16
- package/src/new-metrics.ts +100 -13
- package/src/operational-metrics.ts +24 -0
- package/src/rtcMetrics/constants.ts +3 -0
- package/src/rtcMetrics/index.ts +186 -0
- package/test/unit/spec/behavioral/behavioral-metrics.ts +51 -10
- package/test/unit/spec/business/business-metrics.ts +182 -0
- package/test/unit/spec/call-diagnostic/call-diagnostic-metrics-batcher.ts +2 -1
- package/test/unit/spec/call-diagnostic/call-diagnostic-metrics-latencies.ts +4 -6
- package/test/unit/spec/call-diagnostic/call-diagnostic-metrics.ts +418 -12
- package/test/unit/spec/call-diagnostic/call-diagnostic-metrics.util.ts +22 -8
- package/test/unit/spec/new-metrics.ts +32 -3
- package/test/unit/spec/operational/operational-metrics.ts +115 -0
- package/test/unit/spec/prelogin-metrics-batcher.ts +3 -1
- package/test/unit/spec/rtcMetrics/index.ts +155 -0
- package/dist/behavioral/behavioral-metrics.js.map +0 -1
- package/dist/behavioral/config.js +0 -11
- package/dist/behavioral/config.js.map +0 -1
- package/dist/types/behavioral/behavioral-metrics.d.ts +0 -63
- package/dist/types/behavioral/config.d.ts +0 -1
- package/src/behavioral/behavioral-metrics.ts +0 -179
- package/src/behavioral/config.ts +0 -3
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import {MetricEventProduct, MetricEventAgent, MetricEventVerb, EventPayload} from './metrics.types';
|
|
2
|
+
import GenericMetrics from './generic-metrics';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* @description Util class to handle Behavioral Metrics
|
|
6
|
+
* @export
|
|
7
|
+
* @class BehavioralMetrics
|
|
8
|
+
*/
|
|
9
|
+
export default class BehavioralMetrics extends GenericMetrics {
|
|
10
|
+
/**
|
|
11
|
+
* Submit a behavioral metric to our metrics endpoint.
|
|
12
|
+
* @param {MetricEventProduct} product the product from which the metric is being submitted, e.g. 'webex' web client, 'wxcc_desktop'
|
|
13
|
+
* @param {MetricEventAgent} agent the source of the action for this metric
|
|
14
|
+
* @param {string} target the 'thing' that this metric includes information about
|
|
15
|
+
* @param {MetricEventVerb} verb the action that this metric includes information about
|
|
16
|
+
* @param {EventPayload} payload information specific to this event. This should be flat, i.e. it should not include nested objects.
|
|
17
|
+
* @returns {Promise<any>}
|
|
18
|
+
*/
|
|
19
|
+
public submitBehavioralEvent({
|
|
20
|
+
product,
|
|
21
|
+
agent,
|
|
22
|
+
target,
|
|
23
|
+
verb,
|
|
24
|
+
payload,
|
|
25
|
+
}: {
|
|
26
|
+
product: MetricEventProduct;
|
|
27
|
+
agent: MetricEventAgent;
|
|
28
|
+
target: string;
|
|
29
|
+
verb: MetricEventVerb;
|
|
30
|
+
payload?: EventPayload;
|
|
31
|
+
}) {
|
|
32
|
+
const name = `${product}.${agent}.${target}.${verb}`;
|
|
33
|
+
const event = this.createTaggedEventObject({
|
|
34
|
+
type: ['behavioral'],
|
|
35
|
+
name,
|
|
36
|
+
payload,
|
|
37
|
+
});
|
|
38
|
+
this.submitEvent({kind: 'behavioral-events -> ', name, event});
|
|
39
|
+
}
|
|
40
|
+
}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import GenericMetrics from './generic-metrics';
|
|
2
|
+
import {EventPayload, Table} from './metrics.types';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* @description Util class to handle Buisness Metrics
|
|
6
|
+
* @export
|
|
7
|
+
* @class BusinessMetrics
|
|
8
|
+
*/
|
|
9
|
+
export default class BusinessMetrics extends GenericMetrics {
|
|
10
|
+
/**
|
|
11
|
+
* unfortunately, the pinot team does not allow changes to the schema of wbxapp_callend_metrics
|
|
12
|
+
* so we have to shim this layer specifically for this
|
|
13
|
+
* @param {EventPayload} payload payload of the metric
|
|
14
|
+
* @returns {Promise<any>}
|
|
15
|
+
*/
|
|
16
|
+
private submitCallEndEvent({payload}: {payload: EventPayload}) {
|
|
17
|
+
const event = {
|
|
18
|
+
type: ['business'],
|
|
19
|
+
eventPayload: {
|
|
20
|
+
key: 'callEnd',
|
|
21
|
+
client_timestamp: Date.now(),
|
|
22
|
+
appType: 'Web Client',
|
|
23
|
+
value: {
|
|
24
|
+
...payload,
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
return this.submitEvent({
|
|
30
|
+
kind: 'buisness-events:wbxapp_callend_metrics -> ',
|
|
31
|
+
name: 'wbxapp_callend_metrics',
|
|
32
|
+
event,
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Submit a buisness metric to our metrics endpoint, going to the default business_ucf table
|
|
38
|
+
* all event payload keys are converted into a hex string value
|
|
39
|
+
* unfortunately, the pinot team does not allow changes to the schema of business_metrics
|
|
40
|
+
* so we have to shim this layer specifically for this
|
|
41
|
+
* @param {string} name of the metric
|
|
42
|
+
* @param {EventPayload} payload payload of the metric
|
|
43
|
+
* @returns {Promise<any>}
|
|
44
|
+
*/
|
|
45
|
+
private submitBusinessMetricsEvent({name, payload}: {name: string; payload: EventPayload}) {
|
|
46
|
+
const event = {
|
|
47
|
+
type: ['business'],
|
|
48
|
+
eventPayload: {
|
|
49
|
+
key: name,
|
|
50
|
+
client_timestamp: Date.now(),
|
|
51
|
+
appType: 'Web Client',
|
|
52
|
+
value: {
|
|
53
|
+
...this.getContext(),
|
|
54
|
+
...this.getBrowserDetails(),
|
|
55
|
+
...payload,
|
|
56
|
+
},
|
|
57
|
+
},
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
return this.submitEvent({kind: 'buisness-events:business_metrics -> ', name, event});
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Submit a buisness metric to our metrics endpoint, going to the default business_ucf table
|
|
65
|
+
* all event payload keys are converted into a hex string value
|
|
66
|
+
* @param {string} name of the metric
|
|
67
|
+
* @param {EventPayload} user payload of the metric
|
|
68
|
+
* @returns {Promise<any>}
|
|
69
|
+
*/
|
|
70
|
+
private submitDefaultEvent({name, payload}: {name: string; payload: EventPayload}) {
|
|
71
|
+
const event = {
|
|
72
|
+
type: ['business'],
|
|
73
|
+
eventPayload: {
|
|
74
|
+
key: name,
|
|
75
|
+
appType: 'Web Client',
|
|
76
|
+
client_timestamp: Date.now(),
|
|
77
|
+
context: this.getContext(),
|
|
78
|
+
browserDetails: this.getBrowserDetails(),
|
|
79
|
+
value: payload,
|
|
80
|
+
},
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
return this.submitEvent({kind: 'buisness-events:default -> ', name, event});
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Submit a buisness metric to our metrics endpoint.
|
|
88
|
+
* routes to the correct table with the correct schema payload by table
|
|
89
|
+
* @param {string} name of the metric, ignored if going to wbxapp_callend_metrics
|
|
90
|
+
* @param {EventPayload} payload user payload of the metric
|
|
91
|
+
* @param {Table} table optional - to submit the metric to and adapt the sent schema
|
|
92
|
+
* @returns {Promise<any>}
|
|
93
|
+
*/
|
|
94
|
+
public submitBusinessEvent({
|
|
95
|
+
name,
|
|
96
|
+
payload,
|
|
97
|
+
table,
|
|
98
|
+
}: {
|
|
99
|
+
name: string;
|
|
100
|
+
payload: EventPayload;
|
|
101
|
+
table?: Table;
|
|
102
|
+
}): Promise<void> {
|
|
103
|
+
if (!table) {
|
|
104
|
+
table = 'default';
|
|
105
|
+
}
|
|
106
|
+
switch (table) {
|
|
107
|
+
case 'wbxapp_callend_metrics':
|
|
108
|
+
return this.submitCallEndEvent({payload});
|
|
109
|
+
case 'business_metrics':
|
|
110
|
+
return this.submitBusinessMetricsEvent({name, payload});
|
|
111
|
+
case 'business_ucf':
|
|
112
|
+
return this.submitDefaultEvent({name, payload});
|
|
113
|
+
case 'default':
|
|
114
|
+
default:
|
|
115
|
+
return this.submitDefaultEvent({name, payload});
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
@@ -49,7 +49,7 @@ export default class CallDiagnosticLatencies extends WebexPlugin {
|
|
|
49
49
|
private getMeeting() {
|
|
50
50
|
if (this.meetingId) {
|
|
51
51
|
// @ts-ignore
|
|
52
|
-
return this.webex.meetings.
|
|
52
|
+
return this.webex.meetings.getBasicMeetingInformation(this.meetingId);
|
|
53
53
|
}
|
|
54
54
|
|
|
55
55
|
return undefined;
|
|
@@ -75,6 +75,7 @@ type GetIdentifiersOptions = {
|
|
|
75
75
|
meeting?: any;
|
|
76
76
|
mediaConnections?: any[];
|
|
77
77
|
correlationId?: string;
|
|
78
|
+
sessionCorrelationId?: string;
|
|
78
79
|
preLoginId?: string;
|
|
79
80
|
globalMeetingId?: string;
|
|
80
81
|
webexConferenceIdStr?: string;
|
|
@@ -138,7 +139,7 @@ export default class CallDiagnosticMetrics extends StatelessWebexPlugin {
|
|
|
138
139
|
getIsConvergedArchitectureEnabled({meetingId}: {meetingId?: string}): boolean {
|
|
139
140
|
if (meetingId) {
|
|
140
141
|
// @ts-ignore
|
|
141
|
-
const meeting = this.webex.meetings.
|
|
142
|
+
const meeting = this.webex.meetings.getBasicMeetingInformation(meetingId);
|
|
142
143
|
|
|
143
144
|
return meeting?.meetingInfo?.enableConvergedArchitecture;
|
|
144
145
|
}
|
|
@@ -244,7 +245,7 @@ export default class CallDiagnosticMetrics extends StatelessWebexPlugin {
|
|
|
244
245
|
|
|
245
246
|
if (meetingId) {
|
|
246
247
|
// @ts-ignore
|
|
247
|
-
const meeting = this.webex.meetings.
|
|
248
|
+
const meeting = this.webex.meetings.getBasicMeetingInformation(meetingId);
|
|
248
249
|
if (meeting?.environment) {
|
|
249
250
|
origin.environment = meeting.environment;
|
|
250
251
|
}
|
|
@@ -285,19 +286,29 @@ export default class CallDiagnosticMetrics extends StatelessWebexPlugin {
|
|
|
285
286
|
webexConferenceIdStr,
|
|
286
287
|
globalMeetingId,
|
|
287
288
|
preLoginId,
|
|
289
|
+
sessionCorrelationId,
|
|
288
290
|
} = options;
|
|
289
291
|
const identifiers: Event['event']['identifiers'] = {
|
|
290
|
-
correlationId: 'unknown',
|
|
292
|
+
correlationId: 'unknown', // concerned with setting this to unknown. This will fail diagnostic events parsing because it's not a uuid pattern
|
|
291
293
|
};
|
|
292
294
|
|
|
293
295
|
if (meeting) {
|
|
294
296
|
identifiers.correlationId = meeting.correlationId;
|
|
297
|
+
if (meeting.sessionCorrelationId) {
|
|
298
|
+
identifiers.sessionCorrelationId = meeting.sessionCorrelationId;
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
if (sessionCorrelationId) {
|
|
303
|
+
identifiers.sessionCorrelationId = sessionCorrelationId;
|
|
295
304
|
}
|
|
296
305
|
|
|
297
306
|
if (correlationId) {
|
|
298
307
|
identifiers.correlationId = correlationId;
|
|
299
308
|
}
|
|
300
309
|
|
|
310
|
+
// TODO: should we use patterns.uuid to validate correlationId and session correlation id? they will fail the diagnostic events validation pipeline if improperly formatted
|
|
311
|
+
|
|
301
312
|
if (this.device) {
|
|
302
313
|
const {device} = this;
|
|
303
314
|
const {installationId} = device?.config || {};
|
|
@@ -419,7 +430,7 @@ export default class CallDiagnosticMetrics extends StatelessWebexPlugin {
|
|
|
419
430
|
// events that will most likely happen in join phase
|
|
420
431
|
if (meetingId) {
|
|
421
432
|
// @ts-ignore
|
|
422
|
-
const meeting = this.webex.meetings.
|
|
433
|
+
const meeting = this.webex.meetings.getBasicMeetingInformation(meetingId);
|
|
423
434
|
|
|
424
435
|
if (!meeting) {
|
|
425
436
|
console.warn(
|
|
@@ -620,10 +631,11 @@ export default class CallDiagnosticMetrics extends StatelessWebexPlugin {
|
|
|
620
631
|
});
|
|
621
632
|
}
|
|
622
633
|
|
|
623
|
-
// otherwise return unkown error
|
|
634
|
+
// otherwise return unkown error but passing serviceErrorCode and serviceErrorName so that we know the issue
|
|
624
635
|
return this.getErrorPayloadForClientErrorCode({
|
|
625
636
|
clientErrorCode: UNKNOWN_ERROR,
|
|
626
|
-
serviceErrorCode: UNKNOWN_ERROR,
|
|
637
|
+
serviceErrorCode: serviceErrorCode || UNKNOWN_ERROR,
|
|
638
|
+
serviceErrorName: rawError?.name,
|
|
627
639
|
payloadOverrides: rawError.payloadOverrides,
|
|
628
640
|
rawErrorMessage,
|
|
629
641
|
httpStatusCode,
|
|
@@ -646,10 +658,16 @@ export default class CallDiagnosticMetrics extends StatelessWebexPlugin {
|
|
|
646
658
|
options?: SubmitClientEventOptions;
|
|
647
659
|
errors?: ClientEventPayloadError;
|
|
648
660
|
}) {
|
|
649
|
-
const {
|
|
661
|
+
const {
|
|
662
|
+
meetingId,
|
|
663
|
+
mediaConnections,
|
|
664
|
+
globalMeetingId,
|
|
665
|
+
webexConferenceIdStr,
|
|
666
|
+
sessionCorrelationId,
|
|
667
|
+
} = options;
|
|
650
668
|
|
|
651
669
|
// @ts-ignore
|
|
652
|
-
const meeting = this.webex.meetings.
|
|
670
|
+
const meeting = this.webex.meetings.getBasicMeetingInformation(meetingId);
|
|
653
671
|
|
|
654
672
|
if (!meeting) {
|
|
655
673
|
console.warn(
|
|
@@ -673,6 +691,7 @@ export default class CallDiagnosticMetrics extends StatelessWebexPlugin {
|
|
|
673
691
|
mediaConnections: meeting?.mediaConnections || mediaConnections,
|
|
674
692
|
webexConferenceIdStr,
|
|
675
693
|
globalMeetingId,
|
|
694
|
+
sessionCorrelationId,
|
|
676
695
|
});
|
|
677
696
|
|
|
678
697
|
// create client event object
|
|
@@ -714,11 +733,13 @@ export default class CallDiagnosticMetrics extends StatelessWebexPlugin {
|
|
|
714
733
|
options?: SubmitClientEventOptions;
|
|
715
734
|
errors?: ClientEventPayloadError;
|
|
716
735
|
}) {
|
|
717
|
-
const {correlationId, globalMeetingId, webexConferenceIdStr, preLoginId} =
|
|
736
|
+
const {correlationId, globalMeetingId, webexConferenceIdStr, preLoginId, sessionCorrelationId} =
|
|
737
|
+
options;
|
|
718
738
|
|
|
719
739
|
// grab identifiers
|
|
720
740
|
const identifiers = this.getIdentifiers({
|
|
721
741
|
correlationId,
|
|
742
|
+
sessionCorrelationId,
|
|
722
743
|
preLoginId,
|
|
723
744
|
globalMeetingId,
|
|
724
745
|
webexConferenceIdStr,
|
|
@@ -195,10 +195,12 @@ export const isBrowserMediaErrorName = (errorName: any) => {
|
|
|
195
195
|
};
|
|
196
196
|
|
|
197
197
|
/**
|
|
198
|
+
* @param {Object} webex sdk instance
|
|
198
199
|
* @param webClientDomain
|
|
199
200
|
* @returns
|
|
200
201
|
*/
|
|
201
202
|
export const getBuildType = (
|
|
203
|
+
webex,
|
|
202
204
|
webClientDomain,
|
|
203
205
|
markAsTestEvent = false
|
|
204
206
|
): Event['origin']['buildType'] => {
|
|
@@ -207,6 +209,10 @@ export const getBuildType = (
|
|
|
207
209
|
return 'test';
|
|
208
210
|
}
|
|
209
211
|
|
|
212
|
+
if (webex.internal.metrics?.config?.caBuildType) {
|
|
213
|
+
return webex.internal.metrics.config.caBuildType;
|
|
214
|
+
}
|
|
215
|
+
|
|
210
216
|
if (
|
|
211
217
|
webClientDomain?.includes('localhost') ||
|
|
212
218
|
webClientDomain?.includes('127.0.0.1') ||
|
|
@@ -225,12 +231,19 @@ export const getBuildType = (
|
|
|
225
231
|
* @returns {Object} prepared item
|
|
226
232
|
*/
|
|
227
233
|
export const prepareDiagnosticMetricItem = (webex: any, item: any) => {
|
|
234
|
+
const buildType = getBuildType(
|
|
235
|
+
webex,
|
|
236
|
+
item.eventPayload?.event?.eventData?.webClientDomain,
|
|
237
|
+
item.eventPayload?.event?.eventData?.markAsTestEvent
|
|
238
|
+
);
|
|
239
|
+
|
|
240
|
+
// Set upgradeChannel to 'gold' if buildType is 'prod', otherwise to the buildType value
|
|
241
|
+
const upgradeChannel = buildType === 'prod' ? 'gold' : buildType;
|
|
242
|
+
|
|
228
243
|
const origin: Partial<Event['origin']> = {
|
|
229
|
-
buildType
|
|
230
|
-
item.eventPayload?.event?.eventData?.webClientDomain,
|
|
231
|
-
item.eventPayload?.event?.eventData?.markAsTestEvent
|
|
232
|
-
),
|
|
244
|
+
buildType,
|
|
233
245
|
networkType: 'unknown',
|
|
246
|
+
upgradeChannel,
|
|
234
247
|
};
|
|
235
248
|
|
|
236
249
|
// check event names and append latencies?
|
|
@@ -129,6 +129,7 @@ export const ERROR_DESCRIPTIONS = {
|
|
|
129
129
|
ICE_AND_REACHABILITY_FAILED: 'ICEAndReachabilityFailed',
|
|
130
130
|
SDP_OFFER_CREATION_ERROR: 'SdpOfferCreationError',
|
|
131
131
|
SDP_OFFER_CREATION_ERROR_MISSING_CODEC: 'SdpOfferCreationErrorMissingCodec',
|
|
132
|
+
WDM_RESTRICTED_REGION: 'WdmRestrictedRegion',
|
|
132
133
|
};
|
|
133
134
|
|
|
134
135
|
export const SERVICE_ERROR_CODES_TO_CLIENT_ERROR_CODES_MAP = {
|
|
@@ -288,6 +289,12 @@ export const SERVICE_ERROR_CODES_TO_CLIENT_ERROR_CODES_MAP = {
|
|
|
288
289
|
100005: 4103, // Depracated because of an issue in the UCF Clients
|
|
289
290
|
// If both email-hash and domain-hash are null or undefined.
|
|
290
291
|
100004: 4103,
|
|
292
|
+
|
|
293
|
+
// ---- WDM ----
|
|
294
|
+
// WDM_BLOCKED_ACCESS_BY_COUNTRY_CODE_BANNED_COUNTRY_ERROR_CODE
|
|
295
|
+
4404002: 13000,
|
|
296
|
+
// WDM_BLOCKED_ACCESS_BY_COUNTRY_CODE_RESTRICTED_COUNTRY_ERROR_CODE
|
|
297
|
+
4404003: 13000,
|
|
291
298
|
};
|
|
292
299
|
|
|
293
300
|
export const CLIENT_ERROR_CODE_TO_ERROR_PAYLOAD: Record<number, Partial<ClientEventError>> = {
|
|
@@ -687,6 +694,11 @@ export const CLIENT_ERROR_CODE_TO_ERROR_PAYLOAD: Record<number, Partial<ClientEv
|
|
|
687
694
|
category: 'expected',
|
|
688
695
|
fatal: true,
|
|
689
696
|
},
|
|
697
|
+
13000: {
|
|
698
|
+
errorDescription: ERROR_DESCRIPTIONS.WDM_RESTRICTED_REGION,
|
|
699
|
+
category: 'expected',
|
|
700
|
+
fatal: true,
|
|
701
|
+
},
|
|
690
702
|
};
|
|
691
703
|
|
|
692
704
|
export const CALL_DIAGNOSTIC_EVENT_FAILED_TO_SEND = 'js_sdk_call_diagnostic_event_failed_to_send';
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import {StatelessWebexPlugin} from '@webex/webex-core';
|
|
2
|
+
import {BrowserDetection} from '@webex/common';
|
|
3
|
+
import {merge} from 'lodash';
|
|
4
|
+
import ClientMetricsBatcher from './client-metrics-batcher';
|
|
5
|
+
import {getOSNameInternal} from './metrics';
|
|
6
|
+
import {DeviceContext, TaggedEvent, EventPayload, MetricType} from './metrics.types';
|
|
7
|
+
|
|
8
|
+
const {getOSVersion, getBrowserName, getBrowserVersion} = BrowserDetection();
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* @description top-level abstract class to handle Metrics and common routines.
|
|
12
|
+
* @export
|
|
13
|
+
* @class GenericMetrics
|
|
14
|
+
*/
|
|
15
|
+
export default abstract class GenericMetrics extends StatelessWebexPlugin {
|
|
16
|
+
// @ts-ignore
|
|
17
|
+
private clientMetricsBatcher: ClientMetricsBatcher;
|
|
18
|
+
private logger: any; // to avoid adding @ts-ignore everywhere
|
|
19
|
+
private device: any;
|
|
20
|
+
private version: string;
|
|
21
|
+
private deviceId = '';
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Constructor
|
|
25
|
+
* @param {any[]} args
|
|
26
|
+
*/
|
|
27
|
+
constructor(...args) {
|
|
28
|
+
super(...args);
|
|
29
|
+
// @ts-ignore
|
|
30
|
+
this.logger = this.webex.logger;
|
|
31
|
+
// @ts-ignore
|
|
32
|
+
this.clientMetricsBatcher = new ClientMetricsBatcher({}, {parent: this.webex});
|
|
33
|
+
// @ts-ignore
|
|
34
|
+
this.device = this.webex.internal.device;
|
|
35
|
+
// @ts-ignore
|
|
36
|
+
this.version = this.webex.version;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Submit a buisness metric to our metrics endpoint.
|
|
41
|
+
* @param {string} kind of metric for logging
|
|
42
|
+
* @param {string} name of the metric
|
|
43
|
+
* @param {object} event
|
|
44
|
+
* @returns {Promise<any>}
|
|
45
|
+
*/
|
|
46
|
+
protected submitEvent({kind, name, event}: {kind: string; name: string; event: object}) {
|
|
47
|
+
this.logger.log(kind, `@submitEvent. Submit event: ${name}`);
|
|
48
|
+
|
|
49
|
+
return this.clientMetricsBatcher.request(event);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Returns the deviceId from our registration with WDM.
|
|
54
|
+
* @returns {string} deviceId or empty string
|
|
55
|
+
*/
|
|
56
|
+
protected getDeviceId(): string {
|
|
57
|
+
if (this.deviceId === '') {
|
|
58
|
+
const {url} = this.device;
|
|
59
|
+
if (url && url.length !== 0) {
|
|
60
|
+
const n = url.lastIndexOf('/');
|
|
61
|
+
if (n !== -1) {
|
|
62
|
+
this.deviceId = url.substring(n + 1);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
return this.deviceId;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Returns the context object to be submitted with all metrics.
|
|
72
|
+
* @returns {DeviceContext}
|
|
73
|
+
*/
|
|
74
|
+
protected getContext(): DeviceContext {
|
|
75
|
+
return {
|
|
76
|
+
app: {
|
|
77
|
+
version: this.version,
|
|
78
|
+
},
|
|
79
|
+
device: {
|
|
80
|
+
id: this.getDeviceId(),
|
|
81
|
+
},
|
|
82
|
+
locale: window.navigator.language,
|
|
83
|
+
os: {
|
|
84
|
+
name: getOSNameInternal(),
|
|
85
|
+
version: getOSVersion(),
|
|
86
|
+
},
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Returns the browser details to be included with all metrics.
|
|
92
|
+
* @returns {object}
|
|
93
|
+
*/
|
|
94
|
+
protected getBrowserDetails(): object {
|
|
95
|
+
return {
|
|
96
|
+
browser: getBrowserName(),
|
|
97
|
+
browserHeight: window.innerHeight,
|
|
98
|
+
browserVersion: getBrowserVersion(),
|
|
99
|
+
browserWidth: window.innerWidth,
|
|
100
|
+
domain: window.location.hostname,
|
|
101
|
+
inIframe: window.self !== window.top,
|
|
102
|
+
locale: window.navigator.language,
|
|
103
|
+
os: getOSNameInternal(),
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Returns true once we have the deviceId we need to submit behavioral/operational/buisness events
|
|
109
|
+
* @returns {boolean}
|
|
110
|
+
*/
|
|
111
|
+
public isReadyToSubmitEvents(): boolean {
|
|
112
|
+
const deviceId = this.getDeviceId();
|
|
113
|
+
|
|
114
|
+
return deviceId && deviceId.length !== 0;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Creates the object to send to our metrics endpoint for a tagged event (i.e. behavoral or operational)
|
|
119
|
+
* @param {[MetricType]} list of event type (i.e. ['behavioral'], ['operational', 'behavioral'])
|
|
120
|
+
* @param {string} metric name
|
|
121
|
+
* @param {EventPayload} user payload
|
|
122
|
+
* @returns {EventPayload}
|
|
123
|
+
*/
|
|
124
|
+
protected createTaggedEventObject({
|
|
125
|
+
type,
|
|
126
|
+
name,
|
|
127
|
+
payload,
|
|
128
|
+
}: {
|
|
129
|
+
type: [MetricType];
|
|
130
|
+
name: string;
|
|
131
|
+
payload: EventPayload;
|
|
132
|
+
}): TaggedEvent {
|
|
133
|
+
let allTags: EventPayload = payload;
|
|
134
|
+
allTags = merge(allTags, this.getBrowserDetails());
|
|
135
|
+
|
|
136
|
+
const event = {
|
|
137
|
+
context: this.getContext(),
|
|
138
|
+
metricName: name,
|
|
139
|
+
tags: allTags,
|
|
140
|
+
timestamp: Date.now(),
|
|
141
|
+
type,
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
return event;
|
|
145
|
+
}
|
|
146
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -22,7 +22,10 @@ import * as CALL_DIAGNOSTIC_CONFIG from './call-diagnostic/config';
|
|
|
22
22
|
import * as CallDiagnosticUtils from './call-diagnostic/call-diagnostic-metrics.util';
|
|
23
23
|
import CallDiagnosticMetrics from './call-diagnostic/call-diagnostic-metrics';
|
|
24
24
|
import CallDiagnosticLatencies from './call-diagnostic/call-diagnostic-metrics-latencies';
|
|
25
|
-
import BehavioralMetrics from './behavioral
|
|
25
|
+
import BehavioralMetrics from './behavioral-metrics';
|
|
26
|
+
import OperationalMetrics from './operational-metrics';
|
|
27
|
+
import BusinessMetrics from './business-metrics';
|
|
28
|
+
import RtcMetrics from './rtcMetrics';
|
|
26
29
|
|
|
27
30
|
registerInternalPlugin('metrics', Metrics, {
|
|
28
31
|
config,
|
|
@@ -43,6 +46,9 @@ export {
|
|
|
43
46
|
CallDiagnosticLatencies,
|
|
44
47
|
CallDiagnosticMetrics,
|
|
45
48
|
BehavioralMetrics,
|
|
49
|
+
OperationalMetrics,
|
|
50
|
+
BusinessMetrics,
|
|
51
|
+
RtcMetrics,
|
|
46
52
|
};
|
|
47
53
|
export type {
|
|
48
54
|
ClientEvent,
|
package/src/metrics.types.ts
CHANGED
|
@@ -61,6 +61,7 @@ export type SubmitClientEventOptions = {
|
|
|
61
61
|
mediaConnections?: any[];
|
|
62
62
|
rawError?: any;
|
|
63
63
|
correlationId?: string;
|
|
64
|
+
sessionCorrelationId?: string;
|
|
64
65
|
preLoginId?: string;
|
|
65
66
|
environment?: EnvironmentType;
|
|
66
67
|
newEnvironmentType?: NewEnvironmentType;
|
|
@@ -102,7 +103,7 @@ export interface ClientEvent {
|
|
|
102
103
|
options?: SubmitClientEventOptions;
|
|
103
104
|
}
|
|
104
105
|
|
|
105
|
-
export interface
|
|
106
|
+
export interface DeviceContext {
|
|
106
107
|
app: {version: string};
|
|
107
108
|
device: {id: string};
|
|
108
109
|
locale: string;
|
|
@@ -112,23 +113,38 @@ export interface BehavioralEventContext {
|
|
|
112
113
|
};
|
|
113
114
|
}
|
|
114
115
|
|
|
115
|
-
export
|
|
116
|
-
|
|
116
|
+
export type MetricType = 'behavioral' | 'operational' | 'business';
|
|
117
|
+
|
|
118
|
+
export type Table = 'wbxapp_callend_metrics' | 'business_metrics' | 'business_ucf' | 'default';
|
|
119
|
+
|
|
120
|
+
type InternalEventPayload = string | number | boolean;
|
|
121
|
+
export type EventPayload = Record<string, InternalEventPayload>;
|
|
122
|
+
export type BehavioralEventPayload = EventPayload; // for compatibilty, can be remove after wxcc-desktop did change their imports.
|
|
123
|
+
|
|
124
|
+
export interface BusinessEventPayload {
|
|
117
125
|
metricName: string;
|
|
118
|
-
tags: Record<string, string | number | boolean>;
|
|
119
126
|
timestamp: number;
|
|
120
|
-
|
|
127
|
+
context: DeviceContext;
|
|
128
|
+
browserDetails: EventPayload;
|
|
129
|
+
value: EventPayload;
|
|
121
130
|
}
|
|
122
131
|
|
|
123
|
-
export
|
|
132
|
+
export interface BusinessEvent {
|
|
133
|
+
type: string[];
|
|
134
|
+
eventPayload: BusinessEventPayload;
|
|
135
|
+
}
|
|
124
136
|
|
|
125
|
-
export interface
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
137
|
+
export interface TaggedEvent {
|
|
138
|
+
context: DeviceContext;
|
|
139
|
+
metricName: string;
|
|
140
|
+
tags: EventPayload;
|
|
141
|
+
timestamp: number;
|
|
142
|
+
type: [MetricType];
|
|
130
143
|
}
|
|
131
144
|
|
|
145
|
+
export type BehavioralEvent = TaggedEvent;
|
|
146
|
+
export type OperationalEvent = TaggedEvent;
|
|
147
|
+
|
|
132
148
|
export interface FeatureEvent {
|
|
133
149
|
// TODO: not implemented
|
|
134
150
|
name: never;
|
|
@@ -154,7 +170,8 @@ export type MetricEventNames =
|
|
|
154
170
|
| InternalEvent['name']
|
|
155
171
|
| ClientEvent['name']
|
|
156
172
|
| BehavioralEvent['metricName']
|
|
157
|
-
| OperationalEvent['
|
|
173
|
+
| OperationalEvent['metricName']
|
|
174
|
+
| BusinessEvent['eventPayload']['metricName']
|
|
158
175
|
| FeatureEvent['name']
|
|
159
176
|
| MediaQualityEvent['name'];
|
|
160
177
|
|
|
@@ -190,7 +207,7 @@ export type SubmitBehavioralEvent = (args: {
|
|
|
190
207
|
agent: MetricEventAgent;
|
|
191
208
|
target: string;
|
|
192
209
|
verb: MetricEventVerb;
|
|
193
|
-
payload?:
|
|
210
|
+
payload?: EventPayload;
|
|
194
211
|
}) => void;
|
|
195
212
|
|
|
196
213
|
export type SubmitClientEvent = (args: {
|
|
@@ -200,9 +217,8 @@ export type SubmitClientEvent = (args: {
|
|
|
200
217
|
}) => Promise<any>;
|
|
201
218
|
|
|
202
219
|
export type SubmitOperationalEvent = (args: {
|
|
203
|
-
name: OperationalEvent['
|
|
204
|
-
payload
|
|
205
|
-
options?: any;
|
|
220
|
+
name: OperationalEvent['metricName'];
|
|
221
|
+
payload: EventPayload;
|
|
206
222
|
}) => void;
|
|
207
223
|
|
|
208
224
|
export type SubmitMQE = (args: {
|