# Render Logs

Stream logs from Render services into Gonzo. Render's CLI streams over WebSocket; a lightweight `jq` + `sed` pipe flattens label metadata and strips ANSI codes.

### Quick Start

```bash
render logs -r <service-id> -o json --tail \
  | jq --unbuffered -c '{timestamp: .timestamp, message: .message} + ([.labels[] | {(.name): .value}] | add)' \
  | sed -u 's/\\u001b\[[0-9;]*m//g; s/\\u001b(B//g' \
  | gonzo
```

### Prerequisites

* Gonzo installed
* [Render CLI](https://render.com/docs/cli) installed (`brew install render`)
* `jq` installed (`brew install jq`)

### Setup

```bash
# Authenticate
render login

# Find your service ID (starts with srv-)
render services -o json | jq '.[].service | {id, name}'
```

### Why the Pipe?

Render nests metadata in a `labels` array rather than top-level fields. The `jq` transform flattens all labels dynamically — if Render adds new labels (e.g. `method`, `path`, `status_code` on Professional plans), they appear automatically. The `sed -u` strips ANSI color codes that Render injects into build/deploy messages. The `-u` flag disables sed's output buffering to prevent log stalling.

### Log Phases

Build, deploy, and runtime logs come through a single stream:

| Phase       | How to identify                                     | Example                               |
| ----------- | --------------------------------------------------- | ------------------------------------- |
| **Build**   | Has `resource`, `level`, `type` labels              | `==> Running build command 'yarn'...` |
| **Deploy**  | Has `resource`, `type` but no `level` or `instance` | `==> Your service is live`            |
| **Runtime** | Has `resource`, `instance`, `level`, `type`         | Your app's structured output          |

### Usage Patterns

**Multiple services:**

```bash
render logs -r srv-XXXXX,srv-YYYYY -o json --tail \
  | jq --unbuffered -c '{timestamp: .timestamp, message: .message} + ([.labels[] | {(.name): .value}] | add)' \
  | sed -u 's/\\u001b\[[0-9;]*m//g; s/\\u001b(B//g' \
  | gonzo
```

**Historical query:**

```bash
render logs -r srv-XXXXX -o json --limit 100 \
  --start 2026-03-27T14:00:00Z --end 2026-03-27T15:00:00Z \
  | jq -c '{timestamp: .timestamp, message: .message} + ([.labels[] | {(.name): .value}] | add)' \
  | sed -u 's/\\u001b\[[0-9;]*m//g; s/\\u001b(B//g' \
  | gonzo
```

**Filter at source:**

```bash
render logs -r srv-XXXXX -o json --tail --level error | ...
render logs -r srv-XXXXX -o json --tail --text "timeout" | ...
```

### Rate Limits

**Streaming** (`--tail`) uses WebSocket — **not rate limited**. Recommended mode.

**Fetch mode** (`--limit`, `--start`, `--end`) uses the REST API and is subject to plan-based limits.

**Platform cap:** 6,000 log lines/minute per instance. Excess is silently dropped.

### Structured Logging Tips

Render maps the `level` field from your app's stdout to its internal severity. Emit structured JSON for best results. Same stderr gotcha as Railway — Python's `logging` defaults to stderr, so `logging.info()` calls show up as errors. Use structured JSON to override.

**Time to complete:** 10 minutes **Prerequisites:** Render CLI, `jq`, Gonzo installed **Full guide:** [`guides/RENDER_USAGE_GUIDE.md`](https://github.com/control-theory/gonzo/blob/main/guides/RENDER_USAGE_GUIDE.md)
