@webex/internal-plugin-metrics 3.7.0-next.1 → 3.7.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/business-metrics.js +74 -100
- package/dist/business-metrics.js.map +1 -1
- package/dist/call-diagnostic/call-diagnostic-metrics-latencies.js +5 -1
- package/dist/call-diagnostic/call-diagnostic-metrics-latencies.js.map +1 -1
- package/dist/call-diagnostic/call-diagnostic-metrics.js +9 -2
- package/dist/call-diagnostic/call-diagnostic-metrics.js.map +1 -1
- package/dist/call-diagnostic/config.js +17 -11
- package/dist/call-diagnostic/config.js.map +1 -1
- package/dist/generic-metrics.js +2 -2
- package/dist/generic-metrics.js.map +1 -1
- package/dist/metrics.js +1 -1
- package/dist/metrics.types.js.map +1 -1
- package/dist/new-metrics.js +6 -4
- package/dist/new-metrics.js.map +1 -1
- package/dist/types/business-metrics.d.ts +10 -28
- package/dist/types/call-diagnostic/call-diagnostic-metrics.d.ts +4 -0
- package/dist/types/call-diagnostic/config.d.ts +2 -0
- package/dist/types/generic-metrics.d.ts +2 -2
- package/dist/types/metrics.types.d.ts +3 -0
- package/dist/types/new-metrics.d.ts +4 -3
- package/package.json +12 -12
- package/src/business-metrics.ts +66 -76
- package/src/call-diagnostic/call-diagnostic-metrics-latencies.ts +6 -1
- package/src/call-diagnostic/call-diagnostic-metrics.ts +10 -2
- package/src/call-diagnostic/config.ts +7 -0
- package/src/generic-metrics.ts +2 -2
- package/src/metrics.types.ts +3 -0
- package/src/new-metrics.ts +5 -3
- package/test/unit/spec/business/business-metrics.ts +2 -2
- package/test/unit/spec/call-diagnostic/call-diagnostic-metrics-latencies.ts +12 -0
- package/test/unit/spec/call-diagnostic/call-diagnostic-metrics.ts +60 -2
- package/test/unit/spec/new-metrics.ts +2 -0
|
@@ -17,7 +17,7 @@ export default abstract class GenericMetrics extends StatelessWebexPlugin {
|
|
|
17
17
|
*/
|
|
18
18
|
constructor(...args: any[]);
|
|
19
19
|
/**
|
|
20
|
-
* Submit a
|
|
20
|
+
* Submit a business metric to our metrics endpoint.
|
|
21
21
|
* @param {string} kind of metric for logging
|
|
22
22
|
* @param {string} name of the metric
|
|
23
23
|
* @param {object} event
|
|
@@ -44,7 +44,7 @@ export default abstract class GenericMetrics extends StatelessWebexPlugin {
|
|
|
44
44
|
*/
|
|
45
45
|
protected getBrowserDetails(): object;
|
|
46
46
|
/**
|
|
47
|
-
* Returns true once we have the deviceId we need to submit behavioral/operational/
|
|
47
|
+
* Returns true once we have the deviceId we need to submit behavioral/operational/business events
|
|
48
48
|
* @returns {boolean}
|
|
49
49
|
*/
|
|
50
50
|
isReadyToSubmitEvents(): boolean;
|
|
@@ -11,6 +11,7 @@ export type MetricEventProduct = 'webex' | 'wxcc_desktop';
|
|
|
11
11
|
export type MetricEventAgent = 'user' | 'browser' | 'system' | 'sdk' | 'redux' | 'service' | 'api';
|
|
12
12
|
export type MetricEventVerb = 'abort' | 'accept' | 'activate' | 'apply' | 'answer' | 'authorize' | 'build' | 'cancel' | 'change' | 'click' | 'close' | 'complete' | 'connect' | 'create' | 'deactivate' | 'decrypt' | 'delete' | 'deliver' | 'destroy' | 'disable' | 'disconnect' | 'dismiss' | 'display' | 'download' | 'edit' | 'enable' | 'encrypt' | 'end' | 'expire' | 'fail' | 'fetch' | 'fire' | 'generate' | 'get' | 'hide' | 'hover' | 'ignore' | 'initialize' | 'initiate' | 'invalidate' | 'join' | 'list' | 'load' | 'login' | 'logout' | 'notify' | 'offer' | 'open' | 'press' | 'receive' | 'refer' | 'refresh' | 'register' | 'release' | 'reload' | 'reject' | 'request' | 'reset' | 'resize' | 'respond' | 'retry' | 'revoke' | 'save' | 'search' | 'select' | 'send' | 'set' | 'sign' | 'start' | 'submit' | 'switch' | 'sync' | 'toggle' | 'transfer' | 'unregister' | 'update' | 'upload' | 'use' | 'validate' | 'view' | 'visit' | 'wait' | 'warn' | 'exit';
|
|
13
13
|
export type MetricEventJoinFlowVersion = 'Other' | 'NewFTE';
|
|
14
|
+
export type MetricEventMeetingJoinPhase = 'pre-join' | 'join' | 'in-meeting';
|
|
14
15
|
export type SubmitClientEventOptions = {
|
|
15
16
|
meetingId?: string;
|
|
16
17
|
mediaConnections?: any[];
|
|
@@ -25,6 +26,8 @@ export type SubmitClientEventOptions = {
|
|
|
25
26
|
webexConferenceIdStr?: string;
|
|
26
27
|
globalMeetingId?: string;
|
|
27
28
|
joinFlowVersion?: MetricEventJoinFlowVersion;
|
|
29
|
+
meetingJoinPhase?: MetricEventMeetingJoinPhase;
|
|
30
|
+
triggeredTime?: string;
|
|
28
31
|
};
|
|
29
32
|
export type SubmitMQEOptions = {
|
|
30
33
|
meetingId: string;
|
|
@@ -60,7 +60,7 @@ declare class Metrics extends WebexPlugin {
|
|
|
60
60
|
*/
|
|
61
61
|
isReadyToSubmitOperationalEvents(): boolean;
|
|
62
62
|
/**
|
|
63
|
-
* @returns true once we have the deviceId we need to submit
|
|
63
|
+
* @returns true once we have the deviceId we need to submit business events
|
|
64
64
|
*/
|
|
65
65
|
isReadyToSubmitBusinessEvents(): boolean;
|
|
66
66
|
/**
|
|
@@ -83,13 +83,14 @@ declare class Metrics extends WebexPlugin {
|
|
|
83
83
|
payload?: EventPayload;
|
|
84
84
|
}): void | Promise<void>;
|
|
85
85
|
/**
|
|
86
|
-
*
|
|
86
|
+
* Business event
|
|
87
87
|
* @param args
|
|
88
88
|
*/
|
|
89
|
-
submitBusinessEvent({ name, payload, table, }: {
|
|
89
|
+
submitBusinessEvent({ name, payload, table, metadata, }: {
|
|
90
90
|
name: string;
|
|
91
91
|
payload: EventPayload;
|
|
92
92
|
table?: Table;
|
|
93
|
+
metadata?: EventPayload;
|
|
93
94
|
}): Promise<void>;
|
|
94
95
|
/**
|
|
95
96
|
* Call Analyzer: Media Quality Event
|
package/package.json
CHANGED
|
@@ -26,22 +26,22 @@
|
|
|
26
26
|
"@webex/eslint-config-legacy": "0.0.0",
|
|
27
27
|
"@webex/jest-config-legacy": "0.0.0",
|
|
28
28
|
"@webex/legacy-tools": "0.0.0",
|
|
29
|
-
"@webex/test-helper-chai": "3.7.0-next.
|
|
30
|
-
"@webex/test-helper-mocha": "3.7.0-next.
|
|
31
|
-
"@webex/test-helper-mock-webex": "3.7.0-next.
|
|
32
|
-
"@webex/test-helper-test-users": "3.7.0-next.
|
|
29
|
+
"@webex/test-helper-chai": "3.7.0-next.10",
|
|
30
|
+
"@webex/test-helper-mocha": "3.7.0-next.10",
|
|
31
|
+
"@webex/test-helper-mock-webex": "3.7.0-next.10",
|
|
32
|
+
"@webex/test-helper-test-users": "3.7.0-next.10",
|
|
33
33
|
"eslint": "^8.24.0",
|
|
34
34
|
"prettier": "^2.7.1",
|
|
35
35
|
"sinon": "^9.2.4"
|
|
36
36
|
},
|
|
37
37
|
"dependencies": {
|
|
38
|
-
"@webex/common": "3.7.0-next.
|
|
39
|
-
"@webex/common-timers": "3.7.0-next.
|
|
40
|
-
"@webex/event-dictionary-ts": "^1.0.
|
|
41
|
-
"@webex/internal-plugin-metrics": "3.7.0-next.
|
|
42
|
-
"@webex/test-helper-chai": "3.7.0-next.
|
|
43
|
-
"@webex/test-helper-mock-webex": "3.7.0-next.
|
|
44
|
-
"@webex/webex-core": "3.7.0-next.
|
|
38
|
+
"@webex/common": "3.7.0-next.10",
|
|
39
|
+
"@webex/common-timers": "3.7.0-next.10",
|
|
40
|
+
"@webex/event-dictionary-ts": "^1.0.1643",
|
|
41
|
+
"@webex/internal-plugin-metrics": "3.7.0-next.10",
|
|
42
|
+
"@webex/test-helper-chai": "3.7.0-next.10",
|
|
43
|
+
"@webex/test-helper-mock-webex": "3.7.0-next.10",
|
|
44
|
+
"@webex/webex-core": "3.7.0-next.10",
|
|
45
45
|
"ip-anonymize": "^0.1.0",
|
|
46
46
|
"lodash": "^4.17.21",
|
|
47
47
|
"uuid": "^3.3.2"
|
|
@@ -54,5 +54,5 @@
|
|
|
54
54
|
"test:style": "eslint ./src/**/*.*",
|
|
55
55
|
"test:unit": "webex-legacy-tools test --unit --runner mocha"
|
|
56
56
|
},
|
|
57
|
-
"version": "3.7.0-next.
|
|
57
|
+
"version": "3.7.0-next.10"
|
|
58
58
|
}
|
package/src/business-metrics.ts
CHANGED
|
@@ -2,121 +2,111 @@ import GenericMetrics from './generic-metrics';
|
|
|
2
2
|
import {EventPayload, Table} from './metrics.types';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
|
-
* @description Util class to handle
|
|
5
|
+
* @description Util class to handle Business Metrics
|
|
6
6
|
* @export
|
|
7
7
|
* @class BusinessMetrics
|
|
8
8
|
*/
|
|
9
9
|
export default class BusinessMetrics extends GenericMetrics {
|
|
10
10
|
/**
|
|
11
|
-
*
|
|
12
|
-
* so we have to shim this layer specifically for this
|
|
13
|
-
* https://confluence-eng-gpk2.cisco.com/conf/display/WAP/Table+wbxapp_callend_metrics
|
|
14
|
-
* @param {EventPayload} payload payload of the metric
|
|
15
|
-
* @returns {Promise<any>}
|
|
16
|
-
*/
|
|
17
|
-
private submitCallEndEvent({payload}: {payload: EventPayload}) {
|
|
18
|
-
const event = {
|
|
19
|
-
type: ['business'],
|
|
20
|
-
eventPayload: {
|
|
21
|
-
key: 'callEnd',
|
|
22
|
-
client_timestamp: new Date().toISOString(),
|
|
23
|
-
appType: 'Web Client',
|
|
24
|
-
value: {
|
|
25
|
-
...payload,
|
|
26
|
-
},
|
|
27
|
-
},
|
|
28
|
-
};
|
|
29
|
-
|
|
30
|
-
return this.submitEvent({
|
|
31
|
-
kind: 'buisness-events:wbxapp_callend_metrics -> ',
|
|
32
|
-
name: 'wbxapp_callend_metrics',
|
|
33
|
-
event,
|
|
34
|
-
});
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* Submit a buisness metric to our metrics endpoint, going to the default business_ucf table
|
|
39
|
-
* all event payload keys are converted into a hex string value
|
|
40
|
-
* unfortunately, the pinot team does not allow changes to the schema of business_metrics
|
|
41
|
-
* so we have to shim this layer specifically for this
|
|
42
|
-
* https://confluence-eng-gpk2.cisco.com/conf/display/WAP/Table%3A+business_metrics
|
|
11
|
+
* Build the metric event to submit.
|
|
43
12
|
* @param {string} name of the metric
|
|
44
|
-
* @param {EventPayload} payload payload of the metric
|
|
45
|
-
* @
|
|
46
|
-
|
|
47
|
-
private submitBusinessMetricsEvent({name, payload}: {name: string; payload: EventPayload}) {
|
|
48
|
-
const event = {
|
|
49
|
-
type: ['business'],
|
|
50
|
-
eventPayload: {
|
|
51
|
-
key: name,
|
|
52
|
-
client_timestamp: new Date().toISOString(),
|
|
53
|
-
appType: 'Web Client',
|
|
54
|
-
value: {
|
|
55
|
-
...this.getContext(),
|
|
56
|
-
...this.getBrowserDetails(),
|
|
57
|
-
...payload,
|
|
58
|
-
},
|
|
59
|
-
},
|
|
60
|
-
};
|
|
61
|
-
|
|
62
|
-
return this.submitEvent({kind: 'buisness-events:business_metrics -> ', name, event});
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
/**
|
|
66
|
-
* Submit a buisness metric to our metrics endpoint, going to the default business_ucf table
|
|
67
|
-
* all event payload keys are converted into a hex string value
|
|
68
|
-
* https://confluence-eng-gpk2.cisco.com/conf/display/WAP/Business+metrics++-%3E+ROMA
|
|
69
|
-
* @param {string} name of the metric
|
|
70
|
-
* @param {EventPayload} user payload of the metric
|
|
71
|
-
* @returns {Promise<any>}
|
|
13
|
+
* @param {EventPayload} payload user payload of the metric
|
|
14
|
+
* @param {EventPayload} metadata to include outside of eventPayload.value
|
|
15
|
+
* @returns {MetricEvent} The constructed metric event
|
|
72
16
|
*/
|
|
73
|
-
private
|
|
74
|
-
|
|
17
|
+
private buildEvent({name, payload, metadata}: {name: string; payload: object; metadata: object}) {
|
|
18
|
+
return {
|
|
75
19
|
type: ['business'],
|
|
76
20
|
eventPayload: {
|
|
77
21
|
key: name,
|
|
78
|
-
appType: 'Web Client',
|
|
79
22
|
client_timestamp: new Date().toISOString(),
|
|
80
|
-
|
|
81
|
-
browserDetails: this.getBrowserDetails(),
|
|
23
|
+
...metadata,
|
|
82
24
|
value: payload,
|
|
83
25
|
},
|
|
84
26
|
};
|
|
85
|
-
|
|
86
|
-
return this.submitEvent({kind: 'buisness-events:default -> ', name, event});
|
|
87
27
|
}
|
|
88
28
|
|
|
89
29
|
/**
|
|
90
|
-
* Submit a
|
|
30
|
+
* Submit a business metric to our metrics endpoint.
|
|
91
31
|
* routes to the correct table with the correct schema payload by table
|
|
92
32
|
* https://confluence-eng-gpk2.cisco.com/conf/display/WAP/Business+metrics++-%3E+ROMA
|
|
93
33
|
* @param {string} name of the metric, ignored if going to wbxapp_callend_metrics
|
|
94
34
|
* @param {EventPayload} payload user payload of the metric
|
|
95
35
|
* @param {Table} table optional - to submit the metric to and adapt the sent schema
|
|
36
|
+
* @param {EventPayload} metadata optional - to include outside of eventPayload.value
|
|
96
37
|
* @returns {Promise<any>}
|
|
97
38
|
*/
|
|
98
39
|
public submitBusinessEvent({
|
|
99
40
|
name,
|
|
100
41
|
payload,
|
|
101
42
|
table,
|
|
43
|
+
metadata,
|
|
102
44
|
}: {
|
|
103
45
|
name: string;
|
|
104
46
|
payload: EventPayload;
|
|
105
47
|
table?: Table;
|
|
48
|
+
metadata?: EventPayload;
|
|
106
49
|
}): Promise<void> {
|
|
107
50
|
if (!table) {
|
|
108
51
|
table = 'default';
|
|
109
52
|
}
|
|
53
|
+
if (!metadata) {
|
|
54
|
+
metadata = {};
|
|
55
|
+
}
|
|
56
|
+
if (!metadata.appType) {
|
|
57
|
+
metadata.appType = 'Web Client';
|
|
58
|
+
}
|
|
110
59
|
switch (table) {
|
|
111
|
-
case 'wbxapp_callend_metrics':
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
60
|
+
case 'wbxapp_callend_metrics': {
|
|
61
|
+
// https://confluence-eng-gpk2.cisco.com/conf/display/WAP/Table+wbxapp_callend_metrics
|
|
62
|
+
const callEndEvent = this.buildEvent({name: 'callEnd', payload, metadata});
|
|
63
|
+
|
|
64
|
+
return this.submitEvent({
|
|
65
|
+
kind: 'business-events:wbxapp_callend_metrics -> ',
|
|
66
|
+
name: 'wbxapp_callend_metrics',
|
|
67
|
+
event: callEndEvent,
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
case 'business_metrics': {
|
|
72
|
+
// all event payload keys are converted into a hex string value
|
|
73
|
+
// unfortunately, the pinot team does not allow changes to the schema of business_metrics
|
|
74
|
+
// so we have to shim this layer specifically for this
|
|
75
|
+
// https://confluence-eng-gpk2.cisco.com/conf/display/WAP/Table%3A+business_metrics
|
|
76
|
+
const businessEvent = this.buildEvent({
|
|
77
|
+
name,
|
|
78
|
+
payload: {
|
|
79
|
+
...this.getContext(),
|
|
80
|
+
...this.getBrowserDetails(),
|
|
81
|
+
...payload,
|
|
82
|
+
},
|
|
83
|
+
metadata,
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
return this.submitEvent({
|
|
87
|
+
kind: 'business-events:business_metrics -> ',
|
|
88
|
+
name,
|
|
89
|
+
event: businessEvent,
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
|
|
115
93
|
case 'business_ucf':
|
|
116
|
-
return this.submitDefaultEvent({name, payload});
|
|
117
94
|
case 'default':
|
|
118
|
-
default:
|
|
119
|
-
|
|
95
|
+
default: {
|
|
96
|
+
// all event payload keys are converted into a hex string value
|
|
97
|
+
// https://confluence-eng-gpk2.cisco.com/conf/display/WAP/Business+metrics++-%3E+ROMA
|
|
98
|
+
const defaultEvent = this.buildEvent({
|
|
99
|
+
name,
|
|
100
|
+
payload,
|
|
101
|
+
metadata: {
|
|
102
|
+
context: this.getContext(),
|
|
103
|
+
browserDetails: this.getBrowserDetails(),
|
|
104
|
+
...metadata,
|
|
105
|
+
},
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
return this.submitEvent({kind: 'business-events:default -> ', name, event: defaultEvent});
|
|
109
|
+
}
|
|
120
110
|
}
|
|
121
111
|
}
|
|
122
112
|
}
|
|
@@ -83,11 +83,16 @@ export default class CallDiagnosticLatencies extends WebexPlugin {
|
|
|
83
83
|
key === 'client.media.rx.start' ||
|
|
84
84
|
key === 'client.media.tx.start' ||
|
|
85
85
|
key === 'internal.client.meetinginfo.request' ||
|
|
86
|
-
key === 'internal.client.meetinginfo.response'
|
|
86
|
+
key === 'internal.client.meetinginfo.response' ||
|
|
87
|
+
key === 'client.media-engine.remote-sdp-received'
|
|
87
88
|
) {
|
|
88
89
|
this.saveFirstTimestampOnly(key, value);
|
|
89
90
|
} else {
|
|
90
91
|
this.latencyTimestamps.set(key, value);
|
|
92
|
+
// new offer/answer so reset the remote SDP timestamp
|
|
93
|
+
if (key === 'client.media-engine.local-sdp-generated') {
|
|
94
|
+
this.latencyTimestamps.delete('client.media-engine.remote-sdp-received');
|
|
95
|
+
}
|
|
91
96
|
}
|
|
92
97
|
}
|
|
93
98
|
|
|
@@ -377,7 +377,7 @@ export default class CallDiagnosticMetrics extends StatelessWebexPlugin {
|
|
|
377
377
|
* @returns
|
|
378
378
|
*/
|
|
379
379
|
prepareDiagnosticEvent(eventData: Event['event'], options: any) {
|
|
380
|
-
const {meetingId} = options;
|
|
380
|
+
const {meetingId, triggeredTime} = options;
|
|
381
381
|
const origin = this.getOrigin(options, meetingId);
|
|
382
382
|
|
|
383
383
|
const event: Event = {
|
|
@@ -385,7 +385,7 @@ export default class CallDiagnosticMetrics extends StatelessWebexPlugin {
|
|
|
385
385
|
version: 1,
|
|
386
386
|
origin,
|
|
387
387
|
originTime: {
|
|
388
|
-
triggered: new Date().toISOString(),
|
|
388
|
+
triggered: triggeredTime || new Date().toISOString(),
|
|
389
389
|
// is overridden in prepareRequest batcher
|
|
390
390
|
sent: 'not_defined_yet',
|
|
391
391
|
},
|
|
@@ -723,6 +723,10 @@ export default class CallDiagnosticMetrics extends StatelessWebexPlugin {
|
|
|
723
723
|
clientEventObject.joinFlowVersion = joinFlowVersion;
|
|
724
724
|
}
|
|
725
725
|
|
|
726
|
+
if (options.meetingJoinPhase) {
|
|
727
|
+
clientEventObject.meetingJoinPhase = options.meetingJoinPhase;
|
|
728
|
+
}
|
|
729
|
+
|
|
726
730
|
return clientEventObject;
|
|
727
731
|
}
|
|
728
732
|
|
|
@@ -770,6 +774,10 @@ export default class CallDiagnosticMetrics extends StatelessWebexPlugin {
|
|
|
770
774
|
clientEventObject.joinFlowVersion = options.joinFlowVersion;
|
|
771
775
|
}
|
|
772
776
|
|
|
777
|
+
if (options.meetingJoinPhase) {
|
|
778
|
+
clientEventObject.meetingJoinPhase = options.meetingJoinPhase;
|
|
779
|
+
}
|
|
780
|
+
|
|
773
781
|
return clientEventObject;
|
|
774
782
|
}
|
|
775
783
|
|
|
@@ -17,6 +17,7 @@ export const DTLS_HANDSHAKE_FAILED_CLIENT_CODE = 2008;
|
|
|
17
17
|
export const ICE_FAILED_WITH_TURN_TLS_CLIENT_CODE = 2010;
|
|
18
18
|
export const ICE_FAILED_WITHOUT_TURN_TLS_CLIENT_CODE = 2009;
|
|
19
19
|
export const ICE_AND_REACHABILITY_FAILED_CLIENT_CODE = 2011;
|
|
20
|
+
export const MULTISTREAM_NOT_AVAILABLE_CLIENT_CODE = 2012;
|
|
20
21
|
export const WBX_APP_API_URL = 'wbxappapi'; // MeetingInfo WebexAppApi response object normally contains a body.url that includes the string 'wbxappapi'
|
|
21
22
|
|
|
22
23
|
export const WEBEX_SUB_SERVICE_TYPES: Record<string, ClientSubServiceType> = {
|
|
@@ -127,6 +128,7 @@ export const ERROR_DESCRIPTIONS = {
|
|
|
127
128
|
ICE_FAILED_WITHOUT_TURN_TLS: 'ICEFailedWithoutTURN_TLS',
|
|
128
129
|
ICE_FAILED_WITH_TURN_TLS: 'ICEFailedWithTURN_TLS',
|
|
129
130
|
ICE_AND_REACHABILITY_FAILED: 'ICEAndReachabilityFailed',
|
|
131
|
+
MULTISTREAM_NOT_AVAILABLE: 'MultistreamNotAvailable',
|
|
130
132
|
SDP_OFFER_CREATION_ERROR: 'SdpOfferCreationError',
|
|
131
133
|
SDP_OFFER_CREATION_ERROR_MISSING_CODEC: 'SdpOfferCreationErrorMissingCodec',
|
|
132
134
|
WDM_RESTRICTED_REGION: 'WdmRestrictedRegion',
|
|
@@ -409,6 +411,11 @@ export const CLIENT_ERROR_CODE_TO_ERROR_PAYLOAD: Record<number, Partial<ClientEv
|
|
|
409
411
|
category: 'expected',
|
|
410
412
|
fatal: true,
|
|
411
413
|
},
|
|
414
|
+
[MULTISTREAM_NOT_AVAILABLE_CLIENT_CODE]: {
|
|
415
|
+
errorDescription: ERROR_DESCRIPTIONS.MULTISTREAM_NOT_AVAILABLE,
|
|
416
|
+
category: 'expected',
|
|
417
|
+
fatal: false,
|
|
418
|
+
},
|
|
412
419
|
2050: {
|
|
413
420
|
errorDescription: ERROR_DESCRIPTIONS.SDP_OFFER_CREATION_ERROR,
|
|
414
421
|
category: 'media',
|
package/src/generic-metrics.ts
CHANGED
|
@@ -37,7 +37,7 @@ export default abstract class GenericMetrics extends StatelessWebexPlugin {
|
|
|
37
37
|
}
|
|
38
38
|
|
|
39
39
|
/**
|
|
40
|
-
* Submit a
|
|
40
|
+
* Submit a business metric to our metrics endpoint.
|
|
41
41
|
* @param {string} kind of metric for logging
|
|
42
42
|
* @param {string} name of the metric
|
|
43
43
|
* @param {object} event
|
|
@@ -105,7 +105,7 @@ export default abstract class GenericMetrics extends StatelessWebexPlugin {
|
|
|
105
105
|
}
|
|
106
106
|
|
|
107
107
|
/**
|
|
108
|
-
* Returns true once we have the deviceId we need to submit behavioral/operational/
|
|
108
|
+
* Returns true once we have the deviceId we need to submit behavioral/operational/business events
|
|
109
109
|
* @returns {boolean}
|
|
110
110
|
*/
|
|
111
111
|
public isReadyToSubmitEvents(): boolean {
|
package/src/metrics.types.ts
CHANGED
|
@@ -111,6 +111,7 @@ export type MetricEventVerb =
|
|
|
111
111
|
| 'exit';
|
|
112
112
|
|
|
113
113
|
export type MetricEventJoinFlowVersion = 'Other' | 'NewFTE';
|
|
114
|
+
export type MetricEventMeetingJoinPhase = 'pre-join' | 'join' | 'in-meeting';
|
|
114
115
|
|
|
115
116
|
export type SubmitClientEventOptions = {
|
|
116
117
|
meetingId?: string;
|
|
@@ -126,6 +127,8 @@ export type SubmitClientEventOptions = {
|
|
|
126
127
|
webexConferenceIdStr?: string;
|
|
127
128
|
globalMeetingId?: string;
|
|
128
129
|
joinFlowVersion?: MetricEventJoinFlowVersion;
|
|
130
|
+
meetingJoinPhase?: MetricEventMeetingJoinPhase;
|
|
131
|
+
triggeredTime?: string;
|
|
129
132
|
};
|
|
130
133
|
|
|
131
134
|
export type SubmitMQEOptions = {
|
package/src/new-metrics.ts
CHANGED
|
@@ -141,7 +141,7 @@ class Metrics extends WebexPlugin {
|
|
|
141
141
|
}
|
|
142
142
|
|
|
143
143
|
/**
|
|
144
|
-
* @returns true once we have the deviceId we need to submit
|
|
144
|
+
* @returns true once we have the deviceId we need to submit business events
|
|
145
145
|
*/
|
|
146
146
|
isReadyToSubmitBusinessEvents() {
|
|
147
147
|
this.lazyBuildBusinessMetrics();
|
|
@@ -200,17 +200,19 @@ class Metrics extends WebexPlugin {
|
|
|
200
200
|
}
|
|
201
201
|
|
|
202
202
|
/**
|
|
203
|
-
*
|
|
203
|
+
* Business event
|
|
204
204
|
* @param args
|
|
205
205
|
*/
|
|
206
206
|
submitBusinessEvent({
|
|
207
207
|
name,
|
|
208
208
|
payload,
|
|
209
209
|
table,
|
|
210
|
+
metadata,
|
|
210
211
|
}: {
|
|
211
212
|
name: string;
|
|
212
213
|
payload: EventPayload;
|
|
213
214
|
table?: Table;
|
|
215
|
+
metadata?: EventPayload;
|
|
214
216
|
}) {
|
|
215
217
|
if (!this.isReady) {
|
|
216
218
|
// @ts-ignore
|
|
@@ -223,7 +225,7 @@ class Metrics extends WebexPlugin {
|
|
|
223
225
|
|
|
224
226
|
this.lazyBuildBusinessMetrics();
|
|
225
227
|
|
|
226
|
-
return this.businessMetrics.submitBusinessEvent({name, payload, table});
|
|
228
|
+
return this.businessMetrics.submitBusinessEvent({name, payload, table, metadata});
|
|
227
229
|
}
|
|
228
230
|
|
|
229
231
|
/**
|
|
@@ -154,11 +154,12 @@ describe('internal-plugin-metrics', () => {
|
|
|
154
154
|
businessMetrics.clientMetricsBatcher.request = request;
|
|
155
155
|
|
|
156
156
|
assert.equal(requestCalls.length, 0)
|
|
157
|
-
businessMetrics.submitBusinessEvent({ name: "foobar", payload: {bar:"gee"}, table: 'business_metrics' })
|
|
157
|
+
businessMetrics.submitBusinessEvent({ name: "foobar", payload: {bar: "gee"}, table: 'business_metrics', metadata: {asdf: 'hjkl'} })
|
|
158
158
|
assert.equal(requestCalls.length, 1)
|
|
159
159
|
assert.deepEqual(requestCalls[0], {
|
|
160
160
|
eventPayload: {
|
|
161
161
|
key: 'foobar',
|
|
162
|
+
asdf: 'hjkl',
|
|
162
163
|
appType: 'Web Client',
|
|
163
164
|
client_timestamp: requestCalls[0].eventPayload.client_timestamp, // This is to bypass time check, which is checked below.
|
|
164
165
|
value: {
|
|
@@ -173,7 +174,6 @@ describe('internal-plugin-metrics', () => {
|
|
|
173
174
|
os: getOSNameInternal(),
|
|
174
175
|
app: {version: 'webex-version'},
|
|
175
176
|
device: {id: 'deviceId'},
|
|
176
|
-
locale: 'language',
|
|
177
177
|
}
|
|
178
178
|
},
|
|
179
179
|
type: ['business'],
|
|
@@ -283,6 +283,18 @@ describe('internal-plugin-metrics', () => {
|
|
|
283
283
|
cdl.saveTimestamp({key: 'internal.client.meetinginfo.response', value: 20});
|
|
284
284
|
assert.deepEqual(saveFirstTimestamp.callCount, 1);
|
|
285
285
|
});
|
|
286
|
+
|
|
287
|
+
it('calls saveFirstTimestamp for remote SDP received', () => {
|
|
288
|
+
const saveFirstTimestamp = sinon.stub(cdl, 'saveFirstTimestampOnly');
|
|
289
|
+
cdl.saveTimestamp({key: 'client.media-engine.remote-sdp-received', value: 10});
|
|
290
|
+
assert.deepEqual(saveFirstTimestamp.callCount, 1);
|
|
291
|
+
});
|
|
292
|
+
|
|
293
|
+
it('clears timestamp for remote SDP received when local SDP generated', () => {
|
|
294
|
+
cdl.saveTimestamp({key: 'client.media-engine.remote-sdp-received', value: 10});
|
|
295
|
+
cdl.saveTimestamp({key: 'client.media-engine.local-sdp-generated', value: 20});
|
|
296
|
+
assert.isUndefined(cdl.latencyTimestamps.get('client.media-engine.remote-sdp-received'));
|
|
297
|
+
});
|
|
286
298
|
});
|
|
287
299
|
|
|
288
300
|
it('calculates getShowInterstitialTime correctly', () => {
|
|
@@ -745,6 +745,52 @@ describe('internal-plugin-metrics', () => {
|
|
|
745
745
|
});
|
|
746
746
|
});
|
|
747
747
|
|
|
748
|
+
it('should prepare diagnostic event successfully when triggeredTime is supplied in the options object', () => {
|
|
749
|
+
const options = {meetingId: fakeMeeting.id, triggeredTime: 'fake-triggered-time'};
|
|
750
|
+
const getOriginStub = sinon.stub(cd, 'getOrigin').returns({origin: 'fake-origin'});
|
|
751
|
+
const clearEmptyKeysRecursivelyStub = sinon.stub(
|
|
752
|
+
CallDiagnosticUtils,
|
|
753
|
+
'clearEmptyKeysRecursively'
|
|
754
|
+
);
|
|
755
|
+
|
|
756
|
+
const res = cd.prepareDiagnosticEvent(
|
|
757
|
+
{
|
|
758
|
+
canProceed: false,
|
|
759
|
+
identifiers: {
|
|
760
|
+
correlationId: 'id',
|
|
761
|
+
webexConferenceIdStr: 'webexConferenceIdStr1',
|
|
762
|
+
globalMeetingId: 'globalMeetingId1',
|
|
763
|
+
},
|
|
764
|
+
name: 'client.alert.displayed',
|
|
765
|
+
},
|
|
766
|
+
options
|
|
767
|
+
);
|
|
768
|
+
|
|
769
|
+
assert.calledWith(getOriginStub, options, options.meetingId);
|
|
770
|
+
assert.calledOnce(clearEmptyKeysRecursivelyStub);
|
|
771
|
+
assert.deepEqual(res, {
|
|
772
|
+
event: {
|
|
773
|
+
canProceed: false,
|
|
774
|
+
identifiers: {
|
|
775
|
+
correlationId: 'id',
|
|
776
|
+
webexConferenceIdStr: 'webexConferenceIdStr1',
|
|
777
|
+
globalMeetingId: 'globalMeetingId1',
|
|
778
|
+
},
|
|
779
|
+
name: 'client.alert.displayed',
|
|
780
|
+
},
|
|
781
|
+
eventId: 'my-fake-id',
|
|
782
|
+
origin: {
|
|
783
|
+
origin: 'fake-origin',
|
|
784
|
+
},
|
|
785
|
+
originTime: {
|
|
786
|
+
sent: 'not_defined_yet',
|
|
787
|
+
triggered: 'fake-triggered-time',
|
|
788
|
+
},
|
|
789
|
+
senderCountryCode: 'UK',
|
|
790
|
+
version: 1,
|
|
791
|
+
});
|
|
792
|
+
});
|
|
793
|
+
|
|
748
794
|
describe('#submitClientEvent', () => {
|
|
749
795
|
it('should submit client event successfully with meetingId', () => {
|
|
750
796
|
const prepareDiagnosticEventSpy = sinon.spy(cd, 'prepareDiagnosticEvent');
|
|
@@ -2759,11 +2805,12 @@ describe('internal-plugin-metrics', () => {
|
|
|
2759
2805
|
});
|
|
2760
2806
|
});
|
|
2761
2807
|
|
|
2762
|
-
it('includes expected joinFlowVersion from options when in-meeting', async () => {
|
|
2808
|
+
it('includes expected joinFlowVersion and meetingJoinPhase from options when in-meeting', async () => {
|
|
2763
2809
|
// meetingId means in-meeting
|
|
2764
2810
|
const options = {
|
|
2765
2811
|
meetingId: fakeMeeting.id,
|
|
2766
2812
|
joinFlowVersion: 'NewFTE',
|
|
2813
|
+
meetingJoinPhase: 'join',
|
|
2767
2814
|
};
|
|
2768
2815
|
|
|
2769
2816
|
const triggered = new Date();
|
|
@@ -2777,6 +2824,11 @@ describe('internal-plugin-metrics', () => {
|
|
|
2777
2824
|
fetchOptions.body.metrics[0].eventPayload.event.joinFlowVersion,
|
|
2778
2825
|
options.joinFlowVersion
|
|
2779
2826
|
);
|
|
2827
|
+
|
|
2828
|
+
assert.equal(
|
|
2829
|
+
fetchOptions.body.metrics[0].eventPayload.event.meetingJoinPhase,
|
|
2830
|
+
options.meetingJoinPhase
|
|
2831
|
+
);
|
|
2780
2832
|
});
|
|
2781
2833
|
|
|
2782
2834
|
it('includes expected joinFlowVersion from meeting callStateForMetrics when in-meeting', async () => {
|
|
@@ -2815,12 +2867,13 @@ describe('internal-plugin-metrics', () => {
|
|
|
2815
2867
|
);
|
|
2816
2868
|
});
|
|
2817
2869
|
|
|
2818
|
-
it('includes expected joinFlowVersion from options during prejoin', async () => {
|
|
2870
|
+
it('includes expected joinFlowVersion and meetingJoinPhase from options during prejoin', async () => {
|
|
2819
2871
|
// correlationId and no meeting id means prejoin
|
|
2820
2872
|
const options = {
|
|
2821
2873
|
correlationId: 'myCorrelationId',
|
|
2822
2874
|
preLoginId: 'myPreLoginId',
|
|
2823
2875
|
joinFlowVersion: 'NewFTE',
|
|
2876
|
+
meetingJoinPhase: 'pre-join',
|
|
2824
2877
|
};
|
|
2825
2878
|
|
|
2826
2879
|
const triggered = new Date();
|
|
@@ -2834,6 +2887,11 @@ describe('internal-plugin-metrics', () => {
|
|
|
2834
2887
|
fetchOptions.body.metrics[0].eventPayload.event.joinFlowVersion,
|
|
2835
2888
|
options.joinFlowVersion
|
|
2836
2889
|
);
|
|
2890
|
+
|
|
2891
|
+
assert.equal(
|
|
2892
|
+
fetchOptions.body.metrics[0].eventPayload.event.meetingJoinPhase,
|
|
2893
|
+
options.meetingJoinPhase
|
|
2894
|
+
);
|
|
2837
2895
|
});
|
|
2838
2896
|
});
|
|
2839
2897
|
|
|
@@ -93,12 +93,14 @@ describe('internal-plugin-metrics', () => {
|
|
|
93
93
|
name: 'foobar',
|
|
94
94
|
payload: {},
|
|
95
95
|
table: 'test',
|
|
96
|
+
metadata: { foo: 'bar' },
|
|
96
97
|
});
|
|
97
98
|
|
|
98
99
|
assert.calledWith(webex.internal.newMetrics.businessMetrics.submitBusinessEvent, {
|
|
99
100
|
name: 'foobar',
|
|
100
101
|
payload: {},
|
|
101
102
|
table: 'test',
|
|
103
|
+
metadata: { foo: 'bar' },
|
|
102
104
|
});
|
|
103
105
|
});
|
|
104
106
|
|