@webex/internal-plugin-metrics 3.0.0-beta.417 → 3.0.0-beta.418
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/call-diagnostic/call-diagnostic-metrics-latencies.js +23 -9
- package/dist/call-diagnostic/call-diagnostic-metrics-latencies.js.map +1 -1
- package/dist/call-diagnostic/call-diagnostic-metrics.util.js +1 -0
- package/dist/call-diagnostic/call-diagnostic-metrics.util.js.map +1 -1
- package/dist/metrics.js +1 -1
- package/dist/metrics.types.js.map +1 -1
- package/dist/types/call-diagnostic/call-diagnostic-metrics-latencies.d.ts +14 -7
- package/dist/types/metrics.types.d.ts +1 -1
- package/package.json +8 -8
- package/src/call-diagnostic/call-diagnostic-metrics-latencies.ts +27 -10
- package/src/call-diagnostic/call-diagnostic-metrics.util.ts +1 -0
- package/src/metrics.types.ts +2 -1
- package/test/unit/spec/call-diagnostic/call-diagnostic-metrics-batcher.ts +4 -0
- package/test/unit/spec/call-diagnostic/call-diagnostic-metrics-latencies.ts +29 -22
- package/test/unit/spec/call-diagnostic/call-diagnostic-metrics.ts +54 -23
- package/test/unit/spec/call-diagnostic/call-diagnostic-metrics.util.ts +2 -1
- package/test/unit/spec/prelogin-metrics-batcher.ts +4 -2
|
@@ -54,6 +54,7 @@ var CallDiagnosticLatencies = /*#__PURE__*/function (_WebexPlugin) {
|
|
|
54
54
|
key: "clearTimestamps",
|
|
55
55
|
value: function clearTimestamps() {
|
|
56
56
|
this.latencyTimestamps.clear();
|
|
57
|
+
this.precomputedLatencies.clear();
|
|
57
58
|
}
|
|
58
59
|
|
|
59
60
|
/**
|
|
@@ -83,7 +84,8 @@ var CallDiagnosticLatencies = /*#__PURE__*/function (_WebexPlugin) {
|
|
|
83
84
|
/**
|
|
84
85
|
* Store timestamp value
|
|
85
86
|
* @param key - key
|
|
86
|
-
* @param value -value
|
|
87
|
+
* @param value - value
|
|
88
|
+
* @param options - store options
|
|
87
89
|
* @throws
|
|
88
90
|
* @returns
|
|
89
91
|
*/
|
|
@@ -113,33 +115,33 @@ var CallDiagnosticLatencies = /*#__PURE__*/function (_WebexPlugin) {
|
|
|
113
115
|
* Store precomputed latency value
|
|
114
116
|
* @param key - key
|
|
115
117
|
* @param value - value
|
|
116
|
-
* @param
|
|
118
|
+
* @param accumulate - when it is true, it overwrites existing value with sum of the current value and the new measurement otherwise just store the new measurement
|
|
117
119
|
* @throws
|
|
118
120
|
* @returns
|
|
119
121
|
*/
|
|
120
122
|
}, {
|
|
121
123
|
key: "saveLatency",
|
|
122
124
|
value: function saveLatency(key, value) {
|
|
123
|
-
var
|
|
124
|
-
var existingValue =
|
|
125
|
+
var accumulate = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
|
|
126
|
+
var existingValue = accumulate ? this.precomputedLatencies.get(key) || 0 : 0;
|
|
125
127
|
this.precomputedLatencies.set(key, value + existingValue);
|
|
126
128
|
}
|
|
127
129
|
|
|
128
130
|
/**
|
|
129
131
|
* Measure latency for a request
|
|
130
|
-
* @param key - key
|
|
131
132
|
* @param callback - callback for which you would like to measure latency
|
|
132
|
-
* @param
|
|
133
|
+
* @param key - key
|
|
134
|
+
* @param accumulate - when it is true, it overwrites existing value with sum of the current value and the new measurement otherwise just store the new measurement
|
|
133
135
|
* @returns
|
|
134
136
|
*/
|
|
135
137
|
}, {
|
|
136
138
|
key: "measureLatency",
|
|
137
139
|
value: function measureLatency(callback, key) {
|
|
138
140
|
var _this2 = this;
|
|
139
|
-
var
|
|
141
|
+
var accumulate = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
|
|
140
142
|
var start = performance.now();
|
|
141
143
|
return callback().finally(function () {
|
|
142
|
-
_this2.saveLatency(key, performance.now() - start,
|
|
144
|
+
_this2.saveLatency(key, performance.now() - start, accumulate);
|
|
143
145
|
});
|
|
144
146
|
}
|
|
145
147
|
|
|
@@ -522,8 +524,20 @@ var CallDiagnosticLatencies = /*#__PURE__*/function (_WebexPlugin) {
|
|
|
522
524
|
}
|
|
523
525
|
|
|
524
526
|
/**
|
|
525
|
-
*
|
|
527
|
+
* Get the latency for downloading intelligence models.
|
|
528
|
+
* @returns - latency
|
|
529
|
+
*/
|
|
530
|
+
}, {
|
|
531
|
+
key: "getDownloadIntelligenceModelsReqResp",
|
|
532
|
+
value: function getDownloadIntelligenceModelsReqResp() {
|
|
533
|
+
var downloadIntelligenceModelsReqResp = this.precomputedLatencies.get('internal.api.fetch.intelligence.models');
|
|
534
|
+
return downloadIntelligenceModelsReqResp ? Math.floor(downloadIntelligenceModelsReqResp) : undefined;
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
/**
|
|
538
|
+
* Get the total latency for all other app API requests.
|
|
526
539
|
* Excludes meeting info, because it's measured separately.
|
|
540
|
+
* @returns - latency
|
|
527
541
|
*/
|
|
528
542
|
}, {
|
|
529
543
|
key: "getOtherAppApiReqResp",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["CallDiagnosticLatencies","args","latencyTimestamps","precomputedLatencies","clear","meetingId","webex","meetings","meetingCollection","get","undefined","key","value","Date","getTime","options","setMeetingId","saveFirstTimestampOnly","set","overwrite","existingValue","callback","start","performance","now","finally","saveLatency","has","a","b","end","getDiffBetweenTimestamps","u2cLatency","Math","floor","interstitialJoinClickTimestamp","connectedMedia","lobbyTime","getStayLobbyTime","clickToInterstitial","getClickToInterstitial","interstitialToJoinOk","getInterstitialToJoinOK","joinReqResp","getJoinReqResp","ICESetupTime","getICESetupTime","joinConfJMT","getJoinConfJMT","totalMediaJMT","getMeeting","allowMediaInLobby","reachablityClusterReqResp","exchangeCITokenJMT","refreshCaptchaReqResp","otherAppApiJMT","WebexPlugin"],"sources":["call-diagnostic-metrics-latencies.ts"],"sourcesContent":["/* eslint-disable class-methods-use-this */\n/* eslint-disable valid-jsdoc */\nimport {WebexPlugin} from '@webex/webex-core';\n\nimport {MetricEventNames, PreComputedLatencies} from '../metrics.types';\n\n// we only care about client event and feature event for now\n\n/**\n * @description Helper class to store latencies timestamp and to calculate various latencies for CA.\n * @exports\n * @class CallDiagnosticLatencies\n */\nexport default class CallDiagnosticLatencies extends WebexPlugin {\n latencyTimestamps: Map<MetricEventNames, number>;\n precomputedLatencies: Map<PreComputedLatencies, number>;\n // meetingId that the current latencies are for\n private meetingId?: string;\n\n /**\n * @constructor\n */\n constructor(...args) {\n super(...args);\n this.latencyTimestamps = new Map();\n this.precomputedLatencies = new Map();\n }\n\n /**\n * Clear timestamps\n */\n public clearTimestamps() {\n this.latencyTimestamps.clear();\n }\n\n /**\n * Associate current latencies with a meeting id\n * @param meetingId\n */\n private setMeetingId(meetingId: string) {\n this.meetingId = meetingId;\n }\n\n /**\n * Returns the meeting object associated with current latencies\n * @returns meeting object\n */\n private getMeeting() {\n if (this.meetingId) {\n // @ts-ignore\n return this.webex.meetings.meetingCollection.get(this.meetingId);\n }\n\n return undefined;\n }\n\n /**\n * Store timestamp value\n * @param key - key\n * @param value -value\n * @throws\n * @returns\n */\n public saveTimestamp({\n key,\n value = new Date().getTime(),\n options = {},\n }: {\n key: MetricEventNames;\n value?: number;\n options?: {meetingId?: string};\n }) {\n // save the meetingId so we can use the meeting object in latency calculations if needed\n const {meetingId} = options;\n if (meetingId) {\n this.setMeetingId(meetingId);\n }\n // for some events we're only interested in the first timestamp not last\n // as these events can happen multiple times\n if (\n key === 'client.media.rx.start' ||\n key === 'client.media.tx.start' ||\n key === 'internal.client.meetinginfo.request' ||\n key === 'internal.client.meetinginfo.response'\n ) {\n this.saveFirstTimestampOnly(key, value);\n } else {\n this.latencyTimestamps.set(key, value);\n }\n }\n\n /**\n * Store precomputed latency value\n * @param key - key\n * @param value - value\n * @param overwrite - overwrite existing value or add it\n * @throws\n * @returns\n */\n public saveLatency(key: PreComputedLatencies, value: number, overwrite = true) {\n const existingValue = overwrite ? 0 : this.precomputedLatencies.get(key) || 0;\n this.precomputedLatencies.set(key, value + existingValue);\n }\n\n /**\n * Measure latency for a request\n * @param key - key\n * @param callback - callback for which you would like to measure latency\n * @param overwrite - overwite existing value or add to it\n * @returns\n */\n public measureLatency(\n callback: () => Promise<any>,\n key: PreComputedLatencies,\n overwrite = false\n ) {\n const start = performance.now();\n\n return callback().finally(() => {\n this.saveLatency(key, performance.now() - start, overwrite);\n });\n }\n\n /**\n * Store only the first timestamp value for the given key\n * @param key - key\n * @param value -value\n * @throws\n * @returns\n */\n saveFirstTimestampOnly(key: MetricEventNames, value: number = new Date().getTime()) {\n if (this.latencyTimestamps.has(key)) {\n return;\n }\n this.latencyTimestamps.set(key, value);\n }\n\n /**\n * Helper to calculate end - start\n * @param a start\n * @param b end\n * @returns latency\n */\n public getDiffBetweenTimestamps(a: MetricEventNames, b: MetricEventNames) {\n const start = this.latencyTimestamps.get(a);\n const end = this.latencyTimestamps.get(b);\n if (start && end) {\n return end - start;\n }\n\n return undefined;\n }\n\n /**\n * Meeting Info Request\n * @note Meeting Info request happen not just in the join phase. CA requires\n * metrics around meeting info request that are only part of join phase.\n * This internal.* event is used to track the real timestamps\n * (when the actual request/response happen). This is because the actual CA event is\n * sent inside the join method on the meeting object based on some logic, but that's not exactly when\n * those events are actually fired. The logic only confirms that they have happened, and we send them over.\n * @returns - latency\n */\n public getMeetingInfoReqResp() {\n return this.getDiffBetweenTimestamps(\n 'internal.client.meetinginfo.request',\n 'internal.client.meetinginfo.response'\n );\n }\n\n /**\n * Interstitial Time\n * @returns - latency\n */\n public getShowInterstitialTime() {\n return this.getDiffBetweenTimestamps(\n 'client.interstitial-window.start-launch',\n 'internal.client.interstitial-window.click.joinbutton'\n );\n }\n\n /**\n * getU2CTime\n * @returns - latency\n */\n public getU2CTime() {\n const u2cLatency = this.precomputedLatencies.get('internal.get.u2c.time');\n\n return u2cLatency ? Math.floor(u2cLatency) : undefined;\n }\n\n /**\n * Device Register Time\n * @returns - latency\n */\n public getRegisterWDMDeviceJMT() {\n return this.getDiffBetweenTimestamps(\n 'internal.register.device.request',\n 'internal.register.device.response'\n );\n }\n\n /**\n * Call Init Join Request\n * @returns - latency\n */\n public getCallInitJoinReq() {\n return this.getDiffBetweenTimestamps(\n 'internal.client.interstitial-window.click.joinbutton',\n 'client.locus.join.request'\n );\n }\n\n /**\n * Locus Join Request\n * @returns - latency\n */\n public getJoinReqResp() {\n return this.getDiffBetweenTimestamps('client.locus.join.request', 'client.locus.join.response');\n }\n\n /**\n * Time taken to do turn discovery\n * @returns - latency\n */\n public getTurnDiscoveryTime() {\n return this.getDiffBetweenTimestamps(\n 'internal.client.add-media.turn-discovery.start',\n 'internal.client.add-media.turn-discovery.end'\n );\n }\n\n /**\n * Local SDP Generated Remote SDP REceived\n * @returns - latency\n */\n public getLocalSDPGenRemoteSDPRecv() {\n return this.getDiffBetweenTimestamps(\n 'client.media-engine.local-sdp-generated',\n 'client.media-engine.remote-sdp-received'\n );\n }\n\n /**\n * ICE Setup Time\n * @returns - latency\n */\n public getICESetupTime() {\n return this.getDiffBetweenTimestamps('client.ice.start', 'client.ice.end');\n }\n\n /**\n * Audio ICE time\n * @returns - latency\n */\n public getAudioICESetupTime() {\n return this.getDiffBetweenTimestamps('client.ice.start', 'client.ice.end');\n }\n\n /**\n * Video ICE Time\n * @returns - latency\n */\n public getVideoICESetupTime() {\n return this.getDiffBetweenTimestamps('client.ice.start', 'client.ice.end');\n }\n\n /**\n * Share ICE Time\n * @returns - latency\n */\n public getShareICESetupTime() {\n return this.getDiffBetweenTimestamps('client.ice.start', 'client.ice.end');\n }\n\n /**\n * Stay Lobby Time\n * @returns - latency\n */\n public getStayLobbyTime() {\n return this.getDiffBetweenTimestamps(\n 'client.locus.join.response',\n 'internal.host.meeting.participant.admitted'\n );\n }\n\n /**\n * Page JMT\n * @returns - latency\n */\n public getPageJMT() {\n return this.precomputedLatencies.get('internal.client.pageJMT') || undefined;\n }\n\n /**\n * Download Time JMT\n * @returns - latency\n */\n public getDownloadTimeJMT() {\n return this.precomputedLatencies.get('internal.download.time') || undefined;\n }\n\n /**\n * Click To Interstitial\n * @returns - latency\n */\n public getClickToInterstitial() {\n // for normal join (where green join button exists before interstitial, i.e reminder, space list etc)\n if (this.latencyTimestamps.get('internal.client.meeting.click.joinbutton')) {\n return this.getDiffBetweenTimestamps(\n 'internal.client.meeting.click.joinbutton',\n 'internal.client.meeting.interstitial-window.showed'\n );\n }\n\n // for cross launch and guest flows\n return this.precomputedLatencies.get('internal.click.to.interstitial') || undefined;\n }\n\n /**\n * Interstitial To Join Ok\n * @returns - latency\n */\n public getInterstitialToJoinOK() {\n return this.getDiffBetweenTimestamps(\n 'internal.client.interstitial-window.click.joinbutton',\n 'client.locus.join.response'\n );\n }\n\n /**\n * Call Init To MediaEngineReady\n * @returns - latency\n */\n public getCallInitMediaEngineReady() {\n return this.getDiffBetweenTimestamps(\n 'internal.client.interstitial-window.click.joinbutton',\n 'client.media-engine.ready'\n );\n }\n\n /**\n * Interstitial To Media Ok\n * @returns - latency\n */\n public getInterstitialToMediaOKJMT() {\n const interstitialJoinClickTimestamp = this.latencyTimestamps.get(\n 'internal.client.interstitial-window.click.joinbutton'\n );\n\n // get the first timestamp\n const connectedMedia = this.latencyTimestamps.get('client.ice.end');\n\n const lobbyTime = this.getStayLobbyTime() || 0;\n\n if (interstitialJoinClickTimestamp && connectedMedia) {\n return connectedMedia - interstitialJoinClickTimestamp - lobbyTime;\n }\n\n return undefined;\n }\n\n /**\n * Total JMT\n * @returns - latency\n */\n public getTotalJMT() {\n const clickToInterstitial = this.getClickToInterstitial();\n const interstitialToJoinOk = this.getInterstitialToJoinOK();\n\n if (clickToInterstitial && interstitialToJoinOk) {\n return clickToInterstitial + interstitialToJoinOk;\n }\n\n return undefined;\n }\n\n /**\n * Join Conf JMT\n * @returns - latency\n */\n public getJoinConfJMT() {\n const joinReqResp = this.getJoinReqResp();\n const ICESetupTime = this.getICESetupTime();\n\n if (joinReqResp && ICESetupTime) {\n return joinReqResp + ICESetupTime;\n }\n\n return undefined;\n }\n\n /**\n * Total Media JMT\n * @returns - latency\n */\n public getTotalMediaJMT() {\n const clickToInterstitial = this.getClickToInterstitial();\n const interstitialToJoinOk = this.getInterstitialToJoinOK();\n const joinConfJMT = this.getJoinConfJMT();\n const lobbyTime = this.getStayLobbyTime();\n\n if (clickToInterstitial && interstitialToJoinOk && joinConfJMT) {\n const totalMediaJMT = clickToInterstitial + interstitialToJoinOk + joinConfJMT;\n if (this.getMeeting()?.allowMediaInLobby) {\n return totalMediaJMT;\n }\n\n return totalMediaJMT - lobbyTime;\n }\n\n return undefined;\n }\n\n /**\n * Client JMT\n * @returns - latency\n */\n public getClientJMT() {\n const interstitialToJoinOk = this.getInterstitialToJoinOK();\n const joinConfJMT = this.getJoinConfJMT();\n\n if (interstitialToJoinOk && joinConfJMT) {\n return interstitialToJoinOk - joinConfJMT;\n }\n\n return undefined;\n }\n\n /**\n * Audio setup delay receive\n */\n public getAudioJoinRespRxStart() {\n return this.getDiffBetweenTimestamps('client.locus.join.response', 'client.media.rx.start');\n }\n\n /**\n * Video setup delay receive\n */\n public getVideoJoinRespRxStart() {\n return this.getDiffBetweenTimestamps('client.locus.join.response', 'client.media.rx.start');\n }\n\n /**\n * Total latency for all get cluster request.\n */\n public getReachabilityClustersReqResp() {\n const reachablityClusterReqResp = this.precomputedLatencies.get('internal.get.cluster.time');\n\n return reachablityClusterReqResp ? Math.floor(reachablityClusterReqResp) : undefined;\n }\n\n /**\n * Audio setup delay transmit\n */\n public getAudioJoinRespTxStart() {\n return this.getDiffBetweenTimestamps('client.locus.join.response', 'client.media.tx.start');\n }\n\n /**\n * Video setup delay transmit\n */\n public getVideoJoinRespTxStart() {\n return this.getDiffBetweenTimestamps('client.locus.join.response', 'client.media.tx.start');\n }\n\n /**\n * Total latency for all exchange ci token.\n */\n public getExchangeCITokenJMT() {\n const exchangeCITokenJMT = this.precomputedLatencies.get('internal.exchange.ci.token.time');\n\n return exchangeCITokenJMT ? Math.floor(exchangeCITokenJMT) : undefined;\n }\n\n /**\n * Total latency for all refresh captcha requests.\n */\n public getRefreshCaptchaReqResp() {\n const refreshCaptchaReqResp = this.precomputedLatencies.get('internal.refresh.captcha.time');\n\n return refreshCaptchaReqResp ? Math.floor(refreshCaptchaReqResp) : undefined;\n }\n\n /**\n * Total latency for all other app api requests.\n * Excludes meeting info, because it's measured separately.\n */\n public getOtherAppApiReqResp() {\n const otherAppApiJMT = this.precomputedLatencies.get('internal.other.app.api.time');\n\n return otherAppApiJMT > 0 ? Math.floor(otherAppApiJMT) : undefined;\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"names":["CallDiagnosticLatencies","args","latencyTimestamps","precomputedLatencies","clear","meetingId","webex","meetings","meetingCollection","get","undefined","key","value","Date","getTime","options","setMeetingId","saveFirstTimestampOnly","set","accumulate","existingValue","callback","start","performance","now","finally","saveLatency","has","a","b","end","getDiffBetweenTimestamps","u2cLatency","Math","floor","interstitialJoinClickTimestamp","connectedMedia","lobbyTime","getStayLobbyTime","clickToInterstitial","getClickToInterstitial","interstitialToJoinOk","getInterstitialToJoinOK","joinReqResp","getJoinReqResp","ICESetupTime","getICESetupTime","joinConfJMT","getJoinConfJMT","totalMediaJMT","getMeeting","allowMediaInLobby","reachablityClusterReqResp","exchangeCITokenJMT","refreshCaptchaReqResp","downloadIntelligenceModelsReqResp","otherAppApiJMT","WebexPlugin"],"sources":["call-diagnostic-metrics-latencies.ts"],"sourcesContent":["/* eslint-disable class-methods-use-this */\n/* eslint-disable valid-jsdoc */\nimport {WebexPlugin} from '@webex/webex-core';\n\nimport {MetricEventNames, PreComputedLatencies} from '../metrics.types';\n\n// we only care about client event and feature event for now\n\n/**\n * @description Helper class to store latencies timestamp and to calculate various latencies for CA.\n * @exports\n * @class CallDiagnosticLatencies\n */\nexport default class CallDiagnosticLatencies extends WebexPlugin {\n latencyTimestamps: Map<MetricEventNames, number>;\n precomputedLatencies: Map<PreComputedLatencies, number>;\n // meetingId that the current latencies are for\n private meetingId?: string;\n\n /**\n * @constructor\n */\n constructor(...args) {\n super(...args);\n this.latencyTimestamps = new Map();\n this.precomputedLatencies = new Map();\n }\n\n /**\n * Clear timestamps\n */\n public clearTimestamps() {\n this.latencyTimestamps.clear();\n this.precomputedLatencies.clear();\n }\n\n /**\n * Associate current latencies with a meeting id\n * @param meetingId\n */\n private setMeetingId(meetingId: string) {\n this.meetingId = meetingId;\n }\n\n /**\n * Returns the meeting object associated with current latencies\n * @returns meeting object\n */\n private getMeeting() {\n if (this.meetingId) {\n // @ts-ignore\n return this.webex.meetings.meetingCollection.get(this.meetingId);\n }\n\n return undefined;\n }\n\n /**\n * Store timestamp value\n * @param key - key\n * @param value - value\n * @param options - store options\n * @throws\n * @returns\n */\n public saveTimestamp({\n key,\n value = new Date().getTime(),\n options = {},\n }: {\n key: MetricEventNames;\n value?: number;\n options?: {meetingId?: string};\n }) {\n // save the meetingId so we can use the meeting object in latency calculations if needed\n const {meetingId} = options;\n if (meetingId) {\n this.setMeetingId(meetingId);\n }\n // for some events we're only interested in the first timestamp not last\n // as these events can happen multiple times\n if (\n key === 'client.media.rx.start' ||\n key === 'client.media.tx.start' ||\n key === 'internal.client.meetinginfo.request' ||\n key === 'internal.client.meetinginfo.response'\n ) {\n this.saveFirstTimestampOnly(key, value);\n } else {\n this.latencyTimestamps.set(key, value);\n }\n }\n\n /**\n * Store precomputed latency value\n * @param key - key\n * @param value - value\n * @param accumulate - when it is true, it overwrites existing value with sum of the current value and the new measurement otherwise just store the new measurement\n * @throws\n * @returns\n */\n public saveLatency(key: PreComputedLatencies, value: number, accumulate = false) {\n const existingValue = accumulate ? this.precomputedLatencies.get(key) || 0 : 0;\n this.precomputedLatencies.set(key, value + existingValue);\n }\n\n /**\n * Measure latency for a request\n * @param callback - callback for which you would like to measure latency\n * @param key - key\n * @param accumulate - when it is true, it overwrites existing value with sum of the current value and the new measurement otherwise just store the new measurement\n * @returns\n */\n public measureLatency(\n callback: () => Promise<unknown>,\n key: PreComputedLatencies,\n accumulate = false\n ) {\n const start = performance.now();\n\n return callback().finally(() => {\n this.saveLatency(key, performance.now() - start, accumulate);\n });\n }\n\n /**\n * Store only the first timestamp value for the given key\n * @param key - key\n * @param value -value\n * @throws\n * @returns\n */\n saveFirstTimestampOnly(key: MetricEventNames, value: number = new Date().getTime()) {\n if (this.latencyTimestamps.has(key)) {\n return;\n }\n this.latencyTimestamps.set(key, value);\n }\n\n /**\n * Helper to calculate end - start\n * @param a start\n * @param b end\n * @returns latency\n */\n public getDiffBetweenTimestamps(a: MetricEventNames, b: MetricEventNames) {\n const start = this.latencyTimestamps.get(a);\n const end = this.latencyTimestamps.get(b);\n if (start && end) {\n return end - start;\n }\n\n return undefined;\n }\n\n /**\n * Meeting Info Request\n * @note Meeting Info request happen not just in the join phase. CA requires\n * metrics around meeting info request that are only part of join phase.\n * This internal.* event is used to track the real timestamps\n * (when the actual request/response happen). This is because the actual CA event is\n * sent inside the join method on the meeting object based on some logic, but that's not exactly when\n * those events are actually fired. The logic only confirms that they have happened, and we send them over.\n * @returns - latency\n */\n public getMeetingInfoReqResp() {\n return this.getDiffBetweenTimestamps(\n 'internal.client.meetinginfo.request',\n 'internal.client.meetinginfo.response'\n );\n }\n\n /**\n * Interstitial Time\n * @returns - latency\n */\n public getShowInterstitialTime() {\n return this.getDiffBetweenTimestamps(\n 'client.interstitial-window.start-launch',\n 'internal.client.interstitial-window.click.joinbutton'\n );\n }\n\n /**\n * getU2CTime\n * @returns - latency\n */\n public getU2CTime() {\n const u2cLatency = this.precomputedLatencies.get('internal.get.u2c.time');\n\n return u2cLatency ? Math.floor(u2cLatency) : undefined;\n }\n\n /**\n * Device Register Time\n * @returns - latency\n */\n public getRegisterWDMDeviceJMT() {\n return this.getDiffBetweenTimestamps(\n 'internal.register.device.request',\n 'internal.register.device.response'\n );\n }\n\n /**\n * Call Init Join Request\n * @returns - latency\n */\n public getCallInitJoinReq() {\n return this.getDiffBetweenTimestamps(\n 'internal.client.interstitial-window.click.joinbutton',\n 'client.locus.join.request'\n );\n }\n\n /**\n * Locus Join Request\n * @returns - latency\n */\n public getJoinReqResp() {\n return this.getDiffBetweenTimestamps('client.locus.join.request', 'client.locus.join.response');\n }\n\n /**\n * Time taken to do turn discovery\n * @returns - latency\n */\n public getTurnDiscoveryTime() {\n return this.getDiffBetweenTimestamps(\n 'internal.client.add-media.turn-discovery.start',\n 'internal.client.add-media.turn-discovery.end'\n );\n }\n\n /**\n * Local SDP Generated Remote SDP REceived\n * @returns - latency\n */\n public getLocalSDPGenRemoteSDPRecv() {\n return this.getDiffBetweenTimestamps(\n 'client.media-engine.local-sdp-generated',\n 'client.media-engine.remote-sdp-received'\n );\n }\n\n /**\n * ICE Setup Time\n * @returns - latency\n */\n public getICESetupTime() {\n return this.getDiffBetweenTimestamps('client.ice.start', 'client.ice.end');\n }\n\n /**\n * Audio ICE time\n * @returns - latency\n */\n public getAudioICESetupTime() {\n return this.getDiffBetweenTimestamps('client.ice.start', 'client.ice.end');\n }\n\n /**\n * Video ICE Time\n * @returns - latency\n */\n public getVideoICESetupTime() {\n return this.getDiffBetweenTimestamps('client.ice.start', 'client.ice.end');\n }\n\n /**\n * Share ICE Time\n * @returns - latency\n */\n public getShareICESetupTime() {\n return this.getDiffBetweenTimestamps('client.ice.start', 'client.ice.end');\n }\n\n /**\n * Stay Lobby Time\n * @returns - latency\n */\n public getStayLobbyTime() {\n return this.getDiffBetweenTimestamps(\n 'client.locus.join.response',\n 'internal.host.meeting.participant.admitted'\n );\n }\n\n /**\n * Page JMT\n * @returns - latency\n */\n public getPageJMT() {\n return this.precomputedLatencies.get('internal.client.pageJMT') || undefined;\n }\n\n /**\n * Download Time JMT\n * @returns - latency\n */\n public getDownloadTimeJMT() {\n return this.precomputedLatencies.get('internal.download.time') || undefined;\n }\n\n /**\n * Click To Interstitial\n * @returns - latency\n */\n public getClickToInterstitial() {\n // for normal join (where green join button exists before interstitial, i.e reminder, space list etc)\n if (this.latencyTimestamps.get('internal.client.meeting.click.joinbutton')) {\n return this.getDiffBetweenTimestamps(\n 'internal.client.meeting.click.joinbutton',\n 'internal.client.meeting.interstitial-window.showed'\n );\n }\n\n // for cross launch and guest flows\n return this.precomputedLatencies.get('internal.click.to.interstitial') || undefined;\n }\n\n /**\n * Interstitial To Join Ok\n * @returns - latency\n */\n public getInterstitialToJoinOK() {\n return this.getDiffBetweenTimestamps(\n 'internal.client.interstitial-window.click.joinbutton',\n 'client.locus.join.response'\n );\n }\n\n /**\n * Call Init To MediaEngineReady\n * @returns - latency\n */\n public getCallInitMediaEngineReady() {\n return this.getDiffBetweenTimestamps(\n 'internal.client.interstitial-window.click.joinbutton',\n 'client.media-engine.ready'\n );\n }\n\n /**\n * Interstitial To Media Ok\n * @returns - latency\n */\n public getInterstitialToMediaOKJMT() {\n const interstitialJoinClickTimestamp = this.latencyTimestamps.get(\n 'internal.client.interstitial-window.click.joinbutton'\n );\n\n // get the first timestamp\n const connectedMedia = this.latencyTimestamps.get('client.ice.end');\n\n const lobbyTime = this.getStayLobbyTime() || 0;\n\n if (interstitialJoinClickTimestamp && connectedMedia) {\n return connectedMedia - interstitialJoinClickTimestamp - lobbyTime;\n }\n\n return undefined;\n }\n\n /**\n * Total JMT\n * @returns - latency\n */\n public getTotalJMT() {\n const clickToInterstitial = this.getClickToInterstitial();\n const interstitialToJoinOk = this.getInterstitialToJoinOK();\n\n if (clickToInterstitial && interstitialToJoinOk) {\n return clickToInterstitial + interstitialToJoinOk;\n }\n\n return undefined;\n }\n\n /**\n * Join Conf JMT\n * @returns - latency\n */\n public getJoinConfJMT() {\n const joinReqResp = this.getJoinReqResp();\n const ICESetupTime = this.getICESetupTime();\n\n if (joinReqResp && ICESetupTime) {\n return joinReqResp + ICESetupTime;\n }\n\n return undefined;\n }\n\n /**\n * Total Media JMT\n * @returns - latency\n */\n public getTotalMediaJMT() {\n const clickToInterstitial = this.getClickToInterstitial();\n const interstitialToJoinOk = this.getInterstitialToJoinOK();\n const joinConfJMT = this.getJoinConfJMT();\n const lobbyTime = this.getStayLobbyTime();\n\n if (clickToInterstitial && interstitialToJoinOk && joinConfJMT) {\n const totalMediaJMT = clickToInterstitial + interstitialToJoinOk + joinConfJMT;\n if (this.getMeeting()?.allowMediaInLobby) {\n return totalMediaJMT;\n }\n\n return totalMediaJMT - lobbyTime;\n }\n\n return undefined;\n }\n\n /**\n * Client JMT\n * @returns - latency\n */\n public getClientJMT() {\n const interstitialToJoinOk = this.getInterstitialToJoinOK();\n const joinConfJMT = this.getJoinConfJMT();\n\n if (interstitialToJoinOk && joinConfJMT) {\n return interstitialToJoinOk - joinConfJMT;\n }\n\n return undefined;\n }\n\n /**\n * Audio setup delay receive\n */\n public getAudioJoinRespRxStart() {\n return this.getDiffBetweenTimestamps('client.locus.join.response', 'client.media.rx.start');\n }\n\n /**\n * Video setup delay receive\n */\n public getVideoJoinRespRxStart() {\n return this.getDiffBetweenTimestamps('client.locus.join.response', 'client.media.rx.start');\n }\n\n /**\n * Total latency for all get cluster request.\n */\n public getReachabilityClustersReqResp() {\n const reachablityClusterReqResp = this.precomputedLatencies.get('internal.get.cluster.time');\n\n return reachablityClusterReqResp ? Math.floor(reachablityClusterReqResp) : undefined;\n }\n\n /**\n * Audio setup delay transmit\n */\n public getAudioJoinRespTxStart() {\n return this.getDiffBetweenTimestamps('client.locus.join.response', 'client.media.tx.start');\n }\n\n /**\n * Video setup delay transmit\n */\n public getVideoJoinRespTxStart() {\n return this.getDiffBetweenTimestamps('client.locus.join.response', 'client.media.tx.start');\n }\n\n /**\n * Total latency for all exchange ci token.\n */\n public getExchangeCITokenJMT() {\n const exchangeCITokenJMT = this.precomputedLatencies.get('internal.exchange.ci.token.time');\n\n return exchangeCITokenJMT ? Math.floor(exchangeCITokenJMT) : undefined;\n }\n\n /**\n * Total latency for all refresh captcha requests.\n */\n public getRefreshCaptchaReqResp() {\n const refreshCaptchaReqResp = this.precomputedLatencies.get('internal.refresh.captcha.time');\n\n return refreshCaptchaReqResp ? Math.floor(refreshCaptchaReqResp) : undefined;\n }\n\n /**\n * Get the latency for downloading intelligence models.\n * @returns - latency\n */\n public getDownloadIntelligenceModelsReqResp() {\n const downloadIntelligenceModelsReqResp = this.precomputedLatencies.get(\n 'internal.api.fetch.intelligence.models'\n );\n\n return downloadIntelligenceModelsReqResp\n ? Math.floor(downloadIntelligenceModelsReqResp)\n : undefined;\n }\n\n /**\n * Get the total latency for all other app API requests.\n * Excludes meeting info, because it's measured separately.\n * @returns - latency\n */\n public getOtherAppApiReqResp() {\n const otherAppApiJMT = this.precomputedLatencies.get('internal.other.app.api.time');\n\n return otherAppApiJMT > 0 ? Math.floor(otherAppApiJMT) : undefined;\n }\n}\n"],"mappings":"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"}
|
|
@@ -234,6 +234,7 @@ var prepareDiagnosticMetricItem = function prepareDiagnosticMetricItem(webex, it
|
|
|
234
234
|
joinTimes.meetingInfoReqResp = cdl.getMeetingInfoReqResp();
|
|
235
235
|
joinTimes.clickToInterstitial = cdl.getClickToInterstitial();
|
|
236
236
|
joinTimes.refreshCaptchaServiceReqResp = cdl.getRefreshCaptchaReqResp();
|
|
237
|
+
joinTimes.downloadIntelligenceModelsReqResp = cdl.getDownloadIntelligenceModelsReqResp();
|
|
237
238
|
break;
|
|
238
239
|
case 'client.call.initiated':
|
|
239
240
|
joinTimes.meetingInfoReqResp = cdl.getMeetingInfoReqResp();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["BrowserDetection","getOSName","getOSVersion","getBrowserName","getBrowserVersion","anonymizeIPAddress","localIp","anonymize","userAgentToString","clientName","webexVersion","userAgentOption","browserInfo","clientInfo","util","format","indexOf","toLowerCase","split","osInfo","process","env","NODE_ENV","clearEmptyKeysRecursively","obj","length","forEach","key","filter","x","isLocusServiceErrorCode","errorCode","code","charAt","isMeetingInfoServiceError","rawError","body","data","meetingInfo","url","includes","WBX_APP_API_URL","isNetworkError","WebexHttpError","NetworkOrCORSError","isUnauthorizedError","Unauthorized","isSdpOfferCreationError","name","ERROR_DESCRIPTIONS","SDP_OFFER_CREATION_ERROR","isBrowserMediaErrorName","errorName","BROWSER_MEDIA_ERROR_NAME_TO_CLIENT_ERROR_CODES_MAP","getBuildType","webClientDomain","markAsTestEvent","prepareDiagnosticMetricItem","webex","item","origin","buildType","exports","eventPayload","event","eventData","networkType","eventName","joinTimes","audioSetupDelay","videoSetupDelay","cdl","internal","newMetrics","callDiagnosticLatencies","downloadTime","getDownloadTimeJMT","otherAppApiReqResp","getOtherAppApiReqResp","exchangeCITokenJMT","getExchangeCITokenJMT","meetingInfoReqResp","getMeetingInfoReqResp","clickToInterstitial","getClickToInterstitial","refreshCaptchaServiceReqResp","getRefreshCaptchaReqResp","showInterstitialTime","getShowInterstitialTime","registerWDMDeviceJMT","getRegisterWDMDeviceJMT","getU2CTime","getReachabilityClustersReqResp","callInitJoinReq","getCallInitJoinReq","joinReqResp","getJoinReqResp","pageJmt","getPageJMT","interstitialToJoinOK","getInterstitialToJoinOK","totalJmt","getTotalJMT","clientJmt","getClientJMT","ICESetupTime","getICESetupTime","audioICESetupTime","getAudioICESetupTime","videoICESetupTime","getVideoICESetupTime","shareICESetupTime","getShareICESetupTime","localSDPGenRemoteSDPRecv","getLocalSDPGenRemoteSDPRecv","totalMediaJMT","getTotalMediaJMT","interstitialToMediaOKJMT","getInterstitialToMediaOKJMT","callInitMediaEngineReady","getCallInitMediaEngineReady","stayLobbyTime","getStayLobbyTime","joinRespRxStart","getAudioJoinRespRxStart","joinRespTxStart","getAudioJoinRespTxStart","getVideoJoinRespRxStart","getVideoJoinRespTxStart","logger","log","latencies","Object","fromEntries","latencyTimestamps","setMetricTimings","options","json","JSON","parse","now","Date","toISOString","metrics","metric","originTime","triggered","sent","extractVersionMetadata","version","majorVersion","minorVersion","generateClientErrorCodeForIceFailure","signalingState","iceConnectionState","turnServerUsed","ICE_FAILURE_CLIENT_CODE","MISSING_ROAP_ANSWER_CLIENT_CODE","DTLS_HANDSHAKE_FAILED_CLIENT_CODE","ICE_FAILED_WITH_TURN_TLS_CLIENT_CODE","ICE_FAILED_WITHOUT_TURN_TLS_CLIENT_CODE"],"sources":["call-diagnostic-metrics.util.ts"],"sourcesContent":["/* eslint-disable valid-jsdoc */\nimport anonymize from 'ip-anonymize';\nimport util from 'util';\n\nimport {BrowserDetection} from '@webex/common';\nimport {WebexHttpError} from '@webex/webex-core';\nimport {isEmpty, merge} from 'lodash';\nimport {\n ClientEvent,\n Event,\n MediaQualityEventAudioSetupDelayPayload,\n MediaQualityEventVideoSetupDelayPayload,\n MetricEventNames,\n} from '../metrics.types';\nimport {\n BROWSER_MEDIA_ERROR_NAME_TO_CLIENT_ERROR_CODES_MAP,\n DTLS_HANDSHAKE_FAILED_CLIENT_CODE,\n ICE_FAILED_WITHOUT_TURN_TLS_CLIENT_CODE,\n ICE_FAILED_WITH_TURN_TLS_CLIENT_CODE,\n ICE_FAILURE_CLIENT_CODE,\n MISSING_ROAP_ANSWER_CLIENT_CODE,\n WBX_APP_API_URL,\n ERROR_DESCRIPTIONS,\n} from './config';\n\nconst {getOSName, getOSVersion, getBrowserName, getBrowserVersion} = BrowserDetection();\n\nexport const anonymizeIPAddress = (localIp) => anonymize(localIp, 28, 96);\n\n/**\n * Returns a formated string of the user agent.\n *\n * @returns {string} formatted user agent information\n */\nexport const userAgentToString = ({clientName, webexVersion}) => {\n let userAgentOption;\n let browserInfo;\n const clientInfo = util.format('client=%s', `${clientName}`);\n\n if (\n ['chrome', 'firefox', 'msie', 'msedge', 'safari'].indexOf(getBrowserName().toLowerCase()) !== -1\n ) {\n browserInfo = util.format(\n 'browser=%s',\n `${getBrowserName().toLowerCase()}/${getBrowserVersion().split('.')[0]}`\n );\n }\n const osInfo = util.format('os=%s', `${getOSName()}/${getOSVersion().split('.')[0]}`);\n\n if (browserInfo) {\n userAgentOption = `(${browserInfo}`;\n }\n if (osInfo) {\n userAgentOption = userAgentOption\n ? `${userAgentOption}; ${clientInfo}; ${osInfo}`\n : `${clientInfo}; (${osInfo}`;\n }\n if (userAgentOption) {\n userAgentOption += ')';\n\n return util.format(\n 'webex-js-sdk/%s %s',\n `${process.env.NODE_ENV}-${webexVersion}`,\n userAgentOption\n );\n }\n\n return util.format('webex-js-sdk/%s', `${process.env.NODE_ENV}-${webexVersion}`);\n};\n\n/**\n * Iterates object recursively and removes any\n * property that returns isEmpty for it's associated value\n * isEmpty = implementation from Lodash.\n *\n * It modifies the object in place (mutable)\n *\n * @param obj - input\n * @returns\n */\nexport const clearEmptyKeysRecursively = (obj: any) => {\n // Check if the object is empty\n if (Object.keys(obj).length === 0) {\n return;\n }\n\n Object.keys(obj).forEach((key) => {\n if (\n (typeof obj[key] === 'object' || typeof obj[key] === 'string' || Array.isArray(obj[key])) &&\n isEmpty(obj[key])\n ) {\n delete obj[key];\n }\n if (Array.isArray(obj[key])) {\n obj[key] = [...obj[key].filter((x) => !!x)];\n }\n if (typeof obj[key] === 'object') {\n clearEmptyKeysRecursively(obj[key]);\n }\n });\n};\n\n/**\n * Locus error codes start with 2. The next three digits are the\n * HTTP status code related to the error code (like 400, 403, 502, etc.)\n * The remaining three digits are just an increasing integer.\n * If it is 7 digits and starts with a 2, it is locus.\n *\n * @param errorCode\n * @returns {boolean}\n */\nexport const isLocusServiceErrorCode = (errorCode: string | number) => {\n const code = `${errorCode}`;\n\n if (code.length === 7 && code.charAt(0) === '2') {\n return true;\n }\n\n return false;\n};\n\n/**\n * MeetingInfo errors sometimes has body.data.meetingInfo object\n * MeetingInfo errors come with a wbxappapi url\n *\n * @param {Object} rawError\n * @returns {boolean}\n */\nexport const isMeetingInfoServiceError = (rawError: any) => {\n if (rawError.body?.data?.meetingInfo || rawError.body?.url?.includes(WBX_APP_API_URL)) {\n return true;\n }\n\n return false;\n};\n\n/**\n * Returns true if the raw error is a network related error\n *\n * @param {Object} rawError\n * @returns {boolean}\n */\nexport const isNetworkError = (rawError: any) => {\n if (rawError instanceof WebexHttpError.NetworkOrCORSError) {\n return true;\n }\n\n return false;\n};\n\n/**\n * Returns true if the error is an unauthorized error\n *\n * @param {Object} rawError\n * @returns {boolean}\n */\nexport const isUnauthorizedError = (rawError: any) => {\n if (rawError instanceof WebexHttpError.Unauthorized) {\n return true;\n }\n\n return false;\n};\n\n/**\n * Returns true if the error is an SdpOfferCreation error\n *\n * @param {Object} rawError\n * @returns {boolean}\n */\nexport const isSdpOfferCreationError = (rawError: any) => {\n // would LIKE to do rawError instanceof Errors.SdpOfferCreationError\n // but including internal-media-core in plugin-metrics breaks meetings and metrics unit tests\n if (rawError.name === ERROR_DESCRIPTIONS.SDP_OFFER_CREATION_ERROR) {\n return true;\n }\n\n return false;\n};\n\n/**\n * MDN Media Devices getUserMedia() method returns a name if it errs\n * Documentation can be found here: https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia\n *\n * @param errorCode\n * @returns\n */\nexport const isBrowserMediaErrorName = (errorName: any) => {\n if (BROWSER_MEDIA_ERROR_NAME_TO_CLIENT_ERROR_CODES_MAP[errorName]) {\n return true;\n }\n\n return false;\n};\n\n/**\n * @param webClientDomain\n * @returns\n */\nexport const getBuildType = (\n webClientDomain,\n markAsTestEvent = false\n): Event['origin']['buildType'] => {\n // used temporary to test pre join in production without creating noise data, SPARK-468456\n if (markAsTestEvent) {\n return 'test';\n }\n\n if (\n webClientDomain?.includes('localhost') ||\n webClientDomain?.includes('127.0.0.1') ||\n process.env.NODE_ENV !== 'production'\n ) {\n return 'test';\n }\n\n return 'prod';\n};\n\n/**\n * Prepare metric item for submission.\n * @param {Object} webex sdk instance\n * @param {Object} item\n * @returns {Object} prepared item\n */\nexport const prepareDiagnosticMetricItem = (webex: any, item: any) => {\n const origin: Partial<Event['origin']> = {\n buildType: exports.getBuildType(\n item.eventPayload?.event?.eventData?.webClientDomain,\n item.eventPayload?.event?.eventData?.markAsTestEvent\n ),\n networkType: 'unknown',\n };\n\n // check event names and append latencies?\n const eventName = item.eventPayload?.event?.name as MetricEventNames;\n const joinTimes: ClientEvent['payload']['joinTimes'] = {};\n const audioSetupDelay: MediaQualityEventAudioSetupDelayPayload = {};\n const videoSetupDelay: MediaQualityEventVideoSetupDelayPayload = {};\n\n const cdl = webex.internal.newMetrics.callDiagnosticLatencies;\n\n switch (eventName) {\n case 'client.webexapp.launched':\n joinTimes.downloadTime = cdl.getDownloadTimeJMT();\n break;\n case 'client.login.end':\n joinTimes.otherAppApiReqResp = cdl.getOtherAppApiReqResp();\n joinTimes.exchangeCITokenJMT = cdl.getExchangeCITokenJMT();\n break;\n case 'client.interstitial-window.launched':\n joinTimes.meetingInfoReqResp = cdl.getMeetingInfoReqResp();\n joinTimes.clickToInterstitial = cdl.getClickToInterstitial();\n joinTimes.refreshCaptchaServiceReqResp = cdl.getRefreshCaptchaReqResp();\n break;\n\n case 'client.call.initiated':\n joinTimes.meetingInfoReqResp = cdl.getMeetingInfoReqResp();\n joinTimes.showInterstitialTime = cdl.getShowInterstitialTime();\n joinTimes.registerWDMDeviceJMT = cdl.getRegisterWDMDeviceJMT();\n joinTimes.getU2CTime = cdl.getU2CTime();\n joinTimes.getReachabilityClustersReqResp = cdl.getReachabilityClustersReqResp();\n break;\n\n case 'client.locus.join.response':\n joinTimes.meetingInfoReqResp = cdl.getMeetingInfoReqResp();\n joinTimes.callInitJoinReq = cdl.getCallInitJoinReq();\n joinTimes.joinReqResp = cdl.getJoinReqResp();\n joinTimes.pageJmt = cdl.getPageJMT();\n joinTimes.clickToInterstitial = cdl.getClickToInterstitial();\n joinTimes.interstitialToJoinOK = cdl.getInterstitialToJoinOK();\n joinTimes.totalJmt = cdl.getTotalJMT();\n joinTimes.clientJmt = cdl.getClientJMT();\n joinTimes.downloadTime = cdl.getDownloadTimeJMT();\n break;\n\n case 'client.ice.end':\n joinTimes.ICESetupTime = cdl.getICESetupTime();\n joinTimes.audioICESetupTime = cdl.getAudioICESetupTime();\n joinTimes.videoICESetupTime = cdl.getVideoICESetupTime();\n joinTimes.shareICESetupTime = cdl.getShareICESetupTime();\n break;\n\n case 'client.media.rx.start':\n joinTimes.localSDPGenRemoteSDPRecv = cdl.getLocalSDPGenRemoteSDPRecv();\n break;\n\n case 'client.media-engine.ready':\n joinTimes.totalMediaJMT = cdl.getTotalMediaJMT();\n joinTimes.interstitialToMediaOKJMT = cdl.getInterstitialToMediaOKJMT();\n joinTimes.callInitMediaEngineReady = cdl.getCallInitMediaEngineReady();\n joinTimes.stayLobbyTime = cdl.getStayLobbyTime();\n break;\n\n case 'client.mediaquality.event':\n audioSetupDelay.joinRespRxStart = cdl.getAudioJoinRespRxStart();\n audioSetupDelay.joinRespTxStart = cdl.getAudioJoinRespTxStart();\n videoSetupDelay.joinRespRxStart = cdl.getVideoJoinRespRxStart();\n videoSetupDelay.joinRespTxStart = cdl.getVideoJoinRespTxStart();\n }\n\n if (!isEmpty(joinTimes)) {\n item.eventPayload.event = merge(item.eventPayload.event, {joinTimes});\n }\n\n if (!isEmpty(audioSetupDelay)) {\n item.eventPayload.event = merge(item.eventPayload.event, {audioSetupDelay});\n }\n\n if (!isEmpty(videoSetupDelay)) {\n item.eventPayload.event = merge(item.eventPayload.event, {videoSetupDelay});\n }\n\n item.eventPayload.origin = Object.assign(origin, item.eventPayload.origin);\n\n // @ts-ignore\n webex.logger.log(\n `CallDiagnosticLatencies,prepareDiagnosticMetricItem: ${JSON.stringify({\n latencies: Object.fromEntries(cdl.latencyTimestamps),\n event: item,\n })}`\n );\n\n return item;\n};\n\n/**\n * Sets the originTime value(s) before the request/fetch.\n * This function is only useful if you are about to submit a metrics\n * request using pre-built fetch options;\n *\n * @param {any} options\n * @returns {any} the updated options object\n */\nexport const setMetricTimings = (options) => {\n if (options.body && options.json) {\n const body = JSON.parse(options.body);\n\n const now = new Date().toISOString();\n body.metrics?.forEach((metric) => {\n if (metric.eventPayload) {\n // The event will effectively be triggered and sent at the same time.\n // The existing triggered time is from when the options were built.\n metric.eventPayload.originTime = {\n triggered: now,\n sent: now,\n };\n }\n });\n options.body = JSON.stringify(body);\n }\n\n return options;\n};\n\nexport const extractVersionMetadata = (version: string) => {\n // extract major and minor version\n const [majorVersion, minorVersion] = version.split('.');\n\n return {\n majorVersion: parseInt(majorVersion, 10),\n minorVersion: parseInt(minorVersion, 10),\n };\n};\n\n/**\n * Generates client error codes for specific ice failures\n * that happen when trying to add media in a meeting.\n */\nexport const generateClientErrorCodeForIceFailure = ({\n signalingState,\n iceConnectionState,\n turnServerUsed,\n}: {\n signalingState: RTCPeerConnection['signalingState'];\n iceConnectionState: RTCPeerConnection['iceConnectionState'];\n turnServerUsed: boolean;\n}) => {\n let errorCode = ICE_FAILURE_CLIENT_CODE; // default;\n\n if (signalingState === 'have-local-offer') {\n errorCode = MISSING_ROAP_ANSWER_CLIENT_CODE;\n }\n\n if (signalingState === 'stable' && iceConnectionState === 'connected') {\n errorCode = DTLS_HANDSHAKE_FAILED_CLIENT_CODE;\n }\n\n if (signalingState !== 'have-local-offer' && iceConnectionState !== 'connected') {\n if (turnServerUsed) {\n errorCode = ICE_FAILED_WITH_TURN_TLS_CLIENT_CODE;\n } else {\n errorCode = ICE_FAILED_WITHOUT_TURN_TLS_CLIENT_CODE;\n }\n }\n\n return errorCode;\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"names":["BrowserDetection","getOSName","getOSVersion","getBrowserName","getBrowserVersion","anonymizeIPAddress","localIp","anonymize","userAgentToString","clientName","webexVersion","userAgentOption","browserInfo","clientInfo","util","format","indexOf","toLowerCase","split","osInfo","process","env","NODE_ENV","clearEmptyKeysRecursively","obj","length","forEach","key","filter","x","isLocusServiceErrorCode","errorCode","code","charAt","isMeetingInfoServiceError","rawError","body","data","meetingInfo","url","includes","WBX_APP_API_URL","isNetworkError","WebexHttpError","NetworkOrCORSError","isUnauthorizedError","Unauthorized","isSdpOfferCreationError","name","ERROR_DESCRIPTIONS","SDP_OFFER_CREATION_ERROR","isBrowserMediaErrorName","errorName","BROWSER_MEDIA_ERROR_NAME_TO_CLIENT_ERROR_CODES_MAP","getBuildType","webClientDomain","markAsTestEvent","prepareDiagnosticMetricItem","webex","item","origin","buildType","exports","eventPayload","event","eventData","networkType","eventName","joinTimes","audioSetupDelay","videoSetupDelay","cdl","internal","newMetrics","callDiagnosticLatencies","downloadTime","getDownloadTimeJMT","otherAppApiReqResp","getOtherAppApiReqResp","exchangeCITokenJMT","getExchangeCITokenJMT","meetingInfoReqResp","getMeetingInfoReqResp","clickToInterstitial","getClickToInterstitial","refreshCaptchaServiceReqResp","getRefreshCaptchaReqResp","downloadIntelligenceModelsReqResp","getDownloadIntelligenceModelsReqResp","showInterstitialTime","getShowInterstitialTime","registerWDMDeviceJMT","getRegisterWDMDeviceJMT","getU2CTime","getReachabilityClustersReqResp","callInitJoinReq","getCallInitJoinReq","joinReqResp","getJoinReqResp","pageJmt","getPageJMT","interstitialToJoinOK","getInterstitialToJoinOK","totalJmt","getTotalJMT","clientJmt","getClientJMT","ICESetupTime","getICESetupTime","audioICESetupTime","getAudioICESetupTime","videoICESetupTime","getVideoICESetupTime","shareICESetupTime","getShareICESetupTime","localSDPGenRemoteSDPRecv","getLocalSDPGenRemoteSDPRecv","totalMediaJMT","getTotalMediaJMT","interstitialToMediaOKJMT","getInterstitialToMediaOKJMT","callInitMediaEngineReady","getCallInitMediaEngineReady","stayLobbyTime","getStayLobbyTime","joinRespRxStart","getAudioJoinRespRxStart","joinRespTxStart","getAudioJoinRespTxStart","getVideoJoinRespRxStart","getVideoJoinRespTxStart","logger","log","latencies","Object","fromEntries","latencyTimestamps","setMetricTimings","options","json","JSON","parse","now","Date","toISOString","metrics","metric","originTime","triggered","sent","extractVersionMetadata","version","majorVersion","minorVersion","generateClientErrorCodeForIceFailure","signalingState","iceConnectionState","turnServerUsed","ICE_FAILURE_CLIENT_CODE","MISSING_ROAP_ANSWER_CLIENT_CODE","DTLS_HANDSHAKE_FAILED_CLIENT_CODE","ICE_FAILED_WITH_TURN_TLS_CLIENT_CODE","ICE_FAILED_WITHOUT_TURN_TLS_CLIENT_CODE"],"sources":["call-diagnostic-metrics.util.ts"],"sourcesContent":["/* eslint-disable valid-jsdoc */\nimport anonymize from 'ip-anonymize';\nimport util from 'util';\n\nimport {BrowserDetection} from '@webex/common';\nimport {WebexHttpError} from '@webex/webex-core';\nimport {isEmpty, merge} from 'lodash';\nimport {\n ClientEvent,\n Event,\n MediaQualityEventAudioSetupDelayPayload,\n MediaQualityEventVideoSetupDelayPayload,\n MetricEventNames,\n} from '../metrics.types';\nimport {\n BROWSER_MEDIA_ERROR_NAME_TO_CLIENT_ERROR_CODES_MAP,\n DTLS_HANDSHAKE_FAILED_CLIENT_CODE,\n ICE_FAILED_WITHOUT_TURN_TLS_CLIENT_CODE,\n ICE_FAILED_WITH_TURN_TLS_CLIENT_CODE,\n ICE_FAILURE_CLIENT_CODE,\n MISSING_ROAP_ANSWER_CLIENT_CODE,\n WBX_APP_API_URL,\n ERROR_DESCRIPTIONS,\n} from './config';\n\nconst {getOSName, getOSVersion, getBrowserName, getBrowserVersion} = BrowserDetection();\n\nexport const anonymizeIPAddress = (localIp) => anonymize(localIp, 28, 96);\n\n/**\n * Returns a formated string of the user agent.\n *\n * @returns {string} formatted user agent information\n */\nexport const userAgentToString = ({clientName, webexVersion}) => {\n let userAgentOption;\n let browserInfo;\n const clientInfo = util.format('client=%s', `${clientName}`);\n\n if (\n ['chrome', 'firefox', 'msie', 'msedge', 'safari'].indexOf(getBrowserName().toLowerCase()) !== -1\n ) {\n browserInfo = util.format(\n 'browser=%s',\n `${getBrowserName().toLowerCase()}/${getBrowserVersion().split('.')[0]}`\n );\n }\n const osInfo = util.format('os=%s', `${getOSName()}/${getOSVersion().split('.')[0]}`);\n\n if (browserInfo) {\n userAgentOption = `(${browserInfo}`;\n }\n if (osInfo) {\n userAgentOption = userAgentOption\n ? `${userAgentOption}; ${clientInfo}; ${osInfo}`\n : `${clientInfo}; (${osInfo}`;\n }\n if (userAgentOption) {\n userAgentOption += ')';\n\n return util.format(\n 'webex-js-sdk/%s %s',\n `${process.env.NODE_ENV}-${webexVersion}`,\n userAgentOption\n );\n }\n\n return util.format('webex-js-sdk/%s', `${process.env.NODE_ENV}-${webexVersion}`);\n};\n\n/**\n * Iterates object recursively and removes any\n * property that returns isEmpty for it's associated value\n * isEmpty = implementation from Lodash.\n *\n * It modifies the object in place (mutable)\n *\n * @param obj - input\n * @returns\n */\nexport const clearEmptyKeysRecursively = (obj: any) => {\n // Check if the object is empty\n if (Object.keys(obj).length === 0) {\n return;\n }\n\n Object.keys(obj).forEach((key) => {\n if (\n (typeof obj[key] === 'object' || typeof obj[key] === 'string' || Array.isArray(obj[key])) &&\n isEmpty(obj[key])\n ) {\n delete obj[key];\n }\n if (Array.isArray(obj[key])) {\n obj[key] = [...obj[key].filter((x) => !!x)];\n }\n if (typeof obj[key] === 'object') {\n clearEmptyKeysRecursively(obj[key]);\n }\n });\n};\n\n/**\n * Locus error codes start with 2. The next three digits are the\n * HTTP status code related to the error code (like 400, 403, 502, etc.)\n * The remaining three digits are just an increasing integer.\n * If it is 7 digits and starts with a 2, it is locus.\n *\n * @param errorCode\n * @returns {boolean}\n */\nexport const isLocusServiceErrorCode = (errorCode: string | number) => {\n const code = `${errorCode}`;\n\n if (code.length === 7 && code.charAt(0) === '2') {\n return true;\n }\n\n return false;\n};\n\n/**\n * MeetingInfo errors sometimes has body.data.meetingInfo object\n * MeetingInfo errors come with a wbxappapi url\n *\n * @param {Object} rawError\n * @returns {boolean}\n */\nexport const isMeetingInfoServiceError = (rawError: any) => {\n if (rawError.body?.data?.meetingInfo || rawError.body?.url?.includes(WBX_APP_API_URL)) {\n return true;\n }\n\n return false;\n};\n\n/**\n * Returns true if the raw error is a network related error\n *\n * @param {Object} rawError\n * @returns {boolean}\n */\nexport const isNetworkError = (rawError: any) => {\n if (rawError instanceof WebexHttpError.NetworkOrCORSError) {\n return true;\n }\n\n return false;\n};\n\n/**\n * Returns true if the error is an unauthorized error\n *\n * @param {Object} rawError\n * @returns {boolean}\n */\nexport const isUnauthorizedError = (rawError: any) => {\n if (rawError instanceof WebexHttpError.Unauthorized) {\n return true;\n }\n\n return false;\n};\n\n/**\n * Returns true if the error is an SdpOfferCreation error\n *\n * @param {Object} rawError\n * @returns {boolean}\n */\nexport const isSdpOfferCreationError = (rawError: any) => {\n // would LIKE to do rawError instanceof Errors.SdpOfferCreationError\n // but including internal-media-core in plugin-metrics breaks meetings and metrics unit tests\n if (rawError.name === ERROR_DESCRIPTIONS.SDP_OFFER_CREATION_ERROR) {\n return true;\n }\n\n return false;\n};\n\n/**\n * MDN Media Devices getUserMedia() method returns a name if it errs\n * Documentation can be found here: https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia\n *\n * @param errorCode\n * @returns\n */\nexport const isBrowserMediaErrorName = (errorName: any) => {\n if (BROWSER_MEDIA_ERROR_NAME_TO_CLIENT_ERROR_CODES_MAP[errorName]) {\n return true;\n }\n\n return false;\n};\n\n/**\n * @param webClientDomain\n * @returns\n */\nexport const getBuildType = (\n webClientDomain,\n markAsTestEvent = false\n): Event['origin']['buildType'] => {\n // used temporary to test pre join in production without creating noise data, SPARK-468456\n if (markAsTestEvent) {\n return 'test';\n }\n\n if (\n webClientDomain?.includes('localhost') ||\n webClientDomain?.includes('127.0.0.1') ||\n process.env.NODE_ENV !== 'production'\n ) {\n return 'test';\n }\n\n return 'prod';\n};\n\n/**\n * Prepare metric item for submission.\n * @param {Object} webex sdk instance\n * @param {Object} item\n * @returns {Object} prepared item\n */\nexport const prepareDiagnosticMetricItem = (webex: any, item: any) => {\n const origin: Partial<Event['origin']> = {\n buildType: exports.getBuildType(\n item.eventPayload?.event?.eventData?.webClientDomain,\n item.eventPayload?.event?.eventData?.markAsTestEvent\n ),\n networkType: 'unknown',\n };\n\n // check event names and append latencies?\n const eventName = item.eventPayload?.event?.name as MetricEventNames;\n const joinTimes: ClientEvent['payload']['joinTimes'] = {};\n const audioSetupDelay: MediaQualityEventAudioSetupDelayPayload = {};\n const videoSetupDelay: MediaQualityEventVideoSetupDelayPayload = {};\n\n const cdl = webex.internal.newMetrics.callDiagnosticLatencies;\n\n switch (eventName) {\n case 'client.webexapp.launched':\n joinTimes.downloadTime = cdl.getDownloadTimeJMT();\n break;\n case 'client.login.end':\n joinTimes.otherAppApiReqResp = cdl.getOtherAppApiReqResp();\n joinTimes.exchangeCITokenJMT = cdl.getExchangeCITokenJMT();\n break;\n case 'client.interstitial-window.launched':\n joinTimes.meetingInfoReqResp = cdl.getMeetingInfoReqResp();\n joinTimes.clickToInterstitial = cdl.getClickToInterstitial();\n joinTimes.refreshCaptchaServiceReqResp = cdl.getRefreshCaptchaReqResp();\n joinTimes.downloadIntelligenceModelsReqResp = cdl.getDownloadIntelligenceModelsReqResp();\n break;\n\n case 'client.call.initiated':\n joinTimes.meetingInfoReqResp = cdl.getMeetingInfoReqResp();\n joinTimes.showInterstitialTime = cdl.getShowInterstitialTime();\n joinTimes.registerWDMDeviceJMT = cdl.getRegisterWDMDeviceJMT();\n joinTimes.getU2CTime = cdl.getU2CTime();\n joinTimes.getReachabilityClustersReqResp = cdl.getReachabilityClustersReqResp();\n break;\n\n case 'client.locus.join.response':\n joinTimes.meetingInfoReqResp = cdl.getMeetingInfoReqResp();\n joinTimes.callInitJoinReq = cdl.getCallInitJoinReq();\n joinTimes.joinReqResp = cdl.getJoinReqResp();\n joinTimes.pageJmt = cdl.getPageJMT();\n joinTimes.clickToInterstitial = cdl.getClickToInterstitial();\n joinTimes.interstitialToJoinOK = cdl.getInterstitialToJoinOK();\n joinTimes.totalJmt = cdl.getTotalJMT();\n joinTimes.clientJmt = cdl.getClientJMT();\n joinTimes.downloadTime = cdl.getDownloadTimeJMT();\n break;\n\n case 'client.ice.end':\n joinTimes.ICESetupTime = cdl.getICESetupTime();\n joinTimes.audioICESetupTime = cdl.getAudioICESetupTime();\n joinTimes.videoICESetupTime = cdl.getVideoICESetupTime();\n joinTimes.shareICESetupTime = cdl.getShareICESetupTime();\n break;\n\n case 'client.media.rx.start':\n joinTimes.localSDPGenRemoteSDPRecv = cdl.getLocalSDPGenRemoteSDPRecv();\n break;\n\n case 'client.media-engine.ready':\n joinTimes.totalMediaJMT = cdl.getTotalMediaJMT();\n joinTimes.interstitialToMediaOKJMT = cdl.getInterstitialToMediaOKJMT();\n joinTimes.callInitMediaEngineReady = cdl.getCallInitMediaEngineReady();\n joinTimes.stayLobbyTime = cdl.getStayLobbyTime();\n break;\n\n case 'client.mediaquality.event':\n audioSetupDelay.joinRespRxStart = cdl.getAudioJoinRespRxStart();\n audioSetupDelay.joinRespTxStart = cdl.getAudioJoinRespTxStart();\n videoSetupDelay.joinRespRxStart = cdl.getVideoJoinRespRxStart();\n videoSetupDelay.joinRespTxStart = cdl.getVideoJoinRespTxStart();\n }\n\n if (!isEmpty(joinTimes)) {\n item.eventPayload.event = merge(item.eventPayload.event, {joinTimes});\n }\n\n if (!isEmpty(audioSetupDelay)) {\n item.eventPayload.event = merge(item.eventPayload.event, {audioSetupDelay});\n }\n\n if (!isEmpty(videoSetupDelay)) {\n item.eventPayload.event = merge(item.eventPayload.event, {videoSetupDelay});\n }\n\n item.eventPayload.origin = Object.assign(origin, item.eventPayload.origin);\n\n // @ts-ignore\n webex.logger.log(\n `CallDiagnosticLatencies,prepareDiagnosticMetricItem: ${JSON.stringify({\n latencies: Object.fromEntries(cdl.latencyTimestamps),\n event: item,\n })}`\n );\n\n return item;\n};\n\n/**\n * Sets the originTime value(s) before the request/fetch.\n * This function is only useful if you are about to submit a metrics\n * request using pre-built fetch options;\n *\n * @param {any} options\n * @returns {any} the updated options object\n */\nexport const setMetricTimings = (options) => {\n if (options.body && options.json) {\n const body = JSON.parse(options.body);\n\n const now = new Date().toISOString();\n body.metrics?.forEach((metric) => {\n if (metric.eventPayload) {\n // The event will effectively be triggered and sent at the same time.\n // The existing triggered time is from when the options were built.\n metric.eventPayload.originTime = {\n triggered: now,\n sent: now,\n };\n }\n });\n options.body = JSON.stringify(body);\n }\n\n return options;\n};\n\nexport const extractVersionMetadata = (version: string) => {\n // extract major and minor version\n const [majorVersion, minorVersion] = version.split('.');\n\n return {\n majorVersion: parseInt(majorVersion, 10),\n minorVersion: parseInt(minorVersion, 10),\n };\n};\n\n/**\n * Generates client error codes for specific ice failures\n * that happen when trying to add media in a meeting.\n */\nexport const generateClientErrorCodeForIceFailure = ({\n signalingState,\n iceConnectionState,\n turnServerUsed,\n}: {\n signalingState: RTCPeerConnection['signalingState'];\n iceConnectionState: RTCPeerConnection['iceConnectionState'];\n turnServerUsed: boolean;\n}) => {\n let errorCode = ICE_FAILURE_CLIENT_CODE; // default;\n\n if (signalingState === 'have-local-offer') {\n errorCode = MISSING_ROAP_ANSWER_CLIENT_CODE;\n }\n\n if (signalingState === 'stable' && iceConnectionState === 'connected') {\n errorCode = DTLS_HANDSHAKE_FAILED_CLIENT_CODE;\n }\n\n if (signalingState !== 'have-local-offer' && iceConnectionState !== 'connected') {\n if (turnServerUsed) {\n errorCode = ICE_FAILED_WITH_TURN_TLS_CLIENT_CODE;\n } else {\n errorCode = ICE_FAILED_WITHOUT_TURN_TLS_CLIENT_CODE;\n }\n }\n\n return errorCode;\n};\n"],"mappings":"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"}
|
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 SubmitClientEventOptions = {\n meetingId?: string;\n mediaConnections?: any[];\n rawError?: any;\n correlationId?: 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 BehavioralEvent {\n // TODO: not implemented\n name: 'host.meeting.participant.admitted' | 'sdk.media-flow.started';\n payload?: never;\n options?: never;\n}\n\nexport interface OperationalEvent {\n // TODO: not implemented\n name: never;\n payload?: never;\n options?: never;\n}\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['name']\n | OperationalEvent['name']\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 name: BehavioralEvent['name'];\n payload?: RecursivePartial<BehavioralEvent['payload']>;\n options?: any;\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['name'];\n payload?: RecursivePartial<OperationalEvent['payload']>;\n options?: any;\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"],"mappings":""}
|
|
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 SubmitClientEventOptions = {\n meetingId?: string;\n mediaConnections?: any[];\n rawError?: any;\n correlationId?: 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 BehavioralEvent {\n // TODO: not implemented\n name: 'host.meeting.participant.admitted' | 'sdk.media-flow.started';\n payload?: never;\n options?: never;\n}\n\nexport interface OperationalEvent {\n // TODO: not implemented\n name: never;\n payload?: never;\n options?: never;\n}\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['name']\n | OperationalEvent['name']\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 name: BehavioralEvent['name'];\n payload?: RecursivePartial<BehavioralEvent['payload']>;\n options?: any;\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['name'];\n payload?: RecursivePartial<OperationalEvent['payload']>;\n options?: any;\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"],"mappings":""}
|
|
@@ -30,7 +30,8 @@ export default class CallDiagnosticLatencies extends WebexPlugin {
|
|
|
30
30
|
/**
|
|
31
31
|
* Store timestamp value
|
|
32
32
|
* @param key - key
|
|
33
|
-
* @param value -value
|
|
33
|
+
* @param value - value
|
|
34
|
+
* @param options - store options
|
|
34
35
|
* @throws
|
|
35
36
|
* @returns
|
|
36
37
|
*/
|
|
@@ -45,19 +46,19 @@ export default class CallDiagnosticLatencies extends WebexPlugin {
|
|
|
45
46
|
* Store precomputed latency value
|
|
46
47
|
* @param key - key
|
|
47
48
|
* @param value - value
|
|
48
|
-
* @param
|
|
49
|
+
* @param accumulate - when it is true, it overwrites existing value with sum of the current value and the new measurement otherwise just store the new measurement
|
|
49
50
|
* @throws
|
|
50
51
|
* @returns
|
|
51
52
|
*/
|
|
52
|
-
saveLatency(key: PreComputedLatencies, value: number,
|
|
53
|
+
saveLatency(key: PreComputedLatencies, value: number, accumulate?: boolean): void;
|
|
53
54
|
/**
|
|
54
55
|
* Measure latency for a request
|
|
55
|
-
* @param key - key
|
|
56
56
|
* @param callback - callback for which you would like to measure latency
|
|
57
|
-
* @param
|
|
57
|
+
* @param key - key
|
|
58
|
+
* @param accumulate - when it is true, it overwrites existing value with sum of the current value and the new measurement otherwise just store the new measurement
|
|
58
59
|
* @returns
|
|
59
60
|
*/
|
|
60
|
-
measureLatency(callback: () => Promise<
|
|
61
|
+
measureLatency(callback: () => Promise<unknown>, key: PreComputedLatencies, accumulate?: boolean): Promise<unknown>;
|
|
61
62
|
/**
|
|
62
63
|
* Store only the first timestamp value for the given key
|
|
63
64
|
* @param key - key
|
|
@@ -223,8 +224,14 @@ export default class CallDiagnosticLatencies extends WebexPlugin {
|
|
|
223
224
|
*/
|
|
224
225
|
getRefreshCaptchaReqResp(): number;
|
|
225
226
|
/**
|
|
226
|
-
*
|
|
227
|
+
* Get the latency for downloading intelligence models.
|
|
228
|
+
* @returns - latency
|
|
229
|
+
*/
|
|
230
|
+
getDownloadIntelligenceModelsReqResp(): number;
|
|
231
|
+
/**
|
|
232
|
+
* Get the total latency for all other app API requests.
|
|
227
233
|
* Excludes meeting info, because it's measured separately.
|
|
234
|
+
* @returns - latency
|
|
228
235
|
*/
|
|
229
236
|
getOtherAppApiReqResp(): number;
|
|
230
237
|
}
|
|
@@ -104,4 +104,4 @@ export type BuildClientEventFetchRequestOptions = (args: {
|
|
|
104
104
|
payload?: RecursivePartial<ClientEvent['payload']>;
|
|
105
105
|
options?: SubmitClientEventOptions;
|
|
106
106
|
}) => Promise<any>;
|
|
107
|
-
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';
|
|
107
|
+
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';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@webex/internal-plugin-metrics",
|
|
3
|
-
"version": "3.0.0-beta.
|
|
3
|
+
"version": "3.0.0-beta.418",
|
|
4
4
|
"description": "",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -28,14 +28,14 @@
|
|
|
28
28
|
"build": "yarn run -T tsc --declaration true --declarationDir ./dist/types"
|
|
29
29
|
},
|
|
30
30
|
"dependencies": {
|
|
31
|
-
"@webex/common": "3.0.0-beta.
|
|
32
|
-
"@webex/common-timers": "3.0.0-beta.
|
|
31
|
+
"@webex/common": "3.0.0-beta.418",
|
|
32
|
+
"@webex/common-timers": "3.0.0-beta.418",
|
|
33
33
|
"@webex/event-dictionary-ts": "^1.0.1406",
|
|
34
|
-
"@webex/internal-plugin-device": "3.0.0-beta.
|
|
35
|
-
"@webex/internal-plugin-metrics": "3.0.0-beta.
|
|
36
|
-
"@webex/test-helper-chai": "3.0.0-beta.
|
|
37
|
-
"@webex/test-helper-mock-webex": "3.0.0-beta.
|
|
38
|
-
"@webex/webex-core": "3.0.0-beta.
|
|
34
|
+
"@webex/internal-plugin-device": "3.0.0-beta.418",
|
|
35
|
+
"@webex/internal-plugin-metrics": "3.0.0-beta.418",
|
|
36
|
+
"@webex/test-helper-chai": "3.0.0-beta.418",
|
|
37
|
+
"@webex/test-helper-mock-webex": "3.0.0-beta.418",
|
|
38
|
+
"@webex/webex-core": "3.0.0-beta.418",
|
|
39
39
|
"ip-anonymize": "^0.1.0",
|
|
40
40
|
"lodash": "^4.17.21",
|
|
41
41
|
"uuid": "^3.3.2"
|
|
@@ -31,6 +31,7 @@ export default class CallDiagnosticLatencies extends WebexPlugin {
|
|
|
31
31
|
*/
|
|
32
32
|
public clearTimestamps() {
|
|
33
33
|
this.latencyTimestamps.clear();
|
|
34
|
+
this.precomputedLatencies.clear();
|
|
34
35
|
}
|
|
35
36
|
|
|
36
37
|
/**
|
|
@@ -57,7 +58,8 @@ export default class CallDiagnosticLatencies extends WebexPlugin {
|
|
|
57
58
|
/**
|
|
58
59
|
* Store timestamp value
|
|
59
60
|
* @param key - key
|
|
60
|
-
* @param value -value
|
|
61
|
+
* @param value - value
|
|
62
|
+
* @param options - store options
|
|
61
63
|
* @throws
|
|
62
64
|
* @returns
|
|
63
65
|
*/
|
|
@@ -93,31 +95,31 @@ export default class CallDiagnosticLatencies extends WebexPlugin {
|
|
|
93
95
|
* Store precomputed latency value
|
|
94
96
|
* @param key - key
|
|
95
97
|
* @param value - value
|
|
96
|
-
* @param
|
|
98
|
+
* @param accumulate - when it is true, it overwrites existing value with sum of the current value and the new measurement otherwise just store the new measurement
|
|
97
99
|
* @throws
|
|
98
100
|
* @returns
|
|
99
101
|
*/
|
|
100
|
-
public saveLatency(key: PreComputedLatencies, value: number,
|
|
101
|
-
const existingValue =
|
|
102
|
+
public saveLatency(key: PreComputedLatencies, value: number, accumulate = false) {
|
|
103
|
+
const existingValue = accumulate ? this.precomputedLatencies.get(key) || 0 : 0;
|
|
102
104
|
this.precomputedLatencies.set(key, value + existingValue);
|
|
103
105
|
}
|
|
104
106
|
|
|
105
107
|
/**
|
|
106
108
|
* Measure latency for a request
|
|
107
|
-
* @param key - key
|
|
108
109
|
* @param callback - callback for which you would like to measure latency
|
|
109
|
-
* @param
|
|
110
|
+
* @param key - key
|
|
111
|
+
* @param accumulate - when it is true, it overwrites existing value with sum of the current value and the new measurement otherwise just store the new measurement
|
|
110
112
|
* @returns
|
|
111
113
|
*/
|
|
112
114
|
public measureLatency(
|
|
113
|
-
callback: () => Promise<
|
|
115
|
+
callback: () => Promise<unknown>,
|
|
114
116
|
key: PreComputedLatencies,
|
|
115
|
-
|
|
117
|
+
accumulate = false
|
|
116
118
|
) {
|
|
117
119
|
const start = performance.now();
|
|
118
120
|
|
|
119
121
|
return callback().finally(() => {
|
|
120
|
-
this.saveLatency(key, performance.now() - start,
|
|
122
|
+
this.saveLatency(key, performance.now() - start, accumulate);
|
|
121
123
|
});
|
|
122
124
|
}
|
|
123
125
|
|
|
@@ -483,8 +485,23 @@ export default class CallDiagnosticLatencies extends WebexPlugin {
|
|
|
483
485
|
}
|
|
484
486
|
|
|
485
487
|
/**
|
|
486
|
-
*
|
|
488
|
+
* Get the latency for downloading intelligence models.
|
|
489
|
+
* @returns - latency
|
|
490
|
+
*/
|
|
491
|
+
public getDownloadIntelligenceModelsReqResp() {
|
|
492
|
+
const downloadIntelligenceModelsReqResp = this.precomputedLatencies.get(
|
|
493
|
+
'internal.api.fetch.intelligence.models'
|
|
494
|
+
);
|
|
495
|
+
|
|
496
|
+
return downloadIntelligenceModelsReqResp
|
|
497
|
+
? Math.floor(downloadIntelligenceModelsReqResp)
|
|
498
|
+
: undefined;
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
/**
|
|
502
|
+
* Get the total latency for all other app API requests.
|
|
487
503
|
* Excludes meeting info, because it's measured separately.
|
|
504
|
+
* @returns - latency
|
|
488
505
|
*/
|
|
489
506
|
public getOtherAppApiReqResp() {
|
|
490
507
|
const otherAppApiJMT = this.precomputedLatencies.get('internal.other.app.api.time');
|
|
@@ -252,6 +252,7 @@ export const prepareDiagnosticMetricItem = (webex: any, item: any) => {
|
|
|
252
252
|
joinTimes.meetingInfoReqResp = cdl.getMeetingInfoReqResp();
|
|
253
253
|
joinTimes.clickToInterstitial = cdl.getClickToInterstitial();
|
|
254
254
|
joinTimes.refreshCaptchaServiceReqResp = cdl.getRefreshCaptchaReqResp();
|
|
255
|
+
joinTimes.downloadIntelligenceModelsReqResp = cdl.getDownloadIntelligenceModelsReqResp();
|
|
255
256
|
break;
|
|
256
257
|
|
|
257
258
|
case 'client.call.initiated':
|
package/src/metrics.types.ts
CHANGED
|
@@ -106,6 +106,9 @@ describe('plugin-metrics', () => {
|
|
|
106
106
|
webex.internal.newMetrics.callDiagnosticLatencies.getRefreshCaptchaReqResp = sinon
|
|
107
107
|
.stub()
|
|
108
108
|
.returns(10);
|
|
109
|
+
webex.internal.newMetrics.callDiagnosticLatencies.getDownloadIntelligenceModelsReqResp =
|
|
110
|
+
sinon.stub().returns(42);
|
|
111
|
+
|
|
109
112
|
const promise = webex.internal.newMetrics.callDiagnosticMetrics.submitToCallDiagnostics(
|
|
110
113
|
//@ts-ignore
|
|
111
114
|
{event: {name: 'client.interstitial-window.launched'}}
|
|
@@ -123,6 +126,7 @@ describe('plugin-metrics', () => {
|
|
|
123
126
|
clickToInterstitial: 10,
|
|
124
127
|
meetingInfoReqResp: 10,
|
|
125
128
|
refreshCaptchaServiceReqResp: 10,
|
|
129
|
+
downloadIntelligenceModelsReqResp: 42,
|
|
126
130
|
},
|
|
127
131
|
});
|
|
128
132
|
assert.lengthOf(
|
|
@@ -51,29 +51,29 @@ describe('internal-plugin-metrics', () => {
|
|
|
51
51
|
assert.deepEqual(cdl.precomputedLatencies.get('internal.client.pageJMT'), 20);
|
|
52
52
|
});
|
|
53
53
|
|
|
54
|
-
it('should overwrite latency when
|
|
54
|
+
it('should overwrite latency when accumulate is false', () => {
|
|
55
55
|
assert.deepEqual(cdl.precomputedLatencies.size, 0);
|
|
56
|
-
cdl.saveLatency('internal.client.pageJMT', 10,
|
|
56
|
+
cdl.saveLatency('internal.client.pageJMT', 10, false);
|
|
57
57
|
assert.deepEqual(cdl.precomputedLatencies.size, 1);
|
|
58
58
|
assert.deepEqual(cdl.precomputedLatencies.get('internal.client.pageJMT'), 10);
|
|
59
|
-
cdl.saveLatency('internal.client.pageJMT', 20,
|
|
59
|
+
cdl.saveLatency('internal.client.pageJMT', 20, false);
|
|
60
60
|
assert.deepEqual(cdl.precomputedLatencies.size, 1);
|
|
61
61
|
assert.deepEqual(cdl.precomputedLatencies.get('internal.client.pageJMT'), 20);
|
|
62
62
|
});
|
|
63
63
|
|
|
64
|
-
it('should save latency correctly when
|
|
64
|
+
it('should save latency correctly when accumulate is true', () => {
|
|
65
65
|
assert.deepEqual(cdl.precomputedLatencies.size, 0);
|
|
66
|
-
cdl.saveLatency('internal.client.pageJMT', 10,
|
|
66
|
+
cdl.saveLatency('internal.client.pageJMT', 10, true);
|
|
67
67
|
assert.deepEqual(cdl.precomputedLatencies.size, 1);
|
|
68
68
|
assert.deepEqual(cdl.precomputedLatencies.get('internal.client.pageJMT'), 10);
|
|
69
69
|
});
|
|
70
70
|
|
|
71
|
-
it('should save latency correctly when
|
|
71
|
+
it('should save latency correctly when accumulate is true and there is existing value', () => {
|
|
72
72
|
assert.deepEqual(cdl.precomputedLatencies.size, 0);
|
|
73
73
|
cdl.saveLatency('internal.client.pageJMT', 10);
|
|
74
74
|
assert.deepEqual(cdl.precomputedLatencies.size, 1);
|
|
75
75
|
assert.deepEqual(cdl.precomputedLatencies.get('internal.client.pageJMT'), 10);
|
|
76
|
-
cdl.saveLatency('internal.client.pageJMT', 10,
|
|
76
|
+
cdl.saveLatency('internal.client.pageJMT', 10, true);
|
|
77
77
|
assert.deepEqual(cdl.precomputedLatencies.size, 1);
|
|
78
78
|
assert.deepEqual(cdl.precomputedLatencies.get('internal.client.pageJMT'), 20);
|
|
79
79
|
});
|
|
@@ -108,8 +108,13 @@ describe('internal-plugin-metrics', () => {
|
|
|
108
108
|
cdl.saveTimestamp({key: 'client.alert.displayed'});
|
|
109
109
|
cdl.saveTimestamp({key: 'client.alert.removed'});
|
|
110
110
|
assert.deepEqual(cdl.latencyTimestamps.size, 2);
|
|
111
|
+
cdl.saveLatency('internal.api.fetch.intelligence.models', 42);
|
|
112
|
+
assert.deepEqual(cdl.precomputedLatencies.size, 1);
|
|
113
|
+
|
|
111
114
|
cdl.clearTimestamps();
|
|
115
|
+
|
|
112
116
|
assert.deepEqual(cdl.latencyTimestamps.size, 0);
|
|
117
|
+
assert.deepEqual(cdl.precomputedLatencies.size, 0);
|
|
113
118
|
});
|
|
114
119
|
|
|
115
120
|
it('should calculate diff between timestamps correctly', () => {
|
|
@@ -145,9 +150,9 @@ describe('internal-plugin-metrics', () => {
|
|
|
145
150
|
let clock;
|
|
146
151
|
let saveLatencySpy;
|
|
147
152
|
|
|
148
|
-
beforeEach(() => {
|
|
149
|
-
clock = sinon.useFakeTimers();
|
|
150
|
-
|
|
153
|
+
beforeEach(() => {
|
|
154
|
+
clock = sinon.useFakeTimers();
|
|
155
|
+
|
|
151
156
|
saveLatencySpy = sinon.stub(cdl, 'saveLatency');
|
|
152
157
|
});
|
|
153
158
|
|
|
@@ -155,54 +160,56 @@ describe('internal-plugin-metrics', () => {
|
|
|
155
160
|
clock.restore();
|
|
156
161
|
sinon.restore();
|
|
157
162
|
});
|
|
158
|
-
|
|
159
|
-
it('checks measureLatency with
|
|
163
|
+
|
|
164
|
+
it('checks measureLatency with accumulate false', async () => {
|
|
160
165
|
const key = 'internal.client.pageJMT';
|
|
161
|
-
const
|
|
166
|
+
const accumulate = false;
|
|
167
|
+
|
|
162
168
|
const callbackStub = sinon.stub().callsFake(() => {
|
|
163
169
|
clock.tick(50);
|
|
164
170
|
return Promise.resolve('test');
|
|
165
171
|
});
|
|
166
172
|
|
|
167
|
-
|
|
173
|
+
// accumulate should be false by default
|
|
174
|
+
const promise = cdl.measureLatency(callbackStub, 'internal.client.pageJMT');
|
|
168
175
|
|
|
169
176
|
const resolvedValue = await promise;
|
|
170
177
|
assert.deepEqual(resolvedValue, 'test');
|
|
171
178
|
assert.calledOnceWithExactly(callbackStub);
|
|
172
|
-
assert.calledOnceWithExactly(saveLatencySpy, key, 50,
|
|
179
|
+
assert.calledOnceWithExactly(saveLatencySpy, key, 50, accumulate);
|
|
173
180
|
});
|
|
174
181
|
|
|
175
|
-
it('checks measureLatency with
|
|
182
|
+
it('checks measureLatency with accumulate true', async () => {
|
|
176
183
|
const key = 'internal.download.time';
|
|
177
|
-
const
|
|
184
|
+
const accumulate = true;
|
|
178
185
|
const callbackStub = sinon.stub().callsFake(() => {
|
|
179
186
|
clock.tick(20);
|
|
180
187
|
return Promise.resolve('test123');
|
|
181
188
|
});
|
|
182
189
|
|
|
183
|
-
const promise = cdl.measureLatency(callbackStub, 'internal.download.time',
|
|
190
|
+
const promise = cdl.measureLatency(callbackStub, 'internal.download.time', accumulate);
|
|
184
191
|
|
|
185
192
|
const resolvedValue = await promise;
|
|
186
193
|
assert.deepEqual(resolvedValue, 'test123');
|
|
187
194
|
assert.calledOnceWithExactly(callbackStub);
|
|
188
|
-
assert.calledOnceWithExactly(saveLatencySpy, key, 20,
|
|
195
|
+
assert.calledOnceWithExactly(saveLatencySpy, key, 20, accumulate);
|
|
189
196
|
});
|
|
190
197
|
|
|
191
198
|
it('checks measureLatency when callBack rejects', async () => {
|
|
192
199
|
const key = 'internal.client.pageJMT';
|
|
193
|
-
const
|
|
200
|
+
const accumulate = false;
|
|
194
201
|
const error = new Error('some error');
|
|
195
202
|
const callbackStub = sinon.stub().callsFake(() => {
|
|
196
203
|
clock.tick(50);
|
|
197
204
|
return Promise.reject(error);
|
|
198
205
|
});
|
|
199
206
|
|
|
200
|
-
const promise = cdl.measureLatency(callbackStub, 'internal.client.pageJMT',
|
|
207
|
+
const promise = cdl.measureLatency(callbackStub, 'internal.client.pageJMT', accumulate);
|
|
201
208
|
|
|
202
209
|
const rejectedValue = await assert.isRejected(promise);
|
|
203
210
|
assert.deepEqual(rejectedValue, error);
|
|
204
211
|
assert.calledOnceWithExactly(callbackStub);
|
|
205
|
-
assert.calledOnceWithExactly(saveLatencySpy, key, 50,
|
|
212
|
+
assert.calledOnceWithExactly(saveLatencySpy, key, 50, accumulate);
|
|
206
213
|
});
|
|
207
214
|
});
|
|
208
215
|
|
|
@@ -541,7 +541,10 @@ describe('internal-plugin-metrics', () => {
|
|
|
541
541
|
it('should prepare diagnostic event successfully', () => {
|
|
542
542
|
const options = {meetingId: fakeMeeting.id};
|
|
543
543
|
const getOriginStub = sinon.stub(cd, 'getOrigin').returns({origin: 'fake-origin'});
|
|
544
|
-
const clearEmptyKeysRecursivelyStub = sinon.stub(
|
|
544
|
+
const clearEmptyKeysRecursivelyStub = sinon.stub(
|
|
545
|
+
CallDiagnosticUtils,
|
|
546
|
+
'clearEmptyKeysRecursively'
|
|
547
|
+
);
|
|
545
548
|
|
|
546
549
|
const res = cd.prepareDiagnosticEvent(
|
|
547
550
|
{
|
|
@@ -896,11 +899,13 @@ describe('internal-plugin-metrics', () => {
|
|
|
896
899
|
options
|
|
897
900
|
);
|
|
898
901
|
assert.notCalled(submitToCallDiagnosticsSpy);
|
|
899
|
-
assert.calledWith(
|
|
902
|
+
assert.calledWith(
|
|
903
|
+
submitToCallDiagnosticsPreLoginSpy,
|
|
904
|
+
{
|
|
900
905
|
eventId: 'my-fake-id',
|
|
901
906
|
version: 1,
|
|
902
|
-
origin: {
|
|
903
|
-
originTime: {
|
|
907
|
+
origin: {origin: 'fake-origin'},
|
|
908
|
+
originTime: {triggered: now.toISOString(), sent: 'not_defined_yet'},
|
|
904
909
|
senderCountryCode: 'UK',
|
|
905
910
|
event: {
|
|
906
911
|
name: 'client.alert.displayed',
|
|
@@ -912,12 +917,14 @@ describe('internal-plugin-metrics', () => {
|
|
|
912
917
|
orgId: 'orgId',
|
|
913
918
|
locusUrl: 'locus-url',
|
|
914
919
|
webexConferenceIdStr: 'webexConferenceIdStr1',
|
|
915
|
-
globalMeetingId: 'globalMeetingId1'
|
|
920
|
+
globalMeetingId: 'globalMeetingId1',
|
|
916
921
|
},
|
|
917
|
-
eventData: {
|
|
918
|
-
loginType: 'login-ci'
|
|
922
|
+
eventData: {webClientDomain: 'whatever'},
|
|
923
|
+
loginType: 'login-ci',
|
|
919
924
|
},
|
|
920
|
-
|
|
925
|
+
},
|
|
926
|
+
options.preLoginId
|
|
927
|
+
);
|
|
921
928
|
});
|
|
922
929
|
|
|
923
930
|
it('should use meeting loginType if present and meetingId provided', () => {
|
|
@@ -1382,7 +1389,7 @@ describe('internal-plugin-metrics', () => {
|
|
|
1382
1389
|
});
|
|
1383
1390
|
});
|
|
1384
1391
|
|
|
1385
|
-
describe(
|
|
1392
|
+
describe('#submitToCallDiagnostics', () => {
|
|
1386
1393
|
it('should send request to call diagnostic batcher', () => {
|
|
1387
1394
|
const requestStub = sinon.stub();
|
|
1388
1395
|
//@ts-ignore
|
|
@@ -1391,7 +1398,7 @@ describe('internal-plugin-metrics', () => {
|
|
|
1391
1398
|
cd.submitToCallDiagnostics({event: 'test'});
|
|
1392
1399
|
assert.calledWith(requestStub, {eventPayload: {event: 'test'}, type: ['diagnostic-event']});
|
|
1393
1400
|
});
|
|
1394
|
-
})
|
|
1401
|
+
});
|
|
1395
1402
|
|
|
1396
1403
|
describe('#submitMQE', () => {
|
|
1397
1404
|
it('submits the event correctly', () => {
|
|
@@ -2006,12 +2013,16 @@ describe('internal-plugin-metrics', () => {
|
|
|
2006
2013
|
|
|
2007
2014
|
describe('httpStatusCode', () => {
|
|
2008
2015
|
it('should include httpStatusCode for browser media errors', () => {
|
|
2009
|
-
const res = cd.generateClientEventErrorPayload({
|
|
2016
|
+
const res = cd.generateClientEventErrorPayload({
|
|
2017
|
+
name: 'PermissionDeniedError',
|
|
2018
|
+
message: 'bad times',
|
|
2019
|
+
statusCode: 401,
|
|
2020
|
+
});
|
|
2010
2021
|
assert.deepEqual(res, {
|
|
2011
2022
|
category: 'expected',
|
|
2012
2023
|
errorCode: 4032,
|
|
2013
2024
|
errorData: {
|
|
2014
|
-
errorName: 'PermissionDeniedError'
|
|
2025
|
+
errorName: 'PermissionDeniedError',
|
|
2015
2026
|
},
|
|
2016
2027
|
errorDescription: 'CameraPermissionDenied',
|
|
2017
2028
|
fatal: true,
|
|
@@ -2024,12 +2035,16 @@ describe('internal-plugin-metrics', () => {
|
|
|
2024
2035
|
});
|
|
2025
2036
|
|
|
2026
2037
|
it('should include httpStatusCode for SdpOfferCreationErrors', () => {
|
|
2027
|
-
const res = cd.generateClientEventErrorPayload({
|
|
2038
|
+
const res = cd.generateClientEventErrorPayload({
|
|
2039
|
+
name: 'SdpOfferCreationError',
|
|
2040
|
+
message: 'bad times',
|
|
2041
|
+
statusCode: 404,
|
|
2042
|
+
});
|
|
2028
2043
|
assert.deepEqual(res, {
|
|
2029
2044
|
category: 'media',
|
|
2030
2045
|
errorCode: 2050,
|
|
2031
2046
|
errorData: {
|
|
2032
|
-
errorName: 'SdpOfferCreationError'
|
|
2047
|
+
errorName: 'SdpOfferCreationError',
|
|
2033
2048
|
},
|
|
2034
2049
|
errorDescription: 'SdpOfferCreationError',
|
|
2035
2050
|
fatal: true,
|
|
@@ -2042,7 +2057,11 @@ describe('internal-plugin-metrics', () => {
|
|
|
2042
2057
|
});
|
|
2043
2058
|
|
|
2044
2059
|
it('should include httpStatusCode for service error codes', () => {
|
|
2045
|
-
const res = cd.generateClientEventErrorPayload({
|
|
2060
|
+
const res = cd.generateClientEventErrorPayload({
|
|
2061
|
+
body: {errorCode: 58400},
|
|
2062
|
+
message: 'bad times',
|
|
2063
|
+
statusCode: 400,
|
|
2064
|
+
});
|
|
2046
2065
|
assert.deepEqual(res, {
|
|
2047
2066
|
category: 'signaling',
|
|
2048
2067
|
errorCode: 4100,
|
|
@@ -2057,7 +2076,11 @@ describe('internal-plugin-metrics', () => {
|
|
|
2057
2076
|
});
|
|
2058
2077
|
|
|
2059
2078
|
it('should include httpStatusCode for locus service error codes', () => {
|
|
2060
|
-
const res = cd.generateClientEventErrorPayload({
|
|
2079
|
+
const res = cd.generateClientEventErrorPayload({
|
|
2080
|
+
body: {errorCode: 2403001},
|
|
2081
|
+
message: 'bad times',
|
|
2082
|
+
statusCode: 400,
|
|
2083
|
+
});
|
|
2061
2084
|
assert.deepEqual(res, {
|
|
2062
2085
|
category: 'expected',
|
|
2063
2086
|
errorCode: 3007,
|
|
@@ -2072,7 +2095,11 @@ describe('internal-plugin-metrics', () => {
|
|
|
2072
2095
|
});
|
|
2073
2096
|
|
|
2074
2097
|
it('should include httpStatusCode for meetingInfo service error codes', () => {
|
|
2075
|
-
const res = cd.generateClientEventErrorPayload({
|
|
2098
|
+
const res = cd.generateClientEventErrorPayload({
|
|
2099
|
+
body: {data: {meetingInfo: {}}},
|
|
2100
|
+
message: 'bad times',
|
|
2101
|
+
statusCode: 400,
|
|
2102
|
+
});
|
|
2076
2103
|
assert.deepEqual(res, {
|
|
2077
2104
|
category: 'signaling',
|
|
2078
2105
|
errorCode: 4100,
|
|
@@ -2087,8 +2114,10 @@ describe('internal-plugin-metrics', () => {
|
|
|
2087
2114
|
});
|
|
2088
2115
|
|
|
2089
2116
|
it('should include httpStatusCode for network errors', () => {
|
|
2090
|
-
const error = new WebexHttpError.NetworkOrCORSError(
|
|
2091
|
-
|
|
2117
|
+
const error = new WebexHttpError.NetworkOrCORSError({
|
|
2118
|
+
statusCode: 400,
|
|
2119
|
+
options: {service: '', headers: {}},
|
|
2120
|
+
});
|
|
2092
2121
|
const res = cd.generateClientEventErrorPayload(error);
|
|
2093
2122
|
assert.deepEqual(res, {
|
|
2094
2123
|
category: 'network',
|
|
@@ -2104,8 +2133,10 @@ describe('internal-plugin-metrics', () => {
|
|
|
2104
2133
|
});
|
|
2105
2134
|
|
|
2106
2135
|
it('should include httpStatusCode for unauthorized errors', () => {
|
|
2107
|
-
const error = new WebexHttpError.Unauthorized(
|
|
2108
|
-
|
|
2136
|
+
const error = new WebexHttpError.Unauthorized({
|
|
2137
|
+
statusCode: 401,
|
|
2138
|
+
options: {service: '', headers: {}},
|
|
2139
|
+
});
|
|
2109
2140
|
const res = cd.generateClientEventErrorPayload(error);
|
|
2110
2141
|
assert.deepEqual(res, {
|
|
2111
2142
|
category: 'network',
|
|
@@ -2308,7 +2339,7 @@ describe('internal-plugin-metrics', () => {
|
|
|
2308
2339
|
});
|
|
2309
2340
|
});
|
|
2310
2341
|
|
|
2311
|
-
describe(
|
|
2342
|
+
describe('#submitToCallDiagnosticsPreLogin', () => {
|
|
2312
2343
|
it('should send request to call diagnostic batcher and saves preLoginId', () => {
|
|
2313
2344
|
const requestStub = sinon.stub();
|
|
2314
2345
|
//@ts-ignore
|
|
@@ -2321,7 +2352,7 @@ describe('internal-plugin-metrics', () => {
|
|
|
2321
2352
|
assert.calledWith(cd.preLoginMetricsBatcher.savePreLoginId, preLoginId);
|
|
2322
2353
|
assert.calledWith(requestStub, {eventPayload: {event: 'test'}, type: ['diagnostic-event']});
|
|
2323
2354
|
});
|
|
2324
|
-
})
|
|
2355
|
+
});
|
|
2325
2356
|
|
|
2326
2357
|
describe('#isServiceErrorExpected', () => {
|
|
2327
2358
|
it('returns true for code mapped to "expected"', () => {
|
|
@@ -319,6 +319,7 @@ describe('internal-plugin-metrics', () => {
|
|
|
319
319
|
clickToInterstitial: undefined,
|
|
320
320
|
meetingInfoReqResp: undefined,
|
|
321
321
|
refreshCaptchaServiceReqResp: undefined,
|
|
322
|
+
downloadIntelligenceModelsReqResp: undefined,
|
|
322
323
|
},
|
|
323
324
|
},
|
|
324
325
|
],
|
|
@@ -346,7 +347,7 @@ describe('internal-plugin-metrics', () => {
|
|
|
346
347
|
interstitialToJoinOK: undefined,
|
|
347
348
|
totalJmt: undefined,
|
|
348
349
|
clientJmt: undefined,
|
|
349
|
-
downloadTime: undefined
|
|
350
|
+
downloadTime: undefined,
|
|
350
351
|
},
|
|
351
352
|
},
|
|
352
353
|
],
|
|
@@ -75,6 +75,7 @@ describe('internal-plugin-metrics', () => {
|
|
|
75
75
|
meetingInfoReqResp: undefined,
|
|
76
76
|
clickToInterstitial: undefined,
|
|
77
77
|
refreshCaptchaServiceReqResp: undefined,
|
|
78
|
+
downloadIntelligenceModelsReqResp: undefined,
|
|
78
79
|
},
|
|
79
80
|
name: 'client.interstitial-window.launched',
|
|
80
81
|
},
|
|
@@ -149,7 +150,8 @@ describe('internal-plugin-metrics', () => {
|
|
|
149
150
|
});
|
|
150
151
|
|
|
151
152
|
it('fails if preLoinId is not set', async () => {
|
|
152
|
-
webex.internal.newMetrics.callDiagnosticMetrics.preLoginMetricsBatcher.preLoginId =
|
|
153
|
+
webex.internal.newMetrics.callDiagnosticMetrics.preLoginMetricsBatcher.preLoginId =
|
|
154
|
+
undefined;
|
|
153
155
|
|
|
154
156
|
const promise =
|
|
155
157
|
webex.internal.newMetrics.callDiagnosticMetrics.submitToCallDiagnosticsPreLogin(
|
|
@@ -177,7 +179,7 @@ describe('internal-plugin-metrics', () => {
|
|
|
177
179
|
|
|
178
180
|
describe('prepareItem', () => {
|
|
179
181
|
it('calls prepareDiagnosticMetricItem correctly', async () => {
|
|
180
|
-
|
|
182
|
+
// avoid setting .sent timestamp
|
|
181
183
|
webex.internal.newMetrics.callDiagnosticMetrics.preLoginMetricsBatcher.prepareRequest = (q) =>
|
|
182
184
|
Promise.resolve(q);
|
|
183
185
|
|