@webex/internal-plugin-metrics 3.12.0-webex-services-ready.4 → 3.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.repo-context.json +466 -0
- package/.sdd/manifest.json +626 -0
- package/AGENTS.md +208 -0
- package/README.md +274 -0
- package/dist/call-diagnostic/call-diagnostic-metrics.js +155 -94
- package/dist/call-diagnostic/call-diagnostic-metrics.js.map +1 -1
- package/dist/call-diagnostic/config.js +3 -1
- package/dist/call-diagnostic/config.js.map +1 -1
- package/dist/config.js +7 -0
- package/dist/config.js.map +1 -1
- package/dist/index.js +10 -1
- package/dist/index.js.map +1 -1
- package/dist/metrics.js +118 -5
- package/dist/metrics.js.map +1 -1
- package/dist/metrics.types.js.map +1 -1
- package/dist/network-telemetry.js +610 -0
- package/dist/network-telemetry.js.map +1 -0
- package/dist/new-metrics.js +47 -11
- package/dist/new-metrics.js.map +1 -1
- package/dist/privacy-and-security-permission-enricher/constants.js +18 -0
- package/dist/privacy-and-security-permission-enricher/constants.js.map +1 -0
- package/dist/privacy-and-security-permission-enricher/index.js +143 -0
- package/dist/privacy-and-security-permission-enricher/index.js.map +1 -0
- package/dist/privacy-and-security-permission-enricher/types.js +7 -0
- package/dist/privacy-and-security-permission-enricher/types.js.map +1 -0
- package/dist/privacy-and-security-permission-enricher/utils.js +71 -0
- package/dist/privacy-and-security-permission-enricher/utils.js.map +1 -0
- package/dist/types/call-diagnostic/call-diagnostic-metrics.d.ts +12 -3
- package/dist/types/call-diagnostic/config.d.ts +2 -0
- package/dist/types/config.d.ts +8 -0
- package/dist/types/index.d.ts +2 -2
- package/dist/types/metrics.types.d.ts +7 -3
- package/dist/types/network-telemetry.d.ts +108 -0
- package/dist/types/new-metrics.d.ts +13 -1
- package/dist/types/privacy-and-security-permission-enricher/constants.d.ts +6 -0
- package/dist/types/privacy-and-security-permission-enricher/index.d.ts +40 -0
- package/dist/types/privacy-and-security-permission-enricher/types.d.ts +14 -0
- package/dist/types/privacy-and-security-permission-enricher/utils.d.ts +5 -0
- package/dist/types/unhandled-exception-telemetry/index.d.ts +60 -0
- package/dist/types/unhandled-exception-telemetry/utils.d.ts +6 -0
- package/dist/unhandled-exception-telemetry/index.js +331 -0
- package/dist/unhandled-exception-telemetry/index.js.map +1 -0
- package/dist/unhandled-exception-telemetry/utils.js +105 -0
- package/dist/unhandled-exception-telemetry/utils.js.map +1 -0
- package/docs/adr/index.md +27 -0
- package/docs/architecture.md +437 -0
- package/docs/getting-started.md +131 -0
- package/docs/index.md +52 -0
- package/docs/specs/README.md +88 -0
- package/package.json +11 -11
- package/schemas/repo-context.schema.json +796 -0
- package/src/call-diagnostic/call-diagnostic-metrics.ts +100 -30
- package/src/call-diagnostic/config.ts +2 -0
- package/src/call-diagnostic/docs/README.md +535 -0
- package/src/config.js +7 -0
- package/src/docs/README.md +703 -0
- package/src/index.ts +11 -0
- package/src/metrics.js +123 -5
- package/src/metrics.types.ts +13 -3
- package/src/network-telemetry.ts +757 -0
- package/src/new-metrics.ts +44 -2
- package/src/privacy-and-security-permission-enricher/constants.ts +33 -0
- package/src/privacy-and-security-permission-enricher/docs/README.md +356 -0
- package/src/privacy-and-security-permission-enricher/index.ts +142 -0
- package/src/privacy-and-security-permission-enricher/types.ts +21 -0
- package/src/privacy-and-security-permission-enricher/utils.ts +82 -0
- package/src/rtcMetrics/docs/README.md +447 -0
- package/src/unhandled-exception-telemetry/docs/README.md +536 -0
- package/src/unhandled-exception-telemetry/index.ts +404 -0
- package/src/unhandled-exception-telemetry/utils.ts +101 -0
- package/test/unit/spec/call-diagnostic/call-diagnostic-metrics.ts +485 -21
- package/test/unit/spec/metrics.js +14 -5
- package/test/unit/spec/network-telemetry.ts +610 -0
- package/test/unit/spec/new-metrics.ts +190 -48
- package/test/unit/spec/privacy-and-security-permission-enricher.ts +318 -0
- package/test/unit/spec/unhandled-exception-telemetry/utils.ts +109 -0
- package/test/unit/spec/unhandled-exception-telemetry.ts +689 -0
|
@@ -0,0 +1,703 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: Module Spec
|
|
3
|
+
title: 'Metrics plugin root specification'
|
|
4
|
+
description: Responsibilities, boundaries, design, invariants, and verification for the metrics plugin root module.
|
|
5
|
+
tags: [module, specification]
|
|
6
|
+
---
|
|
7
|
+
<!-- sdd-generated-metadata
|
|
8
|
+
doc_kind: module-spec
|
|
9
|
+
generated_from: module-spec@0.3.0
|
|
10
|
+
generated_by: claude-code
|
|
11
|
+
approved_by: rarajes2@cisco.com
|
|
12
|
+
updated_at: 2026-10-07T04:50:31Z
|
|
13
|
+
validation_status: pass
|
|
14
|
+
-->
|
|
15
|
+
|
|
16
|
+
# Metrics plugin root
|
|
17
|
+
|
|
18
|
+
This source-local document at `src/docs/README.md` owns the stable specification for **the metrics
|
|
19
|
+
plugin root module**: plugin registration, the legacy `metrics` and current `newMetrics` façades, the
|
|
20
|
+
batcher family, tagged-event metrics and SDK network telemetry. Ground every claim in repository
|
|
21
|
+
evidence and link to the [repository architecture](../../docs/architecture.md) instead of repeating
|
|
22
|
+
broader facts.
|
|
23
|
+
|
|
24
|
+
Related context: [documentation index](../../docs/index.md) ·
|
|
25
|
+
[documentation agent instructions](../../AGENTS.md)
|
|
26
|
+
|
|
27
|
+
## Metadata
|
|
28
|
+
|
|
29
|
+
| Field | Value |
|
|
30
|
+
| ------------- | ------------------------------------------------------------ |
|
|
31
|
+
| Owner | Cisco Webex JS SDK — telemetry |
|
|
32
|
+
| Source path | `src/` |
|
|
33
|
+
| Resource kind | package |
|
|
34
|
+
| Status | Active |
|
|
35
|
+
| Last verified | 2026-10-06 at `d6202dd73d` |
|
|
36
|
+
| Module id | `metrics-root` |
|
|
37
|
+
| Parent spec | — |
|
|
38
|
+
| Doc kind | Module spec |
|
|
39
|
+
| Coverage score | Pending coverage assessment |
|
|
40
|
+
| Validation status | pass (2026-10-07; validator runtime 01a1147a-c744-7083-9b15-95e91170c79a; 0 blocking, 0 important, 0 medium, 0 minor; conformance and source-fidelity gates pass, no code/spec mismatches found) |
|
|
41
|
+
|
|
42
|
+
## Applicability
|
|
43
|
+
|
|
44
|
+
Sections preceded by an `Include if` comment are conditional. Retain a
|
|
45
|
+
conditional section only when source evidence or a confirmed developer answer
|
|
46
|
+
satisfies its condition.
|
|
47
|
+
|
|
48
|
+
| Condition ID | Status | Evidence or reason | Owned section |
|
|
49
|
+
| ------------------------------------ | ---------- | -------------------------------------------------------------------------------------------------------------------- | ----------------------------- |
|
|
50
|
+
| `module.has_tiers` | N/A | The repository defines no operational or review tier policy for modules | Tier |
|
|
51
|
+
| `module.has_ui` | N/A | The package renders nothing | UI use-case flow |
|
|
52
|
+
| `module.crosses_service_boundaries` | Applicable | `src/batcher.js` and `src/client-metrics-batcher.js` post to the metrics service; `src/metrics.js` subscribes to SDK request events | Cross-boundary use-case flow |
|
|
53
|
+
| `module.holds_client_state` | Applicable | The network telemetry window in `src/network-telemetry.ts` and the readiness and delay flags in `src/new-metrics.ts` | Client state model |
|
|
54
|
+
| `module.enforces_domain_rules` | Applicable | Counter mapping, failure classification, self-exclusion and endpoint normalization in `src/network-telemetry.ts` | Business rules and invariants |
|
|
55
|
+
| `module.is_concurrent_async` | Applicable | The telemetry interval, in-flight submission tracking and batcher backoff in `src/network-telemetry.ts` and `src/batcher.js` | Concurrency and reactive flow |
|
|
56
|
+
| `module.owns_persistence` | N/A | Nothing is persisted; every aggregate and queue is in-memory | Data, schema, and migration |
|
|
57
|
+
| `module.stateful_transitions` | Applicable | Façade readiness in `src/new-metrics.ts` and the collector lifecycle in `src/metrics.js` | State machine |
|
|
58
|
+
| `module.exposes_wire_protocol` | Applicable | The client metric payload in `src/metrics.js` and the summary metric in `src/network-telemetry.ts` | Protocol and wire format |
|
|
59
|
+
| `module.ui_multi_screen` | N/A | No user interface | UI flow |
|
|
60
|
+
| `module.large_data_model` | N/A | Event types are derived from the external schema in `src/metrics.types.ts` rather than modeled here | Data model |
|
|
61
|
+
| `module.returns_caller_errors` | Applicable | `src/metrics.js` throws when a client metric has no name; pre-login submission rejects without an identifier | Caller-visible failure modes |
|
|
62
|
+
| `module.module_specific_conventions` | Applicable | Ampersand-based JavaScript plugins coexist with TypeScript classes, and telemetry must never fail a caller | Module-specific rules |
|
|
63
|
+
| `module.published_package` | Applicable | `package.json` declares the published entry points and `src/index.ts` the export surface | Export stability |
|
|
64
|
+
| `module.embedded_in_host` | Applicable | `src/index.ts` mounts both plugins into a host SDK instance with a before-logout lifecycle hook | Host integration and theming |
|
|
65
|
+
| `module.has_design_tradeoff` | Applicable | Reset-before-submit telemetry windows and the two-façade layout | Key design trade-off |
|
|
66
|
+
| `module.has_submodules` | Applicable | Derived from the manifest module tree: four child modules | Sub-modules |
|
|
67
|
+
|
|
68
|
+
## Evidence register
|
|
69
|
+
|
|
70
|
+
| Evidence | What it establishes |
|
|
71
|
+
| ----------------------------------------- | --------------------------------------------------------------------------------------------------------------------------- |
|
|
72
|
+
| `src/index.ts` | Plugin registration, the logout hook and the full export surface |
|
|
73
|
+
| `src/metrics.js` | The legacy façade, its batcher children, client metric payload construction and the network telemetry wiring |
|
|
74
|
+
| `src/new-metrics.ts` | The current façade, readiness gating, lazy backends, delay control and composition of the child modules |
|
|
75
|
+
| `src/network-telemetry.ts` | The request-outcome collector, its classification and normalization rules and the summary payload |
|
|
76
|
+
| `src/batcher.js` | Item defaults, the metrics resource transport and network-error backoff |
|
|
77
|
+
| `src/client-metrics-batcher.js` | The client-metrics resource transport |
|
|
78
|
+
| `src/prelogin-metrics-batcher.ts` | The unauthenticated pre-login transport and its identifier requirement |
|
|
79
|
+
| `src/client-metrics-prelogin-batcher.ts` | The pre-login transport used by the legacy façade |
|
|
80
|
+
| `src/generic-metrics.ts` | The shared tagged-event base: context, browser details, device identifier and readiness |
|
|
81
|
+
| `src/behavioral-metrics.ts` | Behavioral event naming and submission |
|
|
82
|
+
| `src/operational-metrics.ts` | Operational event submission |
|
|
83
|
+
| `src/business-metrics.ts` | Business event table routing |
|
|
84
|
+
| `src/prelogin-metrics.ts` | Pre-login business event construction |
|
|
85
|
+
| `src/config.js` | Plugin defaults, including both telemetry features disabled and the ten-minute interval |
|
|
86
|
+
| `src/automated-user.ts` | Automated user classification and its memoization |
|
|
87
|
+
| `src/metrics.types.ts` | The exported type surface derived from the external Call Analyzer schema |
|
|
88
|
+
| `test/unit/spec/network-telemetry.ts` | End-to-end verification of the collector against SDK request events |
|
|
89
|
+
| `test/unit/spec/metrics.js` | Verification of the legacy façade payload, routing and alias request |
|
|
90
|
+
| `test/unit/spec/new-metrics.ts` | Verification of readiness, lazy backends, enrichment wiring and the unhandled-exception start |
|
|
91
|
+
| `test/unit/spec/batcher.js` | Verification of queue clearing, network-error re-enqueue and the retry opt-out |
|
|
92
|
+
| Reconciled owner documentation | Owner-authored network telemetry design and package purpose, reconciled by meaning into this spec; one stale initialization code block corrected against `src/metrics.js` |
|
|
93
|
+
|
|
94
|
+
## Purpose and boundary
|
|
95
|
+
|
|
96
|
+
- Responsibility: the plugin for the Webex Metrics service — the package's registration and transport
|
|
97
|
+
layer — mounting the `metrics` and
|
|
98
|
+
`newMetrics` internal plugins, owning every batcher, building client metric and tagged-event
|
|
99
|
+
payloads, and summarizing SDK request outcomes.
|
|
100
|
+
- In scope: plugin registration and the logout hook; the legacy client-metrics path, including
|
|
101
|
+
pre-login submission and user aliasing; the current façade's readiness gate, lazy backends and
|
|
102
|
+
delay control; behavioral, operational, business and pre-login tagged events; the batcher family;
|
|
103
|
+
and network request telemetry.
|
|
104
|
+
- Network telemetry scope, confirmed by `src/network-telemetry.ts`: the collector counts request and
|
|
105
|
+
response outcomes that pass through `webex.request()` and its interceptors. For failures, it also
|
|
106
|
+
records aggregated error details covering:
|
|
107
|
+
- HTTP responses rejected by the SDK, such as `4xx` and `5xx` responses.
|
|
108
|
+
- Network or CORS failures where no HTTP response is available.
|
|
109
|
+
- Aborted and timed-out SDK requests when the error exposes that information.
|
|
110
|
+
- Request preparation failures that emit `request:failure`.
|
|
111
|
+
- Out of scope: network telemetry does not monitor arbitrary application `fetch()`,
|
|
112
|
+
`XMLHttpRequest`, WebSocket, or other traffic outside the SDK request pipeline. It also does not use
|
|
113
|
+
`PerformanceObserver` or browser-wide request interception. The Call Analyzer event model,
|
|
114
|
+
permission enrichment, WebRTC stats and browser exception capture are each owned by a child module.
|
|
115
|
+
- Consumers: sibling SDK plugins and first party clients, through `webex.internal.metrics` and
|
|
116
|
+
`webex.internal.newMetrics`. This is an internal Cisco Webex plugin. As such, it does not strictly
|
|
117
|
+
adhere to semantic versioning; use it at your own risk. Anyone not working on one of the first party
|
|
118
|
+
clients should use the public developer API and stick to the public plugins.
|
|
119
|
+
|
|
120
|
+
## Structure and key files
|
|
121
|
+
|
|
122
|
+
| Path | Responsibility |
|
|
123
|
+
| ----------------------------------------- | -------------------------------------------------------------------------------------------------------------- |
|
|
124
|
+
| `src/index.ts` | Registration of both plugins and the export surface; authoritative for what the package publishes |
|
|
125
|
+
| `src/metrics.js` | The legacy `metrics` plugin; authoritative for the client metric payload and the network telemetry lifecycle |
|
|
126
|
+
| `src/new-metrics.ts` | The `newMetrics` plugin; authoritative for readiness gating and composition of the child modules |
|
|
127
|
+
| `src/network-telemetry.ts` | The request-outcome collector; authoritative for counters, classification, normalization and the summary shape |
|
|
128
|
+
| `src/batcher.js` | Base batcher for this package; authoritative for item defaults and network-error backoff |
|
|
129
|
+
| `src/client-metrics-batcher.js` | Batcher bound to the client-metrics resource |
|
|
130
|
+
| `src/prelogin-metrics-batcher.ts` | Batcher bound to the unauthenticated pre-login resource |
|
|
131
|
+
| `src/client-metrics-prelogin-batcher.ts` | Pre-login batcher variant without diagnostic preparation, used by the legacy façade |
|
|
132
|
+
| `src/generic-metrics.ts` | Abstract base for tagged events |
|
|
133
|
+
| `src/behavioral-metrics.ts` | Behavioral events |
|
|
134
|
+
| `src/operational-metrics.ts` | Operational events |
|
|
135
|
+
| `src/business-metrics.ts` | Business events and table routing |
|
|
136
|
+
| `src/prelogin-metrics.ts` | Pre-login business events |
|
|
137
|
+
| `src/config.js` | Plugin configuration defaults and OS name mapping |
|
|
138
|
+
| `src/utils.ts` | Shared error serialization for log lines |
|
|
139
|
+
| `src/automated-user.ts` | Automated user classification |
|
|
140
|
+
| `src/metrics.types.ts` | The exported type surface |
|
|
141
|
+
|
|
142
|
+
<!-- Include if: this module contains child modules that own their own specifications. [condition-id: module.has_submodules] -->
|
|
143
|
+
|
|
144
|
+
## Sub-modules
|
|
145
|
+
|
|
146
|
+
| Sub-module | Responsibility | Specification |
|
|
147
|
+
| ------------------------------------------------- | ------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------- |
|
|
148
|
+
| `src/call-diagnostic/` | Call Analyzer events, the latency ledger and error-code mapping | [`src/call-diagnostic/docs/README.md`](../call-diagnostic/docs/README.md) |
|
|
149
|
+
| `src/privacy-and-security-permission-enricher/` | Permission-change enrichment of client events | [`src/privacy-and-security-permission-enricher/docs/README.md`](../privacy-and-security-permission-enricher/docs/README.md) |
|
|
150
|
+
| `src/rtcMetrics/` | WebRTC stats telemetry to the unified telemetry service | [`src/rtcMetrics/docs/README.md`](../rtcMetrics/docs/README.md) |
|
|
151
|
+
| `src/unhandled-exception-telemetry/` | Browser uncaught error and rejection reporting | [`src/unhandled-exception-telemetry/docs/README.md`](../unhandled-exception-telemetry/docs/README.md) |
|
|
152
|
+
|
|
153
|
+
This module references child behavior by contract identifier only: `call-diagnostic-event`,
|
|
154
|
+
`privacy-permission-enricher-sdk`, `rtc-metrics-payload` and `unhandled-exception-metric` in
|
|
155
|
+
`.sdd/manifest.json`.
|
|
156
|
+
|
|
157
|
+
## Public surface
|
|
158
|
+
|
|
159
|
+
| Surface | Consumer | Compatibility commitment | Source |
|
|
160
|
+
| ------------------------------------------ | --------------------------------------------- | ------------------------------------------------------------------------------------------------------------ | -------------------------- |
|
|
161
|
+
| Package import side effect | Any host that imports the package | Importing registers `metrics` and `newMetrics` before the host SDK instance is constructed | `src/index.ts` |
|
|
162
|
+
| `webex.internal.metrics` — `submit`, `submitClientMetrics`, `getClientMetricsPayload`, `aliasUser` | Sibling plugins and the child modules | Additive; `submitClientMetrics` is the only path accepting a pre-login identifier | `src/metrics.js` |
|
|
163
|
+
| `webex.internal.metrics` — `flushNetworkTelemetry`, `stopNetworkTelemetry` | Callers needing an immediate summary; the logout hook | Both resolve immediately when telemetry is disabled | `src/metrics.js` |
|
|
164
|
+
| `webex.internal.newMetrics` — client, feature, MQE, behavioral, operational, business, pre-login and internal submissions | Sibling plugins and first party clients | Client, feature, behavioral, operational, business and pre-login submissions before SDK readiness are logged and resolve without submitting; `submitMQE` and `submitInternalEvent` are not readiness-guarded | `src/new-metrics.ts` |
|
|
165
|
+
| `webex.internal.newMetrics` — readiness probes, delay control, permission setter, alias, fetch helpers, expected-error check | Sibling plugins and first party clients | Additive | `src/new-metrics.ts` |
|
|
166
|
+
| Named exports — classes, utilities, config and types | Workspace siblings | Removing a named export is breaking for the monorepo | `src/index.ts` |
|
|
167
|
+
| Network telemetry configuration | First party clients | `enabled` defaults to false; `intervalMs` defaults to ten minutes and falls back to it when not a positive finite number | `src/config.js` |
|
|
168
|
+
|
|
169
|
+
Network request telemetry is disabled by default. Enable it with
|
|
170
|
+
`metrics.networkTelemetry.enabled: true`. When enabled, the metrics plugin summarizes requests made
|
|
171
|
+
through the Webex SDK request pipeline. The reporting interval is configurable with
|
|
172
|
+
`metrics.networkTelemetry.intervalMs` and defaults to ten minutes. It listens to the SDK-wide
|
|
173
|
+
`request:start`, `request:success`, and `request:failure` events, so individual plugins do not need
|
|
174
|
+
to wrap or replace `webex.request()`. For example, to collect one-minute windows, set
|
|
175
|
+
`metrics.networkTelemetry: {enabled: true, intervalMs: 60 * 1_000}`.
|
|
176
|
+
|
|
177
|
+
Initialization, current in `src/metrics.js`: the listeners and the accumulator are registered during
|
|
178
|
+
metrics plugin initialization. `initialize(...args)` calls `WebexPlugin.prototype.initialize`, then
|
|
179
|
+
returns early when the plugin is constructed standalone with no parent or collection. Otherwise an
|
|
180
|
+
idempotent initializer, guarded on an existing collector and on the enable flag being exactly `true`,
|
|
181
|
+
calls `createNetworkTelemetryCollector` with the interval, a submit callback and a failure callback,
|
|
182
|
+
and uses `listenTo` to subscribe to `request:start`, `request:success` and `request:failure`. Because
|
|
183
|
+
the SDK initializes child plugins before `webex.config` is populated, that initializer runs once
|
|
184
|
+
immediately and once more on the first `change:config` event. The listeners are installed once for
|
|
185
|
+
each Webex instance when `webex.internal.metrics` is constructed and the feature is enabled. The
|
|
186
|
+
metrics package must be imported before constructing the Webex instance; standard Webex SDK bundles
|
|
187
|
+
already import and register the metrics plugin. A caller that needs the current window submitted
|
|
188
|
+
immediately uses `await webex.internal.metrics.flushNetworkTelemetry()`.
|
|
189
|
+
|
|
190
|
+
## Dependencies
|
|
191
|
+
|
|
192
|
+
| Dependency | Why it is required | Failure behavior |
|
|
193
|
+
| ------------------------------------------------- | ---------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------ |
|
|
194
|
+
| `@webex/webex-core` | Plugin base classes, `Batcher`, HTTP error types and plugin registration | A breaking change fails registration at import time |
|
|
195
|
+
| `@webex/webex-core` request events | Source of network telemetry | Absent events produce empty windows: each interval still submits a zeroed summary, while flush and stop skip an empty window |
|
|
196
|
+
| `@webex/common` | Browser and OS detection, the browser-environment flag | Detection degrades to undefined values rather than throwing |
|
|
197
|
+
| `@webex/common-timers` | Telemetry interval and batcher backoff timers | None |
|
|
198
|
+
| Device plugin | Device URL for tagged-event readiness and context | No device means tagged events report not ready |
|
|
199
|
+
| Child modules | Call Analyzer events, enrichment, WebRTC stats, exception capture | Each child's failures are contained inside it |
|
|
200
|
+
| `@webex/event-dictionary-ts` | The authoritative event schema behind `src/metrics.types.ts` | A schema change surfaces at build time |
|
|
201
|
+
| `isbot`, `lodash`, `uuid` | Automated user detection, merging, identifiers | None |
|
|
202
|
+
|
|
203
|
+
## Requirements
|
|
204
|
+
|
|
205
|
+
| ID | WHAT | WHY | Source evidence | Test or example evidence | Assumptions or gaps | Confidence |
|
|
206
|
+
| --------- | ----------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------- | -------------------------------------------- | ------------------- | ---------- |
|
|
207
|
+
| `MOD-001` | Importing the package registers `metrics` and `newMetrics`, and logout stops network telemetry first | Every SDK consumer relies on these mounts existing, and the final telemetry window must be submitted while credentials are still valid | `src/index.ts` | `test/unit/spec/network-telemetry.ts` | The logout hook wiring itself has no case; `stopNetworkTelemetry` is tested directly | Weak |
|
|
208
|
+
| `MOD-002` | `newMetrics` client, feature, behavioral, operational, business and pre-login submissions before the SDK emits ready are logged and resolve without submitting; `submitMQE` and `submitInternalEvent` have no readiness guard and delegate immediately | Before readiness the device and configuration needed to build events are not available | `src/new-metrics.ts` | `test/unit/spec/new-metrics.ts` | none | Present |
|
|
209
|
+
| `MOD-003` | Behavioral, operational and business backends are created lazily, and only after readiness | Their constructors read the device and logger from the SDK instance, which are not usable earlier | `src/new-metrics.ts` | `test/unit/spec/new-metrics.ts` | none | Present |
|
|
210
|
+
| `MOD-004` | Tagged events report ready only once a device identifier can be parsed from the device URL | Tagged events are keyed by device identifier downstream; submitting with an empty one would be unattributable | `src/generic-metrics.ts` | `test/unit/spec/behavioral/behavioral-metrics.ts` | none | Present |
|
|
211
|
+
| `MOD-005` | Client event payloads are enriched with permission changes before reaching Call Analyzer, scoped by correlation identifier | Permission history must follow the call, including across identifier transitions | `src/new-metrics.ts` | `test/unit/spec/new-metrics.ts` | none | Present |
|
|
212
|
+
| `MOD-006` | Unhandled exception telemetry is started when the SDK emits ready | It submits through this module's transport, which is only usable after readiness | `src/new-metrics.ts` | `test/unit/spec/new-metrics.ts` | none | Present |
|
|
213
|
+
| `MOD-007` | A client metric carries application name, version and URL, browser and OS details, SDK version and the client identifier | Ingestion segments every client metric by application and platform | `src/metrics.js` | `test/unit/spec/metrics.js` | none | Present |
|
|
214
|
+
| `MOD-008` | A client metric without a name throws | A nameless metric cannot be routed by ingestion | `src/metrics.js` | `test/unit/spec/metrics.js` | none | Present |
|
|
215
|
+
| `MOD-009` | A client metric with a pre-login identifier is submitted through the unauthenticated pre-login transport | Telemetry before sign-in must still be attributable to one session | `src/metrics.js` | `test/unit/spec/metrics.js` | none | Present |
|
|
216
|
+
| `MOD-010` | Pre-login submission rejects when no pre-login identifier has been saved | An unauthenticated request without its attribution header would be unusable and must never be sent | `src/prelogin-metrics-batcher.ts` | `test/unit/spec/prelogin-metrics-batcher.ts` | none | Present |
|
|
217
|
+
| `MOD-011` | Batched items that fail with a network or CORS error are re-enqueued with a delay that doubles up to the configured plateau, unless retry is disabled | Transient connectivity loss must not lose telemetry, but retry pressure must stay bounded | `src/batcher.js` | `test/unit/spec/batcher.js` | none | Present |
|
|
218
|
+
| `MOD-012` | Network telemetry is disabled by default and listens only when the enable flag is exactly `true` | Request telemetry adds a submission per window to every SDK instance, so it must be opt-in | `src/config.js` | `test/unit/spec/network-telemetry.ts` | none | Present |
|
|
219
|
+
| `MOD-013` | Telemetry initialization runs immediately and again on the first configuration change, at most once, and never for a standalone plugin | The SDK initializes children before configuration is populated, and a standalone plugin has no request events to observe | `src/metrics.js` | none found | The deferred and standalone paths have no dedicated case | Weak |
|
|
220
|
+
| `MOD-014` | Request outcomes are counted per summary and per host-and-endpoint, using the counter mapping in Business rules | Separating send, failed-request, received and failed-response counts distinguishes network failure from server failure | `src/network-telemetry.ts` | `test/unit/spec/network-telemetry.ts` | none | Present |
|
|
221
|
+
| `MOD-015` | Each failure is classified into exactly one error type in a fixed order | Aggregation needs a bounded vocabulary, and the order makes overlapping signals deterministic | `src/network-telemetry.ts` | `test/unit/spec/network-telemetry.ts` | The `request_error` fallback has no case | Present |
|
|
222
|
+
| `MOD-016` | Identical failures are aggregated with a count and at most ten unique tracking identifiers | Keeps payload size bounded during a failure storm while retaining enough identifiers to trace examples | `src/network-telemetry.ts` | `test/unit/spec/network-telemetry.ts` | none | Present |
|
|
223
|
+
| `MOD-017` | Requests to the metrics and unified telemetry services, including the legacy metrics API option, are excluded from collection | A telemetry upload must not appear in its own summary | `src/network-telemetry.ts` | `test/unit/spec/network-telemetry.ts` | none | Present |
|
|
224
|
+
| `MOD-018` | Endpoints drop query data and fragments, and replace numeric, encoded, mixed-case and otherwise non-route-looking segments with `:id` | Keeps aggregate cardinality bounded and keeps identifiers out of telemetry | `src/network-telemetry.ts` | `test/unit/spec/network-telemetry.ts` | none | Present |
|
|
225
|
+
| `MOD-019` | Direct-URI requests use the sanitized URI host and path; service requests use the logical service name as host | The start event can fire before the service URL is resolved, so the logical name is the stable identity | `src/network-telemetry.ts` | `test/unit/spec/network-telemetry.ts` | none | Present |
|
|
226
|
+
| `MOD-020` | Each endpoint reports average, nearest-rank p90 and p99 network duration computed only from samples whose `networkStart` and `networkEnd` timings are finite numbers with end not before start; an endpoint with no valid sample reports zero for all three | Tail latency is the useful signal for SDK request health, and a missing or inverted timing pair would corrupt it rather than describe it | `src/network-telemetry.ts` | `test/unit/spec/network-telemetry.ts` | Requests with no timing metadata are covered and report zero; non-finite or inverted timing pairs have no case | Present |
|
|
227
|
+
| `MOD-021` | Every interval submits the current window, including an empty one as a zeroed summary; the window resets before submission | Requests during an in-flight submission must belong to the next window. The periodic path has no emptiness check, so an idle instance keeps a fixed reporting cadence | `src/network-telemetry.ts` | `test/unit/spec/network-telemetry.ts` | The zeroed second-interval payload is asserted directly; no documented rationale for reporting empty windows was found | Present |
|
|
228
|
+
| `MOD-022` | Flush submits the current window immediately only when it is non-empty and keeps collecting; stop clears the interval, submits any non-empty partial window once and waits for every in-flight submission | Callers need an immediate summary after early call failures, and shutdown must not lose or race the last window | `src/network-telemetry.ts` | `test/unit/spec/network-telemetry.ts` | No case flushes or stops with an empty window | Present |
|
|
229
|
+
| `MOD-023` | A summary submission failure is caught and logged without affecting SDK requests | Telemetry must never degrade the requests it observes | `src/metrics.js` | `test/unit/spec/network-telemetry.ts` | none | Present |
|
|
230
|
+
| `MOD-024` | Business events route by table, defaulting the table and the application type | Each ingestion table has a different schema, and the shim keeps callers unaware of it | `src/business-metrics.ts` | `test/unit/spec/business/business-metrics.ts` | none | Present |
|
|
231
|
+
| `MOD-025` | The automated user verdict is computed once per process | User agent parsing is relatively expensive and the verdict cannot change within a page | `src/automated-user.ts` | `test/unit/spec/automated-user.ts` | none | Present |
|
|
232
|
+
|
|
233
|
+
## Design overview
|
|
234
|
+
|
|
235
|
+
The root module is the package's registration and transport layer. Its design is a deliberate split
|
|
236
|
+
between two façades that share one family of batchers.
|
|
237
|
+
|
|
238
|
+
`metrics` (`src/metrics.js`) is an Ampersand `WebexPlugin` with three `Batcher` children: one for the
|
|
239
|
+
`metrics` resource, one for `clientmetrics` and one for `clientmetrics-prelogin`. It builds the client
|
|
240
|
+
metric payload from host configuration and browser detection, and routes to the pre-login batcher
|
|
241
|
+
whenever a pre-login identifier is supplied. It also owns the network telemetry collector, because the
|
|
242
|
+
collector needs the SDK request events and a transport, and this plugin has both.
|
|
243
|
+
|
|
244
|
+
`newMetrics` (`src/new-metrics.ts`) owns no transport. It eagerly constructs the latency ledger, the
|
|
245
|
+
Call Analyzer builder and the permission enricher, and on the SDK `ready` event constructs the
|
|
246
|
+
pre-login backend, marks itself ready, replays the current delay setting and starts unhandled
|
|
247
|
+
exception telemetry. Behavioral, operational and business backends are created on first use after
|
|
248
|
+
readiness. The client, feature, behavioral, operational, business and pre-login submission methods
|
|
249
|
+
check readiness first, so a caller that fires too early gets a logged no-op rather than a malformed
|
|
250
|
+
event. `submitMQE` and `submitInternalEvent` are the exceptions: they record the latency timestamp and,
|
|
251
|
+
for `submitMQE`, delegate straight to the eagerly constructed Call Analyzer builder without a
|
|
252
|
+
readiness check.
|
|
253
|
+
|
|
254
|
+
The tagged-event classes share `src/generic-metrics.ts`, which builds a context block and browser
|
|
255
|
+
details and derives the device identifier from the device URL. Each class composes the metric name
|
|
256
|
+
its own way — behavioral events join product, agent, target and verb — and posts through its own
|
|
257
|
+
client-metrics batcher.
|
|
258
|
+
|
|
259
|
+
Network telemetry (`src/network-telemetry.ts`) is a closure-based collector with no class. Its state
|
|
260
|
+
is one window of counters plus a set of in-flight submissions. At each interval boundary it
|
|
261
|
+
serializes the window, replaces it with an empty one, and only then calls the submit callback. Event
|
|
262
|
+
flow:
|
|
263
|
+
|
|
264
|
+
```text
|
|
265
|
+
webex.request()
|
|
266
|
+
-> SDK request interceptors
|
|
267
|
+
-> request:start(options)
|
|
268
|
+
-> request:success(options, response) or request:failure(options, reason)
|
|
269
|
+
-> metrics request outcome listeners
|
|
270
|
+
-> aggregate host, endpoint, response, and error counts
|
|
271
|
+
-> every configured interval, submit JS_SDK_NETWORK_REQUEST_SUMMARY
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
## Data flow and sequence coverage
|
|
275
|
+
|
|
276
|
+
Collection is in-process method calls and SDK events; submission is a batched HTTP POST through the
|
|
277
|
+
host request pipeline. Four operation groups have distinct actors or outcomes and are diagrammed
|
|
278
|
+
separately. Child-module flows are owned by their specs.
|
|
279
|
+
|
|
280
|
+
| Operation group | Entry and outcome | Diagram or evidence | Failure and recovery coverage |
|
|
281
|
+
| ----------------------------- | --------------------------------------------------------------------------------------------------------- | ------------------------------------ | ----------------------------------------------------------------------------------------------------- |
|
|
282
|
+
| Façade submission | A caller submits through `newMetrics`; guarded events are gated on readiness, then delegated (`submitMQE` is not gated) | First sequence diagram below | Not ready: logged no-op for guarded methods. Child failures are contained in the child |
|
|
283
|
+
| Client metric submission | A caller or child submits through `metrics`; the payload is built and batched | Second sequence diagram below | Missing name throws; missing pre-login identifier rejects; network errors re-enqueue with backoff |
|
|
284
|
+
| Network telemetry window | Request events accumulate; the interval, a flush or a stop submits the window | Third sequence diagram below | The interval submits even an empty window; flush and stop skip an empty window; submission failure logged and the window dropped |
|
|
285
|
+
| Plugin lifecycle | Construction, configuration change and logout | State machine section | Standalone construction skips telemetry; logout waits for in-flight submissions |
|
|
286
|
+
|
|
287
|
+
```mermaid
|
|
288
|
+
sequenceDiagram
|
|
289
|
+
participant Caller as SDK plugin or client
|
|
290
|
+
participant New as newMetrics
|
|
291
|
+
participant Child as Child module or tagged backend
|
|
292
|
+
Caller->>New: submit event
|
|
293
|
+
alt SDK not ready and method is readiness-guarded
|
|
294
|
+
New->>New: log attempted submission
|
|
295
|
+
New-->>Caller: resolve without submitting
|
|
296
|
+
else ready
|
|
297
|
+
opt tagged backend not built yet
|
|
298
|
+
New->>New: construct backend lazily
|
|
299
|
+
end
|
|
300
|
+
opt client event
|
|
301
|
+
New->>New: record latency timestamp and enrich permissions
|
|
302
|
+
end
|
|
303
|
+
New->>Child: delegate submission
|
|
304
|
+
Child-->>Caller: submission promise
|
|
305
|
+
end
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
```mermaid
|
|
309
|
+
sequenceDiagram
|
|
310
|
+
participant Caller as Caller or child module
|
|
311
|
+
participant Metrics as metrics plugin
|
|
312
|
+
participant Batcher as Client metrics or pre-login batcher
|
|
313
|
+
participant Svc as Webex metrics service
|
|
314
|
+
Caller->>Metrics: submitClientMetrics(name, props, preLoginId)
|
|
315
|
+
alt no name
|
|
316
|
+
Metrics-->>Caller: throw
|
|
317
|
+
end
|
|
318
|
+
Metrics->>Metrics: build tags, fields, context and timestamp
|
|
319
|
+
alt pre-login identifier supplied
|
|
320
|
+
Metrics->>Batcher: save identifier, request on pre-login batcher
|
|
321
|
+
else
|
|
322
|
+
Metrics->>Batcher: request on client metrics batcher
|
|
323
|
+
end
|
|
324
|
+
Batcher->>Svc: POST metrics array
|
|
325
|
+
opt network or CORS error and retry enabled
|
|
326
|
+
Batcher->>Batcher: re-enqueue after a doubling delay
|
|
327
|
+
end
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
```mermaid
|
|
331
|
+
sequenceDiagram
|
|
332
|
+
participant Core as WebexCore request pipeline
|
|
333
|
+
participant Coll as Network telemetry collector
|
|
334
|
+
participant Metrics as metrics plugin
|
|
335
|
+
Core->>Coll: request:start / request:success / request:failure
|
|
336
|
+
alt metrics or unifiedTelemetry service
|
|
337
|
+
Coll-->>Core: ignore
|
|
338
|
+
else tracked request
|
|
339
|
+
Coll->>Coll: update summary, endpoint and error aggregates
|
|
340
|
+
end
|
|
341
|
+
Note over Coll: interval boundary, flush, or stop
|
|
342
|
+
alt flush or stop with an empty window
|
|
343
|
+
Coll-->>Metrics: nothing to submit
|
|
344
|
+
else interval boundary, or window has data
|
|
345
|
+
Coll->>Coll: serialize window, then reset to an empty window
|
|
346
|
+
Coll->>Metrics: submit JS_SDK_NETWORK_REQUEST_SUMMARY
|
|
347
|
+
opt submission rejects or throws
|
|
348
|
+
Coll->>Metrics: report failure, which logs a warning
|
|
349
|
+
end
|
|
350
|
+
end
|
|
351
|
+
opt stop
|
|
352
|
+
Coll->>Coll: clear interval and wait for every in-flight submission
|
|
353
|
+
end
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
## Class and component relationships
|
|
357
|
+
|
|
358
|
+
```mermaid
|
|
359
|
+
classDiagram
|
|
360
|
+
class Index {
|
|
361
|
+
+registerInternalPlugin metrics
|
|
362
|
+
+registerInternalPlugin newMetrics
|
|
363
|
+
}
|
|
364
|
+
class Metrics {
|
|
365
|
+
+batcher
|
|
366
|
+
+clientMetricsBatcher
|
|
367
|
+
+clientMetricsPreloginBatcher
|
|
368
|
+
+networkTelemetry
|
|
369
|
+
+submitClientMetrics()
|
|
370
|
+
+flushNetworkTelemetry()
|
|
371
|
+
+stopNetworkTelemetry()
|
|
372
|
+
}
|
|
373
|
+
class NewMetrics {
|
|
374
|
+
+isReady
|
|
375
|
+
+callDiagnosticLatencies
|
|
376
|
+
+callDiagnosticMetrics
|
|
377
|
+
+submitClientEvent()
|
|
378
|
+
+submitBusinessEvent()
|
|
379
|
+
}
|
|
380
|
+
class NetworkTelemetryCollector
|
|
381
|
+
class MetricsBatcher
|
|
382
|
+
class ClientMetricsBatcher
|
|
383
|
+
class PreLoginMetricsBatcher
|
|
384
|
+
class ClientMetricsPreloginBatcher
|
|
385
|
+
class GenericMetrics
|
|
386
|
+
class BehavioralMetrics
|
|
387
|
+
class OperationalMetrics
|
|
388
|
+
class BusinessMetrics
|
|
389
|
+
class PreLoginMetrics
|
|
390
|
+
Index --> Metrics
|
|
391
|
+
Index --> NewMetrics
|
|
392
|
+
Metrics --> NetworkTelemetryCollector : creates when enabled
|
|
393
|
+
Metrics --> MetricsBatcher
|
|
394
|
+
Metrics --> ClientMetricsBatcher
|
|
395
|
+
Metrics --> ClientMetricsPreloginBatcher
|
|
396
|
+
ClientMetricsBatcher --|> MetricsBatcher
|
|
397
|
+
PreLoginMetricsBatcher --|> MetricsBatcher
|
|
398
|
+
ClientMetricsPreloginBatcher --|> PreLoginMetricsBatcher
|
|
399
|
+
NewMetrics --> BehavioralMetrics : lazy
|
|
400
|
+
NewMetrics --> OperationalMetrics : lazy
|
|
401
|
+
NewMetrics --> BusinessMetrics : lazy
|
|
402
|
+
NewMetrics --> PreLoginMetrics : on ready
|
|
403
|
+
BehavioralMetrics --|> GenericMetrics
|
|
404
|
+
OperationalMetrics --|> GenericMetrics
|
|
405
|
+
BusinessMetrics --|> GenericMetrics
|
|
406
|
+
PreLoginMetrics --|> GenericMetrics
|
|
407
|
+
GenericMetrics --> ClientMetricsBatcher
|
|
408
|
+
PreLoginMetrics --> PreLoginMetricsBatcher
|
|
409
|
+
```
|
|
410
|
+
|
|
411
|
+
## Use cases and flows
|
|
412
|
+
|
|
413
|
+
| Use case | Actor or caller | Primary steps and outcome | Failure or boundary behavior | Evidence |
|
|
414
|
+
| -------- | -------------------------- | --------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------- |
|
|
415
|
+
| `UC-001` | First party client | Enables network telemetry; SDK requests accumulate and one summary is submitted per interval | Telemetry uploads are excluded; an interval with no tracked request still submits a zeroed summary | `src/network-telemetry.ts`, `test/unit/spec/network-telemetry.ts` |
|
|
416
|
+
| `UC-002` | Meetings plugin | An early call failure occurs; it flushes network telemetry for an immediate summary | Disabled telemetry resolves immediately | `src/metrics.js`, `test/unit/spec/network-telemetry.ts` |
|
|
417
|
+
| `UC-003` | Host SDK | Logout stops network telemetry; the partial window is submitted once and in-flight submissions are awaited | Disabled telemetry resolves immediately | `src/index.ts`, `test/unit/spec/network-telemetry.ts` |
|
|
418
|
+
| `UC-004` | First party client | Submits a behavioral event after readiness; the backend is built lazily and the tagged event is batched | Before readiness the call is logged and resolves | `src/new-metrics.ts`, `test/unit/spec/new-metrics.ts` |
|
|
419
|
+
| `UC-005` | Guest before sign-in | Submits a client metric with a pre-login identifier; it is sent unauthenticated with the identifier header, then aliased after sign-in | No saved identifier rejects the batch | `src/metrics.js`, `test/unit/spec/metrics.js` |
|
|
420
|
+
| `UC-006` | Web client | Submits a business event to a specific table; the payload is shaped for that table's schema | Unknown or missing table falls back to the default shape | `src/business-metrics.ts`, `test/unit/spec/business/business-metrics.ts` |
|
|
421
|
+
|
|
422
|
+
<!-- Include if: the module calls another service or crosses an event or network boundary. [condition-id: module.crosses_service_boundaries] -->
|
|
423
|
+
|
|
424
|
+
### Cross-boundary use-case flow
|
|
425
|
+
|
|
426
|
+
- Boundary and transport: inbound, the SDK-wide request lifecycle events; outbound, HTTPS POST to the
|
|
427
|
+
`metrics` service resources `metrics`, `clientmetrics` and `clientmetrics-prelogin`, plus the
|
|
428
|
+
`clientmetrics` alias request with the pre-login header.
|
|
429
|
+
- Ordering: batch items keep arrival order; no cross-batch ordering is promised. Network telemetry
|
|
430
|
+
windows are disjoint by construction because the window resets before submission.
|
|
431
|
+
- Compatibility: the summary metric and the client metric payload are wire contracts with ingestion;
|
|
432
|
+
additions are compatible, removals and renames are not.
|
|
433
|
+
- Timeout and retry: the batchers wait up to the configured service-discovery timeout, and re-enqueue
|
|
434
|
+
network failures with doubling delay up to the plateau. Network telemetry never retries a window.
|
|
435
|
+
- Recovery: a lost telemetry window is not replayed; the next window starts empty.
|
|
436
|
+
|
|
437
|
+
<!-- Include if: the module holds client-side state. [condition-id: module.holds_client_state] -->
|
|
438
|
+
|
|
439
|
+
## Client state model
|
|
440
|
+
|
|
441
|
+
| State or slice | Owner | Initial state | Transition triggers | Reset or persistence boundary |
|
|
442
|
+
| --------------------------- | ---------------- | ------------------- | -------------------------------------------------------------------- | ------------------------------------------------------------------- |
|
|
443
|
+
| Network telemetry window | Collector closure | Empty aggregate | Tracked request events | Replaced at every interval, flush and stop |
|
|
444
|
+
| In-flight submissions | Collector closure | Empty set | A window submission starts or settles | Drained by stop |
|
|
445
|
+
| Collector reference | `metrics` | Undefined | Created once when enabled | Stopped on logout; not recreated |
|
|
446
|
+
| Readiness flag | `newMetrics` | False | SDK `ready` event | Instance lifetime |
|
|
447
|
+
| Delay flags and overrides | `newMetrics` | False, empty | The two delay setters | Disabling delay flushes the child's queue |
|
|
448
|
+
| Lazy tagged backends | `newMetrics` | Undefined | First use after readiness | Instance lifetime |
|
|
449
|
+
| Batcher queues and backoff | Each batcher | Empty | Enqueue, accept, re-enqueue | Per-item delay cleared on acceptance |
|
|
450
|
+
| Saved pre-login identifier | Pre-login batchers | Undefined | Saved on each pre-login submission | Overwritten by the next submission |
|
|
451
|
+
| Device identifier memo | `GenericMetrics` | Empty string | First successful parse of the device URL | Instance lifetime |
|
|
452
|
+
|
|
453
|
+
<!-- Include if: the module enforces domain rules or entity invariants. [condition-id: module.enforces_domain_rules] -->
|
|
454
|
+
|
|
455
|
+
## Business rules and invariants
|
|
456
|
+
|
|
457
|
+
Counter mapping, current in `src/network-telemetry.ts`:
|
|
458
|
+
|
|
459
|
+
| Event or outcome | Summary and endpoint counters |
|
|
460
|
+
| --------------------------------------------------- | --------------------------------------------------------------------------- |
|
|
461
|
+
| `request:start` | `totalSendRequest`, `countSendRequest` |
|
|
462
|
+
| `request:success` | `totalRecvdResponse`, `countRecvdResponse` |
|
|
463
|
+
| `request:failure` without an HTTP response | `totalFailedRequest`, `countFailedRequest` |
|
|
464
|
+
| `request:failure` with an HTTP status (`4xx`/`5xx`) | Received-response counters plus `totalFailedResponse`/`countFailedResponse` |
|
|
465
|
+
|
|
466
|
+
Failure classification, evaluated in this order:
|
|
467
|
+
|
|
468
|
+
| Condition | `errorType` |
|
|
469
|
+
| --------------------------------------------------------------------------------------------------------- | --------------- |
|
|
470
|
+
| Error name is `AbortError` | `aborted` |
|
|
471
|
+
| Status is `408` or `504`, timeout appears in the error details, or the configured request timeout elapsed | `timeout` |
|
|
472
|
+
| Status is `429` | `rate_limited` |
|
|
473
|
+
| Status is `5xx` | `server_error` |
|
|
474
|
+
| Status is `4xx` | `client_error` |
|
|
475
|
+
| No response status is available, or the error name contains `network` | `network_error` |
|
|
476
|
+
| Any other SDK request failure | `request_error` |
|
|
477
|
+
|
|
478
|
+
Telemetry request exclusion: requests to the `metrics` and `unifiedTelemetry` services are excluded
|
|
479
|
+
from both success and failure collection. The exclusion also covers the legacy `api: 'metrics'`
|
|
480
|
+
request option. This prevents a telemetry upload from affecting its own summary. The exclusion is
|
|
481
|
+
centralized in the collector; telemetry request call sites do not require special flags.
|
|
482
|
+
|
|
483
|
+
Endpoint normalization: the `endPoint` value is derived from `options.resource`, or from the URI path
|
|
484
|
+
for a direct-URI request:
|
|
485
|
+
|
|
486
|
+
- Query parameters and fragments are removed.
|
|
487
|
+
- Numeric, percent-encoded, uppercase, and otherwise non-route-looking segments are replaced with `:id`.
|
|
488
|
+
|
|
489
|
+
For example, `rooms/Y2lzY29zcGFyazovL3VzL1JPT00/messages?personId=secret` becomes
|
|
490
|
+
`rooms/:id/messages`.
|
|
491
|
+
|
|
492
|
+
| ID | Invariant | WHY | Enforcement source | Test evidence |
|
|
493
|
+
| --------- | ------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------- | ---------------------------- | ------------------------------------- |
|
|
494
|
+
| `INV-001` | Requests to the `metrics` and `unifiedTelemetry` services never enter a telemetry window | Without it every window would count the SDK's own summary and client-metric uploads | `src/network-telemetry.ts` | `test/unit/spec/network-telemetry.ts` |
|
|
495
|
+
| `INV-002` | A status of zero means no HTTP response; only statuses 100 to 599 count as responses | Separates transport failure from server failure in every counter | `src/network-telemetry.ts` | `test/unit/spec/network-telemetry.ts` |
|
|
496
|
+
| `INV-003` | Every failure has exactly one error type | Bounded aggregation vocabulary | `src/network-telemetry.ts` | `test/unit/spec/network-telemetry.ts` |
|
|
497
|
+
| `INV-004` | An error aggregate holds at most ten unique tracking identifiers | Bounds payload size during failure storms | `src/network-telemetry.ts` | `test/unit/spec/network-telemetry.ts` |
|
|
498
|
+
| `INV-005` | Endpoints contain no query data, fragment or non-route-looking segment | Bounds cardinality and keeps identifiers out of telemetry | `src/network-telemetry.ts` | `test/unit/spec/network-telemetry.ts` |
|
|
499
|
+
| `INV-006` | Flush and stop never submit an empty window; the periodic interval is the only path that does | Flush serves early-failure and shutdown delivery of collected data, so an empty flush would carry nothing | `src/network-telemetry.ts` | none found |
|
|
500
|
+
| `INV-007` | Non-production builds tag metrics with a test environment | Keeps non-production data out of production metrics | `src/batcher.js` | `test/unit/spec/batcher.js` |
|
|
501
|
+
|
|
502
|
+
<!-- Include if: the module is concurrent, asynchronous, reactive, or event-driven. [condition-id: module.is_concurrent_async] -->
|
|
503
|
+
|
|
504
|
+
## Concurrency and reactive flow
|
|
505
|
+
|
|
506
|
+
- Execution model: SDK event listeners, one `safeSetInterval` per collector, and the `Batcher` queue
|
|
507
|
+
with `safeSetTimeout` backoff.
|
|
508
|
+
- Ordering guarantees: the window reset happens synchronously before the submit callback, so an event
|
|
509
|
+
arriving while a submission is pending always lands in the next window.
|
|
510
|
+
- Idempotency and retry: windows are never retried. Batch items are re-enqueued on network errors with
|
|
511
|
+
per-item delay starting at one second and doubling below the plateau.
|
|
512
|
+
- Shared-state protection: single-threaded; every mutation is synchronous. The in-flight set lets stop
|
|
513
|
+
wait for submissions whose window was already reset.
|
|
514
|
+
- Flush and shutdown: the metrics plugin exposes `flushNetworkTelemetry()` for callers that need to
|
|
515
|
+
submit the current non-empty window immediately, such as after an early call failure. When the
|
|
516
|
+
metrics plugin is stopped, any non-empty partial window is submitted once before the collector is
|
|
517
|
+
disposed. Empty windows are not submitted during shutdown, and the shutdown hook waits for the
|
|
518
|
+
submission attempt to settle.
|
|
519
|
+
- Blocking restrictions: no request listener awaits anything, and summary submission failures are
|
|
520
|
+
caught inside the collector, so telemetry cannot slow or fail an SDK request.
|
|
521
|
+
|
|
522
|
+
<!-- Include if: the module has non-trivial state transitions. [condition-id: module.stateful_transitions] -->
|
|
523
|
+
|
|
524
|
+
## State machine
|
|
525
|
+
|
|
526
|
+
```mermaid
|
|
527
|
+
stateDiagram-v2
|
|
528
|
+
state "newMetrics" as NM {
|
|
529
|
+
[*] --> NotReady
|
|
530
|
+
NotReady --> NotReady: guarded submission logged and resolved; MQE delegated
|
|
531
|
+
NotReady --> Ready: SDK ready, pre-login backend built, delay replayed, exception telemetry started
|
|
532
|
+
Ready --> Ready: submissions delegated, tagged backends built lazily
|
|
533
|
+
}
|
|
534
|
+
state "network telemetry" as NT {
|
|
535
|
+
[*] --> Disabled: standalone, or enable flag not true
|
|
536
|
+
Disabled --> Collecting: enable flag true at construction or first config change
|
|
537
|
+
Collecting --> Collecting: interval submits and resets the window, even when empty; flush does so only when non-empty
|
|
538
|
+
Collecting --> Stopped: logout stops, submits partial window, waits for in-flight
|
|
539
|
+
Stopped --> [*]
|
|
540
|
+
}
|
|
541
|
+
```
|
|
542
|
+
|
|
543
|
+
Rejected transitions: a collector is never created twice; `Stopped` does not return to `Collecting`.
|
|
544
|
+
|
|
545
|
+
<!-- Include if: callers depend on a wire protocol or serialized format. [condition-id: module.exposes_wire_protocol] -->
|
|
546
|
+
|
|
547
|
+
## Protocol and wire format
|
|
548
|
+
|
|
549
|
+
| Message or frame | Version | Producer or serializer | Consumer or parser | Compatibility and ordering rule |
|
|
550
|
+
| ----------------------------------- | ------- | ----------------------------- | ------------------------- | ------------------------------------------------------------------------------------------- |
|
|
551
|
+
| Client metric payload | n/a | `src/metrics.js` | Webex metrics ingestion | Additive only; tags and fields are indexed by ingestion |
|
|
552
|
+
| `JS_SDK_NETWORK_REQUEST_SUMMARY` | n/a | `src/network-telemetry.ts` | Webex metrics ingestion | Operational type; the summary is duplicated in `fields` for indexing |
|
|
553
|
+
| Tagged event | n/a | `src/generic-metrics.ts` | Webex metrics ingestion | Metric name, type list, tags, context and timestamp |
|
|
554
|
+
| Business event | n/a | `src/business-metrics.ts` | Webex business tables | Shape depends on the table; the business-metrics table merges context into the value |
|
|
555
|
+
| Metrics batch body | n/a | `src/batcher.js` | Webex metrics service | A `metrics` array; each item gets app type, environment, time, version and post time |
|
|
556
|
+
|
|
557
|
+
One operational client metric named `JS_SDK_NETWORK_REQUEST_SUMMARY` is submitted at the configured
|
|
558
|
+
interval. Its `eventPayload` shape is declared by the `NetworkTelemetry` type in
|
|
559
|
+
[`src/network-telemetry.ts`](../network-telemetry.ts), which is linked here rather than reproduced: a four-counter
|
|
560
|
+
`metricsSummary`, per host-and-endpoint `metrics`, grouped `errorMetrics`, and an
|
|
561
|
+
`errorMetricsSummary`. The outer client metric carries `metricName`
|
|
562
|
+
`JS_SDK_NETWORK_REQUEST_SUMMARY`, `type: 'operational'`, `fields` duplicating `metricsSummary` for
|
|
563
|
+
indexing, and that `eventPayload`.
|
|
564
|
+
|
|
565
|
+
The `metrics` array is grouped by `host` and `endPoint`. For service-based SDK requests, `host` is the
|
|
566
|
+
normalized logical service name. Direct-URI requests use the URI host. `endPoint` is a sanitized
|
|
567
|
+
resource or URI path. `averageNetworkDurationMs` is the average measured network duration of the
|
|
568
|
+
group's requests that carry valid timing, while `maxNetworkDurationP90Ms` and
|
|
569
|
+
`maxNetworkDurationP99Ms` are the maximum durations at the nearest-rank 90th and 99th percentiles of
|
|
570
|
+
those samples; a group with no valid timing sample reports zero for all three. All values are in
|
|
571
|
+
milliseconds.
|
|
572
|
+
|
|
573
|
+
The `errorMetrics` array groups identical failures by host, endpoint, status code, error code,
|
|
574
|
+
method, error type, and error message. `countError` records the number of occurrences, while
|
|
575
|
+
`trackingIds` retains at most ten unique identifiers. `errorMetricsSummary` counts errors by status
|
|
576
|
+
code; status `0` means no HTTP response was available.
|
|
577
|
+
|
|
578
|
+
The SDK adds application metadata to the outer client metric when it wraps this `eventPayload`, as it
|
|
579
|
+
does for every client metric built in `src/metrics.js`:
|
|
580
|
+
|
|
581
|
+
| Property | Source |
|
|
582
|
+
| -------------------- | --------------------------------------------------------------------------- |
|
|
583
|
+
| `tags.app_name` | webex.config.appName, or unknown |
|
|
584
|
+
| `tags.app_version` | webex.config.appVersion, or unknown |
|
|
585
|
+
| `tags.app_url` | Browser origin without path/query data, hostname fallback, or non-browser |
|
|
586
|
+
| `fields.sdk_version` | webex.version |
|
|
587
|
+
|
|
588
|
+
<!-- Include if: the module returns or raises errors callers must handle. [condition-id: module.returns_caller_errors] -->
|
|
589
|
+
|
|
590
|
+
## Caller-visible failure modes
|
|
591
|
+
|
|
592
|
+
| Condition | Signal or result | Caller behavior | Retry or recovery | Evidence |
|
|
593
|
+
| ------------------------------------------- | ---------------------------------------------------- | -------------------------------------------- | ---------------------------------------------- | ----------------------------------- |
|
|
594
|
+
| Client metric submitted without a name | Synchronous `Error` | Supply a metric name | None | `src/metrics.js` |
|
|
595
|
+
| Pre-login submission with no saved identifier | Rejected promise | Pass a pre-login identifier | None | `src/prelogin-metrics-batcher.ts` |
|
|
596
|
+
| Alias request fails | Rejected promise, logged | Caller decides whether to retry | None built in | `src/new-metrics.ts` |
|
|
597
|
+
| Batch transport fails with a network error | Item re-enqueued; the promise stays pending | None required | Doubling delay up to the plateau | `src/batcher.js` |
|
|
598
|
+
| Batch transport fails otherwise | Rejected promise | Callers normally ignore it | None | `src/batcher.js` |
|
|
599
|
+
| Guarded `newMetrics` submission used before ready | Logged; resolved promise with nothing submitted (`submitMQE` is not guarded and delegates immediately) | Submit after the SDK is ready | Use delay mode to defer instead | `src/new-metrics.ts` |
|
|
600
|
+
|
|
601
|
+
## Pitfalls and constraints
|
|
602
|
+
|
|
603
|
+
- Endpoint normalization is heuristic. A short lowercase alphabetic identifier can look like a static
|
|
604
|
+
route segment and survive. Do not place sensitive values directly in a resource path; use normal SDK
|
|
605
|
+
resource identifiers and avoid embedding credentials or personal data in route names. Error messages are
|
|
606
|
+
included because they are part of the error aggregate schema, so callers must not put credentials or
|
|
607
|
+
personal data in thrown error messages.
|
|
608
|
+
- An enabled collector submits a summary every interval even when no tracked request occurred, so an
|
|
609
|
+
idle SDK instance emits one zeroed `JS_SDK_NETWORK_REQUEST_SUMMARY` per interval. Only flush and stop
|
|
610
|
+
skip an empty window.
|
|
611
|
+
- The host of a service request is the logical service name, not the resolved URL host, because the
|
|
612
|
+
start event can fire before the service interceptor resolves a URL.
|
|
613
|
+
- Do not collapse the deferred `change:config` initialization in `src/metrics.js` into a direct call:
|
|
614
|
+
the SDK populates configuration after initializing children.
|
|
615
|
+
- `src/generic-metrics.ts` imports the OS-name helper from `src/metrics.js`; do not add the reverse
|
|
616
|
+
import.
|
|
617
|
+
- The `test` script in `package.json` is broken because it chains scripts this package does not
|
|
618
|
+
define; use `test:unit` and `test:style`.
|
|
619
|
+
|
|
620
|
+
<!-- Include if: the module has conventions beyond repository-wide rules. [condition-id: module.module_specific_conventions] -->
|
|
621
|
+
|
|
622
|
+
## Module-specific rules
|
|
623
|
+
|
|
624
|
+
- Do: keep Ampersand-based plugins and batchers (`src/metrics.js`, `src/batcher.js`,
|
|
625
|
+
`src/client-metrics-batcher.js`, `src/config.js`) in JavaScript and in-style; write new code in
|
|
626
|
+
TypeScript.
|
|
627
|
+
- Do: add new telemetry transports to the self-exclusion rule in `src/network-telemetry.ts`, not at
|
|
628
|
+
the call site.
|
|
629
|
+
- Do: catch and log every telemetry submission failure.
|
|
630
|
+
- Do not: gate a `newMetrics` submission on anything other than the readiness flag at the top of the
|
|
631
|
+
method; the early-return log line is how premature callers are diagnosed.
|
|
632
|
+
- Do not: submit a network telemetry window without resetting it first.
|
|
633
|
+
|
|
634
|
+
<!-- Include if: the module is published or consumed as a package. [condition-id: module.published_package] -->
|
|
635
|
+
|
|
636
|
+
## Export stability
|
|
637
|
+
|
|
638
|
+
| Export or entry point | Consumer | Stability | Versioning and deprecation rule | Declaration or API report |
|
|
639
|
+
| --------------------------------------------- | --------------------------------- | -------------------------------- | -------------------------------------------------------------------------------------------------- | ------------------------- |
|
|
640
|
+
| Default export, `getOSNameInternal` | Workspace siblings | Internal plugin; additive | Internal plugin: not strictly semver; coordinate removals with every dependent workspace package | `src/index.ts` |
|
|
641
|
+
| `NewMetrics`, `BehavioralMetrics`, `OperationalMetrics`, `BusinessMetrics`, `PreLoginMetrics` | Workspace siblings | Internal; additive | Same | `src/index.ts` |
|
|
642
|
+
| `config`, `Utils`, `AutomatedUserUtils`, `isAutomatedUser`, `isAutomatedUserAgent` | Workspace siblings | Internal; additive | Same | `src/index.ts` |
|
|
643
|
+
| Exported types | Workspace siblings | Internal; derived from the event dictionary | Type changes follow the pinned event dictionary version | `src/metrics.types.ts` |
|
|
644
|
+
| `main` and `types` entry points | npm consumers | Published | Must keep resolving to `dist/index.js` and `dist/types/index.d.ts` | `package.json` |
|
|
645
|
+
|
|
646
|
+
<!-- Include if: the module is embedded in a host application. [condition-id: module.embedded_in_host] -->
|
|
647
|
+
|
|
648
|
+
## Host integration and theming
|
|
649
|
+
|
|
650
|
+
- Mount or entry contract: importing `src/index.ts` registers `metrics` with the shared config and an
|
|
651
|
+
`onBeforeLogout` hook that stops network telemetry, and registers `newMetrics` with the same config.
|
|
652
|
+
- Required providers, peers, or host versions: a `WebexCore` instance from `@webex/webex-core`; a
|
|
653
|
+
registered device for tagged events; host configuration under the `metrics` namespace; and, for
|
|
654
|
+
Call Analyzer origin, meetings configuration supplying client types.
|
|
655
|
+
- Theme and design-token contract: not applicable — the package renders nothing.
|
|
656
|
+
- Accessibility and lifecycle obligations: the host must import the package before constructing the
|
|
657
|
+
SDK instance; logout awaits the final telemetry submission.
|
|
658
|
+
|
|
659
|
+
<!-- Include if: the module has a non-obvious design trade-off consumers or maintainers must preserve. [condition-id: module.has_design_tradeoff] -->
|
|
660
|
+
|
|
661
|
+
## Key design trade-off
|
|
662
|
+
|
|
663
|
+
| Chosen trade-off | Preserved invariant or benefit | Cost or limitation | Decision evidence |
|
|
664
|
+
| ---------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------ | -------------------------- |
|
|
665
|
+
| Reset the telemetry window at the reporting boundary before the asynchronous submission | Requests received while a summary is being sent belong to the next window, and the transport's own requests cannot mutate a completed window | A telemetry submission failure is caught and logged, and that window is dropped; nothing is retried | `src/network-telemetry.ts` |
|
|
666
|
+
| Reuse `submitClientMetrics` batching and transport for summaries | Summaries inherit batching and network-error backoff with no new transport; they never pass a pre-login identifier, so they always use the client-metrics batcher | Summaries are subject to the same batcher delays as all client metrics | `src/metrics.js` |
|
|
667
|
+
| Listen to SDK-wide request events instead of wrapping `webex.request()` | Individual plugins need no changes, and every request through the pipeline is observed | Traffic outside the SDK pipeline is invisible, and the events have no shared typed contract | `src/network-telemetry.ts` |
|
|
668
|
+
| Keep two façades rather than merging them | Existing consumers of `metrics` keep working while new families land on `newMetrics` | Two entry points with overlapping responsibility, and the pre-login path lives only on the older one | `src/new-metrics.ts` |
|
|
669
|
+
|
|
670
|
+
## Verification
|
|
671
|
+
|
|
672
|
+
| Requirement or invariant | Test level | Positive evidence | Negative or boundary evidence | Gap |
|
|
673
|
+
| ------------------------ | ---------- | ---------------------------------------------------- | ---------------------------------------------------- | -------------------------------------------------------------------------------- |
|
|
674
|
+
| `MOD-001` | Unit | `test/unit/spec/network-telemetry.ts` | none found | The `onBeforeLogout` registration is not exercised |
|
|
675
|
+
| `MOD-002` | Unit | `test/unit/spec/new-metrics.ts` | `test/unit/spec/new-metrics.ts` | none |
|
|
676
|
+
| `MOD-003` | Unit | `test/unit/spec/new-metrics.ts` | none found | none |
|
|
677
|
+
| `MOD-004` | Unit | `test/unit/spec/behavioral/behavioral-metrics.ts` | `test/unit/spec/behavioral/behavioral-metrics.ts` | none |
|
|
678
|
+
| `MOD-005` | Unit | `test/unit/spec/new-metrics.ts` | `test/unit/spec/new-metrics.ts` | none |
|
|
679
|
+
| `MOD-006` | Unit | `test/unit/spec/new-metrics.ts` | none found | none |
|
|
680
|
+
| `MOD-007` | Unit | `test/unit/spec/metrics.js` | `test/unit/spec/metrics.js` | none |
|
|
681
|
+
| `MOD-008` | Unit | `test/unit/spec/metrics.js` | `test/unit/spec/metrics.js` | none |
|
|
682
|
+
| `MOD-009` | Unit | `test/unit/spec/metrics.js` | `test/unit/spec/client-metrics-prelogin-batcher.ts` | none |
|
|
683
|
+
| `MOD-010` | Unit | `test/unit/spec/prelogin-metrics-batcher.ts` | `test/unit/spec/prelogin-metrics-batcher.ts` | none |
|
|
684
|
+
| `MOD-011` / `INV-007` | Unit | `test/unit/spec/batcher.js` | `test/unit/spec/batcher.js` | none |
|
|
685
|
+
| `MOD-012` | Unit | `test/unit/spec/network-telemetry.ts` | `test/unit/spec/network-telemetry.ts` | none |
|
|
686
|
+
| `MOD-013` | Unit | none found | none found | Deferred `change:config` initialization and the standalone early return are untested |
|
|
687
|
+
| `MOD-014` / `INV-002` | Unit | `test/unit/spec/network-telemetry.ts` | `test/unit/spec/network-telemetry.ts` | none |
|
|
688
|
+
| `MOD-015` / `INV-003` | Unit | `test/unit/spec/network-telemetry.ts` | `test/unit/spec/network-telemetry.ts` | The `request_error` fallback has no case |
|
|
689
|
+
| `MOD-016` / `INV-004` | Unit | `test/unit/spec/network-telemetry.ts` | `test/unit/spec/network-telemetry.ts` | none |
|
|
690
|
+
| `MOD-017` / `INV-001` | Unit | `test/unit/spec/network-telemetry.ts` | `test/unit/spec/network-telemetry.ts` | none |
|
|
691
|
+
| `MOD-018` / `INV-005` | Unit | `test/unit/spec/network-telemetry.ts` | `test/unit/spec/network-telemetry.ts` | none |
|
|
692
|
+
| `MOD-019` | Unit | `test/unit/spec/network-telemetry.ts` | none found | none |
|
|
693
|
+
| `MOD-020` | Unit | `test/unit/spec/network-telemetry.ts` | `test/unit/spec/network-telemetry.ts` | Requests without timing metadata report zero; no case feeds non-finite or inverted timing pairs |
|
|
694
|
+
| `MOD-021` | Unit | `test/unit/spec/network-telemetry.ts` | `test/unit/spec/network-telemetry.ts` | none |
|
|
695
|
+
| `INV-006` | Unit | none found | none found | No case flushes or stops an empty window; the skip in `flush()` is unverified |
|
|
696
|
+
| `MOD-022` | Unit | `test/unit/spec/network-telemetry.ts` | `test/unit/spec/network-telemetry.ts` | No case flushes or stops with an empty window |
|
|
697
|
+
| `MOD-023` | Unit | `test/unit/spec/network-telemetry.ts` | `test/unit/spec/network-telemetry.ts` | none |
|
|
698
|
+
| `MOD-024` | Unit | `test/unit/spec/business/business-metrics.ts` | `test/unit/spec/business/business-metrics.ts` | none |
|
|
699
|
+
| `MOD-025` | Unit | `test/unit/spec/automated-user.ts` | `test/unit/spec/automated-user.ts` | none |
|
|
700
|
+
|
|
701
|
+
Record coverage gaps explicitly and link follow-up work. A module specification
|
|
702
|
+
is complete only when its public surface, invariants, failure modes, and test
|
|
703
|
+
evidence agree with the implementation.
|