Skip to content

chore(tracing): extract format, reader, and writer (TracingSession) into packages/tracing#40671

Open
dgozman wants to merge 6 commits intomicrosoft:mainfrom
dgozman:extract-tracing-package
Open

chore(tracing): extract format, reader, and writer (TracingSession) into packages/tracing#40671
dgozman wants to merge 6 commits intomicrosoft:mainfrom
dgozman:extract-tracing-package

Conversation

@dgozman
Copy link
Copy Markdown
Collaborator

@dgozman dgozman commented May 6, 2026

Summary

Pulls the trace format types, the reader/model, and a new disk-backed TracingSession writer out of playwright-core and the test runner into a self-contained packages/tracing/ library with no @protocol/* or Playwright-server dependency.

  • packages/tracing/src/format/ — was packages/trace/src/. New protocolTypes.ts carries local copies of the small structural types previously imported from @protocol/channels (StackFrame, Point, SerializedError, ClientSideCallMetadata).
  • packages/tracing/src/reader/ — was packages/isomorphic/trace/.
  • packages/tracing/src/writer/ — new. TracingSession is the disk-backed state machine extracted from server tracing.ts (RecordingState, SerializedFS, append/resource/network/zip lifecycle, group stack, source-file collection). zip.ts / stackSession.ts are the trace-related halves of LocalUtils. mergeTraceFiles.ts and snapshotterInjected.ts co-locate here too.
  • Server tracing.ts and worker testTracing.ts are now thin wrappers over TracingSession. The test runner's in-memory _traceEvents[] buffer and separate live-trace file are gone — events stream to disk through the session.
  • HAR helpers in localUtils.ts are intentionally left untouched (not strictly trace-related).
  • progress: Progress parameters in the moved zip / stack-session functions become signal: AbortSignal + a small local race(signal, promise) helper.

The branch is split into seven self-contained commits, each green on flint and the trace + library + artifacts test suites.

dgozman added 6 commits May 6, 2026 12:54
Move the trace format types from packages/trace/ and the reader/model
from packages/isomorphic/trace/ into a new packages/tracing/ library
(format/ + reader/ + versions under format/). Drop the @trace/* alias
in favor of @tracing/*; @isomorphic/trace/* path is gone (callers
repointed to @tracing/reader/*). Local copies of small protocol types
(StackFrame, Point, SerializedError, ClientSideCallMetadata) live in
packages/tracing/src/format/protocolTypes.ts so the new package has
no @protocol/* dependency.

This is a pure code motion + import rename. Phase 1 of a larger
refactor that will also extract a TracingSession writer (server-side
trace recording state machine) into packages/tracing/src/writer/.
Move the trace zip assembly (`zip`) and call-stack session bookkeeping
(`tracingStarted`, `traceDiscarded`, `addStackToTracingNoReply`) out of
`packages/playwright-core/src/server/localUtils.ts` and into
`packages/tracing/src/writer/`. The library functions take an
`AbortSignal` instead of a `Progress`; a tiny `race(signal, promise)`
helper in `packages/tracing/src/writer/race.ts` does the
abort-vs-promise race. The dispatcher passes `progress.signal` and
keeps the outer `progress.race(...)` so the eslint progress-rule
stays satisfied. HAR functions in `localUtils.ts` are left untouched.

The new package has no package.json; sources are bundled and
deps live in the root devDependencies. Per-file
\`node_modules/{fs,os,path,events,yauzl,yazl,mime}\` declarations
in \`packages/tracing/src/DEPS.list\` cover what writer/ needs.
…kages/tracing/writer

snapshotterInjected.ts is pure DOM logic (no Playwright internals)
and now lives next to the rest of the writer; snapshotter.ts
imports it via @tracing/writer/snapshotterInjected.

mergeTraceFiles, previously a private helper at the bottom of
testTracing.ts, is now a generic library function. The
test-trace-entry-name special case is exposed as an
optional `keepEntryName` parameter; the test runner passes
`testTraceEntryName`.
…nto it

Extract the disk-backed writer state machine — RecordingState
(traceFile/networkFile/resourcesDir/chunkOrdinal/sha1 sets/recording/groupStack),
the SerializedFS and tmp-dir lifecycle, the appendTraceEvent /
appendResource / appendNetworkEntry path-and-flush logic, the
chunk-allocate / change-trace-name routines, and group / groupEnd /
closeAllGroups bookkeeping — out of
packages/playwright-core/src/server/trace/recorder/tracing.ts and into
packages/tracing/src/writer/tracingSession.ts.

The session takes an AbortSignal (not a Progress) on stopChunk/stop
and uses the local race() helper. A small `replacer` callback handles
non-JSON-serializable values (Dispatcher, Buffer, Date) so the session
itself stays free of Playwright server types.

Server-side Tracing keeps its InstrumentationListener / Snapshotter /
HarTracer / screencast roles and forwards every event into the
session. _callIds and the original start() options (needed for
snapshotter/screencast wiring) move from the recording state onto
Tracing as plain fields. tracing.ts drops from ~830 lines to ~530;
the rest is the listener methods and screencast/snapshotter glue
that genuinely depend on Playwright internals.
Drop the in-memory _traceEvents[] buffer and the separate _liveTraceFile
plumbing in packages/playwright/src/worker/testTracing.ts. Test-runner
events now stream to disk through a TracingSession (one chunk per test,
trace name "<testId>[-retry<N>]-test" so the live viewer's testId-prefix
scan still finds the on-disk .trace file). The final trace.zip is built
by session.stopChunk('archive') and merged with playwright-core's
per-context chunks via mergeTraceFiles.

Attachments and source files are now resolved at append time (sync
fs.readFileSync) and stored as session resources keyed by content sha1
(or src@<pathSha1>.txt for sources). The _options.attachments=false /
sources=false toggles work by skipping the resource step before
emitting the trace event, instead of via a finalize-time filter pass.

testTimeout can change late in the test, so testTracing emits
context-options twice: once at chunk start (with the value at that
point, possibly undefined) and once again in stopIfNeeded with the
final testInfo.timeout. The reader processes events in order and
overwrites context-entry fields, so last-write-wins gives the right
testTimeout in the model.

Two TracingSession tweaks went alongside:
- New `traceEntryName` option (default 'trace.trace'). The test runner
  passes 'test.trace' so its main entry survives mergeTraceFiles
  unrenamed.
- startChunk no longer auto-emits contextCreatedEvent. Callers
  (server Tracing and TestTracing) now appendTraceEvent it
  explicitly — server patches walltime/monotonic at chunk start;
  TestTracing emits the constructor-time copy and re-emits at stop.
When `sources: true` is set on TracingSession.start(), the session now
walks event.stack[].file for the two event types that carry a stack
('before' and 'error') and accumulates unique source-file paths
per-chunk. At stopChunk time those files are embedded as
`resources/src@<pathSha1>.txt` entries directly from disk (no copy
through resourcesDir).

testTracing.ts loses its _appendSourcesFromStack helper and the
_emittedSourceFiles dedup set: it now just passes
`sources: !!_options.sources` to session.start() and the session does
the rest. As a side effect the per-step sync fs.readFileSync on every
appendBeforeActionForStep / appendForError goes away — source reads
happen once at chunk stop.

Server-side Tracing opts out explicitly with `sources: false`
(per-context source embedding is owned by LocalUtils.zip via the
StackSession callStacks, not the session, so leaving it on would
have been redundant — and worse, would have started pulling
source files in for tracing.group event stacks).

A new tiny helper packages/tracing/src/writer/sourceFiles.ts owns
the `resources/src@<pathSha1>.txt` naming convention so both
TracingSession.stopChunk and LocalUtils.zip use the same form.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants