plane-flyingFly.io Logs

Stream logs from Fly.io apps into Gonzo for real-time analysis, filtering, and AI-powered insights.

Stream logs from Fly.io apps into Gonzo with a lightweight jq transform. Fly's CLI streams structured JSON over NATS, but your app's output is double-encoded inside the message field. The pipe below unwraps it so Gonzo sees clean, flat JSON.

Quick Start

fly logs -a <app-name> -j \
  | jq --unbuffered -c '
    {timestamp, region, instance}
    + (try (.message | fromjson) // empty)' \
  | gonzo

The -j flag gives you structured JSON. The jq transform extracts timestamp, region, and instance from the envelope, parses the inner message for your app's real fields (level, message, custom fields), and silently drops non-JSON lines (init logs, Firecracker boot messages).

Prerequisites

Log Sources

Fly streams multiple sources through a single pipe. The jq transform with // empty keeps only your app's JSON output.

Source
Provider
What it captures

App

app

Your app's stdout/stderr, plus Fly init messages

Runner

runner

Image pulls, Firecracker config, machine start/stop

Proxy

proxy

Machine reachability, startup timing

To include platform logs (useful during deploy debugging), swap // empty for // {message: .message}:

Usage Patterns

Real-time streaming (default):

Filter by region:

Filter by machine:

Buffer dump (no streaming):

--no-tail dumps the current log buffer and exits. For historical queries with date ranges, use Fly's Grafana log searcharrow-up-right (30-day retention).

With local AI (logs never leave your machine):

Machines and Auto-Stop

Fly Machines auto-stoparrow-up-right when there's no inbound traffic. Log streams end when machines stop — this is expected, not a Gonzo or pipe issue. Machines restart on the next request. To keep logs flowing, send periodic requests or set auto_stop_machines = false in fly.toml.

Structured Logging Tips

Emit single-line JSON to stdout for the best Gonzo experience. Multi-line JSON objects are split into separate log entries by Fly's pipeline.

Fly tags all stderr output with "level": "info" at the envelope level, same as stdout. If you rely on stderr for error output (e.g. Python's logging defaults), the envelope level won't reflect real severity. Use structured JSON with an explicit level field instead.

Troubleshooting

Symptom
Cause & fix

No logs appearing

Check fly status -a <app>. Machines may be stopped — hit your app's URL to wake them.

Only build/boot logs, no app logs

Firecracker VM boot takes a few seconds. Wait 10–15s after deploy.

Envelope level always "info"

Expected. Fly doesn't map app log level to envelope. The jq transform extracts the real level.

Logs stall in the pipe

Add --unbuffered to jq. Without it, output buffers and logs appear in delayed bursts.

Init messages mixed with app logs

Fly's init process is tagged provider: "app". The // empty pattern drops these (they're not JSON).

Trial account machines killed after 5m

Add a payment method at fly.io/trialarrow-up-right. Free allowance covers small apps.


Time to complete: 5 minutes Prerequisites: Fly CLI, jq, Gonzo installed Full guide: guides/FLY_USAGE_GUIDE.mdarrow-up-right

Last updated