@webex/internal-plugin-metrics 3.12.0 → 3.13.0-next.2
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/.repo-context.json +466 -0
- package/.sdd/manifest.json +626 -0
- package/AGENTS.md +208 -0
- package/README.md +274 -0
- package/dist/automated-user.js +19 -0
- package/dist/automated-user.js.map +1 -0
- package/dist/batcher.js +3 -0
- package/dist/batcher.js.map +1 -1
- package/dist/call-diagnostic/call-diagnostic-metrics-latencies.js +639 -66
- package/dist/call-diagnostic/call-diagnostic-metrics-latencies.js.map +1 -1
- package/dist/call-diagnostic/call-diagnostic-metrics.js +240 -103
- package/dist/call-diagnostic/call-diagnostic-metrics.js.map +1 -1
- package/dist/call-diagnostic/call-diagnostic-metrics.util.js +7 -2
- package/dist/call-diagnostic/call-diagnostic-metrics.util.js.map +1 -1
- package/dist/call-diagnostic/config.js +19 -4
- package/dist/call-diagnostic/config.js.map +1 -1
- package/dist/config.js +8 -0
- package/dist/config.js.map +1 -1
- package/dist/index.js +25 -1
- package/dist/index.js.map +1 -1
- package/dist/metrics.js +118 -5
- package/dist/metrics.js.map +1 -1
- package/dist/metrics.types.js +4 -0
- package/dist/metrics.types.js.map +1 -1
- package/dist/network-telemetry.js +610 -0
- package/dist/network-telemetry.js.map +1 -0
- package/dist/new-metrics.js +63 -17
- package/dist/new-metrics.js.map +1 -1
- package/dist/privacy-and-security-permission-enricher/constants.js +18 -0
- package/dist/privacy-and-security-permission-enricher/constants.js.map +1 -0
- package/dist/privacy-and-security-permission-enricher/index.js +143 -0
- package/dist/privacy-and-security-permission-enricher/index.js.map +1 -0
- package/dist/privacy-and-security-permission-enricher/types.js +7 -0
- package/dist/privacy-and-security-permission-enricher/types.js.map +1 -0
- package/dist/privacy-and-security-permission-enricher/utils.js +71 -0
- package/dist/privacy-and-security-permission-enricher/utils.js.map +1 -0
- package/dist/types/automated-user.d.ts +2 -0
- package/dist/types/call-diagnostic/call-diagnostic-metrics-latencies.d.ts +208 -5
- package/dist/types/call-diagnostic/call-diagnostic-metrics.d.ts +83 -17
- package/dist/types/call-diagnostic/config.d.ts +6 -0
- package/dist/types/config.d.ts +9 -0
- package/dist/types/index.d.ts +5 -3
- package/dist/types/metrics.types.d.ts +11 -5
- package/dist/types/network-telemetry.d.ts +108 -0
- package/dist/types/new-metrics.d.ts +17 -1
- package/dist/types/privacy-and-security-permission-enricher/constants.d.ts +6 -0
- package/dist/types/privacy-and-security-permission-enricher/index.d.ts +40 -0
- package/dist/types/privacy-and-security-permission-enricher/types.d.ts +14 -0
- package/dist/types/privacy-and-security-permission-enricher/utils.d.ts +5 -0
- package/dist/types/unhandled-exception-telemetry/index.d.ts +60 -0
- package/dist/types/unhandled-exception-telemetry/utils.d.ts +6 -0
- package/dist/unhandled-exception-telemetry/index.js +331 -0
- package/dist/unhandled-exception-telemetry/index.js.map +1 -0
- package/dist/unhandled-exception-telemetry/utils.js +105 -0
- package/dist/unhandled-exception-telemetry/utils.js.map +1 -0
- package/docs/adr/index.md +27 -0
- package/docs/architecture.md +437 -0
- package/docs/getting-started.md +131 -0
- package/docs/index.md +52 -0
- package/docs/specs/README.md +88 -0
- package/package.json +12 -11
- package/schemas/repo-context.schema.json +796 -0
- package/src/automated-user.ts +16 -0
- package/src/batcher.js +4 -0
- package/src/call-diagnostic/call-diagnostic-metrics-latencies.ts +801 -74
- package/src/call-diagnostic/call-diagnostic-metrics.ts +184 -42
- package/src/call-diagnostic/call-diagnostic-metrics.util.ts +7 -1
- package/src/call-diagnostic/config.ts +16 -0
- package/src/call-diagnostic/docs/README.md +535 -0
- package/src/config.js +8 -0
- package/src/docs/README.md +703 -0
- package/src/index.ts +16 -0
- package/src/metrics.js +123 -5
- package/src/metrics.types.ts +29 -6
- package/src/network-telemetry.ts +757 -0
- package/src/new-metrics.ts +56 -6
- package/src/privacy-and-security-permission-enricher/constants.ts +33 -0
- package/src/privacy-and-security-permission-enricher/docs/README.md +356 -0
- package/src/privacy-and-security-permission-enricher/index.ts +142 -0
- package/src/privacy-and-security-permission-enricher/types.ts +21 -0
- package/src/privacy-and-security-permission-enricher/utils.ts +82 -0
- package/src/rtcMetrics/docs/README.md +447 -0
- package/src/unhandled-exception-telemetry/docs/README.md +536 -0
- package/src/unhandled-exception-telemetry/index.ts +404 -0
- package/src/unhandled-exception-telemetry/utils.ts +101 -0
- package/test/unit/spec/automated-user.ts +43 -0
- package/test/unit/spec/batcher.js +43 -0
- package/test/unit/spec/call-diagnostic/call-diagnostic-metrics-batcher.ts +14 -2
- package/test/unit/spec/call-diagnostic/call-diagnostic-metrics-latencies.ts +1435 -304
- package/test/unit/spec/call-diagnostic/call-diagnostic-metrics.ts +1265 -207
- package/test/unit/spec/call-diagnostic/call-diagnostic-metrics.util.ts +27 -0
- package/test/unit/spec/metrics.js +14 -5
- package/test/unit/spec/network-telemetry.ts +610 -0
- package/test/unit/spec/new-metrics.ts +203 -50
- package/test/unit/spec/prelogin-metrics-batcher.ts +71 -36
- package/test/unit/spec/privacy-and-security-permission-enricher.ts +318 -0
- package/test/unit/spec/unhandled-exception-telemetry/utils.ts +109 -0
- package/test/unit/spec/unhandled-exception-telemetry.ts +689 -0
|
@@ -6,6 +6,7 @@ import uuid from 'uuid';
|
|
|
6
6
|
import {merge} from 'lodash';
|
|
7
7
|
import {StatelessWebexPlugin} from '@webex/webex-core';
|
|
8
8
|
import {getOSNameInternal} from '../metrics';
|
|
9
|
+
import * as AutomatedUserUtils from '../automated-user';
|
|
9
10
|
|
|
10
11
|
import {
|
|
11
12
|
anonymizeIPAddress,
|
|
@@ -63,10 +64,17 @@ import {
|
|
|
63
64
|
SDP_OFFER_CREATION_ERROR_MAP,
|
|
64
65
|
CALL_FEATURE_LOG_IDENTIFIER,
|
|
65
66
|
CALL_FEATURE_EVENT_FAILED_TO_SEND,
|
|
67
|
+
LOCUS_RATE_LIMITED_OUTGOING_CLIENT_CODE,
|
|
68
|
+
LOCUS_UNAVAILABLE_CLIENT_CODE,
|
|
66
69
|
} from './config';
|
|
67
70
|
|
|
68
71
|
const {getOSVersion, getBrowserName, getBrowserVersion} = BrowserDetection();
|
|
69
72
|
|
|
73
|
+
const LOCUS_HTTP_STATUS_TO_CLIENT_ERROR_CODE: Partial<Record<number, number>> = {
|
|
74
|
+
429: LOCUS_RATE_LIMITED_OUTGOING_CLIENT_CODE,
|
|
75
|
+
503: LOCUS_UNAVAILABLE_CLIENT_CODE,
|
|
76
|
+
};
|
|
77
|
+
|
|
70
78
|
type GetOriginOptions = {
|
|
71
79
|
clientType: ClientType;
|
|
72
80
|
subClientType: SubClientType;
|
|
@@ -86,6 +94,7 @@ type GetIdentifiersOptions = {
|
|
|
86
94
|
preLoginId?: string;
|
|
87
95
|
globalMeetingId?: string;
|
|
88
96
|
webexConferenceIdStr?: string;
|
|
97
|
+
locusCluster?: string;
|
|
89
98
|
};
|
|
90
99
|
|
|
91
100
|
/**
|
|
@@ -99,7 +108,12 @@ export default class CallDiagnosticMetrics extends StatelessWebexPlugin {
|
|
|
99
108
|
// @ts-ignore
|
|
100
109
|
private preLoginMetricsBatcher: PreLoginMetricsBatcher;
|
|
101
110
|
|
|
102
|
-
|
|
111
|
+
// lazy getter to avoid @ts-ignore on every call site
|
|
112
|
+
private get logger(): any {
|
|
113
|
+
// @ts-ignore
|
|
114
|
+
return this.webex.logger;
|
|
115
|
+
}
|
|
116
|
+
|
|
103
117
|
private hasLoggedBrowserSerial: boolean;
|
|
104
118
|
private device: any;
|
|
105
119
|
private delayedClientEvents: DelayedClientEvent[] = [];
|
|
@@ -108,6 +122,8 @@ export default class CallDiagnosticMetrics extends StatelessWebexPlugin {
|
|
|
108
122
|
private isMercuryConnected = false;
|
|
109
123
|
private eventLimitTracker: Map<string, number> = new Map();
|
|
110
124
|
private eventLimitWarningsLogged: Set<string> = new Set();
|
|
125
|
+
private isTelemetryOptOutManual = false;
|
|
126
|
+
private isTelemetryOptOutAutomatic = false;
|
|
111
127
|
|
|
112
128
|
// the default validator before piping an event to the batcher
|
|
113
129
|
// this function can be overridden by the user
|
|
@@ -124,8 +140,6 @@ export default class CallDiagnosticMetrics extends StatelessWebexPlugin {
|
|
|
124
140
|
constructor(...args) {
|
|
125
141
|
super(...args);
|
|
126
142
|
// @ts-ignore
|
|
127
|
-
this.logger = this.webex.logger;
|
|
128
|
-
// @ts-ignore
|
|
129
143
|
this.callDiagnosticEventsBatcher = new CallDiagnosticEventsBatcher({}, {parent: this.webex});
|
|
130
144
|
// @ts-ignore
|
|
131
145
|
this.preLoginMetricsBatcher = new PreLoginMetricsBatcher({}, {parent: this.webex});
|
|
@@ -145,6 +159,58 @@ export default class CallDiagnosticMetrics extends StatelessWebexPlugin {
|
|
|
145
159
|
return null;
|
|
146
160
|
}
|
|
147
161
|
|
|
162
|
+
/**
|
|
163
|
+
* Returns the user activation state reported from the browser's navigator.userActivation API
|
|
164
|
+
* @returns object with hasBeenActive and isActive booleans, or undefined if unavailable
|
|
165
|
+
*/
|
|
166
|
+
getUserActivation(): {hasBeenActive: boolean; isActive: boolean} | undefined {
|
|
167
|
+
const userActivation =
|
|
168
|
+
typeof navigator !== 'undefined'
|
|
169
|
+
? (navigator as {userActivation?: {hasBeenActive: boolean; isActive: boolean}})
|
|
170
|
+
.userActivation
|
|
171
|
+
: undefined;
|
|
172
|
+
|
|
173
|
+
if (userActivation) {
|
|
174
|
+
return {
|
|
175
|
+
hasBeenActive: userActivation.hasBeenActive,
|
|
176
|
+
isActive: userActivation.isActive,
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
return undefined;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Returns the telemetryOptOut value of the current user
|
|
185
|
+
* @returns one of 'manual', 'automatic', undefined
|
|
186
|
+
*/
|
|
187
|
+
public getTelemetryOptOut() {
|
|
188
|
+
if (this.isTelemetryOptOutManual) {
|
|
189
|
+
return 'manual';
|
|
190
|
+
}
|
|
191
|
+
if (this.isTelemetryOptOutAutomatic) {
|
|
192
|
+
return 'automatic';
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
return undefined;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* Sets the manual telemetry opt-out status for the current user
|
|
200
|
+
* @param value - boolean value indicating manual telemetry opt-out status
|
|
201
|
+
*/
|
|
202
|
+
public setIsTelemetryOptOutManual(value: boolean) {
|
|
203
|
+
this.isTelemetryOptOutManual = value;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Sets the automatic telemetry opt-out status for the current user
|
|
208
|
+
* @param value - boolean value indicating automatic telemetry opt-out status
|
|
209
|
+
*/
|
|
210
|
+
public setIsTelemetryOptOutAutomatic(value: boolean) {
|
|
211
|
+
this.isTelemetryOptOutAutomatic = value;
|
|
212
|
+
}
|
|
213
|
+
|
|
148
214
|
/**
|
|
149
215
|
* Returns if the meeting has converged architecture enabled
|
|
150
216
|
* @param options.meetingId
|
|
@@ -190,6 +256,11 @@ export default class CallDiagnosticMetrics extends StatelessWebexPlugin {
|
|
|
190
256
|
|
|
191
257
|
// if ConvergedArchitecture enable and isConvergedWebinarWebcast -- then webcast
|
|
192
258
|
if (meetingInfo?.enableConvergedArchitecture && meetingInfo?.enableEvent) {
|
|
259
|
+
// if enableConvergedWebinarLargeScale - then large scale webinar
|
|
260
|
+
if (meetingInfo?.enableConvergedWebinarLargeScale) {
|
|
261
|
+
return WEBEX_SUB_SERVICE_TYPES.LARGE_SCALE_WEBINAR;
|
|
262
|
+
}
|
|
263
|
+
|
|
193
264
|
return meetingInfo?.isConvergedWebinarWebcast
|
|
194
265
|
? WEBEX_SUB_SERVICE_TYPES.WEBCAST
|
|
195
266
|
: WEBEX_SUB_SERVICE_TYPES.WEBINAR;
|
|
@@ -213,12 +284,12 @@ export default class CallDiagnosticMetrics extends StatelessWebexPlugin {
|
|
|
213
284
|
getOrigin(options: GetOriginOptions, meetingId?: string) {
|
|
214
285
|
const defaultClientType: ClientType =
|
|
215
286
|
// @ts-ignore
|
|
216
|
-
this.webex.meetings
|
|
287
|
+
this.webex.meetings?.config?.metrics?.clientType;
|
|
217
288
|
const defaultSubClientType: SubClientType =
|
|
218
289
|
// @ts-ignore
|
|
219
|
-
this.webex.meetings
|
|
290
|
+
this.webex.meetings?.config?.metrics?.subClientType;
|
|
220
291
|
// @ts-ignore
|
|
221
|
-
const providedClientVersion: string = this.webex.meetings
|
|
292
|
+
const providedClientVersion: string = this.webex.meetings?.config?.metrics?.clientVersion;
|
|
222
293
|
// @ts-ignore
|
|
223
294
|
const defaultSDKClientVersion = `${CLIENT_NAME}/${this.webex.version}`;
|
|
224
295
|
|
|
@@ -229,6 +300,18 @@ export default class CallDiagnosticMetrics extends StatelessWebexPlugin {
|
|
|
229
300
|
versionMetadata = extractVersionMetadata(providedClientVersion);
|
|
230
301
|
}
|
|
231
302
|
|
|
303
|
+
// Browser details and the support verdict can all be supplied by the host client, which is able
|
|
304
|
+
// to resolve wrapper browsers (Electron, WebOS) to the engine that actually determines
|
|
305
|
+
// capability. The browser fields fall back to the SDK's own detection when not supplied, the
|
|
306
|
+
// same way clientVersion falls back to the SDK version.
|
|
307
|
+
const {
|
|
308
|
+
browser: providedBrowser,
|
|
309
|
+
browserVersion: providedBrowserVersion,
|
|
310
|
+
isSupportedBrowserFamily,
|
|
311
|
+
isOutdatedBrowserVersion,
|
|
312
|
+
// @ts-ignore
|
|
313
|
+
} = this.webex.meetings?.config?.metrics ?? {};
|
|
314
|
+
|
|
232
315
|
if (!this.hasLoggedBrowserSerial) {
|
|
233
316
|
this.logger.log(
|
|
234
317
|
CALL_DIAGNOSTIC_LOG_IDENTIFIER,
|
|
@@ -258,25 +341,27 @@ export default class CallDiagnosticMetrics extends StatelessWebexPlugin {
|
|
|
258
341
|
...versionMetadata,
|
|
259
342
|
publicNetworkPrefix:
|
|
260
343
|
// @ts-ignore
|
|
261
|
-
anonymizeIPAddress(this.webex.meetings
|
|
344
|
+
anonymizeIPAddress(this.webex.meetings?.geoHintInfo?.clientAddress) || undefined,
|
|
262
345
|
localNetworkPrefix:
|
|
263
346
|
anonymizeIPAddress(
|
|
264
347
|
// @ts-ignore
|
|
265
|
-
this.webex.meetings
|
|
266
|
-
|
|
348
|
+
this.webex.meetings?.meetingCollection
|
|
349
|
+
?.get(meetingId)
|
|
267
350
|
?.statsAnalyzer?.getLocalIpAddress()
|
|
268
351
|
) || undefined,
|
|
269
352
|
osVersion: getOSVersion() || 'unknown',
|
|
270
353
|
subClientType: options?.subClientType || defaultSubClientType,
|
|
271
354
|
os: getOSNameInternal(),
|
|
272
|
-
browser: getBrowserName(),
|
|
273
|
-
browserVersion: getBrowserVersion(),
|
|
355
|
+
browser: providedBrowser || getBrowserName(),
|
|
356
|
+
browserVersion: providedBrowserVersion || getBrowserVersion(),
|
|
357
|
+
...(isSupportedBrowserFamily === undefined ? {} : {isSupportedBrowserFamily}),
|
|
358
|
+
...(isOutdatedBrowserVersion === undefined ? {} : {isOutdatedBrowserVersion}),
|
|
274
359
|
},
|
|
275
360
|
};
|
|
276
361
|
|
|
277
362
|
if (meetingId) {
|
|
278
363
|
// @ts-ignore
|
|
279
|
-
const meeting = this.webex.meetings
|
|
364
|
+
const meeting = this.webex.meetings?.getBasicMeetingInformation(meetingId);
|
|
280
365
|
if (meeting?.environment) {
|
|
281
366
|
origin.environment = meeting.environment;
|
|
282
367
|
}
|
|
@@ -308,6 +393,20 @@ export default class CallDiagnosticMetrics extends StatelessWebexPlugin {
|
|
|
308
393
|
throw new Error("ClientType and SubClientType can't be undefined");
|
|
309
394
|
}
|
|
310
395
|
|
|
396
|
+
/**
|
|
397
|
+
* Returns the signed-in user's CI ID derived from credentials tokens.
|
|
398
|
+
* Used as a fallback when no device is registered.
|
|
399
|
+
* @returns the userId, or undefined if it can't be determined
|
|
400
|
+
*/
|
|
401
|
+
private getUserIdFromCredentials(): string | undefined {
|
|
402
|
+
try {
|
|
403
|
+
// @ts-ignore
|
|
404
|
+
return this.webex.credentials.getUserId();
|
|
405
|
+
} catch {
|
|
406
|
+
return undefined;
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
|
|
311
410
|
/**
|
|
312
411
|
* Gather identifier details for call diagnostic payload.
|
|
313
412
|
* @throws Error if initialization fails.
|
|
@@ -322,6 +421,7 @@ export default class CallDiagnosticMetrics extends StatelessWebexPlugin {
|
|
|
322
421
|
globalMeetingId,
|
|
323
422
|
preLoginId,
|
|
324
423
|
sessionCorrelationId,
|
|
424
|
+
locusCluster,
|
|
325
425
|
} = options;
|
|
326
426
|
const identifiers: Event['event']['identifiers'] = {
|
|
327
427
|
correlationId: 'unknown', // concerned with setting this to unknown. This will fail diagnostic events parsing because it's not a uuid pattern
|
|
@@ -352,7 +452,6 @@ export default class CallDiagnosticMetrics extends StatelessWebexPlugin {
|
|
|
352
452
|
const {device} = this;
|
|
353
453
|
const {installationId} = device?.config || {};
|
|
354
454
|
|
|
355
|
-
identifiers.userId = device?.userId || preLoginId;
|
|
356
455
|
identifiers.deviceId = device?.url;
|
|
357
456
|
identifiers.orgId = device?.orgId;
|
|
358
457
|
// @ts-ignore
|
|
@@ -363,6 +462,10 @@ export default class CallDiagnosticMetrics extends StatelessWebexPlugin {
|
|
|
363
462
|
}
|
|
364
463
|
}
|
|
365
464
|
|
|
465
|
+
// Prefer the device's userId, but fall back to the signed-in user's ID from
|
|
466
|
+
// credentials when no device is registered, then to the pre-login ID.
|
|
467
|
+
identifiers.userId = this.device?.userId || this.getUserIdFromCredentials() || preLoginId;
|
|
468
|
+
|
|
366
469
|
if (meeting?.locusInfo?.fullState) {
|
|
367
470
|
identifiers.locusUrl = meeting.locusUrl;
|
|
368
471
|
identifiers.locusId = meeting.locusUrl && meeting.locusUrl.split('/').pop();
|
|
@@ -385,6 +488,10 @@ export default class CallDiagnosticMetrics extends StatelessWebexPlugin {
|
|
|
385
488
|
identifiers.webexSiteName = meeting.meetingInfo?.siteName;
|
|
386
489
|
}
|
|
387
490
|
|
|
491
|
+
if (meeting?.meetingInfo?.locusClusterUrl) {
|
|
492
|
+
identifiers.locusCluster = meeting.meetingInfo.locusClusterUrl;
|
|
493
|
+
}
|
|
494
|
+
|
|
388
495
|
if (mediaConnections) {
|
|
389
496
|
identifiers.mediaAgentAlias = mediaConnections?.[0]?.mediaAgentAlias;
|
|
390
497
|
identifiers.mediaAgentGroupId = mediaConnections?.[0]?.mediaAgentGroupId;
|
|
@@ -398,6 +505,10 @@ export default class CallDiagnosticMetrics extends StatelessWebexPlugin {
|
|
|
398
505
|
identifiers.globalMeetingId = globalMeetingId;
|
|
399
506
|
}
|
|
400
507
|
|
|
508
|
+
if (!identifiers?.locusCluster && locusCluster) {
|
|
509
|
+
identifiers.locusCluster = locusCluster;
|
|
510
|
+
}
|
|
511
|
+
|
|
401
512
|
if (identifiers.correlationId === undefined) {
|
|
402
513
|
throw new Error('Identifiers initialization failed.');
|
|
403
514
|
}
|
|
@@ -426,7 +537,7 @@ export default class CallDiagnosticMetrics extends StatelessWebexPlugin {
|
|
|
426
537
|
sent: 'not_defined_yet',
|
|
427
538
|
},
|
|
428
539
|
// @ts-ignore
|
|
429
|
-
senderCountryCode: this.webex.meetings
|
|
540
|
+
senderCountryCode: this.webex.meetings?.geoHintInfo?.countryCode,
|
|
430
541
|
event: eventData,
|
|
431
542
|
};
|
|
432
543
|
|
|
@@ -602,6 +713,7 @@ export default class CallDiagnosticMetrics extends StatelessWebexPlugin {
|
|
|
602
713
|
mediaEngineSoftwareVersion: getOSVersion() || 'unknown',
|
|
603
714
|
startTime: new Date().toISOString(),
|
|
604
715
|
},
|
|
716
|
+
webexSubServiceType: this.getSubServiceType(meeting),
|
|
605
717
|
};
|
|
606
718
|
|
|
607
719
|
// merge any new properties, or override existing ones
|
|
@@ -624,7 +736,7 @@ export default class CallDiagnosticMetrics extends StatelessWebexPlugin {
|
|
|
624
736
|
* @param arg.clientErrorCode
|
|
625
737
|
* @param arg.serviceErrorCode
|
|
626
738
|
* @param arg.payloadOverrides
|
|
627
|
-
* @param arg.
|
|
739
|
+
* @param arg.httpCode
|
|
628
740
|
* @returns
|
|
629
741
|
*/
|
|
630
742
|
public getErrorPayloadForClientErrorCode({
|
|
@@ -633,14 +745,14 @@ export default class CallDiagnosticMetrics extends StatelessWebexPlugin {
|
|
|
633
745
|
serviceErrorName,
|
|
634
746
|
rawErrorMessage,
|
|
635
747
|
payloadOverrides,
|
|
636
|
-
|
|
748
|
+
httpCode,
|
|
637
749
|
}: {
|
|
638
750
|
clientErrorCode: number;
|
|
639
751
|
serviceErrorCode: any;
|
|
640
752
|
serviceErrorName?: any;
|
|
641
753
|
rawErrorMessage?: string;
|
|
642
754
|
payloadOverrides?: any;
|
|
643
|
-
|
|
755
|
+
httpCode?: number;
|
|
644
756
|
}): ClientEventError {
|
|
645
757
|
let error: ClientEventError;
|
|
646
758
|
|
|
@@ -654,7 +766,7 @@ export default class CallDiagnosticMetrics extends StatelessWebexPlugin {
|
|
|
654
766
|
serviceErrorName ? {errorData: {errorName: serviceErrorName}} : {},
|
|
655
767
|
{serviceErrorCode},
|
|
656
768
|
{rawErrorMessage},
|
|
657
|
-
|
|
769
|
+
httpCode === undefined ? {} : {httpCode},
|
|
658
770
|
partialParsedError,
|
|
659
771
|
payloadOverrides || {}
|
|
660
772
|
);
|
|
@@ -823,7 +935,12 @@ export default class CallDiagnosticMetrics extends StatelessWebexPlugin {
|
|
|
823
935
|
}
|
|
824
936
|
|
|
825
937
|
const rawErrorMessage = rawError.message;
|
|
826
|
-
const
|
|
938
|
+
const httpCode = rawError.statusCode;
|
|
939
|
+
const serviceErrorCode =
|
|
940
|
+
rawError?.error?.body?.errorCode ||
|
|
941
|
+
rawError?.body?.errorCode ||
|
|
942
|
+
rawError?.body?.code ||
|
|
943
|
+
rawError?.body?.reason?.reasonCode;
|
|
827
944
|
let payload;
|
|
828
945
|
|
|
829
946
|
if (rawError.name) {
|
|
@@ -833,7 +950,7 @@ export default class CallDiagnosticMetrics extends StatelessWebexPlugin {
|
|
|
833
950
|
clientErrorCode: BROWSER_MEDIA_ERROR_NAME_TO_CLIENT_ERROR_CODES_MAP[rawError.name],
|
|
834
951
|
serviceErrorName: rawError.name,
|
|
835
952
|
rawErrorMessage,
|
|
836
|
-
|
|
953
|
+
httpCode,
|
|
837
954
|
});
|
|
838
955
|
}
|
|
839
956
|
}
|
|
@@ -848,16 +965,10 @@ export default class CallDiagnosticMetrics extends StatelessWebexPlugin {
|
|
|
848
965
|
SDP_OFFER_CREATION_ERROR_MAP[causeType] || SDP_OFFER_CREATION_ERROR_MAP.GENERAL,
|
|
849
966
|
serviceErrorName: rawError.name,
|
|
850
967
|
rawErrorMessage,
|
|
851
|
-
|
|
968
|
+
httpCode,
|
|
852
969
|
});
|
|
853
970
|
}
|
|
854
971
|
|
|
855
|
-
const serviceErrorCode =
|
|
856
|
-
rawError?.error?.body?.errorCode ||
|
|
857
|
-
rawError?.body?.errorCode ||
|
|
858
|
-
rawError?.body?.code ||
|
|
859
|
-
rawError?.body?.reason?.reasonCode;
|
|
860
|
-
|
|
861
972
|
if (serviceErrorCode) {
|
|
862
973
|
const clientErrorCode = SERVICE_ERROR_CODES_TO_CLIENT_ERROR_CODES_MAP[serviceErrorCode];
|
|
863
974
|
if (clientErrorCode && !payload) {
|
|
@@ -865,17 +976,30 @@ export default class CallDiagnosticMetrics extends StatelessWebexPlugin {
|
|
|
865
976
|
clientErrorCode,
|
|
866
977
|
serviceErrorCode,
|
|
867
978
|
rawErrorMessage,
|
|
868
|
-
|
|
979
|
+
httpCode,
|
|
869
980
|
});
|
|
870
981
|
}
|
|
982
|
+
}
|
|
871
983
|
|
|
984
|
+
const locusHttpClientErrorCode = LOCUS_HTTP_STATUS_TO_CLIENT_ERROR_CODE[httpCode];
|
|
985
|
+
const requestUrl = rawError.options?.uri || rawError.options?.url;
|
|
986
|
+
if (locusHttpClientErrorCode && !payload && requestUrl?.includes('locus')) {
|
|
987
|
+
payload = this.getErrorPayloadForClientErrorCode({
|
|
988
|
+
clientErrorCode: locusHttpClientErrorCode,
|
|
989
|
+
serviceErrorCode,
|
|
990
|
+
rawErrorMessage,
|
|
991
|
+
httpCode,
|
|
992
|
+
});
|
|
993
|
+
}
|
|
994
|
+
|
|
995
|
+
if (serviceErrorCode) {
|
|
872
996
|
// by default, if it is locus error, return new locus err
|
|
873
997
|
if (isLocusServiceErrorCode(serviceErrorCode) && !payload) {
|
|
874
998
|
payload = this.getErrorPayloadForClientErrorCode({
|
|
875
999
|
clientErrorCode: NEW_LOCUS_ERROR_CLIENT_CODE,
|
|
876
1000
|
serviceErrorCode,
|
|
877
1001
|
rawErrorMessage,
|
|
878
|
-
|
|
1002
|
+
httpCode,
|
|
879
1003
|
});
|
|
880
1004
|
}
|
|
881
1005
|
}
|
|
@@ -885,7 +1009,7 @@ export default class CallDiagnosticMetrics extends StatelessWebexPlugin {
|
|
|
885
1009
|
clientErrorCode: MEETING_INFO_LOOKUP_ERROR_CLIENT_CODE,
|
|
886
1010
|
serviceErrorCode,
|
|
887
1011
|
rawErrorMessage,
|
|
888
|
-
|
|
1012
|
+
httpCode,
|
|
889
1013
|
});
|
|
890
1014
|
}
|
|
891
1015
|
|
|
@@ -895,7 +1019,7 @@ export default class CallDiagnosticMetrics extends StatelessWebexPlugin {
|
|
|
895
1019
|
serviceErrorCode,
|
|
896
1020
|
payloadOverrides: rawError.payloadOverrides,
|
|
897
1021
|
rawErrorMessage,
|
|
898
|
-
|
|
1022
|
+
httpCode,
|
|
899
1023
|
});
|
|
900
1024
|
}
|
|
901
1025
|
|
|
@@ -905,7 +1029,7 @@ export default class CallDiagnosticMetrics extends StatelessWebexPlugin {
|
|
|
905
1029
|
serviceErrorCode,
|
|
906
1030
|
payloadOverrides: rawError.payloadOverrides,
|
|
907
1031
|
rawErrorMessage,
|
|
908
|
-
|
|
1032
|
+
httpCode,
|
|
909
1033
|
});
|
|
910
1034
|
}
|
|
911
1035
|
|
|
@@ -917,7 +1041,7 @@ export default class CallDiagnosticMetrics extends StatelessWebexPlugin {
|
|
|
917
1041
|
serviceErrorName: rawError?.name,
|
|
918
1042
|
payloadOverrides: rawError.payloadOverrides,
|
|
919
1043
|
rawErrorMessage,
|
|
920
|
-
|
|
1044
|
+
httpCode,
|
|
921
1045
|
});
|
|
922
1046
|
}
|
|
923
1047
|
|
|
@@ -949,6 +1073,7 @@ export default class CallDiagnosticMetrics extends StatelessWebexPlugin {
|
|
|
949
1073
|
globalMeetingId,
|
|
950
1074
|
webexConferenceIdStr,
|
|
951
1075
|
sessionCorrelationId,
|
|
1076
|
+
locusCluster,
|
|
952
1077
|
} = options;
|
|
953
1078
|
|
|
954
1079
|
// @ts-ignore
|
|
@@ -982,9 +1107,10 @@ export default class CallDiagnosticMetrics extends StatelessWebexPlugin {
|
|
|
982
1107
|
webexConferenceIdStr,
|
|
983
1108
|
globalMeetingId,
|
|
984
1109
|
sessionCorrelationId,
|
|
1110
|
+
locusCluster,
|
|
985
1111
|
});
|
|
986
1112
|
|
|
987
|
-
// create common event object
|
|
1113
|
+
// create common event object structure
|
|
988
1114
|
const commonEventObject = {
|
|
989
1115
|
name,
|
|
990
1116
|
canProceed: true,
|
|
@@ -997,6 +1123,7 @@ export default class CallDiagnosticMetrics extends StatelessWebexPlugin {
|
|
|
997
1123
|
'loginType' in meeting.callStateForMetrics
|
|
998
1124
|
? meeting.callStateForMetrics.loginType
|
|
999
1125
|
: this.getCurLoginType(),
|
|
1126
|
+
telemetryOptOut: this.getTelemetryOptOut(),
|
|
1000
1127
|
isConvergedArchitectureEnabled: this.getIsConvergedArchitectureEnabled({
|
|
1001
1128
|
meetingId,
|
|
1002
1129
|
}),
|
|
@@ -1005,6 +1132,9 @@ export default class CallDiagnosticMetrics extends StatelessWebexPlugin {
|
|
|
1005
1132
|
webexSubServiceType: this.getSubServiceType(meeting),
|
|
1006
1133
|
// @ts-ignore
|
|
1007
1134
|
webClientPreload: this.webex.meetings?.config?.metrics?.webClientPreload,
|
|
1135
|
+
isVipMeeting: meeting?.meetingInfo?.vipmeeting || false,
|
|
1136
|
+
isAutomatedUser: AutomatedUserUtils.isAutomatedUser(),
|
|
1137
|
+
userActivation: this.getUserActivation(),
|
|
1008
1138
|
};
|
|
1009
1139
|
|
|
1010
1140
|
const joinFlowVersion = options.joinFlowVersion ?? meeting.callStateForMetrics?.joinFlowVersion;
|
|
@@ -1018,9 +1148,11 @@ export default class CallDiagnosticMetrics extends StatelessWebexPlugin {
|
|
|
1018
1148
|
commonEventObject.meetingJoinedTime = meetingJoinedTime;
|
|
1019
1149
|
}
|
|
1020
1150
|
|
|
1021
|
-
|
|
1151
|
+
const meetingJoinPhase =
|
|
1152
|
+
options.meetingJoinPhase ?? meeting.callStateForMetrics?.meetingJoinPhase;
|
|
1153
|
+
if (meetingJoinPhase) {
|
|
1022
1154
|
// @ts-ignore
|
|
1023
|
-
commonEventObject.meetingJoinPhase =
|
|
1155
|
+
commonEventObject.meetingJoinPhase = meetingJoinPhase;
|
|
1024
1156
|
}
|
|
1025
1157
|
|
|
1026
1158
|
return commonEventObject;
|
|
@@ -1101,8 +1233,14 @@ export default class CallDiagnosticMetrics extends StatelessWebexPlugin {
|
|
|
1101
1233
|
options?: SubmitClientEventOptions;
|
|
1102
1234
|
errors?: ClientEventPayloadError;
|
|
1103
1235
|
}) {
|
|
1104
|
-
const {
|
|
1105
|
-
|
|
1236
|
+
const {
|
|
1237
|
+
correlationId,
|
|
1238
|
+
globalMeetingId,
|
|
1239
|
+
webexConferenceIdStr,
|
|
1240
|
+
preLoginId,
|
|
1241
|
+
sessionCorrelationId,
|
|
1242
|
+
locusCluster,
|
|
1243
|
+
} = options;
|
|
1106
1244
|
|
|
1107
1245
|
// grab identifiers
|
|
1108
1246
|
const identifiers = this.getIdentifiers({
|
|
@@ -1111,6 +1249,7 @@ export default class CallDiagnosticMetrics extends StatelessWebexPlugin {
|
|
|
1111
1249
|
preLoginId,
|
|
1112
1250
|
globalMeetingId,
|
|
1113
1251
|
webexConferenceIdStr,
|
|
1252
|
+
locusCluster,
|
|
1114
1253
|
});
|
|
1115
1254
|
|
|
1116
1255
|
// create client event object
|
|
@@ -1124,17 +1263,19 @@ export default class CallDiagnosticMetrics extends StatelessWebexPlugin {
|
|
|
1124
1263
|
isMercuryConnected: this.isMercuryConnected,
|
|
1125
1264
|
},
|
|
1126
1265
|
loginType: this.getCurLoginType(),
|
|
1266
|
+
telemetryOptOut: this.getTelemetryOptOut(),
|
|
1127
1267
|
// @ts-ignore
|
|
1128
1268
|
webClientPreload: this.webex.meetings?.config?.metrics?.webClientPreload,
|
|
1269
|
+
isAutomatedUser: AutomatedUserUtils.isAutomatedUser(),
|
|
1270
|
+
userActivation: this.getUserActivation(),
|
|
1129
1271
|
};
|
|
1130
1272
|
|
|
1131
1273
|
if (options.joinFlowVersion) {
|
|
1132
1274
|
clientEventObject.joinFlowVersion = options.joinFlowVersion;
|
|
1133
1275
|
}
|
|
1134
1276
|
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
}
|
|
1277
|
+
// No meeting exists yet for pre-meeting events, so the join phase is pre-join by construction
|
|
1278
|
+
clientEventObject.meetingJoinPhase = options.meetingJoinPhase ?? 'pre-join';
|
|
1138
1279
|
|
|
1139
1280
|
if (options.userNameInput) {
|
|
1140
1281
|
clientEventObject.userNameInput = options.userNameInput;
|
|
@@ -1335,6 +1476,7 @@ export default class CallDiagnosticMetrics extends StatelessWebexPlugin {
|
|
|
1335
1476
|
eventPayload: event,
|
|
1336
1477
|
type: ['diagnostic-event'],
|
|
1337
1478
|
};
|
|
1479
|
+
|
|
1338
1480
|
this.preLoginMetricsBatcher.savePreLoginId(preLoginId);
|
|
1339
1481
|
|
|
1340
1482
|
return this.preLoginMetricsBatcher.request(finalEvent);
|
|
@@ -1382,7 +1524,7 @@ export default class CallDiagnosticMetrics extends StatelessWebexPlugin {
|
|
|
1382
1524
|
},
|
|
1383
1525
|
headers: {},
|
|
1384
1526
|
// @ts-ignore
|
|
1385
|
-
waitForServiceTimeout: this.webex.internal.metrics
|
|
1527
|
+
waitForServiceTimeout: this.webex.internal.metrics?.config?.waitForServiceTimeout,
|
|
1386
1528
|
};
|
|
1387
1529
|
|
|
1388
1530
|
if (options.preLoginId) {
|
|
@@ -284,7 +284,8 @@ export const prepareDiagnosticMetricItem = (webex: any, item: any) => {
|
|
|
284
284
|
devicePairingType: webex.devicemanager.getPairedMethod(),
|
|
285
285
|
deviceURL: pairedDevice.url,
|
|
286
286
|
isPersonalDevice: pairedDevice.mode === 'personal',
|
|
287
|
-
productName:
|
|
287
|
+
productName:
|
|
288
|
+
pairedDevice.devices?.length > 0 ? pairedDevice.devices[0]?.productName : undefined,
|
|
288
289
|
};
|
|
289
290
|
item.eventPayload.event.pairingState = 'paired';
|
|
290
291
|
item.eventPayload.event.pairedDevice = devicePayload;
|
|
@@ -389,6 +390,11 @@ export const prepareDiagnosticMetricItem = (webex: any, item: any) => {
|
|
|
389
390
|
|
|
390
391
|
item.eventPayload.origin = Object.assign(origin, item.eventPayload.origin);
|
|
391
392
|
|
|
393
|
+
// Mark call milestones in logs for easier filtering and analysis
|
|
394
|
+
if (eventName) {
|
|
395
|
+
webex.logger.log('Milestone,CallDiagnostic', eventName);
|
|
396
|
+
}
|
|
397
|
+
|
|
392
398
|
webex.logger.log(
|
|
393
399
|
`CallDiagnosticLatencies,prepareDiagnosticMetricItem: ${JSON.stringify({
|
|
394
400
|
latencies: Object.fromEntries(cdl.latencyTimestamps),
|
|
@@ -8,6 +8,8 @@ export const CALL_DIAGNOSTIC_LOG_IDENTIFIER = 'call-diagnostic-events -> ';
|
|
|
8
8
|
export const CALL_FEATURE_LOG_IDENTIFIER = 'call-diagnostic-events-feature -> ';
|
|
9
9
|
|
|
10
10
|
export const AUTHENTICATION_FAILED_CODE = 1010;
|
|
11
|
+
export const LOCUS_RATE_LIMITED_OUTGOING_CLIENT_CODE = 1002;
|
|
12
|
+
export const LOCUS_UNAVAILABLE_CLIENT_CODE = 1003;
|
|
11
13
|
export const NETWORK_ERROR = 1026;
|
|
12
14
|
export const NEW_LOCUS_ERROR_CLIENT_CODE = 4008;
|
|
13
15
|
export const MEETING_INFO_LOOKUP_ERROR_CLIENT_CODE = 4100;
|
|
@@ -26,6 +28,7 @@ export const WEBEX_SUB_SERVICE_TYPES: Record<string, ClientSubServiceType> = {
|
|
|
26
28
|
SCHEDULED_MEETING: 'ScheduledMeeting',
|
|
27
29
|
WEBINAR: 'Webinar',
|
|
28
30
|
WEBCAST: 'Webcast',
|
|
31
|
+
LARGE_SCALE_WEBINAR: 'LargeScaleWebinar',
|
|
29
32
|
};
|
|
30
33
|
|
|
31
34
|
// Found in https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia
|
|
@@ -136,6 +139,7 @@ export const ERROR_DESCRIPTIONS = {
|
|
|
136
139
|
WEBRTC_API_NOT_AVAILABLE: 'WebrtcApiNotAvailableError',
|
|
137
140
|
WDM_RESTRICTED_REGION: 'WdmRestrictedRegion',
|
|
138
141
|
USER_NOT_ALLOWED_JOIN_WEBINAR: 'UserNotAllowedJoinWebinar',
|
|
142
|
+
INVALID_MEETING_INFO: 'InvalidMeetingInfo',
|
|
139
143
|
};
|
|
140
144
|
|
|
141
145
|
export const SERVICE_ERROR_CODES_TO_CLIENT_ERROR_CODES_MAP = {
|
|
@@ -146,6 +150,8 @@ export const SERVICE_ERROR_CODES_TO_CLIENT_ERROR_CODES_MAP = {
|
|
|
146
150
|
99002: 4100,
|
|
147
151
|
// Cannot find the data. Unkown meeting.
|
|
148
152
|
99009: 4100,
|
|
153
|
+
// The input parameters contain invalid item
|
|
154
|
+
99019: 4105,
|
|
149
155
|
// Meeting is not allow to cross env
|
|
150
156
|
58500: 4100,
|
|
151
157
|
// Input parameters contain invalit item
|
|
@@ -201,6 +207,8 @@ export const SERVICE_ERROR_CODES_TO_CLIENT_ERROR_CODES_MAP = {
|
|
|
201
207
|
423005: 4005,
|
|
202
208
|
// Wrong password or host key with too many requests
|
|
203
209
|
423006: 4005,
|
|
210
|
+
// PanelistPasswordError too many time,please input captcha code
|
|
211
|
+
423008: 4005,
|
|
204
212
|
// PasswordError with right captcha, please input captcha code
|
|
205
213
|
423010: 4005,
|
|
206
214
|
// PasswordOrHostKeyError with right captcha, please input captcha code
|
|
@@ -227,6 +235,8 @@ export const SERVICE_ERROR_CODES_TO_CLIENT_ERROR_CODES_MAP = {
|
|
|
227
235
|
403003: 4101,
|
|
228
236
|
// Attendee email is required
|
|
229
237
|
403030: 4101,
|
|
238
|
+
// webinar need login when un-invited attendee join
|
|
239
|
+
403106: 4104,
|
|
230
240
|
|
|
231
241
|
// ---- Locus ------
|
|
232
242
|
// FREE_USER_MAX_PARTICIPANTS_EXCEEDED
|
|
@@ -696,6 +706,12 @@ export const CLIENT_ERROR_CODE_TO_ERROR_PAYLOAD: Record<number, Partial<ClientEv
|
|
|
696
706
|
category: 'expected',
|
|
697
707
|
fatal: true,
|
|
698
708
|
},
|
|
709
|
+
4105: {
|
|
710
|
+
errorDescription: ERROR_DESCRIPTIONS.INVALID_MEETING_INFO,
|
|
711
|
+
category: 'expected',
|
|
712
|
+
fatal: false,
|
|
713
|
+
shownToUser: true,
|
|
714
|
+
},
|
|
699
715
|
2729: {
|
|
700
716
|
errorDescription: ERROR_DESCRIPTIONS.NO_MEDIA_FOUND,
|
|
701
717
|
category: 'expected',
|