How to View iOS Simulator Console Logs Without Running Xcode

How to View iOS Simulator Console Logs Without Running Xcode

Written by

in

Quick answer: Run xcrun simctl spawn booted log stream in Terminal to stream live logs from the booted simulator, even when Xcode isn’t running the app. For web content in Mobile Safari or a web app, use Safari’s Develop menu to open Web Inspector for the simulator instead.

Why this happens

The Xcode debug console only shows output from a process Xcode launched or attached to. If you open Safari in the Simulator, tap a link, or launch an app from the home screen, nothing appears in Xcode, because it isn’t debugging that process.

The logs still exist. Modern iOS, including the simulated version, writes them to the unified logging system. You just need a tool that reads that stream from the simulator instead of from Xcode.

Older advice tells you to tail -f /var/log/system.log, or to read files under ~/Library/Logs/iOS Simulator/ or ~/Library/Logs/CoreSimulator/<simulator-hash>/system.log. Those paths belonged to older Xcode and macOS releases. On current setups, use the methods below instead.

How to fix it

1. Stream logs with simctl in Terminal

This is the most reliable method and works whether or not Xcode is open. Boot a simulator, then run:

xcrun simctl spawn booted log stream

booted means the currently running simulator. If several are booted, pass the device UDID instead. List them with:

xcrun simctl list devices booted

Then:

xcrun simctl spawn <UDID> log stream

The unfiltered stream is very noisy, because the whole system logs into it. Narrow it down with a predicate:

# Only one process
xcrun simctl spawn booted log stream --predicate 'process == "MobileSafari"'

# Only your app's subsystem
xcrun simctl spawn booted log stream --level debug --predicate 'subsystem == "com.example.myapp"'

By default, log stream hides debug-level messages. Add --level debug if you use Logger or os_log at debug level.

To look at what already happened, instead of streaming live:

xcrun simctl spawn booted log show --last 5m

2. Launch your app from Terminal and attach its output

If you want stdout and stderr (for example from print) of your own app, launch it through simctl:

xcrun simctl launch --console booted com.example.myapp

The app’s output is printed in your terminal. Use --console-pty if you need a pseudo-terminal. Replace the bundle identifier with your own.

If you want to log from your own code in a way that works with the stream above, use Logger:

import os

let logger = Logger(subsystem: "com.example.myapp", category: "network")

func load() {
    logger.debug("Starting request")
    logger.error("Request failed")
}

Then filter on the subsystem as shown in fix 1.

3. Open the system log from the Simulator menu

The accepted answer on the original question mentions a menu item: with the Simulator in front, go to Debug > Open System Log. This opens the simulator’s system log in a viewer on your Mac. Menu items change between Xcode versions, so if you don’t see it, use the simctl approach above, which doesn’t depend on the menu layout.

4. Use Safari Web Inspector for web content

If your goal is to see console output from a web page or web app running in the simulator (JavaScript console.log, network requests, link taps), the system log isn’t the right tool. Use Safari’s inspector:

  1. In desktop Safari, enable the Develop menu. Open Safari’s settings, go to the Advanced tab, and turn on the option to show the Develop menu or web developer features.
  2. Boot the Simulator and open the page in Mobile Safari, or open your web view.
  3. In desktop Safari, choose Develop, then your simulator’s name, then the page’s site name.

This opens the same Web Inspector you would use for a physical iPhone, with a JavaScript console, elements, and network tabs.

For your own WKWebView, set isInspectable = true (iOS 16.4 and later) in debug builds, or it may not appear in the Develop menu:

import WebKit

let webView = WKWebView()
#if DEBUG
if #available(iOS 16.4, *) {
    webView.isInspectable = true
}
#endif

5. Attach Xcode to a running process

If you do want the Xcode console, you can attach after the fact. In Xcode, choose Debug > Attach to Process and pick your running app from the simulator list. The console then shows output from that point on. This only captures new output, not what was logged before attaching.

How to prevent it

  • Use Logger with a consistent subsystem and category so you can filter precisely.
  • Keep a saved Terminal alias or script for xcrun simctl spawn booted log stream with your predicate.
  • Don’t rely on print for anything you may need to read outside Xcode. Unified logging works in every tool.
  • Set isInspectable in debug builds of web views so you can always inspect them.
  • Don’t depend on old log file paths. They have changed several times between Xcode releases.

FAQ

Why does log stream show so many unrelated messages?

The simulator logs everything from its simulated system processes. Filter by process, subsystem, or category with --predicate to see only what matters.

Can I use Console.app instead of Terminal?

Yes, for many cases. Simulator processes log to the unified logging system, so Console.app on your Mac can show them, and you can filter by process name. The simctl command is more precise because it targets one specific simulator.

Why doesn’t my web page’s console show up in the system log?

JavaScript console output belongs to Web Inspector, not the system log. Open it through Safari’s Develop menu, and make sure the web view is inspectable if it is your own app’s WKWebView.

Sources & credits

Parts of this guide are adapted from content licensed under CC BY-SA 3.0; this article is shared under the same license.