# Write Structured Tracing

> Standard for writing structured tracing logs behind debug flags.

- Skill: `r3bl-org/write-structured-tracing` (Agent Skill)
- Install (CLI): `npx skillmds@latest add r3bl-org/write-structured-tracing`
- Raw SKILL.md: https://api.skillmd.com/api/skills/r3bl-org/write-structured-tracing/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: r3bl-org (https://skillmd.com/u/r3bl-org)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/r3bl-org/write-structured-tracing

---


# Write Structured Tracing

This skill documents the project's standard for writing tracing logs (`tracing::info!`, `tracing::debug!`, etc.). It ensures logs are easily filterable, consistently formatted, and don't affect performance when disabled.

## 1. Gating Behind Debug Flags

All `tracing::*!` calls must be gated behind a specific debug flag from `tui/src/tui/mod.rs` (or similar location) using the `.then(|| { ... })` pattern. This ensures the tracing macro and any string allocations are completely bypassed when the flag is disabled.

**Choosing the right flag (Scope Specificity):**
Make sure the flag you use is specifically scoped to the module or subsystem you are debugging. This scope can be narrow or broad depending on the requirements.
- Do NOT reuse a broad orchestrator flag (e.g., `DEBUG_TUI_PTY_MUX`) for a microscopic, high-volume subsystem (like a byte-stream parser). Doing so would spam the orchestrator logs.
- If a suitable module-specific flag does not exist, create a new one (e.g., `DEBUG_TUI_VT100_PARSER`) to ensure developers can isolate and filter logs effectively without overwhelming the IO overhead.

```rust
crate::DEBUG_TUI_MOD.then(|| {
    // ... tracing call ...
});
```

## 2. The `// % is Display, ? is Debug.` Comment

You **MUST** add the exact line comment `// % is Display, ? is Debug.` directly above every `tracing::*!` invocation. This serves as a quick syntax reminder.

## 3. Structured Fields and `message`

Do not use unstructured string formatting (e.g., `tracing::info!("Hello {}", name)`). Instead, use structured fields with an explicit `message` key that identifies the context (e.g., the struct and method name).

```rust
crate::DEBUG_TUI_MOD.then(|| {
    // % is Display, ? is Debug.
    tracing::info! {
        message = "ComponentName::method_name",
        status = "Something happened",
    };
});
```

## 4. Using `inline_string!` vs `format!` for Complex Formatting

When you need to format complex strings within a tracing field, bind it to a field using the `%` (Display) modifier and follow this rule:
- If the resulting string will be **<= 16 bytes**, use the `inline_string!` macro to stack-allocate it.
- If the resulting string will be **> 16 bytes**, use the standard `format!` macro (since `inline_string!` would spill to the heap and allocate anyway).

```rust
crate::DEBUG_TUI_MOD.then(|| {
    // % is Display, ? is Debug.
    tracing::info! {
        message = "AppNoLayout::handle_event",
        input_event = %inline_string!(
            "{a} {b:?}",
            a = glyphs::USER_INPUT_GLYPH,
            b = input_event
        )
    };
});
```

## Example Transformation

**Bad (Unstructured and Un-gated):**
```rust
tracing::debug!("Received input event: {:?}", input_event);
```

**Good (Structured and Gated):**
```rust
crate::DEBUG_TUI_PTY_MUX.then(|| {
    // % is Display, ? is Debug.
    tracing::debug! {
        message = "PTYMux::run_event_loop",
        input_event = %format!("{:?}", input_event)
    };
});
```

