Skip to content

feat: unified trace waterfall with GraphQL field tracing and a request lifecycle band - #220

Open
fpasquet wants to merge 3 commits into
mainfrom
feat/unified-trace-waterfall
Open

feat: unified trace waterfall with GraphQL field tracing and a request lifecycle band#220
fpasquet wants to merge 3 commits into
mainfrom
feat/unified-trace-waterfall

Conversation

@fpasquet

Copy link
Copy Markdown
Contributor

Summary

Turns the Timeline panel into a unified, causally-nested trace waterfall. A new buildTrace step assembles a TraceSpan tree (Profile.trace) that merges every timed operation of a request on one time axis — lifecycle phases (startSpan), outgoing HTTP calls, database queries and each GraphQL resolveField — nested by causality (an explicit parent, else time containment). Spans carry their performance tags (slow, N+1) and self-time, are collapsible, and deep-link to their source panel row.

  • GraphQL field tracingcreateProfilerFieldMiddleware (code-first) times each resolveField and opens a nested CLS scope so the DB/HTTP calls it issues are stamped as its children; an N+1 reads as one field with its repeated child queries. traceFields / minFieldMs tune what is traced.
  • Request Lifecycle band — a flat, Symfony-profiler-style breakdown (guards, controller, validation) above the waterfall for HTTP requests, controlled by the new lifecycleSpans option. Zero-duration phases are dropped; GraphQL/commands/messages keep their own breakdown.
  • Every profile gets a Timeline — the entrypoint root is always emitted, so bare HTTP requests, CLI commands and consumed messages are no longer empty.
  • Example — the GraphQL field middleware is wired into examples/api, and a FEATURE_DATALOADER flag batches Product.reviews to compare the N+1 shape (4 queries) with the batched shape (1 query) in the trace.

Non-breaking: Profile.spans / startSpan still work, and all new fields, options and exports are additive.

Related issue

None.

Checklist

  • Tests were added or updated to cover the change
  • Documentation was added or updated
  • A changeset was added, or this PR does not affect published packages
  • Breaking changes use a major changeset with a BREAKING: note

Breaking changes

  • This PR includes breaking changes

@vercel

vercel Bot commented Jul 18, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
nest-profiler Ready Ready Preview, Comment Jul 22, 2026 7:11pm
nest-profiler-example Ready Ready Preview, Comment Jul 22, 2026 7:11pm

@github-actions github-actions Bot added scope: packages Change to a publishable package scope: docs Change to the documentation site scope: examples Change to example applications package: nest-profiler Affects the @eleven-labs/nest-profiler package package: nest-profiler-typeorm Affects the @eleven-labs/nest-profiler-typeorm package package: nest-profiler-mongoose Affects the @eleven-labs/nest-profiler-mongoose package package: nest-profiler-validator Affects the @eleven-labs/nest-profiler-validator package package: nest-profiler-graphql Affects the @eleven-labs/nest-profiler-graphql package package: nest-profiler-mikro-orm Affects the @eleven-labs/nest-profiler-mikro-orm package package: nest-profiler-commander Affects the @eleven-labs/nest-profiler-commander package package: nest-profiler-http Affects the @eleven-labs/nest-profiler-http package labels Jul 18, 2026
@fpasquet
fpasquet force-pushed the feat/unified-trace-waterfall branch from 313c764 to f523877 Compare July 18, 2026 13:14
@github-actions github-actions Bot added the scope: ci Change to CI/CD workflows or tooling label Jul 18, 2026
@fpasquet
fpasquet marked this pull request as ready for review July 18, 2026 13:14
@fpasquet
fpasquet force-pushed the feat/unified-trace-waterfall branch from f523877 to 6a5d2a1 Compare July 19, 2026 05:40
fpasquet added 3 commits July 22, 2026 21:04
… with a lifecycle band

- assemble a causal TraceSpan tree (buildTrace) merging phases, HTTP, DB and GraphQL-field spans
- nest spans under a reported parentId, else the tightest enclosing container by time, else the root
- only containers (entrypoint, phase, GraphQL field, opt-in `container: true`) adopt children by time, so calls fired concurrently stay siblings instead of chaining into a fictitious ancestry
- widen a parent onto its children when it stopped being timed before the work it triggered resolved
- time every measured surface with a sub-millisecond clock (utils/clock) instead of Date.now(), whose rounding collapsed a whole unit of work onto one instant
- render durations in the unit that fits them (ns, µs, ms, s, m, h) so nothing measured reads as 0ms
- wrap each SQL `BEGIN … COMMIT/ROLLBACK` run in a synthetic transaction span covering the unit of work
- trace each GraphQL resolveField and stamp its span on the DB/HTTP calls it issues
- surface performance tags and self-time on spans; deep-link DB/HTTP spans to their panel row
- compute self-time against the union of the children's intervals, not the sum of their durations
- add a flat request-lifecycle band (guards, controller, validation) above the waterfall (HTTP-only)
- give the badge column a fixed width so a tagged row keeps the same time axis as its neighbours
- always emit the entrypoint root so every HTTP request, command and message gets a Timeline
…g and a DataLoader flag

- wire the GraphQL field middleware into the catalog schema so resolveField spans are traced
- add a FEATURE_DATALOADER flag batching Product.reviews to compare N+1 vs one query in the trace
…ecycle band

- rewrite the Timeline section as the unified nested trace waterfall (self-time, tags, deep-links)
- explain containers versus leaves, and why the `% of total` column does not sum to 100%
- document the sub-millisecond clock and the unit-following duration format
- refresh the Timeline screenshot as a GraphQL N+1 waterfall + a DataLoader-batched counterpart
- teach the screenshots script to shoot both traces (N+1 and DataLoader-batched)
- describe the flat Request Lifecycle band and the lifecycleSpans option
- add createProfilerFieldMiddleware + FieldTracingOptions to the GraphQL guide and API reference
- note the field middleware must be registered conditionally for zero cost when the profiler is off
- update the setup/harden/collector skills for GraphQL field tracing and the lifecycleSpans option
- add TraceSpan and LifecyclePhase to the core API reference
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

package: nest-profiler Affects the @eleven-labs/nest-profiler package package: nest-profiler-cache Affects the @eleven-labs/nest-profiler-cache package package: nest-profiler-commander Affects the @eleven-labs/nest-profiler-commander package package: nest-profiler-graphql Affects the @eleven-labs/nest-profiler-graphql package package: nest-profiler-http Affects the @eleven-labs/nest-profiler-http package package: nest-profiler-mikro-orm Affects the @eleven-labs/nest-profiler-mikro-orm package package: nest-profiler-mongoose Affects the @eleven-labs/nest-profiler-mongoose package package: nest-profiler-rabbitmq Affects the @eleven-labs/nest-profiler-rabbitmq package package: nest-profiler-typeorm Affects the @eleven-labs/nest-profiler-typeorm package package: nest-profiler-validator Affects the @eleven-labs/nest-profiler-validator package scope: ci Change to CI/CD workflows or tooling scope: docs Change to the documentation site scope: examples Change to example applications scope: packages Change to a publishable package

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant