@webex/internal-plugin-metrics 3.5.0-next.16 → 3.5.0-next.18
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/metrics.js +1 -1
- package/dist/metrics.types.js.map +1 -1
- package/dist/rtcMetrics/index.js +33 -12
- package/dist/rtcMetrics/index.js.map +1 -1
- package/dist/types/metrics.types.d.ts +15 -1
- package/dist/types/rtcMetrics/index.d.ts +12 -3
- package/package.json +11 -11
- package/src/metrics.types.ts +63 -22
- package/src/rtcMetrics/index.ts +33 -14
- package/test/unit/spec/rtcMetrics/index.ts +42 -1
package/dist/metrics.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":[],"sources":["metrics.types.ts"],"sourcesContent":["import {\n ClientEvent as RawClientEvent,\n Event as RawEvent,\n MediaQualityEvent as RawMediaQualityEvent,\n} from '@webex/event-dictionary-ts';\n\nexport type Event = Omit<RawEvent, 'event'> & {event: RawClientEvent | RawMediaQualityEvent};\n\nexport type ClientEventError = NonNullable<RawClientEvent['errors']>[0];\n\nexport type EnvironmentType = NonNullable<RawEvent['origin']['environment']>;\n\nexport type NewEnvironmentType = NonNullable<RawEvent['origin']['newEnvironment']>;\n\nexport type ClientLaunchMethodType = NonNullable<\n RawEvent['origin']['clientInfo']\n>['clientLaunchMethod'];\n\nexport type BrowserLaunchMethodType = NonNullable<\n RawEvent['origin']['clientInfo']\n>['browserLaunchMethod'];\n\nexport type MetricEventProduct = 'webex' | 'wxcc_desktop';\n\nexport type MetricEventAgent = 'user' | 'browser' | 'system' | 'sdk' | 'redux' | 'service';\n\nexport type MetricEventVerb =\n | 'create'\n | '
|
|
1
|
+
{"version":3,"names":[],"sources":["metrics.types.ts"],"sourcesContent":["import {\n ClientEvent as RawClientEvent,\n Event as RawEvent,\n MediaQualityEvent as RawMediaQualityEvent,\n} from '@webex/event-dictionary-ts';\n\nexport type Event = Omit<RawEvent, 'event'> & {event: RawClientEvent | RawMediaQualityEvent};\n\nexport type ClientEventError = NonNullable<RawClientEvent['errors']>[0];\n\nexport type EnvironmentType = NonNullable<RawEvent['origin']['environment']>;\n\nexport type NewEnvironmentType = NonNullable<RawEvent['origin']['newEnvironment']>;\n\nexport type ClientLaunchMethodType = NonNullable<\n RawEvent['origin']['clientInfo']\n>['clientLaunchMethod'];\n\nexport type BrowserLaunchMethodType = NonNullable<\n RawEvent['origin']['clientInfo']\n>['browserLaunchMethod'];\n\nexport type MetricEventProduct = 'webex' | 'wxcc_desktop';\n\nexport type MetricEventAgent = 'user' | 'browser' | 'system' | 'sdk' | 'redux' | 'service';\n\nexport type MetricEventVerb =\n | 'abort'\n | 'accept'\n | 'activate'\n | 'apply'\n | 'answer'\n | 'build'\n | 'cancel'\n | 'click'\n | 'close'\n | 'complete'\n | 'create'\n | 'deactivate'\n | 'delete'\n | 'disable'\n | 'dismiss'\n | 'display'\n | 'enable'\n | 'end'\n | 'expire'\n | 'fail'\n | 'fetch'\n | 'fire'\n | 'generate'\n | 'get'\n | 'hide'\n | 'hover'\n | 'ignore'\n | 'invalidate'\n | 'join'\n | 'list'\n | 'load'\n | 'login'\n | 'logout'\n | 'notify'\n | 'open'\n | 'register'\n | 'reload'\n | 'reject'\n | 'request'\n | 'respond'\n | 'retry'\n | 'select'\n | 'set'\n | 'start'\n | 'submit'\n | 'sync'\n | 'toggle'\n | 'unregister'\n | 'update'\n | 'use'\n | 'validate'\n | 'view'\n | 'wait'\n | 'warn'\n | 'exit';\n\nexport type SubmitClientEventOptions = {\n meetingId?: string;\n mediaConnections?: any[];\n rawError?: any;\n correlationId?: string;\n sessionCorrelationId?: string;\n preLoginId?: string;\n environment?: EnvironmentType;\n newEnvironmentType?: NewEnvironmentType;\n clientLaunchMethod?: ClientLaunchMethodType;\n browserLaunchMethod?: BrowserLaunchMethodType;\n webexConferenceIdStr?: string;\n globalMeetingId?: string;\n};\n\nexport type SubmitMQEOptions = {\n meetingId: string;\n mediaConnections?: any[];\n networkType?: Event['origin']['networkType'];\n webexConferenceIdStr?: string;\n globalMeetingId?: string;\n};\n\nexport type InternalEvent = {\n name:\n | 'internal.client.meetinginfo.request'\n | 'internal.client.meetinginfo.response'\n | 'internal.register.device.request'\n | 'internal.register.device.response'\n | 'internal.reset.join.latencies'\n | 'internal.client.meeting.click.joinbutton'\n | 'internal.host.meeting.participant.admitted'\n | 'internal.client.meeting.interstitial-window.showed'\n | 'internal.client.interstitial-window.click.joinbutton'\n | 'internal.client.add-media.turn-discovery.start'\n | 'internal.client.add-media.turn-discovery.end';\n\n payload?: never;\n options?: never;\n};\n\nexport interface ClientEvent {\n name: RawClientEvent['name'];\n payload?: RawClientEvent;\n options?: SubmitClientEventOptions;\n}\n\nexport interface DeviceContext {\n app: {version: string};\n device: {id: string};\n locale: string;\n os: {\n name: string;\n version: string;\n };\n}\n\nexport type MetricType = 'behavioral' | 'operational' | 'business';\n\nexport type Table = 'wbxapp_callend_metrics' | 'business_metrics' | 'business_ucf' | 'default';\n\ntype InternalEventPayload = string | number | boolean;\nexport type EventPayload = Record<string, InternalEventPayload>;\nexport type BehavioralEventPayload = EventPayload; // for compatibilty, can be remove after wxcc-desktop did change their imports.\n\nexport interface BusinessEventPayload {\n metricName: string;\n timestamp: number;\n context: DeviceContext;\n browserDetails: EventPayload;\n value: EventPayload;\n}\n\nexport interface BusinessEvent {\n type: string[];\n eventPayload: BusinessEventPayload;\n}\n\nexport interface TaggedEvent {\n context: DeviceContext;\n metricName: string;\n tags: EventPayload;\n timestamp: number;\n type: [MetricType];\n}\n\nexport type BehavioralEvent = TaggedEvent;\nexport type OperationalEvent = TaggedEvent;\n\nexport interface FeatureEvent {\n // TODO: not implemented\n name: never;\n payload?: never;\n options?: never;\n}\n\nexport interface MediaQualityEvent {\n name: RawMediaQualityEvent['name'];\n payload?: RawMediaQualityEvent;\n options: SubmitMQEOptions;\n}\n\nexport type RecursivePartial<T> = {\n [P in keyof T]?: T[P] extends (infer U)[]\n ? RecursivePartial<U>[]\n : T[P] extends object\n ? RecursivePartial<T[P]>\n : T[P];\n};\n\nexport type MetricEventNames =\n | InternalEvent['name']\n | ClientEvent['name']\n | BehavioralEvent['metricName']\n | OperationalEvent['metricName']\n | BusinessEvent['eventPayload']['metricName']\n | FeatureEvent['name']\n | MediaQualityEvent['name'];\n\nexport type ClientInfo = NonNullable<RawEvent['origin']['clientInfo']>;\nexport type ClientType = NonNullable<RawEvent['origin']['clientInfo']>['clientType'];\nexport type SubClientType = NonNullable<RawEvent['origin']['clientInfo']>['subClientType'];\nexport type NetworkType = NonNullable<RawEvent['origin']>['networkType'];\n\nexport type ClientSubServiceType = ClientEvent['payload']['webexSubServiceType'];\nexport type ClientEventPayload = RecursivePartial<ClientEvent['payload']>;\nexport type ClientEventLeaveReason = ClientEvent['payload']['leaveReason'];\nexport type ClientEventPayloadError = ClientEvent['payload']['errors'];\n\nexport type MediaQualityEventAudioSetupDelayPayload = NonNullable<\n MediaQualityEvent['payload']\n>['audioSetupDelay'];\nexport type MediaQualityEventVideoSetupDelayPayload = NonNullable<\n MediaQualityEvent['payload']\n>['videoSetupDelay'];\n\nexport type SubmitMQEPayload = RecursivePartial<MediaQualityEvent['payload']> & {\n intervals: NonNullable<MediaQualityEvent['payload']>['intervals'];\n};\n\nexport type SubmitInternalEvent = (args: {\n name: InternalEvent['name'];\n payload?: RecursivePartial<InternalEvent['payload']>;\n options?: any;\n}) => void;\n\nexport type SubmitBehavioralEvent = (args: {\n product: MetricEventProduct;\n agent: MetricEventAgent;\n target: string;\n verb: MetricEventVerb;\n payload?: EventPayload;\n}) => void;\n\nexport type SubmitClientEvent = (args: {\n name: ClientEvent['name'];\n payload?: RecursivePartial<ClientEvent['payload']>;\n options?: SubmitClientEventOptions;\n}) => Promise<any>;\n\nexport type SubmitOperationalEvent = (args: {\n name: OperationalEvent['metricName'];\n payload: EventPayload;\n}) => void;\n\nexport type SubmitMQE = (args: {\n name: MediaQualityEvent['name'];\n payload: SubmitMQEPayload;\n options: any;\n}) => void;\n\nexport type BuildClientEventFetchRequestOptions = (args: {\n name: ClientEvent['name'];\n payload?: RecursivePartial<ClientEvent['payload']>;\n options?: SubmitClientEventOptions;\n}) => Promise<any>;\n\nexport type PreComputedLatencies =\n | 'internal.client.pageJMT'\n | 'internal.download.time'\n | 'internal.get.cluster.time'\n | 'internal.click.to.interstitial'\n | 'internal.refresh.captcha.time'\n | 'internal.exchange.ci.token.time'\n | 'internal.get.u2c.time'\n | 'internal.call.init.join.req'\n | 'internal.other.app.api.time'\n | 'internal.api.fetch.intelligence.models';\n\nexport interface IdType {\n meetingId?: string;\n callId?: string;\n}\n\nexport interface IMetricsAttributes {\n type: string;\n version: string;\n userId: string;\n correlationId: string;\n connectionId: string;\n data: any[];\n meetingId?: string;\n callId?: string;\n}\n"],"mappings":""}
|
package/dist/rtcMetrics/index.js
CHANGED
|
@@ -39,10 +39,12 @@ var RtcMetrics = exports.default = /*#__PURE__*/function () {
|
|
|
39
39
|
* Initialize the interval.
|
|
40
40
|
*
|
|
41
41
|
* @param {object} webex - The main `webex` object.
|
|
42
|
-
* @param {
|
|
42
|
+
* @param {IdType} Ids - Meeting or Calling id.
|
|
43
43
|
* @param {string} correlationId - The correlation id.
|
|
44
44
|
*/
|
|
45
|
-
function RtcMetrics(webex,
|
|
45
|
+
function RtcMetrics(webex, _ref, correlationId) {
|
|
46
|
+
var meetingId = _ref.meetingId,
|
|
47
|
+
callId = _ref.callId;
|
|
46
48
|
(0, _classCallCheck2.default)(this, RtcMetrics);
|
|
47
49
|
/**
|
|
48
50
|
* Array of MetricData items to be sent to the metrics service.
|
|
@@ -51,23 +53,37 @@ var RtcMetrics = exports.default = /*#__PURE__*/function () {
|
|
|
51
53
|
(0, _defineProperty2.default)(this, "intervalId", void 0);
|
|
52
54
|
(0, _defineProperty2.default)(this, "webex", void 0);
|
|
53
55
|
(0, _defineProperty2.default)(this, "meetingId", void 0);
|
|
56
|
+
(0, _defineProperty2.default)(this, "callId", void 0);
|
|
54
57
|
(0, _defineProperty2.default)(this, "correlationId", void 0);
|
|
55
58
|
(0, _defineProperty2.default)(this, "connectionId", void 0);
|
|
56
59
|
(0, _defineProperty2.default)(this, "shouldSendMetricsOnNextStatsReport", void 0);
|
|
57
60
|
// `window` is used to prevent typescript from returning a NodeJS.Timer.
|
|
58
61
|
this.intervalId = window.setInterval(this.sendMetricsInQueue.bind(this), 30 * 1000);
|
|
59
62
|
this.meetingId = meetingId;
|
|
63
|
+
this.callId = callId;
|
|
60
64
|
this.webex = webex;
|
|
61
65
|
this.correlationId = correlationId;
|
|
62
66
|
this.resetConnection();
|
|
63
67
|
}
|
|
64
68
|
|
|
65
69
|
/**
|
|
66
|
-
*
|
|
70
|
+
* Updates the call identifier with the provided value.
|
|
67
71
|
*
|
|
72
|
+
* @param {string} callId - The new call identifier to set.
|
|
68
73
|
* @returns {void}
|
|
69
74
|
*/
|
|
70
75
|
(0, _createClass2.default)(RtcMetrics, [{
|
|
76
|
+
key: "updateCallId",
|
|
77
|
+
value: function updateCallId(callId) {
|
|
78
|
+
this.callId = callId;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Check to see if the metrics queue has any items.
|
|
83
|
+
*
|
|
84
|
+
* @returns {void}
|
|
85
|
+
*/
|
|
86
|
+
}, {
|
|
71
87
|
key: "sendMetricsInQueue",
|
|
72
88
|
value: function sendMetricsInQueue() {
|
|
73
89
|
if (this.metricsQueue.length) {
|
|
@@ -175,6 +191,19 @@ var RtcMetrics = exports.default = /*#__PURE__*/function () {
|
|
|
175
191
|
}, {
|
|
176
192
|
key: "sendMetrics",
|
|
177
193
|
value: function sendMetrics() {
|
|
194
|
+
var metricsAttributes = {
|
|
195
|
+
type: 'webrtc',
|
|
196
|
+
version: '1.1.0',
|
|
197
|
+
userId: this.webex.internal.device.userId,
|
|
198
|
+
correlationId: this.correlationId,
|
|
199
|
+
connectionId: this.connectionId,
|
|
200
|
+
data: this.metricsQueue
|
|
201
|
+
};
|
|
202
|
+
if (this.meetingId) {
|
|
203
|
+
metricsAttributes.meetingId = this.meetingId;
|
|
204
|
+
} else if (this.callId) {
|
|
205
|
+
metricsAttributes.callId = this.callId;
|
|
206
|
+
}
|
|
178
207
|
this.webex.request({
|
|
179
208
|
method: 'POST',
|
|
180
209
|
service: 'unifiedTelemetry',
|
|
@@ -184,15 +213,7 @@ var RtcMetrics = exports.default = /*#__PURE__*/function () {
|
|
|
184
213
|
appId: _constants.default.APP_ID
|
|
185
214
|
},
|
|
186
215
|
body: {
|
|
187
|
-
metrics: [
|
|
188
|
-
type: 'webrtc',
|
|
189
|
-
version: '1.1.0',
|
|
190
|
-
userId: this.webex.internal.device.userId,
|
|
191
|
-
meetingId: this.meetingId,
|
|
192
|
-
correlationId: this.correlationId,
|
|
193
|
-
connectionId: this.connectionId,
|
|
194
|
-
data: this.metricsQueue
|
|
195
|
-
}]
|
|
216
|
+
metrics: [metricsAttributes]
|
|
196
217
|
}
|
|
197
218
|
});
|
|
198
219
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["_uuid","_interopRequireDefault","require","CallDiagnosticUtils","_interopRequireWildcard","_constants","_getRequireWildcardCache","e","_WeakMap","r","t","__esModule","_typeof","default","has","get","n","__proto__","a","_Object$defineProperty","_Object$getOwnPropertyDescriptor","u","Object","prototype","hasOwnProperty","call","i","set","parseJsonPayload","payload","JSON","parse","_","RtcMetrics","exports","webex","meetingId","correlationId","_classCallCheck2","_defineProperty2","intervalId","window","setInterval","sendMetricsInQueue","bind","resetConnection","_createClass2","key","value","metricsQueue","length","sendMetrics","sendNextMetrics","shouldSendMetricsOnNextStatsReport","addMetrics","data","name","map","anonymizeIp","push","parsedPayload","console","error","closeMetrics","clearInterval","stats","type","ip","anonymizeIPAddress","undefined","address","relatedAddress","_stringify","connectionId","uuid","v4","request","method","service","resource","headers","appId","RTC_METRICS","APP_ID","body","metrics","version","userId","internal","device"],"sources":["index.ts"],"sourcesContent":["/* eslint-disable class-methods-use-this */\nimport uuid from 'uuid';\nimport * as CallDiagnosticUtils from '../call-diagnostic/call-diagnostic-metrics.util';\nimport RTC_METRICS from './constants';\n\nconst parseJsonPayload = (payload: any[]): any | null => {\n try {\n if (payload && payload[0]) {\n return JSON.parse(payload[0]);\n }\n\n return null;\n } catch (_) {\n return null;\n }\n};\n\n/**\n * Rtc Metrics\n */\nexport default class RtcMetrics {\n /**\n * Array of MetricData items to be sent to the metrics service.\n */\n metricsQueue = [];\n\n intervalId: number;\n\n webex: any;\n\n meetingId: string;\n\n correlationId: string;\n\n connectionId: string;\n\n shouldSendMetricsOnNextStatsReport: boolean;\n\n /**\n * Initialize the interval.\n *\n * @param {object} webex - The main `webex` object.\n * @param {string} meetingId - The meeting id.\n * @param {string} correlationId - The correlation id.\n */\n constructor(webex, meetingId, correlationId) {\n // `window` is used to prevent typescript from returning a NodeJS.Timer.\n this.intervalId = window.setInterval(this.sendMetricsInQueue.bind(this), 30 * 1000);\n this.meetingId = meetingId;\n this.webex = webex;\n this.correlationId = correlationId;\n this.resetConnection();\n }\n\n /**\n * Check to see if the metrics queue has any items.\n *\n * @returns {void}\n */\n public sendMetricsInQueue() {\n if (this.metricsQueue.length) {\n this.sendMetrics();\n this.metricsQueue = [];\n }\n }\n\n /**\n * Forces sending metrics when we get the next stats-report\n *\n * This is useful for cases when something important happens that affects the media connection,\n * for example when we move from lobby into the meeting.\n *\n * @returns {void}\n */\n public sendNextMetrics() {\n this.shouldSendMetricsOnNextStatsReport = true;\n }\n\n /**\n * Add metrics items to the metrics queue.\n *\n * @param {object} data - An object with a payload array of metrics items.\n *\n * @returns {void}\n */\n addMetrics(data) {\n if (data.payload.length) {\n if (data.name === 'stats-report') {\n data.payload = data.payload.map(this.anonymizeIp);\n }\n\n this.metricsQueue.push(data);\n\n if (this.shouldSendMetricsOnNextStatsReport && data.name === 'stats-report') {\n // this is the first useful set of data (WCME gives it to us after 5s), send it out immediately\n // in case the user is unhappy and closes the browser early\n this.sendMetricsInQueue();\n this.shouldSendMetricsOnNextStatsReport = false;\n }\n\n try {\n // If a connection fails, send the rest of the metrics in queue and get a new connection id.\n const parsedPayload = parseJsonPayload(data.payload);\n if (\n data.name === 'onconnectionstatechange' &&\n parsedPayload &&\n parsedPayload.value === 'failed'\n ) {\n this.sendMetricsInQueue();\n this.resetConnection();\n }\n } catch (e) {\n console.error(e);\n }\n }\n }\n\n /**\n * Clear the metrics interval.\n *\n * @returns {void}\n */\n closeMetrics() {\n this.sendMetricsInQueue();\n clearInterval(this.intervalId);\n }\n\n /**\n * Anonymize IP addresses.\n *\n * @param {array} stats - An RTCStatsReport organized into an array of strings.\n * @returns {string}\n */\n anonymizeIp(stats: string): string {\n const data = JSON.parse(stats);\n // on local and remote candidates, anonymize the last 4 bits.\n if (data.type === 'local-candidate' || data.type === 'remote-candidate') {\n data.ip = CallDiagnosticUtils.anonymizeIPAddress(data.ip) || undefined;\n data.address = CallDiagnosticUtils.anonymizeIPAddress(data.address) || undefined;\n data.relatedAddress =\n CallDiagnosticUtils.anonymizeIPAddress(data.relatedAddress) || undefined;\n }\n\n return JSON.stringify(data);\n }\n\n /**\n * Set a new connection id.\n *\n * @returns {void}\n */\n private resetConnection() {\n this.connectionId = uuid.v4();\n this.shouldSendMetricsOnNextStatsReport = true;\n }\n\n /**\n * Send metrics to the metrics service.\n *\n * @returns {void}\n */\n private sendMetrics() {\n this.webex.request({\n method: 'POST',\n service: 'unifiedTelemetry',\n resource: 'metric/v2',\n headers: {\n type: 'webrtcMedia',\n appId: RTC_METRICS.APP_ID,\n },\n body: {\n metrics: [\n {\n type: 'webrtc',\n version: '1.1.0',\n userId: this.webex.internal.device.userId,\n meetingId: this.meetingId,\n correlationId: this.correlationId,\n connectionId: this.connectionId,\n data: this.metricsQueue,\n },\n ],\n },\n });\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"names":["_uuid","_interopRequireDefault","require","CallDiagnosticUtils","_interopRequireWildcard","_constants","_getRequireWildcardCache","e","_WeakMap","r","t","__esModule","_typeof","default","has","get","n","__proto__","a","_Object$defineProperty","_Object$getOwnPropertyDescriptor","u","Object","prototype","hasOwnProperty","call","i","set","parseJsonPayload","payload","JSON","parse","_","RtcMetrics","exports","webex","_ref","correlationId","meetingId","callId","_classCallCheck2","_defineProperty2","intervalId","window","setInterval","sendMetricsInQueue","bind","resetConnection","_createClass2","key","value","updateCallId","metricsQueue","length","sendMetrics","sendNextMetrics","shouldSendMetricsOnNextStatsReport","addMetrics","data","name","map","anonymizeIp","push","parsedPayload","console","error","closeMetrics","clearInterval","stats","type","ip","anonymizeIPAddress","undefined","address","relatedAddress","_stringify","connectionId","uuid","v4","metricsAttributes","version","userId","internal","device","request","method","service","resource","headers","appId","RTC_METRICS","APP_ID","body","metrics"],"sources":["index.ts"],"sourcesContent":["/* eslint-disable class-methods-use-this */\nimport uuid from 'uuid';\nimport * as CallDiagnosticUtils from '../call-diagnostic/call-diagnostic-metrics.util';\nimport RTC_METRICS from './constants';\nimport {IdType, IMetricsAttributes} from '../metrics.types';\n\nconst parseJsonPayload = (payload: any[]): any | null => {\n try {\n if (payload && payload[0]) {\n return JSON.parse(payload[0]);\n }\n\n return null;\n } catch (_) {\n return null;\n }\n};\n\n/**\n * Rtc Metrics\n */\nexport default class RtcMetrics {\n /**\n * Array of MetricData items to be sent to the metrics service.\n */\n metricsQueue = [];\n\n intervalId: number;\n\n webex: any;\n\n meetingId?: string;\n\n callId?: string;\n\n correlationId: string;\n\n connectionId: string;\n\n shouldSendMetricsOnNextStatsReport: boolean;\n\n /**\n * Initialize the interval.\n *\n * @param {object} webex - The main `webex` object.\n * @param {IdType} Ids - Meeting or Calling id.\n * @param {string} correlationId - The correlation id.\n */\n constructor(webex, {meetingId, callId}: IdType, correlationId) {\n // `window` is used to prevent typescript from returning a NodeJS.Timer.\n this.intervalId = window.setInterval(this.sendMetricsInQueue.bind(this), 30 * 1000);\n this.meetingId = meetingId;\n this.callId = callId;\n this.webex = webex;\n this.correlationId = correlationId;\n this.resetConnection();\n }\n\n /**\n * Updates the call identifier with the provided value.\n *\n * @param {string} callId - The new call identifier to set.\n * @returns {void}\n */\n public updateCallId(callId: string) {\n this.callId = callId;\n }\n\n /**\n * Check to see if the metrics queue has any items.\n *\n * @returns {void}\n */\n public sendMetricsInQueue() {\n if (this.metricsQueue.length) {\n this.sendMetrics();\n this.metricsQueue = [];\n }\n }\n\n /**\n * Forces sending metrics when we get the next stats-report\n *\n * This is useful for cases when something important happens that affects the media connection,\n * for example when we move from lobby into the meeting.\n *\n * @returns {void}\n */\n public sendNextMetrics() {\n this.shouldSendMetricsOnNextStatsReport = true;\n }\n\n /**\n * Add metrics items to the metrics queue.\n *\n * @param {object} data - An object with a payload array of metrics items.\n *\n * @returns {void}\n */\n addMetrics(data) {\n if (data.payload.length) {\n if (data.name === 'stats-report') {\n data.payload = data.payload.map(this.anonymizeIp);\n }\n\n this.metricsQueue.push(data);\n\n if (this.shouldSendMetricsOnNextStatsReport && data.name === 'stats-report') {\n // this is the first useful set of data (WCME gives it to us after 5s), send it out immediately\n // in case the user is unhappy and closes the browser early\n this.sendMetricsInQueue();\n this.shouldSendMetricsOnNextStatsReport = false;\n }\n\n try {\n // If a connection fails, send the rest of the metrics in queue and get a new connection id.\n const parsedPayload = parseJsonPayload(data.payload);\n if (\n data.name === 'onconnectionstatechange' &&\n parsedPayload &&\n parsedPayload.value === 'failed'\n ) {\n this.sendMetricsInQueue();\n this.resetConnection();\n }\n } catch (e) {\n console.error(e);\n }\n }\n }\n\n /**\n * Clear the metrics interval.\n *\n * @returns {void}\n */\n closeMetrics() {\n this.sendMetricsInQueue();\n clearInterval(this.intervalId);\n }\n\n /**\n * Anonymize IP addresses.\n *\n * @param {array} stats - An RTCStatsReport organized into an array of strings.\n * @returns {string}\n */\n anonymizeIp(stats: string): string {\n const data = JSON.parse(stats);\n // on local and remote candidates, anonymize the last 4 bits.\n if (data.type === 'local-candidate' || data.type === 'remote-candidate') {\n data.ip = CallDiagnosticUtils.anonymizeIPAddress(data.ip) || undefined;\n data.address = CallDiagnosticUtils.anonymizeIPAddress(data.address) || undefined;\n data.relatedAddress =\n CallDiagnosticUtils.anonymizeIPAddress(data.relatedAddress) || undefined;\n }\n\n return JSON.stringify(data);\n }\n\n /**\n * Set a new connection id.\n *\n * @returns {void}\n */\n private resetConnection() {\n this.connectionId = uuid.v4();\n this.shouldSendMetricsOnNextStatsReport = true;\n }\n\n /**\n * Send metrics to the metrics service.\n *\n * @returns {void}\n */\n private sendMetrics() {\n const metricsAttributes: IMetricsAttributes = {\n type: 'webrtc',\n version: '1.1.0',\n userId: this.webex.internal.device.userId,\n correlationId: this.correlationId,\n connectionId: this.connectionId,\n data: this.metricsQueue,\n };\n\n if (this.meetingId) {\n metricsAttributes.meetingId = this.meetingId;\n } else if (this.callId) {\n metricsAttributes.callId = this.callId;\n }\n\n this.webex.request({\n method: 'POST',\n service: 'unifiedTelemetry',\n resource: 'metric/v2',\n headers: {\n type: 'webrtcMedia',\n appId: RTC_METRICS.APP_ID,\n },\n body: {\n metrics: [metricsAttributes],\n },\n });\n }\n}\n"],"mappings":"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"}
|
|
@@ -9,7 +9,7 @@ export type ClientLaunchMethodType = NonNullable<RawEvent['origin']['clientInfo'
|
|
|
9
9
|
export type BrowserLaunchMethodType = NonNullable<RawEvent['origin']['clientInfo']>['browserLaunchMethod'];
|
|
10
10
|
export type MetricEventProduct = 'webex' | 'wxcc_desktop';
|
|
11
11
|
export type MetricEventAgent = 'user' | 'browser' | 'system' | 'sdk' | 'redux' | 'service';
|
|
12
|
-
export type MetricEventVerb = 'create' | '
|
|
12
|
+
export type MetricEventVerb = 'abort' | 'accept' | 'activate' | 'apply' | 'answer' | 'build' | 'cancel' | 'click' | 'close' | 'complete' | 'create' | 'deactivate' | 'delete' | 'disable' | 'dismiss' | 'display' | 'enable' | 'end' | 'expire' | 'fail' | 'fetch' | 'fire' | 'generate' | 'get' | 'hide' | 'hover' | 'ignore' | 'invalidate' | 'join' | 'list' | 'load' | 'login' | 'logout' | 'notify' | 'open' | 'register' | 'reload' | 'reject' | 'request' | 'respond' | 'retry' | 'select' | 'set' | 'start' | 'submit' | 'sync' | 'toggle' | 'unregister' | 'update' | 'use' | 'validate' | 'view' | 'wait' | 'warn' | 'exit';
|
|
13
13
|
export type SubmitClientEventOptions = {
|
|
14
14
|
meetingId?: string;
|
|
15
15
|
mediaConnections?: any[];
|
|
@@ -138,4 +138,18 @@ export type BuildClientEventFetchRequestOptions = (args: {
|
|
|
138
138
|
options?: SubmitClientEventOptions;
|
|
139
139
|
}) => Promise<any>;
|
|
140
140
|
export type PreComputedLatencies = 'internal.client.pageJMT' | 'internal.download.time' | 'internal.get.cluster.time' | 'internal.click.to.interstitial' | 'internal.refresh.captcha.time' | 'internal.exchange.ci.token.time' | 'internal.get.u2c.time' | 'internal.call.init.join.req' | 'internal.other.app.api.time' | 'internal.api.fetch.intelligence.models';
|
|
141
|
+
export interface IdType {
|
|
142
|
+
meetingId?: string;
|
|
143
|
+
callId?: string;
|
|
144
|
+
}
|
|
145
|
+
export interface IMetricsAttributes {
|
|
146
|
+
type: string;
|
|
147
|
+
version: string;
|
|
148
|
+
userId: string;
|
|
149
|
+
correlationId: string;
|
|
150
|
+
connectionId: string;
|
|
151
|
+
data: any[];
|
|
152
|
+
meetingId?: string;
|
|
153
|
+
callId?: string;
|
|
154
|
+
}
|
|
141
155
|
export {};
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { IdType } from '../metrics.types';
|
|
1
2
|
/**
|
|
2
3
|
* Rtc Metrics
|
|
3
4
|
*/
|
|
@@ -8,7 +9,8 @@ export default class RtcMetrics {
|
|
|
8
9
|
metricsQueue: any[];
|
|
9
10
|
intervalId: number;
|
|
10
11
|
webex: any;
|
|
11
|
-
meetingId
|
|
12
|
+
meetingId?: string;
|
|
13
|
+
callId?: string;
|
|
12
14
|
correlationId: string;
|
|
13
15
|
connectionId: string;
|
|
14
16
|
shouldSendMetricsOnNextStatsReport: boolean;
|
|
@@ -16,10 +18,17 @@ export default class RtcMetrics {
|
|
|
16
18
|
* Initialize the interval.
|
|
17
19
|
*
|
|
18
20
|
* @param {object} webex - The main `webex` object.
|
|
19
|
-
* @param {
|
|
21
|
+
* @param {IdType} Ids - Meeting or Calling id.
|
|
20
22
|
* @param {string} correlationId - The correlation id.
|
|
21
23
|
*/
|
|
22
|
-
constructor(webex: any, meetingId:
|
|
24
|
+
constructor(webex: any, { meetingId, callId }: IdType, correlationId: any);
|
|
25
|
+
/**
|
|
26
|
+
* Updates the call identifier with the provided value.
|
|
27
|
+
*
|
|
28
|
+
* @param {string} callId - The new call identifier to set.
|
|
29
|
+
* @returns {void}
|
|
30
|
+
*/
|
|
31
|
+
updateCallId(callId: string): void;
|
|
23
32
|
/**
|
|
24
33
|
* Check to see if the metrics queue has any items.
|
|
25
34
|
*
|
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.5.0-next.
|
|
30
|
-
"@webex/test-helper-mocha": "3.5.0-next.
|
|
31
|
-
"@webex/test-helper-mock-webex": "3.5.0-next.
|
|
32
|
-
"@webex/test-helper-test-users": "3.5.0-next.
|
|
29
|
+
"@webex/test-helper-chai": "3.5.0-next.18",
|
|
30
|
+
"@webex/test-helper-mocha": "3.5.0-next.18",
|
|
31
|
+
"@webex/test-helper-mock-webex": "3.5.0-next.18",
|
|
32
|
+
"@webex/test-helper-test-users": "3.5.0-next.18",
|
|
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.5.0-next.
|
|
39
|
-
"@webex/common-timers": "3.5.0-next.
|
|
38
|
+
"@webex/common": "3.5.0-next.18",
|
|
39
|
+
"@webex/common-timers": "3.5.0-next.18",
|
|
40
40
|
"@webex/event-dictionary-ts": "^1.0.1546",
|
|
41
|
-
"@webex/internal-plugin-metrics": "3.5.0-next.
|
|
42
|
-
"@webex/test-helper-chai": "3.5.0-next.
|
|
43
|
-
"@webex/test-helper-mock-webex": "3.5.0-next.
|
|
44
|
-
"@webex/webex-core": "3.5.0-next.
|
|
41
|
+
"@webex/internal-plugin-metrics": "3.5.0-next.18",
|
|
42
|
+
"@webex/test-helper-chai": "3.5.0-next.18",
|
|
43
|
+
"@webex/test-helper-mock-webex": "3.5.0-next.18",
|
|
44
|
+
"@webex/webex-core": "3.5.0-next.18",
|
|
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.5.0-next.
|
|
57
|
+
"version": "3.5.0-next.18"
|
|
58
58
|
}
|
package/src/metrics.types.ts
CHANGED
|
@@ -25,36 +25,61 @@ export type MetricEventProduct = 'webex' | 'wxcc_desktop';
|
|
|
25
25
|
export type MetricEventAgent = 'user' | 'browser' | 'system' | 'sdk' | 'redux' | 'service';
|
|
26
26
|
|
|
27
27
|
export type MetricEventVerb =
|
|
28
|
+
| 'abort'
|
|
29
|
+
| 'accept'
|
|
30
|
+
| 'activate'
|
|
31
|
+
| 'apply'
|
|
32
|
+
| 'answer'
|
|
33
|
+
| 'build'
|
|
34
|
+
| 'cancel'
|
|
35
|
+
| 'click'
|
|
36
|
+
| 'close'
|
|
37
|
+
| 'complete'
|
|
28
38
|
| 'create'
|
|
29
|
-
| '
|
|
39
|
+
| 'deactivate'
|
|
40
|
+
| 'delete'
|
|
41
|
+
| 'disable'
|
|
42
|
+
| 'dismiss'
|
|
43
|
+
| 'display'
|
|
44
|
+
| 'enable'
|
|
45
|
+
| 'end'
|
|
46
|
+
| 'expire'
|
|
47
|
+
| 'fail'
|
|
30
48
|
| 'fetch'
|
|
31
|
-
| '
|
|
49
|
+
| 'fire'
|
|
50
|
+
| 'generate'
|
|
51
|
+
| 'get'
|
|
52
|
+
| 'hide'
|
|
53
|
+
| 'hover'
|
|
54
|
+
| 'ignore'
|
|
55
|
+
| 'invalidate'
|
|
56
|
+
| 'join'
|
|
32
57
|
| 'list'
|
|
33
|
-
| '
|
|
58
|
+
| 'load'
|
|
59
|
+
| 'login'
|
|
60
|
+
| 'logout'
|
|
61
|
+
| 'notify'
|
|
62
|
+
| 'open'
|
|
63
|
+
| 'register'
|
|
64
|
+
| 'reload'
|
|
65
|
+
| 'reject'
|
|
66
|
+
| 'request'
|
|
67
|
+
| 'respond'
|
|
68
|
+
| 'retry'
|
|
34
69
|
| 'select'
|
|
35
|
-
| 'view'
|
|
36
70
|
| 'set'
|
|
71
|
+
| 'start'
|
|
72
|
+
| 'submit'
|
|
73
|
+
| 'sync'
|
|
37
74
|
| 'toggle'
|
|
38
|
-
| 'load'
|
|
39
|
-
| 'reload'
|
|
40
|
-
| 'click'
|
|
41
|
-
| 'hover'
|
|
42
|
-
| 'register'
|
|
43
75
|
| 'unregister'
|
|
44
|
-
| '
|
|
45
|
-
| 'disable'
|
|
76
|
+
| 'update'
|
|
46
77
|
| 'use'
|
|
47
|
-
| '
|
|
48
|
-
| '
|
|
49
|
-
| '
|
|
50
|
-
| '
|
|
51
|
-
| '
|
|
52
|
-
| 'sync'
|
|
53
|
-
| 'login'
|
|
54
|
-
| 'logout'
|
|
55
|
-
| 'answer'
|
|
56
|
-
| 'activate'
|
|
57
|
-
| 'deactivate';
|
|
78
|
+
| 'validate'
|
|
79
|
+
| 'view'
|
|
80
|
+
| 'wait'
|
|
81
|
+
| 'warn'
|
|
82
|
+
| 'exit';
|
|
58
83
|
|
|
59
84
|
export type SubmitClientEventOptions = {
|
|
60
85
|
meetingId?: string;
|
|
@@ -244,3 +269,19 @@ export type PreComputedLatencies =
|
|
|
244
269
|
| 'internal.call.init.join.req'
|
|
245
270
|
| 'internal.other.app.api.time'
|
|
246
271
|
| 'internal.api.fetch.intelligence.models';
|
|
272
|
+
|
|
273
|
+
export interface IdType {
|
|
274
|
+
meetingId?: string;
|
|
275
|
+
callId?: string;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
export interface IMetricsAttributes {
|
|
279
|
+
type: string;
|
|
280
|
+
version: string;
|
|
281
|
+
userId: string;
|
|
282
|
+
correlationId: string;
|
|
283
|
+
connectionId: string;
|
|
284
|
+
data: any[];
|
|
285
|
+
meetingId?: string;
|
|
286
|
+
callId?: string;
|
|
287
|
+
}
|
package/src/rtcMetrics/index.ts
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import uuid from 'uuid';
|
|
3
3
|
import * as CallDiagnosticUtils from '../call-diagnostic/call-diagnostic-metrics.util';
|
|
4
4
|
import RTC_METRICS from './constants';
|
|
5
|
+
import {IdType, IMetricsAttributes} from '../metrics.types';
|
|
5
6
|
|
|
6
7
|
const parseJsonPayload = (payload: any[]): any | null => {
|
|
7
8
|
try {
|
|
@@ -28,7 +29,9 @@ export default class RtcMetrics {
|
|
|
28
29
|
|
|
29
30
|
webex: any;
|
|
30
31
|
|
|
31
|
-
meetingId
|
|
32
|
+
meetingId?: string;
|
|
33
|
+
|
|
34
|
+
callId?: string;
|
|
32
35
|
|
|
33
36
|
correlationId: string;
|
|
34
37
|
|
|
@@ -40,18 +43,29 @@ export default class RtcMetrics {
|
|
|
40
43
|
* Initialize the interval.
|
|
41
44
|
*
|
|
42
45
|
* @param {object} webex - The main `webex` object.
|
|
43
|
-
* @param {
|
|
46
|
+
* @param {IdType} Ids - Meeting or Calling id.
|
|
44
47
|
* @param {string} correlationId - The correlation id.
|
|
45
48
|
*/
|
|
46
|
-
constructor(webex, meetingId, correlationId) {
|
|
49
|
+
constructor(webex, {meetingId, callId}: IdType, correlationId) {
|
|
47
50
|
// `window` is used to prevent typescript from returning a NodeJS.Timer.
|
|
48
51
|
this.intervalId = window.setInterval(this.sendMetricsInQueue.bind(this), 30 * 1000);
|
|
49
52
|
this.meetingId = meetingId;
|
|
53
|
+
this.callId = callId;
|
|
50
54
|
this.webex = webex;
|
|
51
55
|
this.correlationId = correlationId;
|
|
52
56
|
this.resetConnection();
|
|
53
57
|
}
|
|
54
58
|
|
|
59
|
+
/**
|
|
60
|
+
* Updates the call identifier with the provided value.
|
|
61
|
+
*
|
|
62
|
+
* @param {string} callId - The new call identifier to set.
|
|
63
|
+
* @returns {void}
|
|
64
|
+
*/
|
|
65
|
+
public updateCallId(callId: string) {
|
|
66
|
+
this.callId = callId;
|
|
67
|
+
}
|
|
68
|
+
|
|
55
69
|
/**
|
|
56
70
|
* Check to see if the metrics queue has any items.
|
|
57
71
|
*
|
|
@@ -160,6 +174,21 @@ export default class RtcMetrics {
|
|
|
160
174
|
* @returns {void}
|
|
161
175
|
*/
|
|
162
176
|
private sendMetrics() {
|
|
177
|
+
const metricsAttributes: IMetricsAttributes = {
|
|
178
|
+
type: 'webrtc',
|
|
179
|
+
version: '1.1.0',
|
|
180
|
+
userId: this.webex.internal.device.userId,
|
|
181
|
+
correlationId: this.correlationId,
|
|
182
|
+
connectionId: this.connectionId,
|
|
183
|
+
data: this.metricsQueue,
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
if (this.meetingId) {
|
|
187
|
+
metricsAttributes.meetingId = this.meetingId;
|
|
188
|
+
} else if (this.callId) {
|
|
189
|
+
metricsAttributes.callId = this.callId;
|
|
190
|
+
}
|
|
191
|
+
|
|
163
192
|
this.webex.request({
|
|
164
193
|
method: 'POST',
|
|
165
194
|
service: 'unifiedTelemetry',
|
|
@@ -169,17 +198,7 @@ export default class RtcMetrics {
|
|
|
169
198
|
appId: RTC_METRICS.APP_ID,
|
|
170
199
|
},
|
|
171
200
|
body: {
|
|
172
|
-
metrics: [
|
|
173
|
-
{
|
|
174
|
-
type: 'webrtc',
|
|
175
|
-
version: '1.1.0',
|
|
176
|
-
userId: this.webex.internal.device.userId,
|
|
177
|
-
meetingId: this.meetingId,
|
|
178
|
-
correlationId: this.correlationId,
|
|
179
|
-
connectionId: this.connectionId,
|
|
180
|
-
data: this.metricsQueue,
|
|
181
|
-
},
|
|
182
|
-
],
|
|
201
|
+
metrics: [metricsAttributes],
|
|
183
202
|
},
|
|
184
203
|
});
|
|
185
204
|
}
|
|
@@ -27,7 +27,7 @@ describe('RtcMetrics', () => {
|
|
|
27
27
|
clock = sinon.useFakeTimers();
|
|
28
28
|
window.setInterval = setInterval;
|
|
29
29
|
webex = new MockWebex();
|
|
30
|
-
metrics = new RtcMetrics(webex, 'mock-meeting-id', 'mock-correlation-id');
|
|
30
|
+
metrics = new RtcMetrics(webex, {meetingId: 'mock-meeting-id'}, 'mock-correlation-id');
|
|
31
31
|
anonymizeIpSpy = sandbox.spy(metrics, 'anonymizeIp');
|
|
32
32
|
});
|
|
33
33
|
|
|
@@ -152,4 +152,45 @@ describe('RtcMetrics', () => {
|
|
|
152
152
|
metrics.addMetrics({ name: 'stats-report', payload: [STATS_WITH_IP] });
|
|
153
153
|
assert.callCount(webex.request, 3);
|
|
154
154
|
});
|
|
155
|
+
|
|
156
|
+
describe('RtcMetrics - callId', () => {
|
|
157
|
+
let metrics: RtcMetrics;
|
|
158
|
+
let webex: MockWebex;
|
|
159
|
+
let clock;
|
|
160
|
+
let sandbox;
|
|
161
|
+
|
|
162
|
+
beforeEach(() => {
|
|
163
|
+
clock = sinon.useFakeTimers();
|
|
164
|
+
window.setInterval = setInterval;
|
|
165
|
+
webex = new MockWebex();
|
|
166
|
+
metrics = new RtcMetrics(webex, {callId: 'mock-call-id'}, 'mock-correlation-id');
|
|
167
|
+
sandbox = sinon.createSandbox();
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
afterEach(() => {
|
|
171
|
+
sandbox.restore();
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
it('sendMetrics should send a webex request with callId', () => {
|
|
175
|
+
assert.notCalled(webex.request);
|
|
176
|
+
|
|
177
|
+
metrics.addMetrics(FAKE_METRICS_ITEM);
|
|
178
|
+
(metrics as any).sendMetrics();
|
|
179
|
+
|
|
180
|
+
assert.callCount(webex.request, 1);
|
|
181
|
+
assert.calledWithMatch(webex.request, sinon.match.has('headers', {
|
|
182
|
+
type: 'webrtcMedia',
|
|
183
|
+
appId: RTC_METRICS.APP_ID,
|
|
184
|
+
}));
|
|
185
|
+
assert.calledWithMatch(webex.request, sinon.match.hasNested('body.metrics[0].data[0].payload', FAKE_METRICS_ITEM.payload));
|
|
186
|
+
assert.calledWithMatch(webex.request, sinon.match.hasNested('body.metrics[0].callId', 'mock-call-id'));
|
|
187
|
+
assert.calledWithMatch(webex.request, sinon.match.hasNested('body.metrics[0].correlationId', 'mock-correlation-id'));
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
it('should update the callId correctly', () => {
|
|
191
|
+
const newCallId = 'new-call-id';
|
|
192
|
+
metrics.updateCallId(newCallId);
|
|
193
|
+
assert.strictEqual(metrics.callId, newCallId);
|
|
194
|
+
});
|
|
195
|
+
});
|
|
155
196
|
});
|