<!-- Source: https://medius.k4tech.net/library/features/tracing -->
# Tracing

_Structured diagnostics over the link_

The `tracing` feature wires the crate into [`tracing`](https://docs.rs/tracing): it emits a span and events as it works the link, but adds no medius functions and changes no behavior. The sections below are what it emits; you read them by installing a [subscriber](/library/features/tracing.md#subscriber).

```bash
cargo add medius --features tracing
```

Off by default; with the feature off the macros expand to nothing, so there's no runtime cost.

## Targets and levels

_What the crate emits and where_

#### TARGETS

| Target | Levels | Emitted |
| --- | --- | --- |
| `medius::device` | `INFO`, `DEBUG`, `WARN` | The `connect` span and `connected` event (`INFO`), handshake retries (`DEBUG`) and failures (`WARN`), query resolved (`DEBUG`) and timed out (`WARN`), the `reconnected` event (`INFO`), plus the box's own logs re-emitted with `device_log=true`. |
| `medius::transport` | `TRACE` | One event per frame written or read, with `dir`, `opcode`, `seq`, and `len`. |
| `medius::flash` | `INFO`, `ERROR` | Reboot-into-download and esptool progress, then tool failure. Present only with the [`flash`](/library/features/flash.md) feature. |

> **Note**
>
> Keepalive has no target of its own; its periodic frame shows up as an ordinary `medius::transport` tx event.

## The connect span

_A span wraps related events_

The `connect` span wraps the handshake; retry and `connected` events nest inside it. Its fields are the numbers [`query_version`](/library/requests.md#version) returns as a [`Version`](/library/types/structs.md#version).

#### EXAMPLE

```rust
// With "medius=debug" and a box that answers on the second probe, the
// fmt subscriber prints the span name on each nested event:
//   DEBUG connect: medius::device: handshake: version probe timed out, retrying
//   INFO  connect: medius::device: connected proto_ver=3 fw_major=1 fw_minor=3 fw_patch=0
// "connect:" is the span; the rest is the event with its fields.
```

## Frames, device logs, and reconnects

_The events worth knowing_

`medius::transport` emits one `TRACE` per frame, the per-frame mirror of the [`frames_tx` / `frames_rx`](/library/diagnostics.md#counters) counters. Each [`LOG`](/native/commands/admin.md#log) frame the box sends is re-emitted on `medius::device` with `device_log=true` at its matching [`LogLevel`](/library/types/enums.md#log-level) (the same data the [`logs`](/library/diagnostics.md#logs) stream hands back). A recovered link fires an `INFO` `reconnected` event with `port` and `reason`.

#### EXAMPLE

```rust
// medius::transport=trace, one line per frame:
//   TRACE medius::transport: dir="tx" opcode=1 seq=7 len=4
// a box log, mirrored:
//   WARN  medius::device: mouse detached device_log=true
// a recovered link:
//   INFO  medius::device: reconnected port="/dev/ttyACM0" reason="rescan"
```

## Install a subscriber

_Print the events to stderr_

The crate ships no subscriber, so add one alongside the feature, usually [`tracing-subscriber`](https://docs.rs/tracing-subscriber). The [`fmt`](https://docs.rs/tracing-subscriber/latest/tracing_subscriber/fmt/index.html) subscriber writes lines to stderr; call `init()` once before opening. Without one, every span and event is dropped silently.

```bash
cargo add tracing-subscriber
```

#### EXAMPLE

```rust
use medius::Device;

tracing_subscriber::fmt::init();

let device = Device::find()?;
device.move_rel(10, 0)?;
// stderr now carries the connect span and an INFO event, e.g.:
//   INFO  connect: medius::device: connected proto_ver=3 fw_major=1 fw_minor=3 fw_patch=0
```

## Filter by level and target

_EnvFilter and RUST_LOG_

Transport events sit below the default `INFO` floor. Lower it with a per-target [`EnvFilter`](https://docs.rs/tracing-subscriber/latest/tracing_subscriber/filter/struct.EnvFilter.html) (target names in [targets](/library/features/tracing.md#targets)).

#### EXAMPLE

```rust
// Code-side: medius events at DEBUG, everything else at the default.
tracing_subscriber::fmt()
    .with_env_filter("medius=debug")
    .init();

// Or set it at runtime instead, no recompile:
//   RUST_LOG=medius=debug ./your-program
//   RUST_LOG=medius::transport=trace ./your-program   # every frame
```

> **Warning**
>
> `medius::transport=trace` emits one line per frame in both directions. Leave it off unless you're chasing a wire-level bug.

## JSON output

_Ship structured events_

Swap the formatter for JSON and each event becomes one object with its fields as keys. Needs `tracing-subscriber`'s `json` feature.

#### EXAMPLE

```rust
// cargo add tracing-subscriber --features json
tracing_subscriber::fmt()
    .json()
    .with_env_filter("medius=debug")
    .init();
// Each event is now a JSON line, e.g.:
//   {"level":"INFO","target":"medius::device","fields":{"message":"connected","proto_ver":3}}
```
