@webex/internal-plugin-metrics 3.3.0 → 3.3.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/behavioral/behavioral-metrics.js +199 -0
- package/dist/behavioral/behavioral-metrics.js.map +1 -0
- package/dist/behavioral/config.js +11 -0
- package/dist/behavioral/config.js.map +1 -0
- package/dist/call-diagnostic/call-diagnostic-metrics.util.js +14 -11
- package/dist/call-diagnostic/call-diagnostic-metrics.util.js.map +1 -1
- package/dist/call-diagnostic/config.js +19 -13
- package/dist/call-diagnostic/config.js.map +1 -1
- package/dist/index.js +7 -0
- 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 +31 -6
- package/dist/new-metrics.js.map +1 -1
- package/dist/types/behavioral/behavioral-metrics.d.ts +63 -0
- package/dist/types/behavioral/config.d.ts +1 -0
- package/dist/types/call-diagnostic/call-diagnostic-metrics.util.d.ts +3 -2
- package/dist/types/call-diagnostic/config.d.ts +2 -0
- package/dist/types/index.d.ts +2 -1
- package/dist/types/metrics.types.d.ts +28 -7
- package/dist/types/new-metrics.d.ts +14 -6
- package/package.json +11 -11
- package/src/behavioral/behavioral-metrics.ts +179 -0
- package/src/behavioral/config.ts +3 -0
- package/src/call-diagnostic/call-diagnostic-metrics.util.ts +16 -17
- package/src/call-diagnostic/config.ts +9 -2
- package/src/index.ts +2 -0
- package/src/metrics.types.ts +56 -8
- package/src/new-metrics.ts +34 -8
- package/test/unit/spec/behavioral/behavioral-metrics.ts +164 -0
- package/test/unit/spec/call-diagnostic/call-diagnostic-metrics-batcher.ts +48 -52
- package/test/unit/spec/call-diagnostic/call-diagnostic-metrics-latencies.ts +1 -1
- package/test/unit/spec/call-diagnostic/call-diagnostic-metrics.util.ts +41 -22
- package/test/unit/spec/prelogin-metrics-batcher.ts +1 -1
|
@@ -7,6 +7,9 @@ export type EnvironmentType = NonNullable<RawEvent['origin']['environment']>;
|
|
|
7
7
|
export type NewEnvironmentType = NonNullable<RawEvent['origin']['newEnvironment']>;
|
|
8
8
|
export type ClientLaunchMethodType = NonNullable<RawEvent['origin']['clientInfo']>['clientLaunchMethod'];
|
|
9
9
|
export type BrowserLaunchMethodType = NonNullable<RawEvent['origin']['clientInfo']>['browserLaunchMethod'];
|
|
10
|
+
export type MetricEventProduct = 'webex' | 'wxcc_desktop';
|
|
11
|
+
export type MetricEventAgent = 'user' | 'browser' | 'system' | 'sdk' | 'redux' | 'service';
|
|
12
|
+
export type MetricEventVerb = 'create' | 'get' | 'fetch' | 'update' | 'list' | 'delete' | 'select' | 'view' | 'set' | 'toggle' | 'load' | 'reload' | 'click' | 'hover' | 'register' | 'unregister' | 'enable' | 'disable' | 'use' | 'complete' | 'submit' | 'apply' | 'cancel' | 'abort' | 'sync' | 'login' | 'logout';
|
|
10
13
|
export type SubmitClientEventOptions = {
|
|
11
14
|
meetingId?: string;
|
|
12
15
|
mediaConnections?: any[];
|
|
@@ -37,11 +40,27 @@ export interface ClientEvent {
|
|
|
37
40
|
payload?: RawClientEvent;
|
|
38
41
|
options?: SubmitClientEventOptions;
|
|
39
42
|
}
|
|
43
|
+
export interface BehavioralEventContext {
|
|
44
|
+
app: {
|
|
45
|
+
version: string;
|
|
46
|
+
};
|
|
47
|
+
device: {
|
|
48
|
+
id: string;
|
|
49
|
+
};
|
|
50
|
+
locale: string;
|
|
51
|
+
os: {
|
|
52
|
+
name: string;
|
|
53
|
+
version: string;
|
|
54
|
+
};
|
|
55
|
+
}
|
|
40
56
|
export interface BehavioralEvent {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
57
|
+
context: BehavioralEventContext;
|
|
58
|
+
metricName: string;
|
|
59
|
+
tags: Record<string, string | number | boolean>;
|
|
60
|
+
timestamp: number;
|
|
61
|
+
type: string[];
|
|
44
62
|
}
|
|
63
|
+
export type BehavioralEventPayload = BehavioralEvent['tags'];
|
|
45
64
|
export interface OperationalEvent {
|
|
46
65
|
name: never;
|
|
47
66
|
payload?: never;
|
|
@@ -60,7 +79,7 @@ export interface MediaQualityEvent {
|
|
|
60
79
|
export type RecursivePartial<T> = {
|
|
61
80
|
[P in keyof T]?: T[P] extends (infer U)[] ? RecursivePartial<U>[] : T[P] extends object ? RecursivePartial<T[P]> : T[P];
|
|
62
81
|
};
|
|
63
|
-
export type MetricEventNames = InternalEvent['name'] | ClientEvent['name'] | BehavioralEvent['
|
|
82
|
+
export type MetricEventNames = InternalEvent['name'] | ClientEvent['name'] | BehavioralEvent['metricName'] | OperationalEvent['name'] | FeatureEvent['name'] | MediaQualityEvent['name'];
|
|
64
83
|
export type ClientInfo = NonNullable<RawEvent['origin']['clientInfo']>;
|
|
65
84
|
export type ClientType = NonNullable<RawEvent['origin']['clientInfo']>['clientType'];
|
|
66
85
|
export type SubClientType = NonNullable<RawEvent['origin']['clientInfo']>['subClientType'];
|
|
@@ -80,9 +99,11 @@ export type SubmitInternalEvent = (args: {
|
|
|
80
99
|
options?: any;
|
|
81
100
|
}) => void;
|
|
82
101
|
export type SubmitBehavioralEvent = (args: {
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
102
|
+
product: MetricEventProduct;
|
|
103
|
+
agent: MetricEventAgent;
|
|
104
|
+
target: string;
|
|
105
|
+
verb: MetricEventVerb;
|
|
106
|
+
payload?: BehavioralEventPayload;
|
|
86
107
|
}) => void;
|
|
87
108
|
export type SubmitClientEvent = (args: {
|
|
88
109
|
name: ClientEvent['name'];
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { WebexPlugin } from '@webex/webex-core';
|
|
2
2
|
import CallDiagnosticMetrics from './call-diagnostic/call-diagnostic-metrics';
|
|
3
|
-
import
|
|
3
|
+
import BehavioralMetrics from './behavioral/behavioral-metrics';
|
|
4
|
+
import { RecursivePartial, MetricEventProduct, MetricEventAgent, MetricEventVerb, ClientEvent, FeatureEvent, BehavioralEventPayload, OperationalEvent, MediaQualityEvent, InternalEvent, SubmitClientEventOptions } from './metrics.types';
|
|
4
5
|
import CallDiagnosticLatencies from './call-diagnostic/call-diagnostic-metrics-latencies';
|
|
5
6
|
/**
|
|
6
7
|
* Metrics plugin to centralize all types of metrics.
|
|
@@ -10,6 +11,7 @@ declare class Metrics extends WebexPlugin {
|
|
|
10
11
|
static instance: Metrics;
|
|
11
12
|
callDiagnosticLatencies: CallDiagnosticLatencies;
|
|
12
13
|
callDiagnosticMetrics: CallDiagnosticMetrics;
|
|
14
|
+
behavioralMetrics: BehavioralMetrics;
|
|
13
15
|
/**
|
|
14
16
|
* Constructor
|
|
15
17
|
* @param args
|
|
@@ -31,15 +33,21 @@ declare class Metrics extends WebexPlugin {
|
|
|
31
33
|
payload?: RecursivePartial<InternalEvent['payload']>;
|
|
32
34
|
options?: any;
|
|
33
35
|
}): void;
|
|
36
|
+
/**
|
|
37
|
+
* @returns true once we have the deviceId we need to submit behavioral events to Amplitude
|
|
38
|
+
*/
|
|
39
|
+
isReadyToSubmitBehavioralEvents(): boolean;
|
|
34
40
|
/**
|
|
35
41
|
* Behavioral event
|
|
36
42
|
* @param args
|
|
37
43
|
*/
|
|
38
|
-
submitBehavioralEvent({
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
44
|
+
submitBehavioralEvent({ product, agent, target, verb, payload, }: {
|
|
45
|
+
product: MetricEventProduct;
|
|
46
|
+
agent: MetricEventAgent;
|
|
47
|
+
target: string;
|
|
48
|
+
verb: MetricEventVerb;
|
|
49
|
+
payload?: BehavioralEventPayload;
|
|
50
|
+
}): any;
|
|
43
51
|
/**
|
|
44
52
|
* Operational event
|
|
45
53
|
* @param args
|
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.3.
|
|
30
|
-
"@webex/test-helper-mocha": "3.3.
|
|
31
|
-
"@webex/test-helper-mock-webex": "3.3.
|
|
32
|
-
"@webex/test-helper-test-users": "3.3.
|
|
29
|
+
"@webex/test-helper-chai": "3.3.1-next.10",
|
|
30
|
+
"@webex/test-helper-mocha": "3.3.1-next.10",
|
|
31
|
+
"@webex/test-helper-mock-webex": "3.3.1-next.10",
|
|
32
|
+
"@webex/test-helper-test-users": "3.3.1-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.3.
|
|
39
|
-
"@webex/common-timers": "3.3.
|
|
38
|
+
"@webex/common": "3.3.1-next.10",
|
|
39
|
+
"@webex/common-timers": "3.3.1-next.10",
|
|
40
40
|
"@webex/event-dictionary-ts": "^1.0.1406",
|
|
41
|
-
"@webex/internal-plugin-metrics": "3.3.
|
|
42
|
-
"@webex/test-helper-chai": "3.3.
|
|
43
|
-
"@webex/test-helper-mock-webex": "3.3.
|
|
44
|
-
"@webex/webex-core": "3.3.
|
|
41
|
+
"@webex/internal-plugin-metrics": "3.3.1-next.10",
|
|
42
|
+
"@webex/test-helper-chai": "3.3.1-next.10",
|
|
43
|
+
"@webex/test-helper-mock-webex": "3.3.1-next.10",
|
|
44
|
+
"@webex/webex-core": "3.3.1-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.3.
|
|
57
|
+
"version": "3.3.1-next.10"
|
|
58
58
|
}
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
import {merge} from 'lodash';
|
|
2
|
+
import {BrowserDetection} from '@webex/common';
|
|
3
|
+
import {StatelessWebexPlugin} from '@webex/webex-core';
|
|
4
|
+
import {getOSNameInternal} from '../metrics';
|
|
5
|
+
import {BEHAVIORAL_LOG_IDENTIFIER} from './config';
|
|
6
|
+
import {
|
|
7
|
+
MetricEventProduct,
|
|
8
|
+
MetricEventAgent,
|
|
9
|
+
MetricEventVerb,
|
|
10
|
+
BehavioralEventContext,
|
|
11
|
+
BehavioralEvent,
|
|
12
|
+
BehavioralEventPayload,
|
|
13
|
+
} from '../metrics.types';
|
|
14
|
+
import ClientMetricsBatcher from '../client-metrics-batcher';
|
|
15
|
+
|
|
16
|
+
const {getOSVersion, getBrowserName, getBrowserVersion} = BrowserDetection();
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* @description Util class to handle Behavioral Metrics
|
|
20
|
+
* @export
|
|
21
|
+
* @class BehavioralMetrics
|
|
22
|
+
*/
|
|
23
|
+
export default class BehavioralMetrics extends StatelessWebexPlugin {
|
|
24
|
+
// @ts-ignore
|
|
25
|
+
private clientMetricsBatcher: ClientMetricsBatcher;
|
|
26
|
+
private logger: any; // to avoid adding @ts-ignore everywhere
|
|
27
|
+
private device: any;
|
|
28
|
+
private version: string;
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Constructor
|
|
32
|
+
* @param {any[]} args
|
|
33
|
+
*/
|
|
34
|
+
constructor(...args) {
|
|
35
|
+
super(...args);
|
|
36
|
+
// @ts-ignore
|
|
37
|
+
this.logger = this.webex.logger;
|
|
38
|
+
// @ts-ignore
|
|
39
|
+
this.device = this.webex.internal.device;
|
|
40
|
+
// @ts-ignore
|
|
41
|
+
this.version = this.webex.version;
|
|
42
|
+
// @ts-ignore
|
|
43
|
+
this.clientMetricsBatcher = new ClientMetricsBatcher({}, {parent: this.webex});
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Returns the deviceId from our registration with WDM.
|
|
48
|
+
* @returns {string} deviceId or empty string
|
|
49
|
+
*/
|
|
50
|
+
private getDeviceId(): string {
|
|
51
|
+
const {url} = this.device;
|
|
52
|
+
if (url && url.length !== 0) {
|
|
53
|
+
const n = url.lastIndexOf('/');
|
|
54
|
+
if (n !== -1) {
|
|
55
|
+
return url.substring(n + 1);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return '';
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Returns the context object to be submitted with all behavioral metrics.
|
|
64
|
+
* @returns {BehavioralEventContext}
|
|
65
|
+
*/
|
|
66
|
+
private getContext(): BehavioralEventContext {
|
|
67
|
+
const context: BehavioralEventContext = {
|
|
68
|
+
app: {
|
|
69
|
+
version: this.version,
|
|
70
|
+
},
|
|
71
|
+
device: {
|
|
72
|
+
id: this.getDeviceId(),
|
|
73
|
+
},
|
|
74
|
+
locale: window.navigator.language,
|
|
75
|
+
os: {
|
|
76
|
+
name: getOSNameInternal(),
|
|
77
|
+
version: getOSVersion(),
|
|
78
|
+
},
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
return context;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Returns the default tags to be included with all behavioral metrics.
|
|
86
|
+
* @returns {BehavioralEventPayload}
|
|
87
|
+
*/
|
|
88
|
+
private getDefaultTags(): BehavioralEventPayload {
|
|
89
|
+
const tags = {
|
|
90
|
+
browser: getBrowserName(),
|
|
91
|
+
browserHeight: window.innerHeight,
|
|
92
|
+
browserVersion: getBrowserVersion(),
|
|
93
|
+
browserWidth: window.innerWidth,
|
|
94
|
+
domain: window.location.hostname,
|
|
95
|
+
inIframe: window.self !== window.top,
|
|
96
|
+
locale: window.navigator.language,
|
|
97
|
+
os: getOSNameInternal(),
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
return tags;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Creates the object to send to our metrics endpoint for a behavioral event
|
|
105
|
+
* @param {MetricEventProduct} product
|
|
106
|
+
* @param {MetricEventAgent} agent
|
|
107
|
+
* @param {string} target
|
|
108
|
+
* @param {MetricEventVerb} verb
|
|
109
|
+
* @returns {BehavioralEventPayload}
|
|
110
|
+
*/
|
|
111
|
+
private createEventObject({
|
|
112
|
+
product,
|
|
113
|
+
agent,
|
|
114
|
+
target,
|
|
115
|
+
verb,
|
|
116
|
+
payload,
|
|
117
|
+
}: {
|
|
118
|
+
product: MetricEventProduct;
|
|
119
|
+
agent: MetricEventAgent;
|
|
120
|
+
target: string;
|
|
121
|
+
verb: MetricEventVerb;
|
|
122
|
+
payload?: BehavioralEventPayload;
|
|
123
|
+
}): BehavioralEvent {
|
|
124
|
+
const metricName = `${product}.${agent}.${target}.${verb}`;
|
|
125
|
+
let allTags: BehavioralEventPayload = payload;
|
|
126
|
+
allTags = merge(allTags, this.getDefaultTags());
|
|
127
|
+
|
|
128
|
+
const event: BehavioralEvent = {
|
|
129
|
+
context: this.getContext(),
|
|
130
|
+
metricName,
|
|
131
|
+
tags: allTags,
|
|
132
|
+
timestamp: Date.now(),
|
|
133
|
+
type: ['behavioral'],
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
return event;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Returns true once we're ready to submit behavioral metrics, after startup.
|
|
141
|
+
* @returns {boolean} true when deviceId is defined and non-empty
|
|
142
|
+
*/
|
|
143
|
+
public isReadyToSubmitBehavioralEvents(): boolean {
|
|
144
|
+
const deviceId = this.getDeviceId();
|
|
145
|
+
|
|
146
|
+
return deviceId && deviceId.length !== 0;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Submit a behavioral metric to our metrics endpoint.
|
|
151
|
+
* @param {MetricEventProduct} product the product from which the metric is being submitted, e.g. 'webex' web client, 'wxcc_desktop'
|
|
152
|
+
* @param {MetricEventAgent} agent the source of the action for this metric
|
|
153
|
+
* @param {string} target the 'thing' that this metric includes information about
|
|
154
|
+
* @param {MetricEventVerb} verb the action that this metric includes information about
|
|
155
|
+
* @param {BehavioralEventPayload} payload information specific to this event. This should be flat, i.e. it should not include nested objects.
|
|
156
|
+
* @returns {Promise<any>}
|
|
157
|
+
*/
|
|
158
|
+
public submitBehavioralEvent({
|
|
159
|
+
product,
|
|
160
|
+
agent,
|
|
161
|
+
target,
|
|
162
|
+
verb,
|
|
163
|
+
payload,
|
|
164
|
+
}: {
|
|
165
|
+
product: MetricEventProduct;
|
|
166
|
+
agent: MetricEventAgent;
|
|
167
|
+
target: string;
|
|
168
|
+
verb: MetricEventVerb;
|
|
169
|
+
payload?: BehavioralEventPayload;
|
|
170
|
+
}) {
|
|
171
|
+
this.logger.log(
|
|
172
|
+
BEHAVIORAL_LOG_IDENTIFIER,
|
|
173
|
+
`BehavioralMetrics: @submitBehavioralEvent. Submit Behavioral event: ${product}.${agent}.${target}.${verb}`
|
|
174
|
+
);
|
|
175
|
+
const behavioralEvent = this.createEventObject({product, agent, target, verb, payload});
|
|
176
|
+
|
|
177
|
+
return this.clientMetricsBatcher.request(behavioralEvent);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
@@ -21,6 +21,7 @@ import {
|
|
|
21
21
|
MISSING_ROAP_ANSWER_CLIENT_CODE,
|
|
22
22
|
WBX_APP_API_URL,
|
|
23
23
|
ERROR_DESCRIPTIONS,
|
|
24
|
+
ICE_AND_REACHABILITY_FAILED_CLIENT_CODE,
|
|
24
25
|
} from './config';
|
|
25
26
|
|
|
26
27
|
const {getOSName, getOSVersion, getBrowserName, getBrowserVersion} = BrowserDetection();
|
|
@@ -225,7 +226,7 @@ export const getBuildType = (
|
|
|
225
226
|
*/
|
|
226
227
|
export const prepareDiagnosticMetricItem = (webex: any, item: any) => {
|
|
227
228
|
const origin: Partial<Event['origin']> = {
|
|
228
|
-
buildType:
|
|
229
|
+
buildType: getBuildType(
|
|
229
230
|
item.eventPayload?.event?.eventData?.webClientDomain,
|
|
230
231
|
item.eventPayload?.event?.eventData?.markAsTestEvent
|
|
231
232
|
),
|
|
@@ -284,6 +285,8 @@ export const prepareDiagnosticMetricItem = (webex: any, item: any) => {
|
|
|
284
285
|
|
|
285
286
|
case 'client.media.rx.start':
|
|
286
287
|
joinTimes.localSDPGenRemoteSDPRecv = cdl.getLocalSDPGenRemoteSDPRecv();
|
|
288
|
+
audioSetupDelay.joinRespRxStart = cdl.getAudioJoinRespRxStart();
|
|
289
|
+
videoSetupDelay.joinRespRxStart = cdl.getVideoJoinRespRxStart();
|
|
287
290
|
break;
|
|
288
291
|
|
|
289
292
|
case 'client.media-engine.ready':
|
|
@@ -293,10 +296,8 @@ export const prepareDiagnosticMetricItem = (webex: any, item: any) => {
|
|
|
293
296
|
joinTimes.stayLobbyTime = cdl.getStayLobbyTime();
|
|
294
297
|
break;
|
|
295
298
|
|
|
296
|
-
case 'client.
|
|
297
|
-
audioSetupDelay.joinRespRxStart = cdl.getAudioJoinRespRxStart();
|
|
299
|
+
case 'client.media.tx.start':
|
|
298
300
|
audioSetupDelay.joinRespTxStart = cdl.getAudioJoinRespTxStart();
|
|
299
|
-
videoSetupDelay.joinRespRxStart = cdl.getVideoJoinRespRxStart();
|
|
300
301
|
videoSetupDelay.joinRespTxStart = cdl.getVideoJoinRespTxStart();
|
|
301
302
|
}
|
|
302
303
|
|
|
@@ -314,7 +315,6 @@ export const prepareDiagnosticMetricItem = (webex: any, item: any) => {
|
|
|
314
315
|
|
|
315
316
|
item.eventPayload.origin = Object.assign(origin, item.eventPayload.origin);
|
|
316
317
|
|
|
317
|
-
// @ts-ignore
|
|
318
318
|
webex.logger.log(
|
|
319
319
|
`CallDiagnosticLatencies,prepareDiagnosticMetricItem: ${JSON.stringify({
|
|
320
320
|
latencies: Object.fromEntries(cdl.latencyTimestamps),
|
|
@@ -370,12 +370,14 @@ export const extractVersionMetadata = (version: string) => {
|
|
|
370
370
|
*/
|
|
371
371
|
export const generateClientErrorCodeForIceFailure = ({
|
|
372
372
|
signalingState,
|
|
373
|
-
|
|
373
|
+
iceConnected,
|
|
374
374
|
turnServerUsed,
|
|
375
|
+
unreachable,
|
|
375
376
|
}: {
|
|
376
377
|
signalingState: RTCPeerConnection['signalingState'];
|
|
377
|
-
|
|
378
|
+
iceConnected: boolean;
|
|
378
379
|
turnServerUsed: boolean;
|
|
380
|
+
unreachable: boolean;
|
|
379
381
|
}) => {
|
|
380
382
|
let errorCode = ICE_FAILURE_CLIENT_CODE; // default;
|
|
381
383
|
|
|
@@ -383,20 +385,17 @@ export const generateClientErrorCodeForIceFailure = ({
|
|
|
383
385
|
errorCode = MISSING_ROAP_ANSWER_CLIENT_CODE;
|
|
384
386
|
}
|
|
385
387
|
|
|
386
|
-
if (
|
|
387
|
-
signalingState === 'stable' &&
|
|
388
|
-
(iceConnectionState === 'connected' || iceConnectionState === 'disconnected')
|
|
389
|
-
) {
|
|
388
|
+
if (signalingState === 'stable' && iceConnected) {
|
|
390
389
|
errorCode = DTLS_HANDSHAKE_FAILED_CLIENT_CODE;
|
|
391
390
|
}
|
|
392
391
|
|
|
393
|
-
if (
|
|
394
|
-
signalingState !== 'have-local-offer' &&
|
|
395
|
-
iceConnectionState !== 'connected' &&
|
|
396
|
-
iceConnectionState !== 'disconnected'
|
|
397
|
-
) {
|
|
392
|
+
if (signalingState !== 'have-local-offer' && !iceConnected) {
|
|
398
393
|
if (turnServerUsed) {
|
|
399
|
-
|
|
394
|
+
if (unreachable) {
|
|
395
|
+
errorCode = ICE_AND_REACHABILITY_FAILED_CLIENT_CODE;
|
|
396
|
+
} else {
|
|
397
|
+
errorCode = ICE_FAILED_WITH_TURN_TLS_CLIENT_CODE;
|
|
398
|
+
}
|
|
400
399
|
} else {
|
|
401
400
|
errorCode = ICE_FAILED_WITHOUT_TURN_TLS_CLIENT_CODE;
|
|
402
401
|
}
|
|
@@ -16,6 +16,7 @@ export const MISSING_ROAP_ANSWER_CLIENT_CODE = 2007;
|
|
|
16
16
|
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
|
+
export const ICE_AND_REACHABILITY_FAILED_CLIENT_CODE = 2011;
|
|
19
20
|
export const WBX_APP_API_URL = 'wbxappapi'; // MeetingInfo WebexAppApi response object normally contains a body.url that includes the string 'wbxappapi'
|
|
20
21
|
|
|
21
22
|
export const WEBEX_SUB_SERVICE_TYPES: Record<string, ClientSubServiceType> = {
|
|
@@ -125,6 +126,7 @@ export const ERROR_DESCRIPTIONS = {
|
|
|
125
126
|
DTLS_HANDSHAKE_FAILED: 'DTLSHandshakeFailed',
|
|
126
127
|
ICE_FAILED_WITHOUT_TURN_TLS: 'ICEFailedWithoutTURN_TLS',
|
|
127
128
|
ICE_FAILED_WITH_TURN_TLS: 'ICEFailedWithTURN_TLS',
|
|
129
|
+
ICE_AND_REACHABILITY_FAILED: 'ICEAndReachabilityFailed',
|
|
128
130
|
SDP_OFFER_CREATION_ERROR: 'SdpOfferCreationError',
|
|
129
131
|
SDP_OFFER_CREATION_ERROR_MISSING_CODEC: 'SdpOfferCreationErrorMissingCodec',
|
|
130
132
|
};
|
|
@@ -377,7 +379,7 @@ export const CLIENT_ERROR_CODE_TO_ERROR_PAYLOAD: Record<number, Partial<ClientEv
|
|
|
377
379
|
},
|
|
378
380
|
[MISSING_ROAP_ANSWER_CLIENT_CODE]: {
|
|
379
381
|
errorDescription: ERROR_DESCRIPTIONS.MISSING_ROAP_ANSWER,
|
|
380
|
-
category: '
|
|
382
|
+
category: 'media',
|
|
381
383
|
fatal: true,
|
|
382
384
|
},
|
|
383
385
|
[DTLS_HANDSHAKE_FAILED_CLIENT_CODE]: {
|
|
@@ -392,7 +394,12 @@ export const CLIENT_ERROR_CODE_TO_ERROR_PAYLOAD: Record<number, Partial<ClientEv
|
|
|
392
394
|
},
|
|
393
395
|
[ICE_FAILED_WITH_TURN_TLS_CLIENT_CODE]: {
|
|
394
396
|
errorDescription: ERROR_DESCRIPTIONS.ICE_FAILED_WITH_TURN_TLS,
|
|
395
|
-
category: '
|
|
397
|
+
category: 'media',
|
|
398
|
+
fatal: true,
|
|
399
|
+
},
|
|
400
|
+
[ICE_AND_REACHABILITY_FAILED_CLIENT_CODE]: {
|
|
401
|
+
errorDescription: ERROR_DESCRIPTIONS.ICE_AND_REACHABILITY_FAILED,
|
|
402
|
+
category: 'expected',
|
|
396
403
|
fatal: true,
|
|
397
404
|
},
|
|
398
405
|
2050: {
|
package/src/index.ts
CHANGED
|
@@ -22,6 +22,7 @@ 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/behavioral-metrics';
|
|
25
26
|
|
|
26
27
|
registerInternalPlugin('metrics', Metrics, {
|
|
27
28
|
config,
|
|
@@ -41,6 +42,7 @@ export {
|
|
|
41
42
|
CallDiagnosticUtils,
|
|
42
43
|
CallDiagnosticLatencies,
|
|
43
44
|
CallDiagnosticMetrics,
|
|
45
|
+
BehavioralMetrics,
|
|
44
46
|
};
|
|
45
47
|
export type {
|
|
46
48
|
ClientEvent,
|
package/src/metrics.types.ts
CHANGED
|
@@ -20,6 +20,39 @@ export type BrowserLaunchMethodType = NonNullable<
|
|
|
20
20
|
RawEvent['origin']['clientInfo']
|
|
21
21
|
>['browserLaunchMethod'];
|
|
22
22
|
|
|
23
|
+
export type MetricEventProduct = 'webex' | 'wxcc_desktop';
|
|
24
|
+
|
|
25
|
+
export type MetricEventAgent = 'user' | 'browser' | 'system' | 'sdk' | 'redux' | 'service';
|
|
26
|
+
|
|
27
|
+
export type MetricEventVerb =
|
|
28
|
+
| 'create'
|
|
29
|
+
| 'get'
|
|
30
|
+
| 'fetch'
|
|
31
|
+
| 'update'
|
|
32
|
+
| 'list'
|
|
33
|
+
| 'delete'
|
|
34
|
+
| 'select'
|
|
35
|
+
| 'view'
|
|
36
|
+
| 'set'
|
|
37
|
+
| 'toggle'
|
|
38
|
+
| 'load'
|
|
39
|
+
| 'reload'
|
|
40
|
+
| 'click'
|
|
41
|
+
| 'hover'
|
|
42
|
+
| 'register'
|
|
43
|
+
| 'unregister'
|
|
44
|
+
| 'enable'
|
|
45
|
+
| 'disable'
|
|
46
|
+
| 'use'
|
|
47
|
+
| 'complete'
|
|
48
|
+
| 'submit'
|
|
49
|
+
| 'apply'
|
|
50
|
+
| 'cancel'
|
|
51
|
+
| 'abort'
|
|
52
|
+
| 'sync'
|
|
53
|
+
| 'login'
|
|
54
|
+
| 'logout';
|
|
55
|
+
|
|
23
56
|
export type SubmitClientEventOptions = {
|
|
24
57
|
meetingId?: string;
|
|
25
58
|
mediaConnections?: any[];
|
|
@@ -66,13 +99,26 @@ export interface ClientEvent {
|
|
|
66
99
|
options?: SubmitClientEventOptions;
|
|
67
100
|
}
|
|
68
101
|
|
|
102
|
+
export interface BehavioralEventContext {
|
|
103
|
+
app: {version: string};
|
|
104
|
+
device: {id: string};
|
|
105
|
+
locale: string;
|
|
106
|
+
os: {
|
|
107
|
+
name: string;
|
|
108
|
+
version: string;
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
|
|
69
112
|
export interface BehavioralEvent {
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
113
|
+
context: BehavioralEventContext;
|
|
114
|
+
metricName: string;
|
|
115
|
+
tags: Record<string, string | number | boolean>;
|
|
116
|
+
timestamp: number;
|
|
117
|
+
type: string[];
|
|
74
118
|
}
|
|
75
119
|
|
|
120
|
+
export type BehavioralEventPayload = BehavioralEvent['tags'];
|
|
121
|
+
|
|
76
122
|
export interface OperationalEvent {
|
|
77
123
|
// TODO: not implemented
|
|
78
124
|
name: never;
|
|
@@ -104,7 +150,7 @@ export type RecursivePartial<T> = {
|
|
|
104
150
|
export type MetricEventNames =
|
|
105
151
|
| InternalEvent['name']
|
|
106
152
|
| ClientEvent['name']
|
|
107
|
-
| BehavioralEvent['
|
|
153
|
+
| BehavioralEvent['metricName']
|
|
108
154
|
| OperationalEvent['name']
|
|
109
155
|
| FeatureEvent['name']
|
|
110
156
|
| MediaQualityEvent['name'];
|
|
@@ -137,9 +183,11 @@ export type SubmitInternalEvent = (args: {
|
|
|
137
183
|
}) => void;
|
|
138
184
|
|
|
139
185
|
export type SubmitBehavioralEvent = (args: {
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
186
|
+
product: MetricEventProduct;
|
|
187
|
+
agent: MetricEventAgent;
|
|
188
|
+
target: string;
|
|
189
|
+
verb: MetricEventVerb;
|
|
190
|
+
payload?: BehavioralEventPayload;
|
|
143
191
|
}) => void;
|
|
144
192
|
|
|
145
193
|
export type SubmitClientEvent = (args: {
|
package/src/new-metrics.ts
CHANGED
|
@@ -6,11 +6,15 @@
|
|
|
6
6
|
import {WebexPlugin} from '@webex/webex-core';
|
|
7
7
|
|
|
8
8
|
import CallDiagnosticMetrics from './call-diagnostic/call-diagnostic-metrics';
|
|
9
|
+
import BehavioralMetrics from './behavioral/behavioral-metrics';
|
|
9
10
|
import {
|
|
10
11
|
RecursivePartial,
|
|
12
|
+
MetricEventProduct,
|
|
13
|
+
MetricEventAgent,
|
|
14
|
+
MetricEventVerb,
|
|
11
15
|
ClientEvent,
|
|
12
16
|
FeatureEvent,
|
|
13
|
-
|
|
17
|
+
BehavioralEventPayload,
|
|
14
18
|
OperationalEvent,
|
|
15
19
|
MediaQualityEvent,
|
|
16
20
|
InternalEvent,
|
|
@@ -32,6 +36,7 @@ class Metrics extends WebexPlugin {
|
|
|
32
36
|
callDiagnosticLatencies: CallDiagnosticLatencies;
|
|
33
37
|
// Helper classes to handle the different types of metrics
|
|
34
38
|
callDiagnosticMetrics: CallDiagnosticMetrics;
|
|
39
|
+
behavioralMetrics: BehavioralMetrics;
|
|
35
40
|
|
|
36
41
|
/**
|
|
37
42
|
* Constructor
|
|
@@ -56,6 +61,8 @@ class Metrics extends WebexPlugin {
|
|
|
56
61
|
this.webex.once('ready', () => {
|
|
57
62
|
// @ts-ignore
|
|
58
63
|
this.callDiagnosticMetrics = new CallDiagnosticMetrics({}, {parent: this.webex});
|
|
64
|
+
// @ts-ignore
|
|
65
|
+
this.behavioralMetrics = new BehavioralMetrics({}, {parent: this.webex});
|
|
59
66
|
});
|
|
60
67
|
}
|
|
61
68
|
|
|
@@ -79,21 +86,40 @@ class Metrics extends WebexPlugin {
|
|
|
79
86
|
}
|
|
80
87
|
}
|
|
81
88
|
|
|
89
|
+
/**
|
|
90
|
+
* @returns true once we have the deviceId we need to submit behavioral events to Amplitude
|
|
91
|
+
*/
|
|
92
|
+
isReadyToSubmitBehavioralEvents() {
|
|
93
|
+
return this.behavioralMetrics.isReadyToSubmitBehavioralEvents();
|
|
94
|
+
}
|
|
95
|
+
|
|
82
96
|
/**
|
|
83
97
|
* Behavioral event
|
|
84
98
|
* @param args
|
|
85
99
|
*/
|
|
86
100
|
submitBehavioralEvent({
|
|
87
|
-
|
|
101
|
+
product,
|
|
102
|
+
agent,
|
|
103
|
+
target,
|
|
104
|
+
verb,
|
|
88
105
|
payload,
|
|
89
|
-
options,
|
|
90
106
|
}: {
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
107
|
+
product: MetricEventProduct;
|
|
108
|
+
agent: MetricEventAgent;
|
|
109
|
+
target: string;
|
|
110
|
+
verb: MetricEventVerb;
|
|
111
|
+
payload?: BehavioralEventPayload;
|
|
94
112
|
}) {
|
|
95
|
-
this.
|
|
96
|
-
|
|
113
|
+
if (!this.behavioralMetrics) {
|
|
114
|
+
// @ts-ignore
|
|
115
|
+
this.webex.logger.log(
|
|
116
|
+
`NewMetrics: @submitBehavioralEvent. Attempted to submit before webex.ready: ${product}.${agent}.${target}.${verb}`
|
|
117
|
+
);
|
|
118
|
+
|
|
119
|
+
return Promise.resolve();
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
return this.behavioralMetrics.submitBehavioralEvent({product, agent, target, verb, payload});
|
|
97
123
|
}
|
|
98
124
|
|
|
99
125
|
/**
|