feat(webview): thin telemetry middleware + generic TelemetryRunner (@microsoft/vscode-ext-webview 0.10.0)#795
feat(webview): thin telemetry middleware + generic TelemetryRunner (@microsoft/vscode-ext-webview 0.10.0)#795tnaum-ms wants to merge 18 commits into
Conversation
Redesign the telemetry middleware to a thin, dependency-free delegator that
resolves the event id and hands control to a generic TelemetryRunner<TEnrichment>.
The runner owns the telemetry scope, chooses what to contribute to ctx via
next({ ctx }), and classifies the outcome from the returned result. Duration is
recorded by the runner backend (e.g. callWithTelemetryAndErrorHandling).
- TelemetryRunner is generic over the ctx enrichment; run(eventId, invocation, invoke).
- telemetryMiddlewareBody(runner, { buildEventId }) is curried.
- Remove the body duration/result stamping and the WithTelemetry helper.
- Add TelemetryMiddlewareOptions.buildEventId.
Return mergeRouters from initWebviewTrpc() and re-export a default-instance mergeRouters from the shared entry, so multi-router consumers can compose a view main router with its events/subscription router without importing initTRPC/mergeRouters directly from @trpc/server.
- Re-export the AnyRouter type from the shared (.) and ./react entries so consumers writing generic client helpers do not import @trpc/server directly (./host already re-exported it). - Replace ProcedureLogger.log with optional onStart/onEnd hooks for symmetric span-style logging; loggingMiddlewareBody fires onStart before next() and onEnd after. Update consoleProcedureLogger, attachTrpc dispatch, and tests.
Adopt the new thin telemetry body in the extension integration layer: - documentDbTelemetryRunner is now TelemetryRunner<RpcEnrichment> and injects the full IActionContext as ctx.actionContext (honest naming), replacing the as-unknown-as-ProcedureTelemetry bridge. - The runner owns outcome classification (Canceled/Failed + parseError error, errorMessage, errorStack, errorCause); duration comes free from callWithTelemetryAndErrorHandling. - Event ids are declarative via buildEventId. - Declare actionContext on the DocumentDB BaseRouterContext so per-view RouterContext types expose it; remove the WithTelemetry helper.
- Replace every `ctx as WithTelemetry<RouterContext>` cast with `ctx as RouterContext` and read `ctx.actionContext.telemetry` across the collection, index, document, and query-insights routers. - Declare `actionContext: IActionContext` on each view RouterContext; view controllers build the root context as Omit<RouterContext, "actionContext"> since the runner injects it per call. - Compose queryInsights with the exposed mergeRouters (retire the flat-record spread workaround); export mergeRouters from the integration trpc module. - Update rpcConcurrencyLogger (+ test) to the ProcedureLogger.onEnd hook.
- Rewrite the ADVANCED.md telemetry adapters section for the thin body and generic TelemetryRunner; update the logger example to onStart/onEnd; replace the WithTelemetry section with contributed-context guidance. - Update README telemetry/logging examples to the new shapes. - Add MIGRATION.md documenting the 0.9.0-preview to 0.9.1-preview upgrade.
There was a problem hiding this comment.
Pull request overview
This PR updates the shared @microsoft/vscode-ext-webview package and the DocumentDB extension’s webview integration to a new telemetry/logging API: telemetry middleware becomes a thin delegator with a generic TelemetryRunner<TEnrichment>, procedure logging gains onStart?/onEnd?, and router composition is standardized via a re-exported mergeRouters.
Changes:
- Refactors telemetry middleware to delegate event-id resolution + context enrichment to a generic
TelemetryRunner, and migrates DocumentDB webview routers to consumectx.actionContext.telemetry. - Exposes and adopts
mergeRoutersto compose Query Insights query/mutation + subscription routers without direct@trpc/serverimports. - Updates logging API from
ProcedureLogger.logto optionalonStart/onEnd, and migrates the concurrency logger + tests accordingly.
Reviewed changes
Copilot reviewed 28 out of 28 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| src/webviews/documentdb/documentView/documentsViewRouter.ts | Migrates router context typing and procedure handlers to use ctx.actionContext model. |
| src/webviews/documentdb/documentView/documentsViewController.ts | Types root tRPC context as Omit<RouterContext, 'actionContext'> to reflect per-call injection. |
| src/webviews/documentdb/collectionView/queryInsights/queryInsightsRouter.ts | Switches telemetry usage to actionContext, and composes routers via mergeRouters. |
| src/webviews/documentdb/collectionView/queryInsights/queryInsightsEventsRouter.ts | Converts subscription exports to a router for mergeRouters composition; updates ctx narrowing. |
| src/webviews/documentdb/collectionView/collectionViewRouter.ts | Adds actionContext to router context and migrates telemetry writes to actionContext.telemetry. |
| src/webviews/documentdb/collectionView/collectionViewController.ts | Types root tRPC context as Omit<RouterContext, 'actionContext'>. |
| src/webviews/_integration/trpc.ts | Implements DocumentDB TelemetryRunner<RpcEnrichment> and wires curried telemetryMiddlewareBody. |
| src/webviews/_integration/README.md | Updates integration-layer docs to reflect RpcEnrichment / actionContext model. |
| src/webviews/_integration/observability/rpcConcurrencyLogger.ts | Migrates to ProcedureLogger.onEnd and updates dev-only console logging call. |
| src/webviews/_integration/observability/rpcConcurrencyLogger.test.ts | Updates tests to the new onEnd logger hook. |
| src/webviews/_integration/appRouter.ts | Removes WithTelemetry re-export and updates docs/examples to ctx as RouterContext narrowing. |
| packages/vscode-ext-webview/src/shared/initWebviewTrpc.ts | Returns and re-exports mergeRouters from the initialized tRPC instance. |
| packages/vscode-ext-webview/src/shared/initWebviewTrpc.test.ts | Adds coverage for mergeRouters behavior via a composed router caller. |
| packages/vscode-ext-webview/src/shared/index.ts | Re-exports mergeRouters and type-only AnyRouter from the shared entry. |
| packages/vscode-ext-webview/src/shared/BaseRouterContext.ts | Updates docs to reflect runner-owned context enrichment and optional telemetry bag semantics. |
| packages/vscode-ext-webview/src/react/index.ts | Re-exports type-only AnyRouter from the React entry. |
| packages/vscode-ext-webview/src/host/middleware/telemetry.ts | Refactors telemetry middleware to curried thin delegator + generic runner contract. |
| packages/vscode-ext-webview/src/host/middleware/telemetry.test.ts | Updates tests to reflect delegated event-id + runner-owned outcome classification. |
| packages/vscode-ext-webview/src/host/middleware/logging.ts | Replaces log with optional onStart/onEnd hooks and emits start/end events. |
| packages/vscode-ext-webview/src/host/middleware/logging.test.ts | Updates tests to onEnd and adds coverage for onStart ordering. |
| packages/vscode-ext-webview/src/host/middleware/index.ts | Updates host middleware exports for new logging/telemetry types and removes WithTelemetry. |
| packages/vscode-ext-webview/src/host/index.ts | Updates top-level host exports for new middleware type surface. |
| packages/vscode-ext-webview/src/host/attachTrpc.ts | Updates dispatch logging call-site to use logger.onEnd?.(...). |
| packages/vscode-ext-webview/src/host/attachTrpc.test.ts | Migrates logger mocks/usages to onEnd. |
| packages/vscode-ext-webview/README.md | Updates public docs/snippets for new telemetry runner contract and logger hooks. |
| packages/vscode-ext-webview/package.json | Bumps package version to 0.9.2. |
| packages/vscode-ext-webview/MIGRATION.md | Adds 0.9.1 → 0.9.2 migration guide for telemetry/logger/mergeRouters/AnyRouter. |
| packages/vscode-ext-webview/ADVANCED.md | Updates advanced docs to the new logger hooks and runner-owned context enrichment model. |
The 0.9.1 -> 0.9.2 bump shipped source-breaking API changes (generic TelemetryRunner, curried telemetry body, removed WithTelemetry, reshaped ProcedureLogger) as a patch. For a pre-1.0 package, npm treats 0.9.2 as satisfying the common ^0.9.1 caret range (>=0.9.1 <0.10.0), so consumers would receive breaking changes on a clean install without opting in. Bump to 0.10.0 (minor) so the release falls outside ^0.9.1 and upgrades are opt-in. Update MIGRATION.md heading to 0.9.1 -> 0.10.0, the After label, and add a note explaining the minor-bump rationale. Sync the package-lock workspace entry to 0.10.0.
F1 addressed — breaking changes now ship as
|
The dispatch pump advertised the symmetric ProcedureLogger contract (onStart? / onEnd?) but only invoked onEnd, so a consumer passing an onStart-only logger through the panel telemetry option received no events at all. attachTrpc now fires onStart exactly once before each query, mutation, and subscription runs, paired one-to-one with the existing onEnd - even when procedure setup fails, the start hook has already fired and the outer catch still logs the matching completion. Both hooks stay optional. - Add a logProcedureStart helper mirroring logProcedure. - Fire it in handleDefaultMessage and handleSubscriptionMessage before the procedure runs. - Add transport tests for onStart/onEnd ordering, exactly-once delivery, early subscription setup failure, and onStart-only loggers. - Document the dispatch-layer onStart/onEnd behavior in ADVANCED.md.
F2 addressed —
|
PR #795 removed the WithTelemetry helper and replaced the per-call ctx.telemetry slot with an injected ctx.actionContext (the full IActionContext contributed by the DocumentDB TelemetryRunner). The two skill guides still taught the deleted APIs, so the examples no longer compile and the "trpcToTelemetry" narrative no longer matches the code. webview-trpc-messaging/SKILL.md: - Drop the WithTelemetry import and casts; narrow with `ctx as RouterContext` and read telemetry via `ctx.actionContext.telemetry`. - Remove WithTelemetry from the trpc.ts key-files row (now RpcEnrichment contributed to ctx.actionContext). - Replace the "trpcToTelemetry (file-local)" description with telemetryMiddlewareBody delegating to the DocumentDB TelemetryRunner. - Fix the telemetry column of the publicProcedure comparison table and the abort/subscription examples and pitfalls list. - Frontmatter: telemetry middleware example name -> telemetryMiddlewareBody. telemetry-instrumentation/SKILL.md: - tRPC procedures section now reads ctx.actionContext.telemetry after narrowing to RouterContext (the callWithTelemetryAndErrorHandling examples that use ctx.telemetry are unchanged - there ctx *is* the action context).
F4 addressed — skill guides updated to the
|
The telemetry reshape in this PR removed the trpcToTelemetry helper name (the equivalent is now telemetryMiddlewareBody delegating to the DocumentDB TelemetryRunner) and moved the per-call telemetry slot from ctx.telemetry to ctx.actionContext. Three explanatory comments in queryInsightsEventsRouter.ts still referenced the old names, which misdescribed how the Stage 3 completion event relates to middleware timing. Comment-only change; no behavior change.
F5 addressed — refreshed stale
|
…chment (F3) Previously each view's RouterContext declared actionContext as a required field, and controllers subtracted it with Omit<RouterContext, 'actionContext'>. That let an uninstrumented procedure (documentsView getInfo on plain publicProcedure) cast ctx as RouterContext and assert actionContext exists even though the telemetry runner never injected it - a latent TypeError waiting for the first myCtx.actionContext access. Invert the model (Option C): actionContext is no longer part of the base RouterContext. Add WithTelemetry<T> = T & RpcEnrichment in trpc.ts and narrow to WithTelemetry<RouterContext> only in publicProcedureWithTelemetry procedures that actually read actionContext. Plain publicProcedure procedures narrow to bare RouterContext, so reading actionContext there is now a compile error instead of a runtime undefined. - trpc.ts: add + export WithTelemetry<T>; update RpcEnrichment docs. - appRouter.ts: re-export type WithTelemetry. - collectionViewRouter / documentsViewRouter: drop actionContext from RouterContext; flip the instrumented casts that read it. - queryInsightsRouter: flip Stage1/Stage2 casts. - controllers: root context is now plain RouterContext (no Omit). - D1: instrument documentsView.getInfo (publicProcedureWithTelemetry + WithTelemetry<RouterContext>) to match collectionView.getInfo, making its cast honest. - Update the webview-trpc-messaging and telemetry-instrumentation skill guides to teach the WithTelemetry<RouterContext> narrowing.
F3 addressed —
|
- README.md: Status line 0.9.0-preview -> 0.10.0 (matches package.json).
- MIGRATION.md: document the additive WithTelemetry<T> = T & { actionContext }
consumer pattern as the recommended alternative to baking actionContext
into RouterContext + Omit, so an uninstrumented (plain publicProcedure)
procedure can't assert an actionContext that was never injected. This is
the pattern the DocumentDB reference extension now uses (F3).
Verified: l10n (no string changes), prettier, eslint, full jest (2674),
and build all pass.
Final documentation & 0.10.0 migration reviewCommit: 87f3766 Swept all manuals, docs, and skills for
Reviewed and confirmed already-consistent (no change needed):
Verification (full PR checklist):
|
…WithTelemetry cast
Follow-up — skill example consistencyCommit: 4c7cf5c Audited every One internal inconsistency fixed: the |
|
@microsoft-github-policy-service |
…ailed fix explanations
✅ Code Quality Checks
This comment is updated automatically on each push. |
📦 Build Size Report
Download artifact · updated automatically on each push. |
Summary
De-engineers the
@microsoft/vscode-ext-webviewtelemetry middleware and adopts the new shape across the extension's webviews. Based on feedback from thevscode-cosmosdbintegration attempt, the telemetry body becomes a thin delegator and theTelemetryRunnerbecomes generic over the context enrichment, so a consumer's runner owns the telemetry scope, chooses what to contribute toctx, and classifies the outcome. Duration and error classification are no longer duplicated by the package — the runner's backend (e.g.callWithTelemetryAndErrorHandling) already records them.Bumps the package
0.9.1→0.10.0(minor, not patch — see Breaking changes).Package changes (
@microsoft/vscode-ext-webview)TelemetryRunner<TEnrichment>.run(eventId, invocation, invoke);telemetryMiddlewareBody(runner, { buildEventId })is curried and wires aspublicProcedure.use(telemetryMiddlewareBody(runner, options)); the body no longer stamps duration/result.ProcedureLoggergains symmetric optionalonStart/onEndhooks (replaces the singlelog). Both fire at the dispatch layer (attachTrpc), paired one-to-one:onStartruns once before each query/mutation/subscription, and a matchingonEndalways follows — including on early setup failure. AnonStart-only logger passed through the panel option now receives events.mergeRoutersis now returned frominitWebviewTrpc()and re-exported from the shared entry (no more direct@trpc/serverimport to compose routers).AnyRouteris re-exported from.and./react(was already on./host).See
packages/vscode-ext-webview/MIGRATION.mdfor the full0.9.1 → 0.10.0upgrade guide, and the updatedADVANCED.md/README.md.Extension changes
IActionContextasctx.actionContext.actionContextis not a field on the baseRouterContext; it is modeled as an additive enrichment (WithTelemetry<T> = T & RpcEnrichmentin_integration/trpc.ts). Instrumented procedures (publicProcedureWithTelemetry) narrow toWithTelemetry<RouterContext>to readctx.actionContext.telemetry; plainpublicProcedureprocedures narrow to bareRouterContext, so readingactionContextthere is a compile error instead of a runtimeundefined. Controllers build the plainRouterContext(noOmit<...>root type).mergeRouters(retires the flat-record workaround).rpcConcurrencyLoggeradopts theonEndhook..github/skills/authoring guides (webview-trpc-messaging,telemetry-instrumentation) and the staletrpcToTelemetrycode comments inqueryInsightsEventsRouter.tsare updated to the newtelemetryMiddlewareBody/TelemetryRunner/ctx.actionContextsurface.Breaking changes
The package is pre-1.0; the telemetry/logger API changes are breaking but internal — only this extension and
vscode-cosmosdbconsume the package. The release is a minor bump (0.10.0), not a patch: a patch (0.9.2) satisfies the common^0.9.1range (>=0.9.1 <0.10.0), so consumers would have received the breaking release on a clean install. The minor bump moves it outside that range, making the upgrade opt-in. All changes are documented inMIGRATION.md.Review dispositions
next({ ctx }): not reproducible. tRPC v11 shallow-merges the override over the existing context ({ ...opts.ctx, ...nextOpts.ctx }), so base fields (signal,sessionId,clusterId, …) are preserved. Thread resolved.getInfocast: fixed.documentsView.getInfois now instrumented, andactionContextmoved off the base context, so the cast is honest andtscenforces the invariant everywhere.Verification
npm run build✅ ·npm run lint✅jest: 2674 passingjest: 95 passing