@webex/internal-plugin-metrics
Advanced tools
Comparing version 3.0.0 to 3.1.0
@@ -56,2 +56,3 @@ "use strict"; | ||
this.latencyTimestamps.clear(); | ||
this.precomputedLatencies.clear(); | ||
} | ||
@@ -86,3 +87,4 @@ | ||
* @param key - key | ||
* @param value -value | ||
* @param value - value | ||
* @param options - store options | ||
* @throws | ||
@@ -116,3 +118,4 @@ * @returns | ||
* @param key - key | ||
* @param value -value | ||
* @param value - value | ||
* @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 | ||
* @throws | ||
@@ -124,6 +127,26 @@ * @returns | ||
value: function saveLatency(key, value) { | ||
this.precomputedLatencies.set(key, value); | ||
var accumulate = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false; | ||
var existingValue = accumulate ? this.precomputedLatencies.get(key) || 0 : 0; | ||
this.precomputedLatencies.set(key, value + existingValue); | ||
} | ||
/** | ||
* Measure latency for a request | ||
* @param callback - callback for which you would like to measure latency | ||
* @param key - key | ||
* @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 | ||
* @returns | ||
*/ | ||
}, { | ||
key: "measureLatency", | ||
value: function measureLatency(callback, key) { | ||
var _this2 = this; | ||
var accumulate = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false; | ||
var start = performance.now(); | ||
return callback().finally(function () { | ||
_this2.saveLatency(key, performance.now() - start, accumulate); | ||
}); | ||
} | ||
/** | ||
* Store only the first timestamp value for the given key | ||
@@ -189,2 +212,13 @@ * @param key - key | ||
/** | ||
* getU2CTime | ||
* @returns - latency | ||
*/ | ||
}, { | ||
key: "getU2CTime", | ||
value: function getU2CTime() { | ||
var u2cLatency = this.precomputedLatencies.get('internal.get.u2c.time'); | ||
return u2cLatency ? Math.floor(u2cLatency) : undefined; | ||
} | ||
/** | ||
* Device Register Time | ||
@@ -220,13 +254,2 @@ * @returns - latency | ||
/** | ||
* Locus Join Response Sent Received | ||
* @returns - latency | ||
*/ | ||
}, { | ||
key: "getJoinRespSentReceived", | ||
value: function getJoinRespSentReceived() { | ||
// TODO: not clear SPARK-440554 | ||
return undefined; | ||
} | ||
/** | ||
* Time taken to do turn discovery | ||
@@ -461,2 +484,12 @@ * @returns - latency | ||
/** | ||
* Total latency for all get cluster request. | ||
*/ | ||
}, { | ||
key: "getReachabilityClustersReqResp", | ||
value: function getReachabilityClustersReqResp() { | ||
var reachablityClusterReqResp = this.precomputedLatencies.get('internal.get.cluster.time'); | ||
return reachablityClusterReqResp ? Math.floor(reachablityClusterReqResp) : undefined; | ||
} | ||
/** | ||
* Audio setup delay transmit | ||
@@ -478,2 +511,45 @@ */ | ||
} | ||
/** | ||
* Total latency for all exchange ci token. | ||
*/ | ||
}, { | ||
key: "getExchangeCITokenJMT", | ||
value: function getExchangeCITokenJMT() { | ||
var exchangeCITokenJMT = this.precomputedLatencies.get('internal.exchange.ci.token.time'); | ||
return exchangeCITokenJMT ? Math.floor(exchangeCITokenJMT) : undefined; | ||
} | ||
/** | ||
* Total latency for all refresh captcha requests. | ||
*/ | ||
}, { | ||
key: "getRefreshCaptchaReqResp", | ||
value: function getRefreshCaptchaReqResp() { | ||
var refreshCaptchaReqResp = this.precomputedLatencies.get('internal.refresh.captcha.time'); | ||
return refreshCaptchaReqResp ? Math.floor(refreshCaptchaReqResp) : undefined; | ||
} | ||
/** | ||
* Get the latency for downloading intelligence models. | ||
* @returns - latency | ||
*/ | ||
}, { | ||
key: "getDownloadIntelligenceModelsReqResp", | ||
value: function getDownloadIntelligenceModelsReqResp() { | ||
var downloadIntelligenceModelsReqResp = this.precomputedLatencies.get('internal.api.fetch.intelligence.models'); | ||
return downloadIntelligenceModelsReqResp ? Math.floor(downloadIntelligenceModelsReqResp) : undefined; | ||
} | ||
/** | ||
* Get the total latency for all other app API requests. | ||
* Excludes meeting info, because it's measured separately. | ||
* @returns - latency | ||
*/ | ||
}, { | ||
key: "getOtherAppApiReqResp", | ||
value: function getOtherAppApiReqResp() { | ||
var otherAppApiJMT = this.precomputedLatencies.get('internal.other.app.api.time'); | ||
return otherAppApiJMT > 0 ? Math.floor(otherAppApiJMT) : undefined; | ||
} | ||
}]); | ||
@@ -480,0 +556,0 @@ return CallDiagnosticLatencies; |
@@ -236,2 +236,5 @@ "use strict"; | ||
} | ||
if (options !== null && options !== void 0 && options.browserLaunchMethod) { | ||
origin.clientInfo.browserLaunchMethod = options.browserLaunchMethod; | ||
} | ||
return origin; | ||
@@ -270,2 +273,4 @@ } | ||
var device = this.webex.internal.device; | ||
var _ref2 = device.config || {}, | ||
installationId = _ref2.installationId; | ||
identifiers.userId = device.userId || preLoginId; | ||
@@ -276,2 +281,5 @@ identifiers.deviceId = device.url; | ||
identifiers.locusUrl = this.webex.internal.services.get('locus'); | ||
if (installationId) { | ||
identifiers.machineId = installationId; | ||
} | ||
} | ||
@@ -368,6 +376,6 @@ if (meeting !== null && meeting !== void 0 && (_meeting$locusInfo = meeting.locusInfo) !== null && _meeting$locusInfo !== void 0 && _meeting$locusInfo.fullState) { | ||
key: "submitMQE", | ||
value: function submitMQE(_ref2) { | ||
var name = _ref2.name, | ||
payload = _ref2.payload, | ||
options = _ref2.options; | ||
value: function submitMQE(_ref3) { | ||
var name = _ref3.name, | ||
payload = _ref3.payload, | ||
options = _ref3.options; | ||
var meetingId = options.meetingId, | ||
@@ -447,9 +455,9 @@ mediaConnections = options.mediaConnections, | ||
key: "getErrorPayloadForClientErrorCode", | ||
value: function getErrorPayloadForClientErrorCode(_ref3) { | ||
var clientErrorCode = _ref3.clientErrorCode, | ||
serviceErrorCode = _ref3.serviceErrorCode, | ||
serviceErrorName = _ref3.serviceErrorName, | ||
rawErrorMessage = _ref3.rawErrorMessage, | ||
payloadOverrides = _ref3.payloadOverrides, | ||
httpStatusCode = _ref3.httpStatusCode; | ||
value: function getErrorPayloadForClientErrorCode(_ref4) { | ||
var clientErrorCode = _ref4.clientErrorCode, | ||
serviceErrorCode = _ref4.serviceErrorCode, | ||
serviceErrorName = _ref4.serviceErrorName, | ||
rawErrorMessage = _ref4.rawErrorMessage, | ||
payloadOverrides = _ref4.payloadOverrides, | ||
httpStatusCode = _ref4.httpStatusCode; | ||
var error; | ||
@@ -571,2 +579,3 @@ if (clientErrorCode) { | ||
serviceErrorCode: _config2.UNKNOWN_ERROR, | ||
payloadOverrides: rawError.payloadOverrides, | ||
rawErrorMessage: rawErrorMessage, | ||
@@ -586,6 +595,6 @@ httpStatusCode: httpStatusCode | ||
key: "createClientEventObjectInMeeting", | ||
value: function createClientEventObjectInMeeting(_ref4) { | ||
var name = _ref4.name, | ||
options = _ref4.options, | ||
errors = _ref4.errors; | ||
value: function createClientEventObjectInMeeting(_ref5) { | ||
var name = _ref5.name, | ||
options = _ref5.options, | ||
errors = _ref5.errors; | ||
var meetingId = options.meetingId, | ||
@@ -646,6 +655,6 @@ mediaConnections = options.mediaConnections, | ||
key: "createClientEventObjectPreMeeting", | ||
value: function createClientEventObjectPreMeeting(_ref5) { | ||
var name = _ref5.name, | ||
options = _ref5.options, | ||
errors = _ref5.errors; | ||
value: function createClientEventObjectPreMeeting(_ref6) { | ||
var name = _ref6.name, | ||
options = _ref6.options, | ||
errors = _ref6.errors; | ||
var correlationId = options.correlationId, | ||
@@ -689,6 +698,6 @@ globalMeetingId = options.globalMeetingId, | ||
key: "prepareClientEvent", | ||
value: function prepareClientEvent(_ref6) { | ||
var name = _ref6.name, | ||
payload = _ref6.payload, | ||
options = _ref6.options; | ||
value: function prepareClientEvent(_ref7) { | ||
var name = _ref7.name, | ||
payload = _ref7.payload, | ||
options = _ref7.options; | ||
var meetingId = options.meetingId, | ||
@@ -745,6 +754,6 @@ correlationId = options.correlationId, | ||
key: "submitClientEvent", | ||
value: function submitClientEvent(_ref7) { | ||
var name = _ref7.name, | ||
payload = _ref7.payload, | ||
options = _ref7.options; | ||
value: function submitClientEvent(_ref8) { | ||
var name = _ref8.name, | ||
payload = _ref8.payload, | ||
options = _ref8.options; | ||
this.logger.log(_config2.CALL_DIAGNOSTIC_LOG_IDENTIFIER, 'CallDiagnosticMetrics: @submitClientEvent. Submit Client Event CA event.', "name: ".concat(name)); | ||
@@ -794,3 +803,3 @@ var diagnosticEvent = this.prepareClientEvent({ | ||
function () { | ||
var _buildClientEventFetchRequestOptions = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee(_ref8) { | ||
var _buildClientEventFetchRequestOptions = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee(_ref9) { | ||
var name, payload, options, clientEvent, diagnosticEvent, request; | ||
@@ -800,3 +809,3 @@ return _regenerator.default.wrap(function _callee$(_context) { | ||
case 0: | ||
name = _ref8.name, payload = _ref8.payload, options = _ref8.options; | ||
name = _ref9.name, payload = _ref9.payload, options = _ref9.options; | ||
this.logger.log(_config2.CALL_DIAGNOSTIC_LOG_IDENTIFIER, 'CallDiagnosticMetrics: @buildClientEventFetchRequestOptions. Building request options object for fetch()...', "name: ".concat(name)); | ||
@@ -803,0 +812,0 @@ clientEvent = this.prepareClientEvent({ |
@@ -218,5 +218,11 @@ "use strict"; | ||
break; | ||
case 'client.login.end': | ||
joinTimes.otherAppApiReqResp = cdl.getOtherAppApiReqResp(); | ||
joinTimes.exchangeCITokenJMT = cdl.getExchangeCITokenJMT(); | ||
break; | ||
case 'client.interstitial-window.launched': | ||
joinTimes.meetingInfoReqResp = cdl.getMeetingInfoReqResp(); | ||
joinTimes.clickToInterstitial = cdl.getClickToInterstitial(); | ||
joinTimes.refreshCaptchaServiceReqResp = cdl.getRefreshCaptchaReqResp(); | ||
joinTimes.downloadIntelligenceModelsReqResp = cdl.getDownloadIntelligenceModelsReqResp(); | ||
break; | ||
@@ -227,2 +233,4 @@ case 'client.call.initiated': | ||
joinTimes.registerWDMDeviceJMT = cdl.getRegisterWDMDeviceJMT(); | ||
joinTimes.getU2CTime = cdl.getU2CTime(); | ||
joinTimes.getReachabilityClustersReqResp = cdl.getReachabilityClustersReqResp(); | ||
break; | ||
@@ -233,3 +241,2 @@ case 'client.locus.join.response': | ||
joinTimes.joinReqResp = cdl.getJoinReqResp(); | ||
joinTimes.joinReqSentReceived = cdl.getJoinRespSentReceived(); | ||
joinTimes.pageJmt = cdl.getPageJMT(); | ||
@@ -340,6 +347,6 @@ joinTimes.clickToInterstitial = cdl.getClickToInterstitial(); | ||
} | ||
if (signalingState === 'stable' && iceConnectionState === 'connected') { | ||
if (signalingState === 'stable' && (iceConnectionState === 'connected' || iceConnectionState === 'disconnected')) { | ||
errorCode = _config.DTLS_HANDSHAKE_FAILED_CLIENT_CODE; | ||
} | ||
if (signalingState !== 'have-local-offer' && iceConnectionState !== 'connected') { | ||
if (signalingState !== 'have-local-offer' && iceConnectionState !== 'connected' && iceConnectionState !== 'disconnected') { | ||
if (turnServerUsed) { | ||
@@ -346,0 +353,0 @@ errorCode = _config.ICE_FAILED_WITH_TURN_TLS_CLIENT_CODE; |
@@ -21,2 +21,3 @@ "use strict"; | ||
var _clientMetricsBatcher = _interopRequireDefault(require("./client-metrics-batcher")); | ||
var _clientMetricsPreloginBatcher = _interopRequireDefault(require("./client-metrics-prelogin-batcher")); | ||
function ownKeys(e, r) { var t = _Object$keys(e); if (_Object$getOwnPropertySymbols) { var o = _Object$getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return _Object$getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; } | ||
@@ -53,3 +54,4 @@ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { (0, _defineProperty2.default)(e, r, t[r]); }) : _Object$getOwnPropertyDescriptors ? _Object$defineProperties(e, _Object$getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { _Object$defineProperty(e, r, _Object$getOwnPropertyDescriptor(t, r)); }); } return e; } /* eslint-disable default-param-last */ /*! | ||
batcher: _batcher.default, | ||
clientMetricsBatcher: _clientMetricsBatcher.default | ||
clientMetricsBatcher: _clientMetricsBatcher.default, | ||
clientMetricsPreloginBatcher: _clientMetricsPreloginBatcher.default | ||
}, | ||
@@ -69,2 +71,3 @@ namespace: 'Metrics', | ||
getClientMetricsPayload: function getClientMetricsPayload(eventName, props) { | ||
var _this$webex$meetings, _this$webex$meetings$, _this$webex$meetings$2; | ||
if (!eventName) { | ||
@@ -76,5 +79,8 @@ throw Error('Missing behavioral metric name. Please provide one'); | ||
}; | ||
// @ts-ignore | ||
var providedClientVersion = (_this$webex$meetings = this.webex.meetings) === null || _this$webex$meetings === void 0 ? void 0 : (_this$webex$meetings$ = _this$webex$meetings.config) === null || _this$webex$meetings$ === void 0 ? void 0 : (_this$webex$meetings$2 = _this$webex$meetings$.metrics) === null || _this$webex$meetings$2 === void 0 ? void 0 : _this$webex$meetings$2.clientVersion; | ||
payload.tags = _objectSpread(_objectSpread({}, props.tags), {}, { | ||
browser: getBrowserName(), | ||
os: getOSNameInternal(), | ||
appVersion: providedClientVersion, | ||
// Node does not like this so we need to check if it exists or not | ||
@@ -125,10 +131,4 @@ // eslint-disable-next-line no-undef | ||
if (preLoginId) { | ||
var _payload = { | ||
metrics: [payload] | ||
}; | ||
// Do not batch these because pre-login events occur during onboarding, so we will be partially blind | ||
// to users' progress through the reg flow if we wait to persist pre-login metrics for people who drop off because | ||
// their metrics will not post from a queue flush in time | ||
return this.postPreLoginMetric(_payload, preLoginId); | ||
this.clientMetricsPreloginBatcher.savePreLoginId(preLoginId); | ||
return this.clientMetricsPreloginBatcher.request(payload); | ||
} | ||
@@ -156,20 +156,5 @@ return this.clientMetricsBatcher.request(payload); | ||
}, | ||
postPreLoginMetric: function postPreLoginMetric(payload, preLoginId) { | ||
var _this = this; | ||
return this.webex.credentials.getClientToken().then(function (token) { | ||
return _this.request({ | ||
method: 'POST', | ||
api: 'metrics', | ||
resource: 'clientmetrics-prelogin', | ||
headers: { | ||
authorization: token.toString(), | ||
'x-prelogin-userid': preLoginId | ||
}, | ||
body: payload | ||
}); | ||
}); | ||
}, | ||
version: "3.0.0" | ||
version: "3.1.0" | ||
}); | ||
var _default = exports.default = Metrics; | ||
//# sourceMappingURL=metrics.js.map |
@@ -53,2 +53,4 @@ "use strict"; | ||
_this = _super.call.apply(_super, [this].concat(args)); | ||
// @ts-ignore | ||
// Call Diagnostic latencies | ||
@@ -58,2 +60,5 @@ (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "callDiagnosticLatencies", void 0); | ||
(0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "callDiagnosticMetrics", void 0); | ||
_this.callDiagnosticLatencies = new _callDiagnosticMetricsLatencies.default({}, { | ||
parent: _this.webex | ||
}); | ||
_this.onReady(); | ||
@@ -76,6 +81,2 @@ return _this; | ||
}); | ||
// @ts-ignore | ||
_this2.callDiagnosticLatencies = new _callDiagnosticMetricsLatencies.default({}, { | ||
parent: _this2.webex | ||
}); | ||
}); | ||
@@ -82,0 +83,0 @@ } |
@@ -54,3 +54,3 @@ "use strict"; | ||
var _this = this; | ||
var batchId = (0, _lodash.uniqueId)('prelogin-ca-batch-'); | ||
var batchId = (0, _lodash.uniqueId)('prelogin-batch-'); | ||
if (this.preLoginId === undefined) { | ||
@@ -57,0 +57,0 @@ this.webex.logger.error(PRE_LOGIN_METRICS_IDENTIFIER, "PreLoginMetricsBatcher: @submitHttpRequest#".concat(batchId, ". PreLoginId is not set.")); |
@@ -33,3 +33,4 @@ import { WebexPlugin } from '@webex/webex-core'; | ||
* @param key - key | ||
* @param value -value | ||
* @param value - value | ||
* @param options - store options | ||
* @throws | ||
@@ -48,8 +49,17 @@ * @returns | ||
* @param key - key | ||
* @param value -value | ||
* @param value - value | ||
* @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 | ||
* @throws | ||
* @returns | ||
*/ | ||
saveLatency(key: PreComputedLatencies, value: number): void; | ||
saveLatency(key: PreComputedLatencies, value: number, accumulate?: boolean): void; | ||
/** | ||
* Measure latency for a request | ||
* @param callback - callback for which you would like to measure latency | ||
* @param key - key | ||
* @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 | ||
* @returns | ||
*/ | ||
measureLatency(callback: () => Promise<unknown>, key: PreComputedLatencies, accumulate?: boolean): Promise<unknown>; | ||
/** | ||
* Store only the first timestamp value for the given key | ||
@@ -86,2 +96,7 @@ * @param key - key | ||
/** | ||
* getU2CTime | ||
* @returns - latency | ||
*/ | ||
getU2CTime(): number; | ||
/** | ||
* Device Register Time | ||
@@ -102,7 +117,2 @@ * @returns - latency | ||
/** | ||
* Locus Join Response Sent Received | ||
* @returns - latency | ||
*/ | ||
getJoinRespSentReceived(): any; | ||
/** | ||
* Time taken to do turn discovery | ||
@@ -201,2 +211,6 @@ * @returns - latency | ||
/** | ||
* Total latency for all get cluster request. | ||
*/ | ||
getReachabilityClustersReqResp(): number; | ||
/** | ||
* Audio setup delay transmit | ||
@@ -209,2 +223,21 @@ */ | ||
getVideoJoinRespTxStart(): number; | ||
/** | ||
* Total latency for all exchange ci token. | ||
*/ | ||
getExchangeCITokenJMT(): number; | ||
/** | ||
* Total latency for all refresh captcha requests. | ||
*/ | ||
getRefreshCaptchaReqResp(): number; | ||
/** | ||
* Get the latency for downloading intelligence models. | ||
* @returns - latency | ||
*/ | ||
getDownloadIntelligenceModelsReqResp(): number; | ||
/** | ||
* Get the total latency for all other app API requests. | ||
* Excludes meeting info, because it's measured separately. | ||
* @returns - latency | ||
*/ | ||
getOtherAppApiReqResp(): number; | ||
} |
import { StatelessWebexPlugin } from '@webex/webex-core'; | ||
import { Event, ClientType, SubClientType, NetworkType, EnvironmentType, NewEnvironmentType, ClientEvent, SubmitClientEventOptions, MediaQualityEvent, SubmitMQEOptions, SubmitMQEPayload, ClientLaunchMethodType, ClientEventError, ClientEventPayload, ClientSubServiceType } from '../metrics.types'; | ||
import { Event, ClientType, SubClientType, NetworkType, EnvironmentType, NewEnvironmentType, ClientEvent, SubmitClientEventOptions, MediaQualityEvent, SubmitMQEOptions, SubmitMQEPayload, ClientLaunchMethodType, ClientEventError, ClientEventPayload, ClientSubServiceType, BrowserLaunchMethodType } from '../metrics.types'; | ||
type GetOriginOptions = { | ||
@@ -8,2 +8,3 @@ clientType: ClientType; | ||
clientLaunchMethod?: ClientLaunchMethodType; | ||
browserLaunchMethod?: BrowserLaunchMethodType; | ||
environment?: EnvironmentType; | ||
@@ -79,3 +80,3 @@ newEnvironment?: NewEnvironmentType; | ||
clientInfo?: { | ||
os?: "windows" | "mac" | "ios" | "android" | "chrome" | "linux" | "other" | "android-x64" | "android-arm64" | "uwp-arm64"; | ||
os?: "other" | "chrome" | "windows" | "mac" | "ios" | "android" | "linux" | "android-x64" | "android-arm64" | "uwp-arm64"; | ||
osVersion?: string; | ||
@@ -92,14 +93,8 @@ localIP?: string; | ||
clientType?: "MEETING_CENTER" | "EVENT_CENTER" | "TRAINING_CENTER" | "TEAMS_CLIENT" | "TEAMS_DEVICE" | "TEAMS_SHARE" | "SIP" | "RECORDING" | "CLOUD_AWARE_SIP" | "TEAMS_WXC_CLIENT" | "WXC_CLIENT" | "WXC_DEVICE" | "WEBEX_JS_SDK" | "VOICEA_CLIENT" | "CISCO_SIP_GW" | "WEBEX_SDK" | "CPAAS_THIRD_PARTY_SDK" | "WXC_THIRD_PARTY" | "WXCC"; | ||
subClientType?: "TEAMS_DEVICE" | "DESKTOP_APP" | "DESKTOP_APP_VDI" | "DEVICE_CURRENT" | "DEVICE_LEGACY_2020" | "HOLOGRAM_HEADSET_APP" | "HVDI_APP" | "MOBILE_APP" | "MOBILE_NETWORK" | "VDI_APP" | "WEB_APP"; | ||
clientVersion?: string; /** | ||
* Returns the login type of the current user | ||
* @returns one of 'login-ci','unverified-guest', null | ||
*/ | ||
subClientType?: "TEAMS_DEVICE" | "DESKTOP_APP" | "DESKTOP_APP_VDI" | "DEVICE_CURRENT" | "DEVICE_LEGACY_2020" | "HOLOGRAM_HEADSET_APP" | "HVDI_APP" | "MIXED" | "MOBILE_APP" | "MOBILE_NETWORK" | "PAGE" | "VDI_APP" | "WEB_APP"; | ||
clientVersion?: string; | ||
clientVersionStatus?: "CURRENT" | "LEGACY" | "UNSUPPORTED"; | ||
localClientVersion?: string; | ||
modelNumber?: string; | ||
joinFirstUpdateLater?: "ep-enabled" | "sp-enabled" | "not-enabled"; /** | ||
* Returns if the meeting has converged architecture enabled | ||
* @param options.meetingId | ||
*/ | ||
joinFirstUpdateLater?: "ep-enabled" | "sp-enabled" | "not-enabled"; | ||
standbyUsed?: boolean; | ||
@@ -191,2 +186,3 @@ prefetchDocShowUsed?: boolean; | ||
msteamsConferenceId?: string; | ||
msteamsMeetingId?: string; | ||
oauth2ClientId?: string; | ||
@@ -263,2 +259,3 @@ orgId?: string; | ||
msteamsConferenceId?: string; | ||
msteamsMeetingId?: string; | ||
oauth2ClientId?: string; | ||
@@ -346,3 +343,3 @@ orgId?: string; | ||
fatal: boolean; | ||
category: "other" | "signaling" | "media" | "network" | "expected"; | ||
category: "signaling" | "media" | "network" | "other" | "expected"; | ||
errorDescription?: string; | ||
@@ -355,2 +352,3 @@ errorCode?: number; | ||
rawErrorMessage?: string; | ||
mediaDeviceErrors?: string; | ||
shownToUser: boolean; | ||
@@ -357,0 +355,0 @@ serviceErrorCode?: number; |
@@ -8,3 +8,3 @@ /*! | ||
import * as Utils from './utils'; | ||
import { ClientEvent, ClientEventLeaveReason, SubmitBehavioralEvent, SubmitClientEvent, SubmitInternalEvent, SubmitOperationalEvent, SubmitMQE } from './metrics.types'; | ||
import { ClientEvent, ClientEventLeaveReason, SubmitBehavioralEvent, SubmitClientEvent, SubmitInternalEvent, SubmitOperationalEvent, SubmitMQE, PreComputedLatencies } from './metrics.types'; | ||
import * as CALL_DIAGNOSTIC_CONFIG from './call-diagnostic/config'; | ||
@@ -16,2 +16,2 @@ import * as CallDiagnosticUtils from './call-diagnostic/call-diagnostic-metrics.util'; | ||
export { config, CALL_DIAGNOSTIC_CONFIG, NewMetrics, Utils, CallDiagnosticUtils, CallDiagnosticLatencies, CallDiagnosticMetrics, }; | ||
export type { ClientEvent, ClientEventLeaveReason, SubmitBehavioralEvent, SubmitClientEvent, SubmitInternalEvent, SubmitMQE, SubmitOperationalEvent, }; | ||
export type { ClientEvent, ClientEventLeaveReason, SubmitBehavioralEvent, SubmitClientEvent, SubmitInternalEvent, SubmitMQE, SubmitOperationalEvent, PreComputedLatencies, }; |
@@ -9,2 +9,3 @@ import { ClientEvent as RawClientEvent, Event as RawEvent, MediaQualityEvent as RawMediaQualityEvent } from '@webex/event-dictionary-ts'; | ||
export type ClientLaunchMethodType = NonNullable<RawEvent['origin']['clientInfo']>['clientLaunchMethod']; | ||
export type BrowserLaunchMethodType = NonNullable<RawEvent['origin']['clientInfo']>['browserLaunchMethod']; | ||
export type SubmitClientEventOptions = { | ||
@@ -19,2 +20,3 @@ meetingId?: string; | ||
clientLaunchMethod?: ClientLaunchMethodType; | ||
browserLaunchMethod?: BrowserLaunchMethodType; | ||
webexConferenceIdStr?: string; | ||
@@ -107,2 +109,2 @@ globalMeetingId?: string; | ||
}) => Promise<any>; | ||
export type PreComputedLatencies = 'internal.client.pageJMT' | 'internal.download.time' | 'internal.click.to.interstitial' | 'internal.call.init.join.req'; | ||
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'; |
@@ -29,6 +29,6 @@ { | ||
"@webex/legacy-tools": "0.0.0", | ||
"@webex/test-helper-chai": "3.0.0", | ||
"@webex/test-helper-mocha": "3.0.0", | ||
"@webex/test-helper-mock-webex": "3.0.0", | ||
"@webex/test-helper-test-users": "3.0.0", | ||
"@webex/test-helper-chai": "3.1.0", | ||
"@webex/test-helper-mocha": "3.1.0", | ||
"@webex/test-helper-mock-webex": "3.1.0", | ||
"@webex/test-helper-test-users": "3.1.0", | ||
"eslint": "^8.24.0", | ||
@@ -39,10 +39,10 @@ "prettier": "^2.7.1", | ||
"dependencies": { | ||
"@webex/common": "3.0.0", | ||
"@webex/common-timers": "3.0.0", | ||
"@webex/event-dictionary-ts": "^1.0.1329", | ||
"@webex/internal-plugin-device": "3.0.0", | ||
"@webex/internal-plugin-metrics": "3.0.0", | ||
"@webex/test-helper-chai": "3.0.0", | ||
"@webex/test-helper-mock-webex": "3.0.0", | ||
"@webex/webex-core": "3.0.0", | ||
"@webex/common": "3.1.0", | ||
"@webex/common-timers": "3.1.0", | ||
"@webex/event-dictionary-ts": "^1.0.1406", | ||
"@webex/internal-plugin-device": "3.1.0", | ||
"@webex/internal-plugin-metrics": "3.1.0", | ||
"@webex/test-helper-chai": "3.1.0", | ||
"@webex/test-helper-mock-webex": "3.1.0", | ||
"@webex/webex-core": "3.1.0", | ||
"ip-anonymize": "^0.1.0", | ||
@@ -60,3 +60,3 @@ "lodash": "^4.17.21", | ||
}, | ||
"version": "3.0.0" | ||
"version": "3.1.0" | ||
} |
@@ -34,2 +34,3 @@ /* eslint-disable class-methods-use-this */ | ||
this.latencyTimestamps.clear(); | ||
this.precomputedLatencies.clear(); | ||
} | ||
@@ -61,3 +62,4 @@ | ||
* @param key - key | ||
* @param value -value | ||
* @param value - value | ||
* @param options - store options | ||
* @throws | ||
@@ -97,11 +99,32 @@ * @returns | ||
* @param key - key | ||
* @param value -value | ||
* @param value - value | ||
* @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 | ||
* @throws | ||
* @returns | ||
*/ | ||
public saveLatency(key: PreComputedLatencies, value: number) { | ||
this.precomputedLatencies.set(key, value); | ||
public saveLatency(key: PreComputedLatencies, value: number, accumulate = false) { | ||
const existingValue = accumulate ? this.precomputedLatencies.get(key) || 0 : 0; | ||
this.precomputedLatencies.set(key, value + existingValue); | ||
} | ||
/** | ||
* Measure latency for a request | ||
* @param callback - callback for which you would like to measure latency | ||
* @param key - key | ||
* @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 | ||
* @returns | ||
*/ | ||
public measureLatency( | ||
callback: () => Promise<unknown>, | ||
key: PreComputedLatencies, | ||
accumulate = false | ||
) { | ||
const start = performance.now(); | ||
return callback().finally(() => { | ||
this.saveLatency(key, performance.now() - start, accumulate); | ||
}); | ||
} | ||
/** | ||
* Store only the first timestamp value for the given key | ||
@@ -165,2 +188,12 @@ * @param key - key | ||
/** | ||
* getU2CTime | ||
* @returns - latency | ||
*/ | ||
public getU2CTime() { | ||
const u2cLatency = this.precomputedLatencies.get('internal.get.u2c.time'); | ||
return u2cLatency ? Math.floor(u2cLatency) : undefined; | ||
} | ||
/** | ||
* Device Register Time | ||
@@ -196,11 +229,2 @@ * @returns - latency | ||
/** | ||
* Locus Join Response Sent Received | ||
* @returns - latency | ||
*/ | ||
public getJoinRespSentReceived() { | ||
// TODO: not clear SPARK-440554 | ||
return undefined; | ||
} | ||
/** | ||
* Time taken to do turn discovery | ||
@@ -428,2 +452,11 @@ * @returns - latency | ||
/** | ||
* Total latency for all get cluster request. | ||
*/ | ||
public getReachabilityClustersReqResp() { | ||
const reachablityClusterReqResp = this.precomputedLatencies.get('internal.get.cluster.time'); | ||
return reachablityClusterReqResp ? Math.floor(reachablityClusterReqResp) : undefined; | ||
} | ||
/** | ||
* Audio setup delay transmit | ||
@@ -441,2 +474,45 @@ */ | ||
} | ||
/** | ||
* Total latency for all exchange ci token. | ||
*/ | ||
public getExchangeCITokenJMT() { | ||
const exchangeCITokenJMT = this.precomputedLatencies.get('internal.exchange.ci.token.time'); | ||
return exchangeCITokenJMT ? Math.floor(exchangeCITokenJMT) : undefined; | ||
} | ||
/** | ||
* Total latency for all refresh captcha requests. | ||
*/ | ||
public getRefreshCaptchaReqResp() { | ||
const refreshCaptchaReqResp = this.precomputedLatencies.get('internal.refresh.captcha.time'); | ||
return refreshCaptchaReqResp ? Math.floor(refreshCaptchaReqResp) : undefined; | ||
} | ||
/** | ||
* Get the latency for downloading intelligence models. | ||
* @returns - latency | ||
*/ | ||
public getDownloadIntelligenceModelsReqResp() { | ||
const downloadIntelligenceModelsReqResp = this.precomputedLatencies.get( | ||
'internal.api.fetch.intelligence.models' | ||
); | ||
return downloadIntelligenceModelsReqResp | ||
? Math.floor(downloadIntelligenceModelsReqResp) | ||
: undefined; | ||
} | ||
/** | ||
* Get the total latency for all other app API requests. | ||
* Excludes meeting info, because it's measured separately. | ||
* @returns - latency | ||
*/ | ||
public getOtherAppApiReqResp() { | ||
const otherAppApiJMT = this.precomputedLatencies.get('internal.other.app.api.time'); | ||
return otherAppApiJMT > 0 ? Math.floor(otherAppApiJMT) : undefined; | ||
} | ||
} |
@@ -42,2 +42,3 @@ /* eslint-disable @typescript-eslint/no-unused-vars */ | ||
ClientSubServiceType, | ||
BrowserLaunchMethodType, | ||
} from '../metrics.types'; | ||
@@ -69,2 +70,3 @@ import CallDiagnosticEventsBatcher from './call-diagnostic-metrics-batcher'; | ||
clientLaunchMethod?: ClientLaunchMethodType; | ||
browserLaunchMethod?: BrowserLaunchMethodType; | ||
environment?: EnvironmentType; | ||
@@ -263,2 +265,6 @@ newEnvironment?: NewEnvironmentType; | ||
if (options?.browserLaunchMethod) { | ||
origin.clientInfo.browserLaunchMethod = options.browserLaunchMethod; | ||
} | ||
return origin; | ||
@@ -299,2 +305,4 @@ } | ||
const {device} = this.webex.internal; | ||
const {installationId} = device.config || {}; | ||
identifiers.userId = device.userId || preLoginId; | ||
@@ -305,2 +313,6 @@ identifiers.deviceId = device.url; | ||
identifiers.locusUrl = this.webex.internal.services.get('locus'); | ||
if (installationId) { | ||
identifiers.machineId = installationId; | ||
} | ||
} | ||
@@ -615,2 +627,3 @@ | ||
serviceErrorCode: UNKNOWN_ERROR, | ||
payloadOverrides: rawError.payloadOverrides, | ||
rawErrorMessage, | ||
@@ -617,0 +630,0 @@ httpStatusCode, |
@@ -247,5 +247,11 @@ /* eslint-disable valid-jsdoc */ | ||
break; | ||
case 'client.login.end': | ||
joinTimes.otherAppApiReqResp = cdl.getOtherAppApiReqResp(); | ||
joinTimes.exchangeCITokenJMT = cdl.getExchangeCITokenJMT(); | ||
break; | ||
case 'client.interstitial-window.launched': | ||
joinTimes.meetingInfoReqResp = cdl.getMeetingInfoReqResp(); | ||
joinTimes.clickToInterstitial = cdl.getClickToInterstitial(); | ||
joinTimes.refreshCaptchaServiceReqResp = cdl.getRefreshCaptchaReqResp(); | ||
joinTimes.downloadIntelligenceModelsReqResp = cdl.getDownloadIntelligenceModelsReqResp(); | ||
break; | ||
@@ -257,2 +263,4 @@ | ||
joinTimes.registerWDMDeviceJMT = cdl.getRegisterWDMDeviceJMT(); | ||
joinTimes.getU2CTime = cdl.getU2CTime(); | ||
joinTimes.getReachabilityClustersReqResp = cdl.getReachabilityClustersReqResp(); | ||
break; | ||
@@ -264,3 +272,2 @@ | ||
joinTimes.joinReqResp = cdl.getJoinReqResp(); | ||
joinTimes.joinReqSentReceived = cdl.getJoinRespSentReceived(); | ||
joinTimes.pageJmt = cdl.getPageJMT(); | ||
@@ -382,7 +389,14 @@ joinTimes.clickToInterstitial = cdl.getClickToInterstitial(); | ||
if (signalingState === 'stable' && iceConnectionState === 'connected') { | ||
if ( | ||
signalingState === 'stable' && | ||
(iceConnectionState === 'connected' || iceConnectionState === 'disconnected') | ||
) { | ||
errorCode = DTLS_HANDSHAKE_FAILED_CLIENT_CODE; | ||
} | ||
if (signalingState !== 'have-local-offer' && iceConnectionState !== 'connected') { | ||
if ( | ||
signalingState !== 'have-local-offer' && | ||
iceConnectionState !== 'connected' && | ||
iceConnectionState !== 'disconnected' | ||
) { | ||
if (turnServerUsed) { | ||
@@ -389,0 +403,0 @@ errorCode = ICE_FAILED_WITH_TURN_TLS_CLIENT_CODE; |
@@ -21,2 +21,3 @@ /*! | ||
SubmitMQE, | ||
PreComputedLatencies, | ||
} from './metrics.types'; | ||
@@ -55,2 +56,3 @@ import * as CALL_DIAGNOSTIC_CONFIG from './call-diagnostic/config'; | ||
SubmitOperationalEvent, | ||
PreComputedLatencies, | ||
}; |
@@ -13,2 +13,3 @@ /* eslint-disable default-param-last */ | ||
import ClientMetricsBatcher from './client-metrics-batcher'; | ||
import ClientMetricsPreloginBatcher from './client-metrics-prelogin-batcher'; | ||
@@ -41,2 +42,3 @@ const {getOSName, getOSVersion, getBrowserName, getBrowserVersion} = BrowserDetection(); | ||
clientMetricsBatcher: ClientMetricsBatcher, | ||
clientMetricsPreloginBatcher: ClientMetricsPreloginBatcher, | ||
}, | ||
@@ -61,2 +63,4 @@ | ||
const payload = {metricName: eventName}; | ||
// @ts-ignore | ||
const providedClientVersion = this.webex.meetings?.config?.metrics?.clientVersion; | ||
@@ -67,2 +71,3 @@ payload.tags = { | ||
os: getOSNameInternal(), | ||
appVersion: providedClientVersion, | ||
@@ -121,10 +126,5 @@ // Node does not like this so we need to check if it exists or not | ||
if (preLoginId) { | ||
const _payload = { | ||
metrics: [payload], | ||
}; | ||
this.clientMetricsPreloginBatcher.savePreLoginId(preLoginId); | ||
// Do not batch these because pre-login events occur during onboarding, so we will be partially blind | ||
// to users' progress through the reg flow if we wait to persist pre-login metrics for people who drop off because | ||
// their metrics will not post from a queue flush in time | ||
return this.postPreLoginMetric(_payload, preLoginId); | ||
return this.clientMetricsPreloginBatcher.request(payload); | ||
} | ||
@@ -154,19 +154,4 @@ | ||
}, | ||
postPreLoginMetric(payload, preLoginId) { | ||
return this.webex.credentials.getClientToken().then((token) => | ||
this.request({ | ||
method: 'POST', | ||
api: 'metrics', | ||
resource: 'clientmetrics-prelogin', | ||
headers: { | ||
authorization: token.toString(), | ||
'x-prelogin-userid': preLoginId, | ||
}, | ||
body: payload, | ||
}) | ||
); | ||
}, | ||
}); | ||
export default Metrics; |
@@ -19,2 +19,6 @@ import { | ||
export type BrowserLaunchMethodType = NonNullable< | ||
RawEvent['origin']['clientInfo'] | ||
>['browserLaunchMethod']; | ||
export type SubmitClientEventOptions = { | ||
@@ -29,2 +33,3 @@ meetingId?: string; | ||
clientLaunchMethod?: ClientLaunchMethodType; | ||
browserLaunchMethod?: BrowserLaunchMethodType; | ||
webexConferenceIdStr?: string; | ||
@@ -169,3 +174,9 @@ globalMeetingId?: string; | ||
| 'internal.download.time' | ||
| 'internal.get.cluster.time' | ||
| 'internal.click.to.interstitial' | ||
| 'internal.call.init.join.req'; | ||
| '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'; |
@@ -46,2 +46,4 @@ /* eslint-disable @typescript-eslint/no-unused-vars */ | ||
// @ts-ignore | ||
this.callDiagnosticLatencies = new CallDiagnosticLatencies({}, {parent: this.webex}); | ||
this.onReady(); | ||
@@ -58,4 +60,2 @@ } | ||
this.callDiagnosticMetrics = new CallDiagnosticMetrics({}, {parent: this.webex}); | ||
// @ts-ignore | ||
this.callDiagnosticLatencies = new CallDiagnosticLatencies({}, {parent: this.webex}); | ||
}); | ||
@@ -62,0 +62,0 @@ } |
@@ -51,3 +51,3 @@ import {uniqueId} from 'lodash'; | ||
submitHttpRequest(payload: any) { | ||
const batchId = uniqueId('prelogin-ca-batch-'); | ||
const batchId = uniqueId('prelogin-batch-'); | ||
if (this.preLoginId === undefined) { | ||
@@ -54,0 +54,0 @@ this.webex.logger.error( |
@@ -106,2 +106,8 @@ /*! | ||
.returns(10); | ||
webex.internal.newMetrics.callDiagnosticLatencies.getRefreshCaptchaReqResp = sinon | ||
.stub() | ||
.returns(10); | ||
webex.internal.newMetrics.callDiagnosticLatencies.getDownloadIntelligenceModelsReqResp = | ||
sinon.stub().returns(42); | ||
const promise = webex.internal.newMetrics.callDiagnosticMetrics.submitToCallDiagnostics( | ||
@@ -123,2 +129,4 @@ //@ts-ignore | ||
meetingInfoReqResp: 10, | ||
refreshCaptchaServiceReqResp: 10, | ||
downloadIntelligenceModelsReqResp: 42, | ||
}, | ||
@@ -136,2 +144,8 @@ }); | ||
.returns(10); | ||
webex.internal.newMetrics.callDiagnosticLatencies.getU2CTime = sinon | ||
.stub() | ||
.returns(20); | ||
webex.internal.newMetrics.callDiagnosticLatencies.getReachabilityClustersReqResp = sinon | ||
.stub() | ||
.returns(10); | ||
const promise = webex.internal.newMetrics.callDiagnosticMetrics.submitToCallDiagnostics( | ||
@@ -153,2 +167,4 @@ //@ts-ignore | ||
showInterstitialTime: 10, | ||
getU2CTime: 20, | ||
getReachabilityClustersReqResp: 10 | ||
}, | ||
@@ -166,5 +182,2 @@ }); | ||
.returns(10); | ||
webex.internal.newMetrics.callDiagnosticLatencies.getJoinRespSentReceived = sinon | ||
.stub() | ||
.returns(20); | ||
webex.internal.newMetrics.callDiagnosticLatencies.getPageJMT = sinon.stub().returns(30); | ||
@@ -199,3 +212,2 @@ webex.internal.newMetrics.callDiagnosticLatencies.getClientJMT = sinon.stub().returns(5); | ||
joinReqResp: 10, | ||
joinReqSentReceived: 20, | ||
meetingInfoReqResp: 10, | ||
@@ -366,5 +378,4 @@ pageJmt: 30, | ||
//TODO: The following two skipped tests needs investigation: https://jira-eng-gpk2.cisco.com/jira/browse/SPARK-485382 | ||
describe('when the request fails', () => { | ||
it.skip('does not clear the queue', async () => { | ||
it('does not clear the queue', async () => { | ||
// avoid setting .sent timestamp | ||
@@ -416,3 +427,3 @@ webex.internal.newMetrics.callDiagnosticMetrics.callDiagnosticEventsBatcher.prepareRequest = | ||
describe('prepareItem', () => { | ||
it.skip('calls prepareDiagnosticMetricItem correctly', async () => { | ||
it('calls prepareDiagnosticMetricItem correctly', async () => { | ||
// avoid setting .sent timestamp | ||
@@ -419,0 +430,0 @@ webex.internal.newMetrics.callDiagnosticMetrics.callDiagnosticEventsBatcher.prepareRequest = |
@@ -44,3 +44,3 @@ import {assert} from '@webex/test-helper-chai'; | ||
it('should save latency correctly', () => { | ||
it('should save latency correctly by default and overwrites', () => { | ||
assert.deepEqual(cdl.precomputedLatencies.size, 0); | ||
@@ -50,4 +50,34 @@ cdl.saveLatency('internal.client.pageJMT', 10); | ||
assert.deepEqual(cdl.precomputedLatencies.get('internal.client.pageJMT'), 10); | ||
cdl.saveLatency('internal.client.pageJMT', 20); | ||
assert.deepEqual(cdl.precomputedLatencies.size, 1); | ||
assert.deepEqual(cdl.precomputedLatencies.get('internal.client.pageJMT'), 20); | ||
}); | ||
it('should overwrite latency when accumulate is false', () => { | ||
assert.deepEqual(cdl.precomputedLatencies.size, 0); | ||
cdl.saveLatency('internal.client.pageJMT', 10, false); | ||
assert.deepEqual(cdl.precomputedLatencies.size, 1); | ||
assert.deepEqual(cdl.precomputedLatencies.get('internal.client.pageJMT'), 10); | ||
cdl.saveLatency('internal.client.pageJMT', 20, false); | ||
assert.deepEqual(cdl.precomputedLatencies.size, 1); | ||
assert.deepEqual(cdl.precomputedLatencies.get('internal.client.pageJMT'), 20); | ||
}); | ||
it('should save latency correctly when accumulate is true', () => { | ||
assert.deepEqual(cdl.precomputedLatencies.size, 0); | ||
cdl.saveLatency('internal.client.pageJMT', 10, true); | ||
assert.deepEqual(cdl.precomputedLatencies.size, 1); | ||
assert.deepEqual(cdl.precomputedLatencies.get('internal.client.pageJMT'), 10); | ||
}); | ||
it('should save latency correctly when accumulate is true and there is existing value', () => { | ||
assert.deepEqual(cdl.precomputedLatencies.size, 0); | ||
cdl.saveLatency('internal.client.pageJMT', 10); | ||
assert.deepEqual(cdl.precomputedLatencies.size, 1); | ||
assert.deepEqual(cdl.precomputedLatencies.get('internal.client.pageJMT'), 10); | ||
cdl.saveLatency('internal.client.pageJMT', 10, true); | ||
assert.deepEqual(cdl.precomputedLatencies.size, 1); | ||
assert.deepEqual(cdl.precomputedLatencies.get('internal.client.pageJMT'), 20); | ||
}); | ||
it('should save only first timestamp correctly', () => { | ||
@@ -83,4 +113,9 @@ assert.deepEqual(cdl.latencyTimestamps.size, 0); | ||
assert.deepEqual(cdl.latencyTimestamps.size, 2); | ||
cdl.saveLatency('internal.api.fetch.intelligence.models', 42); | ||
assert.deepEqual(cdl.precomputedLatencies.size, 1); | ||
cdl.clearTimestamps(); | ||
assert.deepEqual(cdl.latencyTimestamps.size, 0); | ||
assert.deepEqual(cdl.precomputedLatencies.size, 0); | ||
}); | ||
@@ -117,2 +152,123 @@ | ||
describe('measureLatency', () => { | ||
let clock; | ||
let saveLatencySpy; | ||
beforeEach(() => { | ||
clock = sinon.useFakeTimers(); | ||
saveLatencySpy = sinon.stub(cdl, 'saveLatency'); | ||
}); | ||
afterEach(() => { | ||
clock.restore(); | ||
sinon.restore(); | ||
}); | ||
it('checks measureLatency with accumulate false', async () => { | ||
const key = 'internal.client.pageJMT'; | ||
const accumulate = false; | ||
const callbackStub = sinon.stub().callsFake(() => { | ||
clock.tick(50); | ||
return Promise.resolve('test'); | ||
}); | ||
// accumulate should be false by default | ||
const promise = cdl.measureLatency(callbackStub, 'internal.client.pageJMT'); | ||
const resolvedValue = await promise; | ||
assert.deepEqual(resolvedValue, 'test'); | ||
assert.calledOnceWithExactly(callbackStub); | ||
assert.calledOnceWithExactly(saveLatencySpy, key, 50, accumulate); | ||
}); | ||
it('checks measureLatency with accumulate true', async () => { | ||
const key = 'internal.download.time'; | ||
const accumulate = true; | ||
const callbackStub = sinon.stub().callsFake(() => { | ||
clock.tick(20); | ||
return Promise.resolve('test123'); | ||
}); | ||
const promise = cdl.measureLatency(callbackStub, 'internal.download.time', accumulate); | ||
const resolvedValue = await promise; | ||
assert.deepEqual(resolvedValue, 'test123'); | ||
assert.calledOnceWithExactly(callbackStub); | ||
assert.calledOnceWithExactly(saveLatencySpy, key, 20, accumulate); | ||
}); | ||
it('checks measureLatency when callBack rejects', async () => { | ||
const key = 'internal.client.pageJMT'; | ||
const accumulate = false; | ||
const error = new Error('some error'); | ||
const callbackStub = sinon.stub().callsFake(() => { | ||
clock.tick(50); | ||
return Promise.reject(error); | ||
}); | ||
const promise = cdl.measureLatency(callbackStub, 'internal.client.pageJMT', accumulate); | ||
const rejectedValue = await assert.isRejected(promise); | ||
assert.deepEqual(rejectedValue, error); | ||
assert.calledOnceWithExactly(callbackStub); | ||
assert.calledOnceWithExactly(saveLatencySpy, key, 50, accumulate); | ||
}); | ||
}); | ||
describe('getRefreshCaptchaReqResp', () => { | ||
it('returns undefined when no precomputed value available', () => { | ||
assert.deepEqual(cdl.getRefreshCaptchaReqResp(), undefined); | ||
}); | ||
it('returns the correct value', () => { | ||
cdl.saveLatency('internal.refresh.captcha.time', 123); | ||
assert.deepEqual(cdl.getRefreshCaptchaReqResp(), 123); | ||
}); | ||
it('returns the correct whole number', () => { | ||
cdl.saveLatency('internal.refresh.captcha.time', 321.44); | ||
assert.deepEqual(cdl.getRefreshCaptchaReqResp(), 321); | ||
}); | ||
}); | ||
describe('getReachabilityClustersReqResp', () => { | ||
it('returns undefined when no precomputed value available', () => { | ||
assert.deepEqual(cdl.getReachabilityClustersReqResp(), undefined); | ||
}); | ||
it('returns the correct value', () => { | ||
cdl.saveLatency('internal.get.cluster.time', 123); | ||
assert.deepEqual(cdl.getReachabilityClustersReqResp(), 123); | ||
}); | ||
it('returns the correct whole number', () => { | ||
cdl.saveLatency('internal.get.cluster.time', 321.44); | ||
assert.deepEqual(cdl.getReachabilityClustersReqResp(), 321); | ||
}); | ||
}); | ||
describe('getExchangeCITokenJMT', () => { | ||
it('returns undefined when no precomputed value available', () => { | ||
assert.deepEqual(cdl.getExchangeCITokenJMT(), undefined); | ||
}); | ||
it('returns the correct value', () => { | ||
cdl.saveLatency('internal.exchange.ci.token.time', 123); | ||
assert.deepEqual(cdl.getExchangeCITokenJMT(), 123); | ||
}); | ||
it('returns the correct whole number', () => { | ||
cdl.saveLatency('internal.exchange.ci.token.time', 321.44); | ||
assert.deepEqual(cdl.getExchangeCITokenJMT(), 321); | ||
}); | ||
}); | ||
describe('saveTimestamp', () => { | ||
@@ -519,2 +675,20 @@ afterEach(() => { | ||
it('calculates getU2CTime correctly', () => { | ||
it('returns undefined when no precomputed value available', () => { | ||
assert.deepEqual(cdl.getU2CTime(), undefined); | ||
}); | ||
it('returns the correct value', () => { | ||
cdl.saveLatency('internal.get.u2c.time', 123); | ||
assert.deepEqual(cdl.getU2CTime(), 123); | ||
}); | ||
it('returns the correct whole number', () => { | ||
cdl.saveLatency('internal.get.u2c.time', 321.44); | ||
assert.deepEqual(cdl.getU2CTime(), 321); | ||
}); | ||
}); | ||
it('calculates getDownloadTimeJMT correctly', () => { | ||
@@ -524,3 +698,27 @@ cdl.saveLatency('internal.download.time', 1000); | ||
}); | ||
describe('getOtherAppApiReqResp', () => { | ||
it('returns undefined when no precomputed value available', () => { | ||
assert.deepEqual(cdl.getOtherAppApiReqResp(), undefined); | ||
}); | ||
it('returns undefined if it is less than 0', () => { | ||
cdl.saveLatency('internal.other.app.api.time', 0); | ||
assert.deepEqual(cdl.getOtherAppApiReqResp(), undefined); | ||
}); | ||
it('returns the correct value', () => { | ||
cdl.saveLatency('internal.other.app.api.time', 123); | ||
assert.deepEqual(cdl.getOtherAppApiReqResp(), 123); | ||
}); | ||
it('returns the correct whole number', () => { | ||
cdl.saveLatency('internal.other.app.api.time', 321.44); | ||
assert.deepEqual(cdl.getOtherAppApiReqResp(), 321); | ||
}); | ||
}); | ||
}); | ||
}); |
@@ -304,8 +304,20 @@ import {assert} from '@webex/test-helper-chai'; | ||
['client.exit.app', {}], | ||
['client.webexapp.launched', { | ||
joinTimes: { | ||
downloadTime: undefined, | ||
} | ||
}], | ||
[ | ||
'client.login.end', | ||
{ | ||
joinTimes: { | ||
otherAppApiReqResp: undefined, | ||
exchangeCITokenJMT: undefined, | ||
}, | ||
}, | ||
], | ||
[ | ||
'client.webexapp.launched', | ||
{ | ||
joinTimes: { | ||
downloadTime: undefined, | ||
}, | ||
}, | ||
], | ||
[ | ||
'client.interstitial-window.launched', | ||
@@ -316,2 +328,4 @@ { | ||
meetingInfoReqResp: undefined, | ||
refreshCaptchaServiceReqResp: undefined, | ||
downloadIntelligenceModelsReqResp: undefined, | ||
}, | ||
@@ -327,2 +341,4 @@ }, | ||
registerWDMDeviceJMT: undefined, | ||
getU2CTime: undefined, | ||
getReachabilityClustersReqResp: undefined, | ||
}, | ||
@@ -338,3 +354,2 @@ }, | ||
joinReqResp: undefined, | ||
joinReqSentReceived: undefined, | ||
pageJmt: undefined, | ||
@@ -345,3 +360,3 @@ clickToInterstitial: undefined, | ||
clientJmt: undefined, | ||
downloadTime: undefined | ||
downloadTime: undefined, | ||
}, | ||
@@ -610,2 +625,8 @@ }, | ||
signalingState: 'stable', | ||
iceConnectionState: 'disconnected', | ||
turnServerUsed: true, | ||
errorCode: DTLS_HANDSHAKE_FAILED_CLIENT_CODE, | ||
}, | ||
{ | ||
signalingState: 'stable', | ||
iceConnectionState: 'failed', | ||
@@ -612,0 +633,0 @@ turnServerUsed: true, |
@@ -107,5 +107,11 @@ /*! | ||
webex.config.metrics.appType = 'sdk'; | ||
webex.meetings = { | ||
config: { | ||
metrics: { | ||
clientVersion: '43.0.105' | ||
} | ||
} | ||
} | ||
sinon.spy(webex, 'request'); | ||
sinon.spy(metrics, 'postPreLoginMetric'); | ||
sinon.spy(metrics, 'aliasUser'); | ||
@@ -184,2 +190,3 @@ }); | ||
tags: { | ||
appVersion: '43.0.105', | ||
browser: '', | ||
@@ -204,3 +211,3 @@ domain: 'whatever', | ||
describe('before login', () => { | ||
it('posts pre-login metric', () => { | ||
it('clientMetricsPreloginBatcher pre-login metric', () => { | ||
const date = clock.now; | ||
@@ -213,4 +220,2 @@ const promise = metrics.submitClientMetrics(eventName, mockPayload, preLoginId); | ||
.then(() => { | ||
assert.called(metrics.postPreLoginMetric); | ||
assert.calledOnce(webex.credentials.getClientToken); | ||
assert.calledOnce(webex.request); | ||
@@ -303,29 +308,2 @@ const req = webex.request.args[0][0]; | ||
describe('#postPreLoginMetric()', () => { | ||
it('returns an HttpResponse object', () => { | ||
const promise = metrics.postPreLoginMetric(preLoginProps, preLoginId); | ||
return promiseTick(50) | ||
.then(() => clock.tick(config.metrics.batcherWait)) | ||
.then(() => promise) | ||
.then(() => { | ||
assert.calledOnce(webex.request); | ||
const req = webex.request.args[0][0]; | ||
const metric = req.body.metrics[0]; | ||
const {headers} = req; | ||
assert.property(headers, 'x-prelogin-userid'); | ||
assert.property(metric, 'metricName'); | ||
assert.property(metric, 'tags'); | ||
assert.property(metric, 'fields'); | ||
assert.property(metric, 'timestamp'); | ||
assert.equal(metric.timestamp, transformedProps.timestamp); | ||
assert.equal(metric.metricName, eventName); | ||
assert.equal(metric.tags.testTag, 'tag value'); | ||
assert.equal(metric.fields.testField, 123); | ||
}); | ||
}); | ||
}); | ||
describe('#aliasUser()', () => { | ||
@@ -332,0 +310,0 @@ it('returns an HttpResponse object', () => |
import {assert} from '@webex/test-helper-chai'; | ||
import {NewMetrics} from '@webex/internal-plugin-metrics'; | ||
import {NewMetrics, CallDiagnosticLatencies} from '@webex/internal-plugin-metrics'; | ||
import MockWebex from '@webex/test-helper-mock-webex'; | ||
@@ -9,20 +9,22 @@ import sinon from 'sinon'; | ||
const mockWebex = () => new MockWebex({ | ||
children: { | ||
newMetrics: NewMetrics, | ||
}, | ||
meetings: { | ||
meetingCollection: { | ||
get: sinon.stub(), | ||
}, | ||
}, | ||
request: sinon.stub().resolves({}), | ||
logger: { | ||
log: sinon.stub(), | ||
error: sinon.stub(), | ||
} | ||
}); | ||
describe('check submitClientEvent when webex is not ready', () => { | ||
let webex; | ||
//@ts-ignore | ||
webex = new MockWebex({ | ||
children: { | ||
newMetrics: NewMetrics, | ||
}, | ||
meetings: { | ||
meetingCollection: { | ||
get: sinon.stub(), | ||
}, | ||
}, | ||
request: sinon.stub().resolves({}), | ||
logger: { | ||
log: sinon.stub(), | ||
error: sinon.stub(), | ||
} | ||
}); | ||
webex = mockWebex(); | ||
@@ -42,2 +44,12 @@ it('checks the log', () => { | ||
}); | ||
describe('new-metrics contstructor', () => { | ||
it('checks callDiagnosticLatencies is defined before ready emit', () => { | ||
const webex = mockWebex(); | ||
assert.instanceOf(webex.internal.newMetrics.callDiagnosticLatencies, CallDiagnosticLatencies); | ||
}); | ||
}); | ||
describe('new-metrics', () => { | ||
@@ -48,17 +60,3 @@ let webex; | ||
//@ts-ignore | ||
webex = new MockWebex({ | ||
children: { | ||
newMetrics: NewMetrics, | ||
}, | ||
meetings: { | ||
meetingCollection: { | ||
get: sinon.stub(), | ||
}, | ||
}, | ||
request: sinon.stub().resolves({}), | ||
logger: { | ||
log: sinon.stub(), | ||
error: sinon.stub(), | ||
} | ||
}); | ||
webex = mockWebex(); | ||
@@ -65,0 +63,0 @@ webex.emit('ready'); |
@@ -77,2 +77,4 @@ /*! | ||
clickToInterstitial: undefined, | ||
refreshCaptchaServiceReqResp: undefined, | ||
downloadIntelligenceModelsReqResp: undefined, | ||
}, | ||
@@ -142,3 +144,3 @@ name: 'client.interstitial-window.launched', | ||
'Pre Login Metrics -->', | ||
`PreLoginMetricsBatcher: @submitHttpRequest#prelogin-ca-batch-${expectedBatchId}. Request failed:`, | ||
`PreLoginMetricsBatcher: @submitHttpRequest#prelogin-batch-${expectedBatchId}. Request failed:`, | ||
`error: formattedError` | ||
@@ -153,3 +155,4 @@ ); | ||
it('fails if preLoinId is not set', async () => { | ||
webex.internal.newMetrics.callDiagnosticMetrics.preLoginMetricsBatcher.preLoginId = undefined; | ||
webex.internal.newMetrics.callDiagnosticMetrics.preLoginMetricsBatcher.preLoginId = | ||
undefined; | ||
@@ -182,3 +185,3 @@ const promise = | ||
it('calls prepareDiagnosticMetricItem correctly', async () => { | ||
// avoid setting .sent timestamp | ||
// avoid setting .sent timestamp | ||
webex.internal.newMetrics.callDiagnosticMetrics.preLoginMetricsBatcher.prepareRequest = (q) => | ||
@@ -185,0 +188,0 @@ Promise.resolve(q); |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
678822
78
12618
0
+ Added@webex/common@3.1.0(transitive)
+ Added@webex/common-timers@3.1.0(transitive)
+ Added@webex/http-core@3.1.0(transitive)
+ Added@webex/internal-plugin-device@3.1.0(transitive)
+ Added@webex/plugin-logger@3.1.0(transitive)
+ Added@webex/storage-adapter-spec@3.1.0(transitive)
+ Added@webex/test-helper-chai@3.1.0(transitive)
+ Added@webex/test-helper-file@3.1.0(transitive)
+ Added@webex/test-helper-make-local-url@3.1.0(transitive)
+ Added@webex/test-helper-mocha@3.1.0(transitive)
+ Added@webex/test-helper-mock-webex@3.1.0(transitive)
+ Added@webex/test-helper-retry@3.1.0(transitive)
+ Added@webex/test-helper-test-users@3.1.0(transitive)
+ Added@webex/test-users@3.1.0(transitive)
+ Added@webex/webex-core@3.1.0(transitive)
- Removed@webex/common@3.0.0(transitive)
- Removed@webex/common-timers@3.0.0(transitive)
- Removed@webex/http-core@3.0.0(transitive)
- Removed@webex/internal-plugin-device@3.0.0(transitive)
- Removed@webex/plugin-logger@3.0.0(transitive)
- Removed@webex/storage-adapter-spec@3.0.0(transitive)
- Removed@webex/test-helper-chai@3.0.0(transitive)
- Removed@webex/test-helper-file@3.0.0(transitive)
- Removed@webex/test-helper-make-local-url@3.0.0(transitive)
- Removed@webex/test-helper-mocha@3.0.0(transitive)
- Removed@webex/test-helper-mock-webex@3.0.0(transitive)
- Removed@webex/test-helper-retry@3.0.0(transitive)
- Removed@webex/test-helper-test-users@3.0.0(transitive)
- Removed@webex/test-users@3.0.0(transitive)
- Removed@webex/webex-core@3.0.0(transitive)
Updated@webex/common@3.1.0
Updated@webex/common-timers@3.1.0
Updated@webex/webex-core@3.1.0