# How to Monitor Real-Time Resource Usage of Containers with Apple Container

> Monitor real-time container resource usage with the apple container stats command. Stream live CPU, memory, and I/O data or get a single JSON snapshot. Learn more today.

- Repository: [Apple/container](https://github.com/apple/container)
- Tags: how-to-guide
- Published: 2026-06-20

---

**Use the `container stats` command to stream live CPU, memory, network, and block I/O metrics from running containers, or add `--no-stream` for a single JSON snapshot.**

The **Apple container** toolset provides native support for observing live resource consumption through the `container stats` command. This interface delivers per-container metrics by integrating CLI parsing, XPC-based client-server communication, and runtime statistics collection. Whether you need continuous monitoring or programmatic access to resource data, the tool exposes detailed usage statistics directly from the underlying daemon.

## Architecture of the `container stats` Command

The implementation spans three architectural layers that handle everything from user input to kernel-level data retrieval.

### CLI Front-End (`ContainerStats`)

The entry point resides in [`Sources/ContainerCommands/Container/ContainerStats.swift`](https://github.com/apple/container/blob/main/Sources/ContainerCommands/Container/ContainerStats.swift). The `ContainerStats` command parses user flags such as `--format` (accepting `table` or `json`) and `--no-stream` to determine execution mode. It then routes to either **streaming** or **static** logic based on these options.

### Client-Server API Layer

Communication flows through `ContainerClient`, which dispatches XPC calls to the daemon. The critical method is `stats(id:)`, defined in the client interface, which returns a `ContainerResource.ContainerStats` value. This data structure—modeled in [`Sources/ContainerResource/Container/ContainerStats.swift`](https://github.com/apple/container/blob/main/Sources/ContainerResource/Container/ContainerStats.swift)—encapsulates raw metrics including memory bytes, CPU microseconds, network I/O, block I/O, and process counts.

### Runtime Service Layer

On the daemon side, [`Sources/Services/RuntimeLinux/Server/RuntimeService.swift`](https://github.com/apple/container/blob/main/Sources/Services/RuntimeLinux/Server/RuntimeService.swift) implements the `RuntimeService` class. This service invokes `container.statistics()` against the underlying container runtime, then returns a `ContainerStatistics`-derived struct that the client decodes and formats for display.

## How Resource Monitoring Works

The command distinguishes between two operational modes, each handled by distinct internal methods.

### Streaming Mode (Real-Time)

When invoked without `--no-stream`, the command executes `runStreaming()` from [`ContainerStats.swift`](https://github.com/apple/container/blob/main/ContainerStats.swift). This method enters an alternate screen buffer and repeatedly fetches fresh snapshots via `client.stats(id:)`. It clears the screen between iterations and renders an updated table using `statsTable(_:)`, producing a `top`-like interface that continues until you press **Ctrl-C**.

### Static Mode (Single Snapshot)

When you pass `--no-stream`, the command calls `runStatic()`. This routine:
1. Enumerates all running containers via `client.list(...)`
2. Invokes `collectStats()` to gather an initial sample (`stats1`)
3. Pauses for 2 seconds
4. Gathers a second sample (`stats2`)
5. Calculates CPU percentage via `calculateCPUPercent()` using the delta of `cpuUsageUsec` between snapshots
6. Outputs results using `formatBytes(_:)` for human-readable sizes (KiB/MiB/GiB) and the appropriate formatter for the chosen `--format`

## Container Metrics Explained

Each stats payload contains the following fields, directly mapped from the `ContainerStats` struct:

- **CPU %**: Percentage of a full CPU core consumed, computed from the difference in `cpuUsageUsec` between two 2-second samples.
- **Memory Usage / Limit**: Current resident memory in bytes versus the container-configured memory limit.
- **Network Rx/Tx**: Cumulative bytes received and transmitted across all network interfaces.
- **Block I/O**: Total bytes read from and written to block devices.
- **PIDs**: Current number of processes running inside the container namespace.

## Practical Examples

### Stream Live Statistics for All Containers

```bash
container stats

```

This opens an alternate screen buffer and continuously refreshes a table showing all running containers until interrupted.

### Export a Single Snapshot as JSON

```bash
container stats --format json --no-stream

```

This invokes `runStatic()`, producing a parseable JSON array suitable for scripting and automation.

### Monitor a Specific Container

```bash
container stats my-web-app

```

Replace `my-web-app` with a container ID or name. Without `--no-stream`, this streams updates for only that container.

### JSON Output Structure

When using `--format json`, the output matches the Swift model defined in [`Sources/ContainerResource/Container/ContainerStats.swift`](https://github.com/apple/container/blob/main/Sources/ContainerResource/Container/ContainerStats.swift):

```json
[
  {
    "id": "e5f9a7c3b2d1",
    "memoryUsageBytes": 104857600,
    "memoryLimitBytes": 2147483648,
    "cpuUsageUsec": 12345678,
    "networkRxBytes": 5242880,
    "networkTxBytes": 1048576,
    "blockReadBytes": 262144,
    "blockWriteBytes": 131072,
    "numProcesses": 12
  }
]

```

## Key Source Files

- **[`Sources/ContainerCommands/Container/ContainerStats.swift`](https://github.com/apple/container/blob/main/Sources/ContainerCommands/Container/ContainerStats.swift)** – Implements `run()`, `runStatic()`, `runStreaming()`, `collectStats()`, and formatting helpers.
- **[`Sources/ContainerResource/Container/ContainerStats.swift`](https://github.com/apple/container/blob/main/Sources/ContainerResource/Container/ContainerStats.swift)** – Defines the `ContainerStats` data model with properties for memory, CPU, network, block I/O, and PIDs.
- **[`Sources/Services/RuntimeLinux/Server/RuntimeService.swift`](https://github.com/apple/container/blob/main/Sources/Services/RuntimeLinux/Server/RuntimeService.swift)** – Daemon-side service that fetches raw statistics from the runtime via `container.statistics()`.
- **[`Sources/Services/ContainerAPIService/Server/Containers/ContainersService.swift`](https://github.com/apple/container/blob/main/Sources/Services/ContainerAPIService/Server/Containers/ContainersService.swift)** – Exposes the `stats(id:)` RPC endpoint over XPC.

## Summary

- The `container stats` command provides real-time visibility into container resource usage through a three-tier architecture spanning CLI, XPC client, and runtime service.
- **Streaming mode** (`runStreaming()`) offers a continuously updating TUI for interactive monitoring.
- **Static mode** (`runStatic()`) with `--no-stream` delivers snapshot data in table or JSON format for scripting.
- CPU utilization is calculated from the delta of `cpuUsageUsec` across two 2-second samples.
- All metrics—including memory, network I/O, block I/O, and process counts—originate from [`RuntimeService.swift`](https://github.com/apple/container/blob/main/RuntimeService.swift) and propagate through the `ContainerClient` API.

## Frequently Asked Questions

### How does the `container stats` command calculate CPU percentage?

The command calls `collectStats()` to retrieve two samples approximately 2 seconds apart, then executes `calculateCPUPercent()`. This function computes the delta between the first sample's `cpuUsageUsec` and the second sample's `cpuUsageUsec`, converting that time difference into a percentage of total CPU capacity.

### Can I monitor resource usage programmatically without the TUI?

Yes. Append `--format json --no-stream` to any `container stats` invocation. This triggers `runStatic()` and outputs a JSON array containing the current metrics for all specified containers, bypassing the alternate screen buffer used by streaming mode.

### What is the difference between streaming and static mode?

**Streaming mode** (default) invokes `runStreaming()`, which enters an alternate screen buffer and refreshes the display indefinitely until interrupted. **Static mode** (enabled with `--no-stream`) invokes `runStatic()`, which collects a single set of statistics, calculates CPU percentages from two temporal samples, prints the results, and exits immediately.

### Where does the daemon retrieve underlying container metrics?

According to the source in [`Sources/Services/RuntimeLinux/Server/RuntimeService.swift`](https://github.com/apple/container/blob/main/Sources/Services/RuntimeLinux/Server/RuntimeService.swift), the `RuntimeService` calls `container.statistics()` on the runtime instance. This method returns a `ContainerStatistics` object containing raw cgroup and namespace data that the service wraps into the `ContainerStats` struct returned to clients.