Skip to content

feat(minimald,minvmd,minimal): OTEL-compatible log format and trace propagation - #835

Merged
norrietaylor merged 5 commits into
mainfrom
feat/diag-unit4-otel
Jul 21, 2026
Merged

feat(minimald,minvmd,minimal): OTEL-compatible log format and trace propagation#835
norrietaylor merged 5 commits into
mainfrom
feat/diag-unit4-otel

Conversation

@norrietaylor

@norrietaylor norrietaylor commented Jul 17, 2026

Copy link
Copy Markdown
Member

Unit 4 of the diagnostics series (spec: #802, epic: #801). Builds on Unit 3 (#833, merged): the JSON layer replaces the file fmt layers Unit 3 introduced, installed through a shared mlog layer. 467 insertions.

What

Make correlation a grep and a future OTLP export a field-copy. The only OTEL-orbit crates involved execute nothing at collection time: opentelemetry-semantic-conventions (string constants) and json-subscriber (a serializer on the log-write path of a healthy process).

Refs: #801

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features
    • Added end-to-end W3C trace context propagation from CLI to daemon RPC sessions.
    • Exposed trace utilities for creating, formatting, and validating traceparent values.
    • Added JSON-lines file logging via a shared logging layer, including service metadata and flattened trace/span fields.
  • Improvements
    • Improved RPC handling observability by instrumenting each incoming RPC with propagated or newly minted trace spans.

@coderabbitai

coderabbitai Bot commented Jul 17, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Adds W3C-style trace context creation, validation, and SSH propagation from the CLI to daemon RPC handlers. Introduces the shared mlog JSON logging crate and switches minimald and minvmd file logging to structured JSON output.

Changes

Tracing and daemon observability

Layer / File(s) Summary
Trace context contract
crates/minimald-rpc/Cargo.toml, crates/minimald-rpc/src/{lib.rs,trace.rs}
Adds TraceContext, TRACEPARENT, traceparent formatting/parsing, ID minting, flag preservation, and validation tests.
CLI-to-daemon trace propagation
crates/minimal/src/{lib.rs,client.rs}, crates/minimald/src/rpc.rs, crates/minimald/Cargo.toml
Creates a process-wide CLI context, sends it through SSH channel environment requests, and instruments daemon RPC handlers with parsed or minted spans.
Shared JSON file logging
Cargo.toml, crates/mlog/*, crates/{minimald,minvmd}/**
Adds mlog::json_file_layer with OTEL resource fields and tests, then uses it for both daemon file sinks.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant MinimalCLI
  participant SSHChannel
  participant minimald
  participant RPCHandler
  MinimalCLI->>SSHChannel: Send TRACEPARENT environment request
  SSHChannel->>minimald: Deliver RPC channel request
  minimald->>minimald: Parse or mint trace context
  minimald->>RPCHandler: Spawn instrumented RPC future
  RPCHandler->>minimald: Emit structured JSON log events
Loading

Possibly related PRs

Suggested reviewers: twitchyliquid64

Poem

A rabbit sent a trace through the wire,
While JSON logs neatly climbed higher.
Spans hopped in line,
With IDs that shine,
And daemons recorded the choir.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description covers the change and refs, but it omits the required Summary, Testing, and Checklist sections from the template. Add the template sections: Summary, Testing with evidence, and Checklist items including docs and BREAKING CHANGE if applicable.
✅ Passed checks (4 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title is a clear conventional-commit subject that matches the PR's main focus on OTEL-compatible logging and trace propagation.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch

Comment @coderabbitai help to get the list of available commands.

@norrietaylor
norrietaylor force-pushed the feat/diag-unit4-otel branch from aaa29fc to 468b40d Compare July 20, 2026 17:31
Base automatically changed from feat/diag-unit3-daemon-logs to main July 20, 2026 19:05
@norrietaylor
norrietaylor force-pushed the feat/diag-unit4-otel branch from 468b40d to 99707ea Compare July 20, 2026 19:28
…ce propagation

File logs become JSON-lines with span context and OTLP-shaped ids, so
correlation is a grep and a future OTLP export is a field-copy — with
zero OTEL runtime dependencies.

minimald-rpc grows the wire-contract trace module: TraceContext mints
16/8-byte non-zero ids, formats/parses the W3C version-00 traceparent,
and TRACEPARENT_ENV names the channel env variable both sides reference.
The CLI mints one context per invocation, carries it on a root span at
command dispatch, and sends it on every channel open (oneshot RPCs,
exec, workspace upload) as a reply-less env request — the same
mechanism MINIMAL_SESSION_ID already rides, so no wire change. The
daemon parses it in the RPC dispatch, adopting the trace id with a
fresh span id and the client's span as parent; absent or malformed
values mint fresh, never error.

Both daemons' file appenders switch from human-format fmt layers to
json-subscriber layers: flat records with span fields flattened to the
top level and static service.name/service.version resource fields named
by opentelemetry-semantic-conventions. Console output stays
human-format.

Refs: #801
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@norrietaylor
norrietaylor force-pushed the feat/diag-unit4-otel branch from 99707ea to 001f197 Compare July 20, 2026 21:35
@norrietaylor
norrietaylor marked this pull request as ready for review July 20, 2026 21:40
norrietaylor and others added 2 commits July 20, 2026 15:48
…rate

The JSON-lines file-log layer (R4.1/R4.2) was defined twice — in
minimald's DaemonLogger and minvmd's init_tracing — with byte-identical
bodies bar a hardcoded vs. parameterized service name. Two copies of a
pinned wire contract drift silently, and the shape test guarded only the
minvmd copy.

Hoist it into a new leaf crate `mlog` both daemons depend on: one
json_file_layer(writer, service_name), one json_log_shape contract test.
The shared version::LONG_VERSION is read internally (identical for every
binary), so only the service name is a parameter. json-subscriber and
opentelemetry-semantic-conventions move off both daemons and become
transitive via mlog.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@crates/minimald-rpc/src/trace.rs`:
- Around line 22-25: Update TraceContext and the
parse_traceparent/child/traceparent flow to preserve the parent traceparent
flags through child contexts and emitted headers, while enforcing W3C-compliant
lowercase hexadecimal input. Do not normalize accepted flags to 01; either
retain valid flags in TraceContext or reject values other than 01, with parsing
rejecting uppercase hex.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 67bded5a-3fac-4925-a851-4cb54d6779a9

📥 Commits

Reviewing files that changed from the base of the PR and between ebadd19 and 6278716.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (13)
  • Cargo.toml
  • crates/minimal/src/client.rs
  • crates/minimal/src/lib.rs
  • crates/minimald-rpc/Cargo.toml
  • crates/minimald-rpc/src/lib.rs
  • crates/minimald-rpc/src/trace.rs
  • crates/minimald/Cargo.toml
  • crates/minimald/src/logging.rs
  • crates/minimald/src/rpc.rs
  • crates/minvmd/Cargo.toml
  • crates/minvmd/src/main.rs
  • crates/mlog/Cargo.toml
  • crates/mlog/src/lib.rs

Comment thread crates/minimald-rpc/src/trace.rs
norrietaylor and others added 2 commits July 20, 2026 17:45
parse_traceparent accepted arbitrary 2-hex flags but TraceContext stored
none, so traceparent() always emitted `01` — a version-00 `00` (not
sampled) parent round-tripped to sampled. It also accepted uppercase hex,
looser than the W3C version-00 contract the module claims to follow.

Carry a `flags` byte on TraceContext: mint() sets it sampled, child()
inherits it, parse stores it, and traceparent() emits it — so a parsed
context re-emits its parent's sampling decision unchanged. Reject
uppercase in the trace/span/flags fields. Tests cover flag preservation
through child()/re-emission and uppercase rejection.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

@twitchyliquid64 twitchyliquid64 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I likey!

@norrietaylor
norrietaylor merged commit 89eb2b5 into main Jul 21, 2026
28 checks passed
@norrietaylor
norrietaylor deleted the feat/diag-unit4-otel branch July 21, 2026 19:16
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