@webex/internal-plugin-metrics 3.12.0-next.46 → 3.12.0-next.48

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.
@@ -0,0 +1 @@
1
+ {"version":3,"names":["_commonTimers","require","_createForOfIteratorHelper","r","e","t","_Symbol","_Symbol$iterator","_Array$isArray","_unsupportedIterableToArray","length","_n","F","s","n","done","value","f","TypeError","o","a","u","call","next","return","_arrayLikeToArray","toString","slice","constructor","name","_Array$from","test","Array","ownKeys","_Object$keys","_Object$getOwnPropertySymbols","filter","_Object$getOwnPropertyDescriptor","enumerable","push","apply","_objectSpread","arguments","Object","forEach","_defineProperty2","default","_Object$getOwnPropertyDescriptors","_Object$defineProperties","_Object$defineProperty","NETWORK_REQUEST_SUMMARY_METRIC","exports","NETWORK_TELEMETRY_INTERVAL_MS","SAFE_ROUTE_SEGMENT","MAX_TRACKING_IDS","UNKNOWN","String","undefined","getService","options","service","api","trim","toLowerCase","normalizeRouteSegment","segment","getOperation","resource","path","split","segments","Boolean","map","join","getDirectRequestIdentity","uri","url","requestUrl","URL","host","endPoint","pathname","_unused","getRequestIdentity","directRequestIdentity","getNetworkDuration","_options$$timings","_options$$timings2","start","$timings","networkStart","end","networkEnd","_isFinite","recordNetworkDuration","metric","duration","totalNetworkDurationMs","networkDurationsMs","getMethod","method","toUpperCase","getStatusCode","reason","_reason$statusCode","statusCode","status","_isInteger","getWrappedError","body","_typeof2","isTimeoutSignal","signal","includes","isTimeoutFailure","_options$$timings3","_options$$timings4","wrappedError","code","message","timeout","getErrorType","getErrorCode","errorCode","getErrorMessage","shouldTrackNetworkRequest","createNetworkErrorMetric","_options$headers","identity","trackingId","headers","trackingid","errorType","errorMessage","trackingIds","countError","createEmptyNetworkTelemetry","metricsSummary","totalSendRequest","totalFailedRequest","totalRecvdResponse","totalFailedResponse","metrics","errorMetrics","errorMetricsSummary","getRequestMetric","telemetry","_iterator","_step","err","countSendRequest","countFailedRequest","countRecvdResponse","countFailedResponse","isSameError","first","second","recordError","errorMetric","_iterator2","_step2","existingMetric","getDurationPercentile","durations","percentile","sortedDurations","_toConsumableArray2","sort","rank","Math","max","ceil","serializeRequestMetric","measuredRequestCount","averageNetworkDurationMs","maxNetworkDurationP90Ms","maxNetworkDurationP99Ms","serializeNetworkTelemetry","hasNetworkTelemetry","createNetworkTelemetryCollector","_ref","intervalMs","onSubmissionFailure","submitMetric","inFlightSubmissions","_set","trackSubmission","submission","add","then","delete","recordRequest","recordResponse","requestMetric","recordFailure","statusSummary","count","submitSummary","completedTelemetry","payload","_promise","resolve","type","tags","fields","eventPayload","_unused2","telemetryIntervalMs","telemetryInterval","safeSetInterval","flush","stop","clearInterval","all"],"sources":["network-telemetry.ts"],"sourcesContent":["// TypeScript signatures own the types; JSDoc contains descriptions only.\n/* eslint valid-jsdoc: [\"error\", {\"requireParamType\": false, \"requireReturnType\": false}] */\n\nimport {safeSetInterval} from '@webex/common-timers';\n\nexport const NETWORK_REQUEST_SUMMARY_METRIC = 'JS_SDK_NETWORK_REQUEST_SUMMARY';\nexport const NETWORK_TELEMETRY_INTERVAL_MS = 10 * 60 * 1_000;\n\n// Only segments that follow the SDK's static route naming convention are kept.\n// Numeric, mixed-case, encoded, and otherwise dynamic-looking values are redacted.\n// Lowercase alphabetic identifiers remain ambiguous because requests do not provide route templates.\n// Examples: `rooms/12345/messages` becomes `rooms/:id/messages`, and\n// `v1/rooms/65f81b6e-19dc-4a99-9175-59e9b34a5d42` becomes `v1/rooms/:id`.\n// `reports/a%2Fb/download` becomes `reports/:id/download`; `rooms`, `meeting-info`, and `v1` stay unchanged.\nconst SAFE_ROUTE_SEGMENT = /^(?:[a-z]+(?:-[a-z]+)*|v[1-9]\\d?)$/;\nconst MAX_TRACKING_IDS = 10;\nconst UNKNOWN = 'unknown';\n\ntype Headers = Record<string, unknown>;\n\ntype MetricsSummary = {\n totalSendRequest: number;\n totalFailedRequest: number;\n totalRecvdResponse: number;\n totalFailedResponse: number;\n};\n\ntype RequestMetric = {\n host: string;\n endPoint: string;\n countSendRequest: number;\n countFailedRequest: number;\n countRecvdResponse: number;\n countFailedResponse: number;\n averageNetworkDurationMs: number;\n maxNetworkDurationP90Ms: number;\n maxNetworkDurationP99Ms: number;\n};\n\ntype RequestIdentity = Pick<RequestMetric, 'host' | 'endPoint'>;\n\nexport type NetworkErrorMetric = {\n host: string;\n endPoint: string;\n statusCode: number;\n errorCode: string;\n method: string;\n errorType: string;\n errorMessage: string;\n trackingIds: string[];\n countError: number;\n};\n\nexport type NetworkTelemetry = {\n metricsSummary: MetricsSummary;\n metrics: RequestMetric[];\n errorMetrics: NetworkErrorMetric[];\n errorMetricsSummary: Record<string, {count: number}>;\n};\n\ntype RequestMetricState = Omit<\n RequestMetric,\n 'averageNetworkDurationMs' | 'maxNetworkDurationP90Ms' | 'maxNetworkDurationP99Ms'\n> & {\n totalNetworkDurationMs: number;\n networkDurationsMs: number[];\n};\n\ntype NetworkTelemetryState = Omit<NetworkTelemetry, 'metrics'> & {\n metrics: RequestMetricState[];\n};\n\ntype ErrorDetails = {\n code?: number | string;\n errorCode?: number | string;\n message?: string;\n name?: string;\n};\n\n// Request events come from JavaScript in webex-core and have no shared TypeScript\n// contract. This local type intentionally contains only fields used by telemetry.\ntype RequestOptions = {\n api?: string;\n headers?: Headers;\n method?: string;\n resource?: string;\n service?: string;\n timeout?: number;\n uri?: string;\n url?: string;\n // The network timing interceptor adds internal fields with a `$` prefix.\n $timings?: {\n networkEnd?: number;\n networkStart?: number;\n };\n};\n\ntype RequestFailure = ErrorDetails & {\n body?: ErrorDetails | string;\n status?: number;\n statusCode?: number;\n};\n\ntype NetworkMetricProperties = {\n type: 'operational';\n tags: Record<string, string>;\n fields: MetricsSummary;\n eventPayload: NetworkTelemetry;\n};\n\ntype NetworkTelemetryCollectorOptions = {\n intervalMs?: number;\n onSubmissionFailure: () => void;\n submitMetric: (name: string, properties: NetworkMetricProperties) => unknown;\n};\n\ntype NetworkTelemetryCollector = {\n recordRequest: (options?: RequestOptions) => void;\n recordResponse: (options?: RequestOptions) => void;\n recordFailure: (options?: RequestOptions, reason?: RequestFailure) => void;\n flush: () => Promise<void>;\n stop: () => Promise<void>;\n};\n\n/**\n * Converts a non-empty string or number to a string.\n * @param value Value to convert.\n * @returns The converted string, or undefined for unsupported values.\n */\nfunction toString(value: unknown): string | undefined {\n if (typeof value === 'number') {\n return String(value);\n }\n\n return typeof value === 'string' && value.length > 0 ? value : undefined;\n}\n\n/**\n * Returns the normalized SDK service name.\n * @param options Request options containing the service or API name.\n * @returns The normalized service name.\n */\nfunction getService(options: RequestOptions): string {\n const service = options.service || options.api;\n\n return typeof service === 'string' ? service.trim().toLowerCase() : '';\n}\n\n/**\n * Replaces values that may be resource identifiers with a stable placeholder.\n * @param segment Endpoint path segment.\n * @returns The original static segment or the identifier placeholder.\n */\nfunction normalizeRouteSegment(segment: string): string {\n return SAFE_ROUTE_SEGMENT.test(segment) ? segment : ':id';\n}\n\n/**\n * Removes query data and redacts dynamic-looking endpoint segments.\n * @param resource SDK resource path.\n * @returns The normalized endpoint.\n */\nexport function getOperation(resource?: string): string {\n if (typeof resource !== 'string' || resource.length === 0) {\n return UNKNOWN;\n }\n\n const path = resource.split(/[?#]/, 1)[0];\n const segments = path.split('/').filter(Boolean).map(normalizeRouteSegment);\n\n return segments.length > 0 ? segments.join('/') : 'root';\n}\n\n/**\n * Extracts only the direct URL parts allowed in telemetry. URL credentials,\n * query parameters, and fragments are not returned, while the pathname is\n * converted to a sanitized endpoint.\n * @param options Request options containing a direct URL.\n * @returns The sanitized request identity, or undefined without a valid URL.\n */\nfunction getDirectRequestIdentity(options: RequestOptions): RequestIdentity | undefined {\n const value = options.uri || options.url;\n\n if (typeof value !== 'string') {\n return undefined;\n }\n\n try {\n const requestUrl = new URL(value);\n\n return {\n host: requestUrl.host.toLowerCase() || UNKNOWN,\n endPoint: getOperation(requestUrl.pathname),\n };\n } catch {\n return undefined;\n }\n}\n\n/**\n * Uses the logical service as the host because request:start may run before the\n * service interceptor resolves a physical URL. Direct-URL requests use URL.host.\n * @param options Request options used to resolve the identity.\n * @returns The request host and endpoint.\n */\nfunction getRequestIdentity(options: RequestOptions): RequestIdentity {\n const directRequestIdentity = getDirectRequestIdentity(options);\n const service = getService(options);\n\n return {\n host: service || directRequestIdentity?.host || UNKNOWN,\n endPoint: options.resource\n ? getOperation(options.resource)\n : directRequestIdentity?.endPoint || UNKNOWN,\n };\n}\n\n/**\n * Returns the measured network duration when both timing points are valid.\n * @param options Request options containing network timing metadata.\n * @returns The duration in milliseconds, or undefined when timing is unavailable.\n */\nfunction getNetworkDuration(options: RequestOptions): number | undefined {\n const start = options.$timings?.networkStart;\n const end = options.$timings?.networkEnd;\n\n return typeof start === 'number' &&\n Number.isFinite(start) &&\n typeof end === 'number' &&\n Number.isFinite(end) &&\n end >= start\n ? end - start\n : undefined;\n}\n\n/**\n * Adds a completed request's network duration to its endpoint aggregate.\n * @param metric Endpoint aggregate to update.\n * @param options Request options containing network timing metadata.\n * @returns Nothing.\n */\nfunction recordNetworkDuration(metric: RequestMetricState, options: RequestOptions): void {\n const duration = getNetworkDuration(options);\n\n if (duration === undefined) {\n return;\n }\n\n metric.totalNetworkDurationMs += duration;\n metric.networkDurationsMs.push(duration);\n}\n\n/**\n * Returns a normalized uppercase HTTP method.\n * @param method HTTP method from the request options.\n * @returns The normalized method.\n */\nfunction getMethod(method?: string): string {\n return typeof method === 'string' && method.length > 0 ? method.toUpperCase() : 'UNKNOWN';\n}\n\n/**\n * Status zero represents a failure for which no valid HTTP response was received.\n * @param reason Request failure.\n * @returns A valid HTTP status code, or zero when no response was received.\n */\nfunction getStatusCode(reason: RequestFailure): number {\n const statusCode = reason.statusCode ?? reason.status;\n\n return typeof statusCode === 'number' &&\n Number.isInteger(statusCode) &&\n statusCode >= 100 &&\n statusCode <= 599\n ? statusCode\n : 0;\n}\n\n/**\n * Returns an error nested in a Webex HTTP error body.\n * @param reason Request failure.\n * @returns The wrapped error, when present.\n */\nfunction getWrappedError(reason: RequestFailure): ErrorDetails | undefined {\n return reason.body && typeof reason.body === 'object' ? reason.body : undefined;\n}\n\n/**\n * Checks the timeout forms emitted by browser and Node transports.\n * @param value Possible timeout signal.\n * @returns Whether the value represents a timeout.\n */\nfunction isTimeoutSignal(value: unknown): boolean {\n if (typeof value !== 'string') {\n return false;\n }\n\n const signal = value.toLowerCase();\n\n return signal.includes('timeout') || signal === 'etimedout' || signal === 'esockettimedout';\n}\n\n/**\n * Detects direct errors, transport errors wrapped in body, and requests whose\n * measured network duration reached the configured timeout.\n * @param reason Request failure.\n * @param options Request options containing timeout metadata.\n * @returns Whether the request timed out.\n */\nfunction isTimeoutFailure(reason: RequestFailure, options: RequestOptions): boolean {\n const wrappedError = getWrappedError(reason);\n\n if (\n isTimeoutSignal(reason.name) ||\n isTimeoutSignal(reason.code) ||\n isTimeoutSignal(reason.message) ||\n isTimeoutSignal(reason.body) ||\n isTimeoutSignal(wrappedError?.name) ||\n isTimeoutSignal(wrappedError?.code) ||\n isTimeoutSignal(wrappedError?.message)\n ) {\n return true;\n }\n\n const start = options.$timings?.networkStart;\n const end = options.$timings?.networkEnd;\n\n return (\n typeof options.timeout === 'number' &&\n options.timeout > 0 &&\n typeof start === 'number' &&\n typeof end === 'number' &&\n end >= start &&\n end - start >= options.timeout\n );\n}\n\n/**\n * Converts errors into a bounded set of categories for aggregation.\n * @param reason Request failure.\n * @param options Request options.\n * @param statusCode Normalized status code.\n * @returns The aggregate error category.\n */\nfunction getErrorType(reason: RequestFailure, options: RequestOptions, statusCode: number): string {\n const name = typeof reason.name === 'string' ? reason.name.toLowerCase() : '';\n\n if (name === 'aborterror') {\n return 'aborted';\n }\n\n if (statusCode === 408 || statusCode === 504 || isTimeoutFailure(reason, options)) {\n return 'timeout';\n }\n\n if (statusCode === 429) {\n return 'rate_limited';\n }\n\n if (statusCode >= 500) {\n return 'server_error';\n }\n\n if (statusCode >= 400) {\n return 'client_error';\n }\n\n return statusCode === 0 || name?.includes('network') ? 'network_error' : 'request_error';\n}\n\n/**\n * Returns the most specific available error code.\n * @param reason Request failure.\n * @returns The error code or the unknown fallback.\n */\nfunction getErrorCode(reason: RequestFailure): string {\n const wrappedError = getWrappedError(reason);\n\n return (\n toString(wrappedError?.errorCode) ||\n toString(wrappedError?.code) ||\n toString(reason.errorCode) ||\n toString(reason.code) ||\n UNKNOWN\n );\n}\n\n/**\n * Returns the most specific available error message.\n * @param reason Request failure.\n * @returns The error message or the unknown fallback.\n */\nfunction getErrorMessage(reason: RequestFailure): string {\n const wrappedError = getWrappedError(reason);\n\n return (\n toString(wrappedError?.message) || toString(reason.body) || toString(reason.message) || UNKNOWN\n );\n}\n\n/**\n * Excludes the transports used to submit telemetry, preventing self-reporting.\n * @param options Request options.\n * @returns Whether the request should be tracked.\n */\nexport function shouldTrackNetworkRequest(options: RequestOptions = {}): boolean {\n const service = getService(options);\n\n return service !== 'metrics' && service !== 'unifiedtelemetry';\n}\n\n/**\n * Creates the error entry produced by one failed request.\n * @param options Request options.\n * @param reason Request failure.\n * @returns The normalized error metric.\n */\nexport function createNetworkErrorMetric(\n options: RequestOptions = {},\n reason: RequestFailure = {}\n): NetworkErrorMetric {\n const identity = getRequestIdentity(options);\n const statusCode = getStatusCode(reason);\n // WebexTrackingIdInterceptor stores the request ID under this lowercase key.\n const trackingId = toString(options.headers?.trackingid);\n\n return {\n ...identity,\n statusCode,\n errorCode: getErrorCode(reason),\n method: getMethod(options.method),\n errorType: getErrorType(reason, options, statusCode),\n errorMessage: getErrorMessage(reason),\n trackingIds: trackingId ? [trackingId] : [],\n countError: 1,\n };\n}\n\n/**\n * Creates an empty ten-minute telemetry window.\n * @returns An empty telemetry aggregate.\n */\nfunction createEmptyNetworkTelemetry(): NetworkTelemetryState {\n return {\n metricsSummary: {\n totalSendRequest: 0,\n totalFailedRequest: 0,\n totalRecvdResponse: 0,\n totalFailedResponse: 0,\n },\n metrics: [],\n errorMetrics: [],\n errorMetricsSummary: {},\n };\n}\n\n/**\n * Finds or creates the request counters for one host and endpoint.\n * @param telemetry Current telemetry aggregate.\n * @param options Request options.\n * @returns The matching endpoint counters.\n */\nfunction getRequestMetric(\n telemetry: NetworkTelemetryState,\n options: RequestOptions\n): RequestMetricState {\n const identity = getRequestIdentity(options);\n\n for (const metric of telemetry.metrics) {\n if (metric.host === identity.host && metric.endPoint === identity.endPoint) {\n return metric;\n }\n }\n\n const metric = {\n ...identity,\n countSendRequest: 0,\n countFailedRequest: 0,\n countRecvdResponse: 0,\n countFailedResponse: 0,\n totalNetworkDurationMs: 0,\n networkDurationsMs: [],\n };\n\n telemetry.metrics.push(metric);\n\n return metric;\n}\n\n/**\n * Error entries aggregate only when every identifying field matches.\n * @param first First error metric.\n * @param second Second error metric.\n * @returns Whether both errors belong to the same aggregate.\n */\nfunction isSameError(first: NetworkErrorMetric, second: NetworkErrorMetric): boolean {\n return (\n first.host === second.host &&\n first.endPoint === second.endPoint &&\n first.statusCode === second.statusCode &&\n first.errorCode === second.errorCode &&\n first.method === second.method &&\n first.errorType === second.errorType &&\n first.errorMessage === second.errorMessage\n );\n}\n\n/**\n * Adds a failure to its error aggregate and retains at most ten unique IDs.\n * @param telemetry Current telemetry aggregate.\n * @param errorMetric Error metric to record.\n * @returns Nothing.\n */\nfunction recordError(telemetry: NetworkTelemetryState, errorMetric: NetworkErrorMetric): void {\n for (const existingMetric of telemetry.errorMetrics) {\n if (isSameError(existingMetric, errorMetric)) {\n existingMetric.countError += 1;\n\n const trackingId = errorMetric.trackingIds[0];\n\n if (\n trackingId &&\n existingMetric.trackingIds.length < MAX_TRACKING_IDS &&\n !existingMetric.trackingIds.includes(trackingId)\n ) {\n existingMetric.trackingIds.push(trackingId);\n }\n\n return;\n }\n }\n\n telemetry.errorMetrics.push(errorMetric);\n}\n\n/**\n * Returns a nearest-rank percentile from the measured durations.\n * @param durations Measured network durations in milliseconds.\n * @param percentile Percentile to calculate, between zero and one.\n * @returns The percentile duration, or zero when no durations were measured.\n */\nfunction getDurationPercentile(durations: number[], percentile: number): number {\n if (durations.length === 0) {\n return 0;\n }\n\n const sortedDurations = [...durations].sort((first, second) => first - second);\n const rank = Math.max(1, Math.ceil(sortedDurations.length * percentile));\n\n return sortedDurations[rank - 1];\n}\n\n/**\n * Converts internal duration samples into the public endpoint metric shape.\n * @param metric Internal endpoint aggregate.\n * @returns Endpoint aggregate with average and p90 duration statistics.\n */\nfunction serializeRequestMetric(metric: RequestMetricState): RequestMetric {\n const measuredRequestCount = metric.networkDurationsMs.length;\n\n return {\n host: metric.host,\n endPoint: metric.endPoint,\n countSendRequest: metric.countSendRequest,\n countFailedRequest: metric.countFailedRequest,\n countRecvdResponse: metric.countRecvdResponse,\n countFailedResponse: metric.countFailedResponse,\n averageNetworkDurationMs:\n measuredRequestCount > 0 ? metric.totalNetworkDurationMs / measuredRequestCount : 0,\n maxNetworkDurationP90Ms: getDurationPercentile(metric.networkDurationsMs, 0.9),\n maxNetworkDurationP99Ms: getDurationPercentile(metric.networkDurationsMs, 0.99),\n };\n}\n\n/**\n * Converts the internal telemetry state into the submitted payload shape.\n * @param telemetry Internal telemetry aggregate.\n * @returns Telemetry payload with no internal duration samples.\n */\nfunction serializeNetworkTelemetry(telemetry: NetworkTelemetryState): NetworkTelemetry {\n return {\n metricsSummary: telemetry.metricsSummary,\n metrics: telemetry.metrics.map(serializeRequestMetric),\n errorMetrics: telemetry.errorMetrics,\n errorMetricsSummary: telemetry.errorMetricsSummary,\n };\n}\n\n/**\n * Checks whether the current window contains anything worth flushing.\n * @param telemetry Current telemetry aggregate.\n * @returns Whether the aggregate contains request data.\n */\nfunction hasNetworkTelemetry(telemetry: NetworkTelemetryState): boolean {\n return telemetry.metrics.length > 0 || telemetry.errorMetrics.length > 0;\n}\n\n/**\n * Creates a network telemetry collector and starts its periodic timer.\n * @param options Submission callbacks.\n * @returns The network telemetry collector.\n */\nexport function createNetworkTelemetryCollector({\n intervalMs,\n onSubmissionFailure,\n submitMetric,\n}: NetworkTelemetryCollectorOptions): NetworkTelemetryCollector {\n let telemetry = createEmptyNetworkTelemetry();\n const inFlightSubmissions = new Set<Promise<void>>();\n\n /**\n * Tracks a submission until it settles so shutdown can wait for requests\n * whose telemetry window has already been reset.\n * @param submission Submission promise.\n * @returns The tracked submission promise.\n */\n function trackSubmission(submission: Promise<void>): Promise<void> {\n inFlightSubmissions.add(submission);\n submission.then(\n () => inFlightSubmissions.delete(submission),\n () => inFlightSubmissions.delete(submission)\n );\n\n return submission;\n }\n\n /**\n * Records a request being sent.\n * @param options Request options.\n * @returns Nothing.\n */\n function recordRequest(options: RequestOptions = {}): void {\n if (!shouldTrackNetworkRequest(options)) {\n return;\n }\n\n telemetry.metricsSummary.totalSendRequest += 1;\n getRequestMetric(telemetry, options).countSendRequest += 1;\n }\n\n /**\n * Records a successful response.\n * @param options Request options.\n * @returns Nothing.\n */\n function recordResponse(options: RequestOptions = {}): void {\n if (!shouldTrackNetworkRequest(options)) {\n return;\n }\n\n telemetry.metricsSummary.totalRecvdResponse += 1;\n const requestMetric = getRequestMetric(telemetry, options);\n requestMetric.countRecvdResponse += 1;\n recordNetworkDuration(requestMetric, options);\n }\n\n /**\n * A real HTTP status is a failed response. Status zero means the request\n * failed before the SDK received a valid HTTP response.\n * @param options Request options.\n * @param reason Request failure.\n * @returns Nothing.\n */\n function recordFailure(options: RequestOptions = {}, reason: RequestFailure = {}): void {\n if (!shouldTrackNetworkRequest(options)) {\n return;\n }\n\n const errorMetric = createNetworkErrorMetric(options, reason);\n const requestMetric = getRequestMetric(telemetry, options);\n recordNetworkDuration(requestMetric, options);\n\n if (errorMetric.statusCode === 0) {\n telemetry.metricsSummary.totalFailedRequest += 1;\n requestMetric.countFailedRequest += 1;\n } else {\n telemetry.metricsSummary.totalRecvdResponse += 1;\n telemetry.metricsSummary.totalFailedResponse += 1;\n requestMetric.countRecvdResponse += 1;\n requestMetric.countFailedResponse += 1;\n }\n\n recordError(telemetry, errorMetric);\n\n const statusCode = String(errorMetric.statusCode);\n const statusSummary = telemetry.errorMetricsSummary[statusCode];\n\n if (statusSummary) {\n statusSummary.count += 1;\n } else {\n telemetry.errorMetricsSummary[statusCode] = {count: 1};\n }\n }\n\n /**\n * Submits the completed window and starts collecting the next one.\n * @returns A promise that settles after submission succeeds or is reported as failed.\n */\n function submitSummary(): Promise<void> {\n const completedTelemetry = telemetry;\n const payload = serializeNetworkTelemetry(completedTelemetry);\n\n // Reset before submission so requests emitted by the telemetry transport,\n // or while it is pending, cannot mutate the completed window.\n telemetry = createEmptyNetworkTelemetry();\n\n try {\n const submission = Promise.resolve(\n submitMetric(NETWORK_REQUEST_SUMMARY_METRIC, {\n type: 'operational',\n tags: {},\n fields: completedTelemetry.metricsSummary,\n eventPayload: payload,\n })\n ).then(\n () => undefined,\n () => {\n onSubmissionFailure();\n }\n );\n\n return trackSubmission(submission);\n } catch {\n // submitMetric may throw before returning a promise.\n onSubmissionFailure();\n\n return Promise.resolve();\n }\n }\n\n const telemetryIntervalMs =\n typeof intervalMs === 'number' && Number.isFinite(intervalMs) && intervalMs > 0\n ? intervalMs\n : NETWORK_TELEMETRY_INTERVAL_MS;\n const telemetryInterval = safeSetInterval(submitSummary, telemetryIntervalMs);\n\n /**\n * Submits the current non-empty window immediately.\n * @returns A promise that settles after submission succeeds or is reported as failed.\n */\n function flush(): Promise<void> {\n return hasNetworkTelemetry(telemetry) ? submitSummary() : Promise.resolve();\n }\n\n /**\n * Stops periodic submission and releases data from the current window.\n * @returns A promise that settles after the final window is submitted or failure is reported.\n */\n function stop(): Promise<void> {\n clearInterval(telemetryInterval);\n\n flush();\n\n return Promise.all(inFlightSubmissions).then(() => undefined);\n }\n\n return {recordRequest, recordResponse, recordFailure, flush, stop};\n}\n"],"mappings":"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","ignoreList":[]}
@@ -11,6 +11,11 @@ declare namespace _default {
11
11
  namespace unhandledExceptionTelemetry {
12
12
  const enabled: boolean;
13
13
  }
14
+ namespace networkTelemetry {
15
+ const enabled_1: boolean;
16
+ export { enabled_1 as enabled };
17
+ export const intervalMs: number;
18
+ }
14
19
  const batcherWait: number;
15
20
  const batcherMaxCalls: number;
16
21
  const batcherMaxWait: number;
@@ -0,0 +1,108 @@
1
+ export declare const NETWORK_REQUEST_SUMMARY_METRIC = "JS_SDK_NETWORK_REQUEST_SUMMARY";
2
+ export declare const NETWORK_TELEMETRY_INTERVAL_MS: number;
3
+ type Headers = Record<string, unknown>;
4
+ type MetricsSummary = {
5
+ totalSendRequest: number;
6
+ totalFailedRequest: number;
7
+ totalRecvdResponse: number;
8
+ totalFailedResponse: number;
9
+ };
10
+ type RequestMetric = {
11
+ host: string;
12
+ endPoint: string;
13
+ countSendRequest: number;
14
+ countFailedRequest: number;
15
+ countRecvdResponse: number;
16
+ countFailedResponse: number;
17
+ averageNetworkDurationMs: number;
18
+ maxNetworkDurationP90Ms: number;
19
+ maxNetworkDurationP99Ms: number;
20
+ };
21
+ export type NetworkErrorMetric = {
22
+ host: string;
23
+ endPoint: string;
24
+ statusCode: number;
25
+ errorCode: string;
26
+ method: string;
27
+ errorType: string;
28
+ errorMessage: string;
29
+ trackingIds: string[];
30
+ countError: number;
31
+ };
32
+ export type NetworkTelemetry = {
33
+ metricsSummary: MetricsSummary;
34
+ metrics: RequestMetric[];
35
+ errorMetrics: NetworkErrorMetric[];
36
+ errorMetricsSummary: Record<string, {
37
+ count: number;
38
+ }>;
39
+ };
40
+ type ErrorDetails = {
41
+ code?: number | string;
42
+ errorCode?: number | string;
43
+ message?: string;
44
+ name?: string;
45
+ };
46
+ type RequestOptions = {
47
+ api?: string;
48
+ headers?: Headers;
49
+ method?: string;
50
+ resource?: string;
51
+ service?: string;
52
+ timeout?: number;
53
+ uri?: string;
54
+ url?: string;
55
+ $timings?: {
56
+ networkEnd?: number;
57
+ networkStart?: number;
58
+ };
59
+ };
60
+ type RequestFailure = ErrorDetails & {
61
+ body?: ErrorDetails | string;
62
+ status?: number;
63
+ statusCode?: number;
64
+ };
65
+ type NetworkMetricProperties = {
66
+ type: 'operational';
67
+ tags: Record<string, string>;
68
+ fields: MetricsSummary;
69
+ eventPayload: NetworkTelemetry;
70
+ };
71
+ type NetworkTelemetryCollectorOptions = {
72
+ intervalMs?: number;
73
+ onSubmissionFailure: () => void;
74
+ submitMetric: (name: string, properties: NetworkMetricProperties) => unknown;
75
+ };
76
+ type NetworkTelemetryCollector = {
77
+ recordRequest: (options?: RequestOptions) => void;
78
+ recordResponse: (options?: RequestOptions) => void;
79
+ recordFailure: (options?: RequestOptions, reason?: RequestFailure) => void;
80
+ flush: () => Promise<void>;
81
+ stop: () => Promise<void>;
82
+ };
83
+ /**
84
+ * Removes query data and redacts dynamic-looking endpoint segments.
85
+ * @param resource SDK resource path.
86
+ * @returns The normalized endpoint.
87
+ */
88
+ export declare function getOperation(resource?: string): string;
89
+ /**
90
+ * Excludes the transports used to submit telemetry, preventing self-reporting.
91
+ * @param options Request options.
92
+ * @returns Whether the request should be tracked.
93
+ */
94
+ export declare function shouldTrackNetworkRequest(options?: RequestOptions): boolean;
95
+ /**
96
+ * Creates the error entry produced by one failed request.
97
+ * @param options Request options.
98
+ * @param reason Request failure.
99
+ * @returns The normalized error metric.
100
+ */
101
+ export declare function createNetworkErrorMetric(options?: RequestOptions, reason?: RequestFailure): NetworkErrorMetric;
102
+ /**
103
+ * Creates a network telemetry collector and starts its periodic timer.
104
+ * @param options Submission callbacks.
105
+ * @returns The network telemetry collector.
106
+ */
107
+ export declare function createNetworkTelemetryCollector({ intervalMs, onSubmissionFailure, submitMetric, }: NetworkTelemetryCollectorOptions): NetworkTelemetryCollector;
108
+ export {};
package/package.json CHANGED
@@ -40,7 +40,7 @@
40
40
  "@webex/event-dictionary-ts": "^1.0.2220",
41
41
  "@webex/test-helper-chai": "3.12.0-next.6",
42
42
  "@webex/test-helper-mock-webex": "3.12.0-next.6",
43
- "@webex/webex-core": "3.12.0-next.46",
43
+ "@webex/webex-core": "3.12.0-next.48",
44
44
  "ip-anonymize": "^0.1.0",
45
45
  "isbot": "5.2.1",
46
46
  "lodash": "^4.17.21",
@@ -54,5 +54,5 @@
54
54
  "test:style": "eslint ./src/**/*.*",
55
55
  "test:unit": "webex-legacy-tools test --unit --runner mocha"
56
56
  },
57
- "version": "3.12.0-next.46"
57
+ "version": "3.12.0-next.48"
58
58
  }
package/src/config.js CHANGED
@@ -18,6 +18,10 @@ export default {
18
18
  unhandledExceptionTelemetry: {
19
19
  enabled: false,
20
20
  },
21
+ networkTelemetry: {
22
+ enabled: false,
23
+ intervalMs: 10 * 60 * 1_000,
24
+ },
21
25
  batcherWait: 500,
22
26
  batcherMaxCalls: 50,
23
27
  batcherMaxWait: 1500,
package/src/index.ts CHANGED
@@ -2,6 +2,8 @@
2
2
  * Copyright (c) 2015-2020 Cisco Systems, Inc. See LICENSE file.
3
3
  */
4
4
 
5
+ /* eslint-disable valid-jsdoc */
6
+
5
7
  import {registerInternalPlugin} from '@webex/webex-core';
6
8
 
7
9
  import Metrics from './metrics';
@@ -35,6 +37,13 @@ import PreLoginMetrics from './prelogin-metrics';
35
37
 
36
38
  registerInternalPlugin('metrics', Metrics, {
37
39
  config,
40
+ /**
41
+ * Stops network telemetry before SDK logout.
42
+ * @returns
43
+ */
44
+ onBeforeLogout() {
45
+ return this.stopNetworkTelemetry();
46
+ },
38
47
  });
39
48
 
40
49
  registerInternalPlugin('newMetrics', NewMetrics, {
package/src/metrics.js CHANGED
@@ -1,4 +1,5 @@
1
1
  /* eslint-disable default-param-last */
2
+ /* eslint-disable valid-jsdoc */
2
3
 
3
4
  /*!
4
5
  * Copyright (c) 2015-2020 Cisco Systems, Inc. See LICENSE file.
@@ -11,6 +12,7 @@ import {OS_NAME, OSMap, CLIENT_NAME} from './config';
11
12
  import Batcher from './batcher';
12
13
  import ClientMetricsBatcher from './client-metrics-batcher';
13
14
  import ClientMetricsPreloginBatcher from './client-metrics-prelogin-batcher';
15
+ import {createNetworkTelemetryCollector} from './network-telemetry';
14
16
 
15
17
  const {getOSName, getOSVersion, getBrowserName, getBrowserVersion} = BrowserDetection();
16
18
 
@@ -43,6 +45,119 @@ const Metrics = WebexPlugin.extend({
43
45
 
44
46
  namespace: 'Metrics',
45
47
 
48
+ /**
49
+ * Registers SDK request outcome monitoring.
50
+ * @param args
51
+ * @returns
52
+ */
53
+ initialize(...args) {
54
+ WebexPlugin.prototype.initialize.call(this, ...args);
55
+
56
+ // Metrics may also be constructed as a standalone plugin. Request events are
57
+ // available only when it is attached to a Webex instance.
58
+ if (!this.parent && !this.collection) {
59
+ return;
60
+ }
61
+
62
+ const initializeNetworkTelemetry = () => {
63
+ if (
64
+ this.networkTelemetry ||
65
+ this.webex?.config?.metrics?.networkTelemetry?.enabled !== true
66
+ ) {
67
+ return;
68
+ }
69
+
70
+ this.networkTelemetry = createNetworkTelemetryCollector({
71
+ intervalMs: this.webex.config.metrics.networkTelemetry.intervalMs,
72
+ submitMetric: this.submitNetworkTelemetryMetric.bind(this),
73
+ onSubmissionFailure: this.handleNetworkTelemetrySubmissionFailure.bind(this),
74
+ });
75
+ this.listenTo(this.webex, 'request:start', this.recordNetworkRequestStart);
76
+ this.listenTo(this.webex, 'request:success', this.recordNetworkRequestSuccess);
77
+ this.listenTo(this.webex, 'request:failure', this.recordNetworkRequestFailure);
78
+ };
79
+
80
+ // Ampersand initializes children before WebexCore.initialize() populates
81
+ // webex.config. Run immediately for already-configured hosts (including
82
+ // MockWebex), and listen for the real core's post-initialization notification.
83
+ this.listenToOnce(this.webex, 'change:config', initializeNetworkTelemetry);
84
+ initializeNetworkTelemetry();
85
+ },
86
+
87
+ /**
88
+ * Records an SDK request being sent in the current reporting window.
89
+ * @param options
90
+ * @returns
91
+ */
92
+ recordNetworkRequestStart(options) {
93
+ this.networkTelemetry.recordRequest(options);
94
+ },
95
+
96
+ /**
97
+ * Records a successful SDK request for the current reporting window.
98
+ * @param options
99
+ * @returns
100
+ */
101
+ recordNetworkRequestSuccess(options) {
102
+ this.networkTelemetry.recordResponse(options);
103
+ },
104
+
105
+ /**
106
+ * Records a failed SDK request for the current reporting window.
107
+ * @param options
108
+ * @param reason
109
+ * @returns
110
+ */
111
+ recordNetworkRequestFailure(options, reason) {
112
+ this.networkTelemetry.recordFailure(options, reason);
113
+ },
114
+
115
+ /**
116
+ * Submits the current network telemetry window immediately.
117
+ * @returns
118
+ */
119
+ flushNetworkTelemetry() {
120
+ if (!this.networkTelemetry) {
121
+ return Promise.resolve();
122
+ }
123
+
124
+ return this.networkTelemetry.flush();
125
+ },
126
+
127
+ /**
128
+ * Submits a completed network telemetry window through client metrics.
129
+ * @param name
130
+ * @param properties
131
+ * @returns
132
+ */
133
+ submitNetworkTelemetryMetric(name, properties) {
134
+ return this.submitClientMetrics(name, properties);
135
+ },
136
+
137
+ /**
138
+ * Logs a network telemetry submission failure without affecting SDK requests.
139
+ * @returns
140
+ */
141
+ handleNetworkTelemetrySubmissionFailure() {
142
+ this.webex.logger?.warn('metrics: failed to submit network request summary telemetry');
143
+ },
144
+
145
+ /**
146
+ * Stops network telemetry collection and submission.
147
+ * @returns
148
+ */
149
+ stopNetworkTelemetry() {
150
+ if (!this.networkTelemetry) {
151
+ return Promise.resolve();
152
+ }
153
+
154
+ this.stopListening(this.webex, 'request:start', this.recordNetworkRequestStart);
155
+ this.stopListening(this.webex, 'request:success', this.recordNetworkRequestSuccess);
156
+ this.stopListening(this.webex, 'request:failure', this.recordNetworkRequestFailure);
157
+
158
+ return this.networkTelemetry.stop();
159
+ },
160
+
46
161
  submit(key, value) {
47
162
  return this.batcher.request({key, ...value});
48
163
  },
@@ -60,17 +175,20 @@ const Metrics = WebexPlugin.extend({
60
175
  const payload = {metricName: eventName};
61
176
  // @ts-ignore
62
177
  const providedClientVersion = this.webex.meetings?.config?.metrics?.clientVersion;
178
+ const {appName, appVersion} = this.webex.config;
179
+ // Browser location is unavailable when the SDK runs in Node.js.
180
+ // eslint-disable-next-line no-undef
181
+ const browserLocation = typeof window !== 'undefined' ? window.location : undefined;
63
182
 
64
183
  payload.tags = {
65
184
  ...props.tags,
185
+ app_name: appName ?? 'unknown',
186
+ app_url: browserLocation?.origin || browserLocation?.hostname || 'non-browser',
187
+ app_version: appVersion ?? 'unknown',
66
188
  browser: getBrowserName(),
67
189
  os: getOSNameInternal(),
68
190
  appVersion: providedClientVersion,
69
-
70
- // Node does not like this so we need to check if it exists or not
71
- // eslint-disable-next-line no-undef
72
- domain:
73
- typeof window !== 'undefined' ? window.location.hostname || 'non-browser' : 'non-browser', // Check what else we could measure
191
+ domain: browserLocation?.hostname || 'non-browser',
74
192
  };
75
193
 
76
194
  payload.fields = {