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.
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).
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 search (30-day retention).
With local AI (logs never leave your machine):
Machines and Auto-Stop
Fly Machines auto-stop 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/trial. Free allowance covers small apps.
Time to complete: 5 minutes Prerequisites: Fly CLI, jq, Gonzo installed Full guide:guides/FLY_USAGE_GUIDE.md