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

# Read machine metrics and console logs

> Read GPU and system telemetry and kernel or serial console logs for capacity you hold.

Read the same metrics and console logs shown on a reservation's **Observability** tab from your own tooling. Use a physical node ID from [List reserved GPU nodes](/api-reference/nodes/list), or the ID of a VM in one of your reservations.

## What you can read

* **Your reservation window only.** Reads are clamped to the reservation's start and end. Samples and log lines outside it are omitted, and a cancelled reservation returns `404`. An empty result means no data in your window; it does not mean the machine is down.
* **Customer metrics.** `cpu_utilization`, `cpu_temperature`, `gpu_utilization`, `gpu_temperature`, `gpu_power_w`, `gpu_fan_speed_percent`, `component_temperature_max`, `memory_utilization`, `gpu_memory_utilization`, `storage_utilization`, and `ethernet_latency_ms`. A metric appears only when the machine reports it.
* **String values.** Latest-sample `values` are strings; parse numbers yourself. Physical nodes can also report `gpus`, a JSON-encoded array of per-GPU readings.
* **Staleness.** Check `observed_at`. A stored sample is not proof that the machine is reachable now.

A machine outside your organization's reservations returns `404` with `{"error": "not_found"}`.

## Read the latest sample and recent logs

**CLI**

```bash theme={null}
ornn check <machine>
ornn machines metrics <machine> --start 2026-10-14T11:00:00Z \
  --end 2026-10-14T12:00:00Z --max-points 60 --format json
ornn machines logs <machine> --stream kernel --limit 200 --format json
```

`ornn check` combines lifecycle, health, reachability, metrics, and logs for one machine or cluster.

**REST**

```bash theme={null}
export ORNN_API_URL='https://api.ornn.com'
export NODE_ID='<node-id>'
END="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
START="$(date -u -d '1 hour ago' +%Y-%m-%dT%H:%M:%SZ)"  # GNU date

curl --fail-with-body \
  "$ORNN_API_URL/v1/observability/nodes/$NODE_ID/telemetry/latest" \
  -H "Authorization: Bearer $ORNN_API_KEY"

curl --fail-with-body -G \
  "$ORNN_API_URL/v1/observability/nodes/$NODE_ID/telemetry/query" \
  -H "Authorization: Bearer $ORNN_API_KEY" \
  --data-urlencode "start=$START" --data-urlencode "end=$END" \
  --data-urlencode 'metrics=gpu_utilization,gpu_temperature' \
  --data-urlencode 'max_points=60'

curl --fail-with-body -G \
  "$ORNN_API_URL/v1/observability/nodes/$NODE_ID/logs/kernel/query" \
  -H "Authorization: Bearer $ORNN_API_KEY" \
  --data-urlencode "start=$START" --data-urlencode "end=$END" \
  --data-urlencode 'limit=200'
```

**Python**

```python theme={null}
import json
import os
from datetime import datetime, timedelta, timezone

import requests

API = "https://api.ornn.com"
session = requests.Session()
session.headers["Authorization"] = f"Bearer {os.environ['ORNN_API_KEY']}"
node_id = os.environ["NODE_ID"]

latest = session.get(f"{API}/v1/observability/nodes/{node_id}/telemetry/latest", timeout=30)
latest.raise_for_status()
points = latest.json()
if not points:
    print("No telemetry in your reservation window yet.")
else:
    values = points[0]["values"]
    print(points[0]["observed_at"], values.get("gpu_utilization"))
    for gpu in json.loads(values.get("gpus", "[]")):
        print(gpu.get("index"), gpu.get("utilization_percent"), gpu.get("temperature_celsius"))

end = datetime.now(timezone.utc)
window = {"start": (end - timedelta(hours=1)).isoformat(), "end": end.isoformat()}
cursor = None
while True:
    params = {**window, "limit": 200, **({"cursor": cursor} if cursor else {})}
    page = session.get(
        f"{API}/v1/observability/nodes/{node_id}/logs/kernel/query", params=params, timeout=30
    )
    page.raise_for_status()
    body = page.json()
    for line in body["lines"]:
        if line["severity"] == "error":
            print(line["date"], line["message"])
    cursor = body["next_cursor"]
    if not cursor:
        break
```

For a VM, use the same requests under `/v1/observability/virtual-machines/{virtual_machine_id}/`. Per-GPU history (`gpu_uuid`) is available only for physical nodes, over at most 24 hours.

## History resolution

[Query telemetry history](/api-reference/monitoring/node-telemetry-query) returns one window per metric and time bucket. Ornn picks the `tier` from the span and `max_points`: `full` returns raw samples (each window's `start` equals its `end`), while `hour`, `day`, and `month` summarize each bucket with `mean`, `median`, `std`, `min`, and `max`. Request a shorter span or more points for finer detail; `max_points` accepts 1 to 500.

## Console log pages

[Console log queries](/api-reference/monitoring/node-logs) return the newest page first by default. Keep `start`, `end`, and `order` fixed and pass `next_cursor` to read further back; `null` means no more lines in the range. Streams are `kernel` and `serial`. Each line has a `severity` of `error`, `warning`, or `info`.

## Dashboards across many machines

[Get latest telemetry for many machines](/api-reference/monitoring/telemetry-batch) accepts up to 5,000 node and VM IDs in one request. If any ID is outside your organization's reservations, the whole request returns `404`, so batch one reservation's machines at a time. For larger sets, send the chunks in parallel with a small random delay rather than one after another.

Compare `observed_at` between polls to detect a new sample. Back off on `429` and `5xx` responses.


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