# How to Retrieve Logs from a Running Container or System Process: Three Methods Explained

> Learn three methods to retrieve logs from running containers or system processes using the container CLI. Access stdout/stderr streams efficiently.

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

---

**The `container` CLI provides three distinct commands—`container logs`, `container machine logs`, and `container system logs`—to retrieve stdout/stderr streams from containers, virtual machines, and the container subsystem itself via file handle-based XPC transport.**

The Apple **container** repository provides a Swift-based CLI for managing containerized workloads on macOS. When debugging running applications or diagnosing system issues, you need to retrieve logs from a running container or system process efficiently. The tool implements three specialized commands that stream log data directly through file handles rather than copying buffers over XPC, ensuring high-performance log retrieval even for large outputs.

## Retrieving Container Logs with `container logs`

The `container logs` command displays the stdout/stderr output of a container's main process. According to the source code in [`Sources/ContainerCommands/ContainerLogs.swift`](https://github.com/apple/container/blob/main/Sources/ContainerCommands/ContainerLogs.swift), the `ContainerLogs.run()` method creates a `ContainerClient`, calls `client.logs(id:)` (implemented in **ContainerAPIService**), and receives a pair of `FileHandle` objects—one for the container's stdio and one for the boot log.

### Basic Usage and Flags

```bash

# Show the complete stdout/stderr of the container

container logs my-web-server

# Show only the last 100 lines

container logs -n 100 my-web-server

# Follow the log output in real-time (like tail -f)

container logs --follow my-web-server

# View the VM boot log instead of the app's stdio

container logs --boot my-web-server

```

Under the hood, the command selects the appropriate handle using the boolean flag: `boot ? fhs[1] : fhs[0]`. When retrieving historical lines, it invokes `tail()` which walks backward from the end of the file to collect the requested number of lines. When `--follow` is set, it switches to an `AsyncStream` that watches the file descriptor for new data, handling log rotation and container restarts gracefully.

## Accessing Container Machine Logs

Container machines are the virtual machines that run one or more containers. The `container machine logs` command, implemented in [`Sources/ContainerCommands/Machine/MachineLogs.swift`](https://github.com/apple/container/blob/main/Sources/ContainerCommands/Machine/MachineLogs.swift), mirrors the container-log flow but targets the VM itself.

```bash

# Show the latest logs from the default machine

container machine logs

# Show the last 200 lines of a specific machine

container machine logs -n 200 my-machine

# Follow the log output live

container machine logs --follow my-machine

# Include the VM boot log

container machine logs --boot my-machine

```

The `MachineLogs` command contacts the XPC **MachineAPIService** via `MachinesService.logs(id:)`, which returns an array of `FileHandle`s representing the machine's logs. The command then prints or follows the selected handle exactly as `ContainerLogs` does, using the same async streaming mechanism for real-time updates.

## Querying System Logs

Unlike container and machine logs that read from file handles provided by XPC services, the `container system logs` command interfaces directly with macOS's unified logging system. Located in [`Sources/ContainerCommands/SystemLogs.swift`](https://github.com/apple/container/blob/main/Sources/ContainerCommands/SystemLogs.swift), the `SystemLogs.run()` method constructs a `log` command line and executes it via `Process`.

```bash

# Show logs from the last 5 minutes (default)

container system logs

# Show logs from the last 2 hours

container system logs --last 2h

# Follow system-log events as they occur

container system logs --follow

```

The implementation builds arguments such as `log show --last 5m --predicate "subsystem = 'com.apple.container'"`. If `--follow` is supplied, it uses `log stream` instead. The process stdout/stderr are attached directly to the CLI, so output appears immediately without buffering.

## Programmatic Log Access

You can also retrieve logs programmatically using the Swift client libraries directly:

```swift
// Using the ContainerClient to fetch stdio and boot logs
let client = ContainerClient()
let handles = try await client.logs(id: "my-web-server")
// handles[0] = stdio log, handles[1] = boot log
let stdioData = try handles[0].readToEnd()
print(String(data: stdioData!, encoding: .utf8)!)

```

```swift
// Fetching machine logs via the XPC client
let machineClient = MachineClient()
let machineHandles = try await machineClient.logs(id: "my-machine")
let logData = try machineHandles[0].readToEnd()
print(String(data: logData!, encoding: .utf8)!)

```

```swift
// Executing system logs manually via Process
let process = Process()
process.launchPath = "/usr/bin/env"
process.arguments = ["log", "show", "--last", "10m",
                    "--predicate", "subsystem = 'com.apple.container'"]
process.standardOutput = FileHandle.standardOutput
try process.run()
process.waitUntilExit()

```

## Key Implementation Files

The log retrieval architecture spans these critical source files:

- **[`ContainerLogs.swift`](https://github.com/apple/container/blob/main/ContainerLogs.swift)** – CLI command implementing the `container logs` subcommand with tail/follow logic and file-handle selection
- **[`MachineLogs.swift`](https://github.com/apple/container/blob/main/MachineLogs.swift)** – CLI command for `container machine logs` that mirrors container-log handling for virtual machines
- **[`SystemLogs.swift`](https://github.com/apple/container/blob/main/SystemLogs.swift)** – CLI command for `container system logs` that builds and executes the OS `log` utility
- **[`ContainersService.swift`](https://github.com/apple/container/blob/main/ContainersService.swift)** – XPC server method `logs(id:)` that opens the container's log files and returns file descriptors
- **[`MachinesService.swift`](https://github.com/apple/container/blob/main/MachinesService.swift)** – XPC server method `logs(id:)` for container-machine log files
- **[`ContainerClient.swift`](https://github.com/apple/container/blob/main/ContainerClient.swift)** – Client wrapper that issues the XPC `logs` request and returns `[FileHandle]`
- **[`MachineClient.swift`](https://github.com/apple/container/blob/main/MachineClient.swift)** – Client wrapper for machine-log XPC calls

## Summary

- **Three distinct commands** handle different log sources: `container logs` for application output, `container machine logs` for VM-level logs, and `container system logs` for subsystem diagnostics.
- **File-handle transport** avoids network copying by passing direct file descriptors from XPC services to the CLI, enabling efficient streaming of large log files.
- **Real-time following** uses `AsyncStream` implementations in [`ContainerLogs.swift`](https://github.com/apple/container/blob/main/ContainerLogs.swift) and [`MachineLogs.swift`](https://github.com/apple/container/blob/main/MachineLogs.swift) to watch file descriptors for new data without polling.
- **Boot log access** is available for both containers and machines via the `--boot` flag, which selects the second file handle in the returned array.
- **System integration** leverages macOS's native `log` utility for consistent formatting, time-filtering (`--last`), and predicate-based filtering of subsystem messages.

## Frequently Asked Questions

### What's the difference between container logs and machine logs?

**Container logs** (`container logs`) capture the stdout/stderr of the specific container process, while **machine logs** (`container machine logs`) capture output from the virtual machine hosting the containers. According to [`MachineLogs.swift`](https://github.com/apple/container/blob/main/MachineLogs.swift), the machine logs include lower-level VM operations and boot sequences that occur before individual containers start, whereas container logs focus on application-level output.

### How does the `--follow` flag work for real-time streaming?

When `--follow` is specified, the code in [`ContainerLogs.swift`](https://github.com/apple/container/blob/main/ContainerLogs.swift) switches from a historical tail operation to an `AsyncStream` that monitors the file descriptor for new data. This approach handles log rotation and container restarts gracefully by watching the underlying file handle rather than buffering the entire output, providing true real-time log streaming similar to `tail -f`.

### Can I retrieve boot logs from a stopped container?

Yes. The `container logs --boot` command accesses the boot log file handle (`fhs[1]` in the returned array) which persists independently of the running container process. As implemented in [`ContainersService.swift`](https://github.com/apple/container/blob/main/ContainersService.swift), the XPC service opens these log files directly from the filesystem, making them available even if the container has stopped, provided the log files haven't been rotated or deleted.

### Why do system logs use a different implementation than container logs?

**System logs** (`container system logs`) target the macOS unified logging subsystem rather than container-specific files. As shown in [`SystemLogs.swift`](https://github.com/apple/container/blob/main/SystemLogs.swift), this command constructs and executes the native `log show` or `log stream` commands via `Process`, leveraging the operating system's built-in log management, filtering, and formatting capabilities rather than implementing custom file parsing logic.