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

# Go SDK: live logs and status

> Stream an application's live logs, status and system events with c.Apps.Realtime, an iterator that merges status frames and reconnects on its own.

`c.Apps.Realtime(ctx, appID)` opens a live stream of an app's logs, status and system events and returns a `*squarecloud.Realtime`. It is an **iterator**: call `Next` in a loop until it returns an error, and always `Close` it.

```go theme={"system"}
package main

import (
	"context"
	"errors"
	"fmt"
	"io"
	"log"
	"os"

	"github.com/squarecloudofc/sdk-api-go/v3"
)

func main() {
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()
	c := squarecloud.New(os.Getenv("SQUARECLOUD_API_KEY"))
	appID := "abc123def456abc123def456"

	r, err := c.Apps.Realtime(ctx, appID)
	if err != nil {
		log.Fatal(err)
	}
	defer r.Close()

	for {
		ev, err := r.Next()
		if err != nil {
			if errors.Is(err, io.EOF) || ctx.Err() != nil {
				break // the stream ended, or ctx was canceled
			}
			log.Fatal(err)
		}

		switch ev.Event {
		case "logs":
			fmt.Println(ev.Stream, ev.Line) // "stdout" | "stderr"
		case "status":
			fmt.Println(ev.Status.CPU, ev.Status.RAM) // never nil: always the full, merged state
		default:
			fmt.Println(ev.Event, ev.Data) // "system", "error" or "message"
		}
	}
}
```

The `ctx` passed to `Realtime` governs the whole stream: `Next` takes no arguments. To stop a loop blocked in `Next` from another goroutine, cancel that `ctx`.

## Events

Every `RealtimeEvent` has `Event`, `Data` (the raw frame text) and `ID` (the last event id, `""` if none).

| `Event` | Extra fields | Description |
| - | - | - |
| `logs` | `Stream`, `Line` | One log line. The first character of `Data` tells the stream (`\u0001` stdout, `\u0002` stderr); the SDK strips it into `Line` and sets `Stream` to `"stdout"` or `"stderr"` |
| `status` | `Status` | Live container metrics. The first frame is complete and the next ones only carry what changed: the SDK merges them, so `Status` (a `*RealtimeStatus`, never `nil` on this event) is always the full state |
| `system` | | Connection events such as `REALTIME_CONNECTING \| <id>`, `REALTIME_TIMEOUT` or `REALTIME_DISCONNECTED` |
| `error` | | An error code such as `CONTAINER_NOT_FOUND` |
| `message` | | A frame without an `event` name |

### The `Status` struct

| Field | Description |
| - | - |
| `CPU` (`cpu`) | CPU usage (%) |
| `CPULimit` (`cpuLimit`) | Number of CPU cores allocated (e.g. `1` or `0.5`) |
| `RAM` (`ram`) | `[usedMB, limitMB]` as a `[2]float64` |
| `Status` (`status`) | Container state, e.g. `running` |
| `NetIO` (`netIO`) | Network `In`/`Out` totals (`i`, `o`), with `New` for the latest interval, in bytes per second |
| `BlockIO` (`bIO`) | Disk `In`/`Out` totals (`i`, `o`) |
| `Uptime` (`uptime`) | Unix ms of the container start |

## Ending the stream

`Next` returns `io.EOF` when:

* the server closes the connection cleanly (each connection lasts up to **10 minutes**);
* the server sent `REALTIME_DISCONNECTED` (the event is delivered first, then `io.EOF`);
* you called `Close`.

When the `ctx` passed to `Realtime` is canceled or its deadline passes, `Next` returns the bare `ctx.Err()` (`context.Canceled` or `context.DeadlineExceeded`), not an `*APIError`. To leave the loop yourself, just `break`: the deferred `Close` releases the connection.

To keep watching past 10 minutes, call `Realtime` again when the loop ends.

## Reconnection

A dropped connection, or the server handing reconnection to the client (`REALTIME_RECONNECT`), reopens the stream on its own:

* up to **3 times in a row**; any `logs` or `status` event resets the count;
* each reopen at least **5.5 s** after the previous open, to stay under the API's pace of one open per 5 seconds per app.

The merged `Status` survives reconnections. Past 3 failed reconnections, `Next` returns an `*APIError` with `NETWORK_ERROR` (status `0`).

## Limits and errors

* **5** concurrent connections per account and **30** per app, across all users. Going over is 429 `REALTIME_MAX_CONNECTIONS` or `REALTIME_MAX_CONNECTIONS_APP`.
* The HTTP status is checked before streaming, so these errors (and 404 for an unknown app) are returned by `Realtime` itself, before the first `Next`.
* When `ctx` has no deadline, the `WithTimeout` deadline only covers the open, until the response headers arrive (`TIMEOUT` if they don't). The stream itself has no deadline besides `ctx`.

## Next steps

<CardGroup cols={3}>
  <Card title="Snapshots" icon="clock-rotate-left" href="/en/sdks/go/snapshots">
    Back up and restore apps and databases.
  </Card>

  <Card title="Realtime API reference" icon="code" href="/en/api-reference/endpoint/apps/realtime">
    The REST endpoint behind this stream.
  </Card>

  <Card title="Logs from the CLI" icon="terminal" href="/en/cli-reference/logs">
    The same stream from the terminal.
  </Card>
</CardGroup>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.