> ## Documentation Index
> Fetch the complete documentation index at: https://docs.podflare.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Observability

> W3C Trace Context propagation, structured spans, JSON logs.

<Note>
  Every Podflare HTTP request gets a `http_request` tracing span. Every
  executor operation (`create`, `exec`, `fork`, `merge_into`, `destroy`)
  emits a nested event inside that span with structured fields. Pass a
  `traceparent` header (or SDK kwarg) and Podflare binds your upstream
  `trace_id` + `parent_span_id` to every log line.
</Note>

## Propagation

Supply a W3C Trace Context `traceparent` string (`00-<trace>-<span>-<flags>`)
and the SDK forwards it on every HTTP request:

<CodeGroup>
  ```python Python theme={null}
  from podflare import Sandbox, Client

  # Option 1: per-Sandbox
  with Sandbox(traceparent="00-4bf92f35...4736-00f067aa0ba902b7-01") as s:
      s.run_code("...")

  # Option 2: per-Client (reused across many sandboxes)
  client = Client(traceparent="00-...-01")
  sbx = Sandbox(client=client)

  # Option 3: env var (picked up automatically)
  # PODFLARE_TRACEPARENT=00-...-01
  ```

  ```ts TypeScript theme={null}
  import { Sandbox, Client } from "podflare";

  const sbx = await Sandbox.create({
    traceparent: "00-4bf92f35...4736-00f067aa0ba902b7-01",
  });

  // or per-client:
  const client = new Client({ traceparent: "00-...-01" });
  const sbx2 = await Sandbox.create({ client });

  // PODFLARE_TRACEPARENT env var also works.
  ```
</CodeGroup>

## What shows up in hostd logs

Default (text) formatter:

```
2026-04-18T14:00:00Z INFO http_request method=POST path=/v1/sandboxes/sbx_x/exec trace_id=4bf92f35...4736 parent_span_id=00f067aa0ba902b7 message="agent connected" id=sbx_x connect_ms=0
```

Every nested log line carries the request's `trace_id` + `parent_span_id`
— ready for grep-based correlation or pipe-into-structured-log-aggregator.

JSON formatter (`PODFLARE_LOG_FORMAT=json`):

```json theme={null}
{
  "timestamp": "2026-04-18T14:00:00Z",
  "level": "INFO",
  "message": "agent connected",
  "span": {"name": "http_request", "trace_id": "4bf92f35...4736", "parent_span_id": "00f067aa0ba902b7"},
  "sandbox_id": "sbx_x",
  "connect_ms": 0
}
```

Ship those JSON lines to Langfuse, LangSmith, Braintrust, Datadog, Loki,
or your log aggregator of choice.

## Fields Podflare emits

<ParamField path="span" type="http_request">
  Per-HTTP-request root span. Fields:
</ParamField>

* `method` — HTTP method.
* `path` — request path, e.g. `/v1/sandboxes/:id/exec`.
* `trace_id` — from incoming `traceparent`, empty if not provided.
* `parent_span_id` — ditto.

Inner events use names like `sandbox claimed`, `VM booted`, `fork complete`,
`agent connected`, etc., with the operation's relevant fields (template,
sandbox id, durations in ms, source = `pool`/`on_demand`/`snapshot`).

## Recommended: ship logs as OTel events

Podflare emits structured `tracing` spans. You can bridge those to OTLP
by running hostd with [`tracing-opentelemetry`](https://crates.io/crates/tracing-opentelemetry)
configured (planned; contributions welcome). Until then the simplest path
is: set `PODFLARE_LOG_FORMAT=json`, pipe stdout to `vector` / `otel-collector`
/ `fluent-bit` configured as an OTLP exporter.

## Environment

<ParamField path="PODFLARE_LOG_FORMAT" type="string" default="text">
  Set to `json` for one-line-per-event JSON (span fields + message).
</ParamField>

<ParamField path="PODFLARE_TRACEPARENT" type="string">
  SDK-side: fallback value for `Client(traceparent=...)` / `Sandbox(traceparent=...)`
  when none is passed explicitly. Useful for quick experimentation.
</ParamField>

<ParamField path="RUST_LOG" type="string" default="info,tower_http=info">
  hostd-side: [tracing-subscriber EnvFilter](https://docs.rs/tracing-subscriber/latest/tracing_subscriber/filter/struct.EnvFilter.html)
  syntax. `trace` / `debug` levels surface more detail per operation.
</ParamField>
