# How the `[wt-trace]` Logging Mechanism Works: Unified Tracing in Worktrunk

> Discover how Worktrunk’s `[wt-trace]` unified tracing system records subprocess commands and in-process operations for performance analysis using RAII guards and structured JSON-L output.

- Repository: [Maximilian Roos/worktrunk](https://github.com/max-sixty/worktrunk)
- Tags: internals
- Published: 2026-09-14

---

**The `[wt-trace]` logging mechanism is Worktrunk’s unified tracing system that records subprocess commands and in‑process operations using RAII guards, outputting structured data to both human‑readable **stderr** and machine‑parseable **JSON‑L** files for performance analysis.**

The `[wt-trace]` logging mechanism powers observability in the Worktrunk repository, capturing every significant event from git command execution to template rendering. This tracing system ensures comprehensive visibility into subprocess lifecycles and internal operations through a centralized emitter architecture implemented across [`src/trace/emit.rs`](https://github.com/max-sixty/worktrunk/blob/main/src/trace/emit.rs), [`src/logging.rs`](https://github.com/max-sixty/worktrunk/blob/main/src/logging.rs), and [`src/trace/parse.rs`](https://github.com/max-sixty/worktrunk/blob/main/src/trace/parse.rs).

## Architecture of the `[wt-trace]` Tracing System

The system consists of three tightly coupled layers that guarantee every spawn path flows through a single guard, preventing untraced gaps in performance timelines.

### The Emitter Layer

The **emitter** in [`src/trace/emit.rs`](https://github.com/max-sixty/worktrunk/blob/main/src/trace/emit.rs) serves as the centralized creation point for all trace records. It defines the `CommandTrace` and `Span` structures used throughout the codebase. This layer ensures that every external command spawn creates a consistent record containing fields such as `cmd`, `argv`, `ts` (timestamp), `tid` (thread ID), `dur_us` (duration in microseconds), and a final `ok` flag indicating success or failure.

### The Formatter Layer

Located in [`src/logging.rs`](https://github.com/max-sixty/worktrunk/blob/main/src/logging.rs), the **formatter** transforms structured records into the textual `[wt-trace]` lines that appear on stderr and in `trace.log`. This layer also routes records to a JSON‑L stream (`trace.jsonl`) for programmatic consumption. The formatter operates as a layer within the `tracing-subscriber` stack, bridging legacy `log::*` calls into the unified trace pipeline.

### The Parser and Consumer Layer

The **parser** in [`src/trace/parse.rs`](https://github.com/max-sixty/worktrunk/blob/main/src/trace/parse.rs) reads the JSON‑L output and reconstructs spans for analysis tools. This layer powers the `wt-perf timeline` subcommand, enabling developers to generate Chrome‑Trace‑compatible timelines or column‑aligned text views of execution performance.

## Command Tracing with `CommandTrace`

External command execution follows a strict tracing protocol centered on the `CommandTrace` RAII guard. This design pattern ensures that timing measurements begin immediately before process spawning and conclude automatically when the guard drops.

### Automatic Tracing via `shell_exec::Cmd`

The canonical method for running subprocesses uses the `Cmd` wrapper defined in [`src/shell_exec.rs`](https://github.com/max-sixty/worktrunk/blob/main/src/shell_exec.rs). This wrapper automatically instantiates a `CommandTrace` guard before spawning the process and calls `complete()` or `fail()` on drop, eliminating manual instrumentation overhead.

```rust
use crate::shell_exec::Cmd;

fn list_worktrees(repo: &Repository) -> Result<()> {
    // The `Cmd` wrapper creates a `CommandTrace` automatically.
    Cmd::new("git")
        .args(["worktree", "list"])
        .current_dir(repo.path())
        .context("listing worktrees")
        .run()?;               // On exit the guard logs a `[wt-trace]` record.
    Ok(())
}

```

The resulting output appears in both stderr and `trace.log`:

```text
[wt-trace] cmd=git argv=worktree list ts=2026-09-14T12:34:56.789Z dur_us=1450 ok=true

```

### Manual `CommandTrace` Guards

For custom spawn sites that cannot use the `Cmd` wrapper, developers must construct a `CommandTrace` manually. The guard carries a `#[must_use]` annotation, triggering compile‑time or debug‑assertion failures if the trace is not properly completed.

```rust
use crate::trace::emit::CommandTrace;

fn spawn_custom() -> Result<()> {
    let _trace = CommandTrace::start("my_tool", &["--do", "thing"]);
    // … custom spawning logic …
    
    // On success:
    _trace.complete(Ok(()));
    
    // On error:
    // _trace.fail(anyhow!("failed"));
    Ok(())
}

```

**Critical implementation rule:** According to the Worktrunk source code, the `[wt-trace]` command record has exactly one emitter. Any new spawn site running an in‑process command must construct a `CommandTrace`, starting it just before spawn and calling `complete(success)` after waiting or `fail(err)` on spawn/wait errors.

## In-Process Span Tracing

For operations that do not involve subprocesses—such as template rendering or hook dispatch—the system uses a `Span` RAII guard. Dropping the guard emits a `[wt-trace] span="name" dur_us=…` line that the profiler converts into timeline entries.

```rust
use crate::trace::emit::Span;

fn render_template() {
    let _span = Span::new("template_render");
    // ... heavy rendering work ...
    // When `_span` drops, a `[wt-trace] span="template_render" dur_us=…` line is emitted.
}

```

This mechanism allows the `wt-perf` tool to attribute latency to specific internal operations, not just external commands.

## Output Formats and Structured Logging

The `[wt-trace]` mechanism produces dual-output streams simultaneously through the subscriber layer in [`src/logging.rs`](https://github.com/max-sixty/worktrunk/blob/main/src/logging.rs).

### Human-Readable stderr Output

During execution, concise `[wt-trace]` lines stream to stderr, providing immediate visual feedback on command timing and success states. This output uses a compact key=value format optimized for terminal readability.

### Machine-Readable JSON-L Stream

Simultaneously, the system writes to `trace.jsonl` (JSON Lines format) in the project directory. Each line contains a fully typed JSON object representing the trace record, enabling precise parsing without regex extraction. The [`src/trace/parse.rs`](https://github.com/max-sixty/worktrunk/blob/main/src/trace/parse.rs) module consumes this file to reconstruct execution timelines.

## Profiling and Analysis Tools

The trace output feeds directly into Worktrunk’s performance tooling. The `wt-perf timeline` subcommand reads `trace.jsonl` and generates actionable insights.

```bash

# Capture a run with verbose tracing enabled

wt -vv list > /dev/null 2> trace.log

# Generate a human-readable timeline

wt-perf timeline --trace trace.log

```

This workflow parses the structured JSON, sorts spans by duration, and identifies bottlenecks such as slow git operations or redundant cache misses. The tool can also export Chrome‑Trace JSON for visualization in Perfetto.

## Practical Implementation Examples

### Example 1: Basic Git Command with Auto-Tracing

```rust
use crate::shell_exec::Cmd;

fn fetch_remote() -> Result<()> {
    Cmd::new("git")
        .args(["fetch", "--all"])
        .run()  // Automatically creates `[wt-trace]` record
}

```

### Example 2: Manual Error Handling

```rust
use crate::trace::emit::CommandTrace;

fn risky_operation() -> Result<()> {
    let trace = CommandTrace::start("legacy_tool", &["--batch"]);
    
    match run_legacy_code() {
        Ok(_) => {
            trace.complete(Ok(()));
            Ok(())
        }
        Err(e) => {
            trace.fail(e);
            Err(e)
        }
    }
}

```

### Example 3: Template Rendering Span

```rust
use crate::trace::emit::Span;

fn generate_config() {
    let _span = Span::new("config_generation");
    // Expensive operations here are traced automatically
}

```

## Summary

- **Unified Emitter:** The `CommandTrace` and `Span` guards in [`src/trace/emit.rs`](https://github.com/max-sixty/worktrunk/blob/main/src/trace/emit.rs) guarantee that every subprocess and significant operation produces exactly one trace record.
- **RAII Safety:** Both tracing guards use Rust’s drop semantics and `#[must_use]` attributes to prevent untraced execution paths.
- **Dual Output:** The formatter in [`src/logging.rs`](https://github.com/max-sixty/worktrunk/blob/main/src/logging.rs) produces human‑readable stderr lines and machine‑parseable `trace.jsonl` simultaneously.
- **Performance Integration:** The parser in [`src/trace/parse.rs`](https://github.com/max-sixty/worktrunk/blob/main/src/trace/parse.rs) enables `wt-perf timeline` to reconstruct execution flows and identify bottlenecks.
- **Zero-Cost Abstraction:** The `Cmd` wrapper in [`src/shell_exec.rs`](https://github.com/max-sixty/worktrunk/blob/main/src/shell_exec.rs) provides automatic tracing without requiring manual instrumentation at every call site.

## Frequently Asked Questions

### What triggers a `[wt-trace]` log entry?

A `[wt-trace]` entry triggers when a `CommandTrace` or `Span` RAII guard is dropped at the end of a scope. For subprocesses, this occurs after the command completes or fails. For in‑process spans, this happens when the guarded block exits. The [`src/logging.rs`](https://github.com/max-sixty/worktrunk/blob/main/src/logging.rs) formatter then writes the record to both stderr and `trace.jsonl`.

### How does Worktrunk prevent untraced command executions?

Worktrunk enforces tracing through the `#[must_use]` annotation on the `CommandTrace` guard. Developers must either use the `Cmd` wrapper—which automatically manages the guard lifecycle—or manually construct a `CommandTrace`. Forgetting to handle the guard triggers a compile‑time warning or debug assertion, ensuring the rule that all spawn paths flow through the single emitter in [`src/trace/emit.rs`](https://github.com/max-sixty/worktrunk/blob/main/src/trace/emit.rs).

### Can I consume `[wt-trace]` output programmatically?

Yes. While stderr provides human‑readable output, the `trace.jsonl` file contains structured JSON objects with typed fields including `cmd`, `argv`, `dur_us`, and `ok`. The [`src/trace/parse.rs`](https://github.com/max-sixty/worktrunk/blob/main/src/trace/parse.rs) module provides the official parser, and the `wt-perf timeline` command demonstrates how to transform this data into performance reports or Chrome‑Trace visualizations.

### What is the performance overhead of the `[wt-trace]` mechanism?

The tracing system uses RAII guards that record high‑resolution timestamps and write to asynchronous streams, introducing minimal overhead. The `-vv` flag enables high‑resolution tracing for debugging, while production builds can disable verbose logging levels. The JSON‑L appends are buffered, and the `tracing-subscriber` architecture ensures that disabled levels incur near‑zero cost through compile‑time filtering.