iOS Simulator
console logs
iOS development
debugging
Xcode tips

How can I get the console logs from the iOS Simulator?

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

Introduction

The fastest way to get console logs from the iOS Simulator is through Xcode's debug console, which appears automatically when you run your app with Cmd + R. For more advanced filtering, use the xcrun simctl spawn command in Terminal or open the macOS Console app. Each method serves a different debugging workflow, from quick print() checks to structured log analysis.

Method 1: Xcode Debug Console

This is the default approach and covers most debugging scenarios.

Setup

  1. Open your project in Xcode and select an iOS Simulator as the run destination.
  2. Run the app with Cmd + R.
  3. Open the debug console with Cmd + Shift + C or navigate to View > Debug Area > Activate Console.

The console appears at the bottom of the Xcode window and shows output in real time.

What Appears in the Console

The Xcode console captures output from:

swift
1// Swift
2print("User tapped login button")          // stdout
3debugPrint(userObject)                      // stdout with debug description
4NSLog("Network request started")            // system log + stdout
5
6// Objective-C
7NSLog(@"Network request started: %@", url); // system log + stdout

The key difference between print() and NSLog() is that NSLog() writes to the system log with a timestamp and process identifier, while print() writes only to stdout. Both appear in the Xcode console, but only NSLog() output appears in the macOS Console app.

Filtering Console Output

Xcode's console has a filter bar at the bottom. You can type keywords to narrow the output, or use the toggle buttons to show only your app's output versus all process output.

For structured filtering, use the os logging framework instead of print():

swift
1import os
2
3let logger = Logger(subsystem: "com.myapp", category: "networking")
4
5logger.debug("Starting request to \(url)")
6logger.info("Response received: \(statusCode)")
7logger.error("Request failed: \(error.localizedDescription)")

This produces log entries with severity levels that Xcode can filter by category and type.

Method 2: Terminal With xcrun simctl

The simctl tool gives you direct access to simulator log streams from the command line. This is useful when you want to capture logs without Xcode or apply complex filtering.

List Available Simulators

bash
xcrun simctl list devices booted

This shows only currently running simulators with their UDIDs.

Stream Logs in Real Time

bash
xcrun simctl spawn booted log stream --level debug

This streams all log output from the booted simulator. The output is verbose, so filtering is essential.

Filter by Process Name

bash
xcrun simctl spawn booted log stream \
  --predicate 'process == "MyApp"' \
  --level debug

Filter by Subsystem and Category

If your app uses the os logging framework:

bash
xcrun simctl spawn booted log stream \
  --predicate 'subsystem == "com.myapp" AND category == "networking"' \
  --level debug

Filter by Message Content

bash
xcrun simctl spawn booted log stream \
  --predicate 'eventMessage CONTAINS "error"' \
  --level debug

Output Styles

bash
1# Compact format (one line per entry)
2xcrun simctl spawn booted log stream --style compact
3
4# JSON format (for piping to jq or scripts)
5xcrun simctl spawn booted log stream --style json
6
7# Syslog format
8xcrun simctl spawn booted log stream --style syslog

Method 3: macOS Console App

The Console app (Applications > Utilities > Console) provides a graphical interface for browsing logs from all processes, including simulators.

Steps

  1. Open Console.app.
  2. In the left sidebar, find the simulator device under the devices list. Booted simulators appear by name.
  3. Click the simulator device to view its log stream.
  4. Use the search bar to filter by your app's bundle identifier or specific keywords.

The Console app is particularly useful when you need to see logs from system frameworks that interact with your app, such as networking, push notifications, or background task scheduling. These logs are not visible in the Xcode console.

Method 4: Reading Log Archives

For debugging crashes or issues that already happened, you can read historical logs:

bash
1# Show logs from the last 5 minutes
2xcrun simctl spawn booted log show --last 5m \
3  --predicate 'process == "MyApp"'
4
5# Show logs from a specific time range
6xcrun simctl spawn booted log show \
7  --start "2024-03-15 14:00:00" \
8  --end "2024-03-15 14:05:00" \
9  --predicate 'process == "MyApp"'

Collecting a Log Archive

To share logs with a colleague or attach them to a bug report:

bash
xcrun simctl spawn booted log collect --output ~/Desktop/sim-logs.logarchive

Open the .logarchive file with Console.app for a full browsable view.

Comparison of Methods

MethodReal-timeHistoricalFilteringBest for
Xcode ConsoleYesNoBasic text filterDay-to-day development
xcrun simctl log streamYesNoPredicate-based (powerful)Advanced filtering, headless CI
xcrun simctl log showNoYesPredicate-based (powerful)Post-crash analysis
macOS Console.appYesYesGUI search barSystem-level log inspection

Logging Best Practices for Simulator Debugging

Use os.Logger Instead of print()

The os logging framework provides structured output with severity levels, subsystem grouping, and automatic redaction of sensitive data in release builds:

swift
1import os
2
3private let logger = Logger(subsystem: "com.myapp", category: "auth")
4
5func login(username: String) {
6    logger.info("Login attempt for user: \(username, privacy: .private)")
7    // ...
8    logger.error("Login failed: \(error.localizedDescription)")
9}

The privacy: .private modifier redacts the value in non-debug builds, preventing sensitive data from leaking into production logs.

Add Signpost Intervals for Performance

swift
1import os
2
3let signposter = OSSignposter(subsystem: "com.myapp", category: "performance")
4
5func loadData() {
6    let id = signposter.makeSignpostID()
7    let state = signposter.beginInterval("DataLoad", id: id)
8    // ... load data ...
9    signposter.endInterval("DataLoad", state)
10}

Signpost intervals appear in Instruments and help you correlate log output with performance traces.

Common Pitfalls

Relying exclusively on print() means your log output disappears the moment the Xcode session ends. print() does not write to the system log, so the Console app and log show commands cannot retrieve it. Use os.Logger or NSLog() for anything you might need to review after the fact.

Forgetting to filter by process name when using simctl log stream produces an overwhelming volume of system log output. Always add a --predicate filter to focus on your app's process.

Assuming the Xcode console shows all system logs is incorrect. Xcode only shows stdout/stderr from your process and os log output at the default level or above. System framework logs, kernel messages, and other process output require the Console app or simctl.

Not checking that the simulator is actually booted before running simctl spawn booted causes a "No devices are booted" error. Run xcrun simctl list devices booted first to verify.

Using NSLog() heavily in production code introduces performance overhead because it performs synchronous I/O. Reserve it for debug builds or migrate to os.Logger, which is designed for high-performance logging.

Summary

  • Use the Xcode debug console (Cmd + Shift + C) for standard development logging.
  • Use xcrun simctl spawn booted log stream with --predicate filters for advanced terminal-based log analysis.
  • Use xcrun simctl spawn booted log show to read historical logs after a crash or issue.
  • Use the macOS Console app to inspect system-level logs that do not appear in Xcode.
  • Prefer os.Logger over print() for structured, filterable, production-safe logging.
  • Always filter by process name or subsystem to avoid drowning in system log noise.

Related reading
Free course
Beginner
7 lessons
2 hours
Tackling System Design Interview Problems

A short course that equips you with the skills to approach system design interviews methodically.

Start the free course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

All Rights Reserved.