Skip to content

refactor(tracing): add lazy typed trace events#228

Draft
evan-forbes wants to merge 4 commits into
mainfrom
reduce-tracing
Draft

refactor(tracing): add lazy typed trace events#228
evan-forbes wants to merge 4 commits into
mainfrom
reduce-tracing

Conversation

@evan-forbes

@evan-forbes evan-forbes commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

Motivation

Zakura's production JSONL trace events were assembled through mutable raw JSON maps at call sites. This scattered schema ownership across reactors and drivers, made required fields implicit, and performed some peer hashing and diagnostic projection work before knowing whether the trace channel could accept an event.

Solution

  • add typed JSONL tables, events, and a reserve-first JsonlEventEmitter while preserving the public raw-map compatibility API
  • move block reactor, peer-routine, sequencer, header/block driver, chain-tip mirror, handler, discovery, exchange, and legacy trace construction into owner-local trace modules
  • reduce production control flow to semantic trace_* calls while leaving metrics and ordinary tracing logs beside the state changes they observe
  • replace the zakurad commit-state property bag and key-dispatch helpers with typed owner projections
  • absorb newly added exact header-operation identities and legacy peer-attribution traces into typed, reserve-first owner projections
  • construct peer labels, display hashes, error strings, elapsed durations, collection counts, and event projections only after reserving channel capacity
  • preserve existing table names, file names, event names, field representations, ordering, and null-versus-omitted behavior
  • add literal JSON-order tests, parsed-shape tests, laziness tests, and inventory tests that reject serializer construction in core owner files

The block-sync sparse row projection remains internal to block-sync trace modules; it is no longer imported or constructed by reactor, peer-routine, or sequencer core logic.

Size

The initial PR state was GitHub +3,798/-2,309 (net +1,489) and +754 production Rust LoC by the counter below. The current PR is GitHub +6,344/-3,960 (net +2,384) and +1,289 production Rust LoC.

Production LoC is defined as non-blank, non-comment physical Rust lines excluding tests, testkit, benches, bench.rs, tests.rs, and brace-delimited items immediately preceded by #[cfg(test)]; strings and comments are stripped before brace counting. The semantic owner split was kept despite the increase because it removes serialization policy and mutable field assembly from production control flow.

Compatibility results

  • exact key-order and parsed-shape tests pass for the typed owner projections and optional branches
  • fixed handler null fields, sparse omissions, legacy-request null peers, numeric widths, hashed peers, display hashes, and error representations remain covered
  • disabled, full, and closed emitters do not invoke event builders
  • the smoke trace oracle passed after a 203-block from-scratch kind-6 catch-up and reorg recovery
  • the plotting parser produced non-empty SVGs from node2: 1,452 trace samples over heights 1-204, with no HoL stall samples or reorder growth
  • GitHub Actions passed all 44 executed checks after rebasing onto current main

Testing

  • cargo fmt --all -- --check
  • cargo test -p zakura-jsonl-trace
  • cargo test -p zakura-network --lib trace::tests
  • CXXFLAGS='-include cstdint' cargo test -p zakura --lib trace::tests
  • cargo clippy -p zakura-jsonl-trace --all-targets -- -D warnings
  • cargo clippy -p zakura-network --lib -- -D warnings
  • CXXFLAGS='-include cstdint' cargo clippy -p zakura --lib -- -D warnings
  • python3 docker/zakura-regtest-e2e/trace_oracle.py --self-test
  • CXXFLAGS='-include cstdint' ZAKURA_E2E_MODE=smoke docker/zakura-regtest-e2e/run.sh
  • python3 .agents/skills/zakura-trace-plots/scripts/plot_zakura_traces.py /tmp/zakura-regtest-e2e-traces-zakura-smoke/node2 --out-dir /tmp/zakura-regtest-e2e-trace-plots
  • git diff --check

Specifications & References

  • Existing JSONL trace schemas are preserved for downstream trace-oracle and plotting consumers.

@v12-auditor

v12-auditor Bot commented Jul 17, 2026

Copy link
Copy Markdown

Note

Complete: Audit complete. V12 did not find any issues that need review.

Open the full results here.

Analyzed 23 files, diff cb83db6...56f9421.

@evan-forbes evan-forbes left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

net gain LoC, mainly due to typing, isolation, and testing

however imo we're getting a massive readability gain

if we wanted to pursue macros we could likely remove most of the tracing files as well

Comment on lines -729 to -738
fn trace_body_submitted(&self, height: block::Height, token: BlockApplyToken) {
self.trace.emit_with(BLOCK_SYNC_TABLE, |row| {
row.insert(
bs_trace::EVENT.to_string(),
serde_json::Value::String(bs_trace::BLOCK_BODY_SUBMITTED.to_string()),
);
bs_insert_height(row, bs_trace::HEIGHT, height);
bs_insert_u64(row, bs_trace::APPLY_TOKEN, token);
});
}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

followed the refactor we did in headersync where we move the tracing code to it's own file

Comment on lines 378 to +379
) {
trace.emit_with(DISCOVERY_TABLE, |row| {
row.insert(
d_trace::EVENT.to_string(),
serde_json::Value::String(d_trace::DISCOVERY_DIAL_RESULT.to_string()),
);
row.insert(
d_trace::RESULT.to_string(),
serde_json::Value::String(result.label().to_string()),
);
let peer = ZakuraPeerId::new(node_id.as_bytes().to_vec())
.map(|peer_id| peer_label(&peer_id))
.ok();
row.insert(
d_trace::PEER.to_string(),
peer.map_or(serde_json::Value::Null, serde_json::Value::String),
);
});
trace.emit_event(|| DiscoveryDialResultEvent::new(node_id.as_bytes(), result));

@evan-forbes evan-forbes Jul 18, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

while net gain in LoC

we're getting imo massive readability gain here using a single line to do the same work as before

Comment on lines +257 to +254
self.trace_get_headers_sent(
&identity.peer,
range,
range.count,
peer_cap,
GetHeadersTraceMeta {
request_id,
session_id: identity.session_id,
stream_version: ZAKURA_HEADER_SYNC_STREAM_VERSION,
},
);
self.trace_get_headers_sent(range, peer_cap, &identity, request_id);

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

another example

our goal here is just be sane with readability

@evan-forbes evan-forbes left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

net gain LoC, mainly due to typing, isolation, and testing

however imo we're getting a massive readability gain

if we wanted to pursue macros we could likely remove most of the tracing files as well

@evan-forbes
evan-forbes marked this pull request as ready for review July 18, 2026 17:40
@ebfull
ebfull marked this pull request as draft July 18, 2026 20:42
@ebfull

ebfull commented Jul 18, 2026

Copy link
Copy Markdown
Contributor

main's history was rewritten to remove the 68 MB Sprout-history artifact from git (old tip 089a0baa0b9d0ebd0c). This branch is based on the old history — merging before rebasing would re-add stale base commits including the blob. Converted to draft.

To fix:

git fetch origin
git rebase --onto origin/main 089a0baa087cbf19cef6e7023014d91a0212f4dc
git push --force-with-lease

This branch contains a merge commit; add --rebase-merges if you want to keep it. Mark ready for review after.

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