XcodeのConsoleは、NSLog、print、os_logの出力やアプリのクラッシュログをリアルタイムで表示するiOS開発用のデバッグツールです。Apple Unified Loggingによると、iOS 10以降、AppleはUnified Logging Systemによるメッセージの集中収集のために、NSLogの代わりにos_logを使用することを推奨しています。Consoleはデバッガの出力とシステムメッセージを単一のDebug Areaウィンドウに統合し、開発のどの時点でもアクセス可能です。
重要なポイント
ConsoleはXcodeのDebug Areaの一部で、エディタの下部パネルにあります(View → Debug Area → Activate Console、ショートカットCmd + Shift + Y)。Consoleは実行中のアプリからのすべてのテキスト出力(NSLog、os_log、printからのメッセージ、実行時警告、アプリクラッシュ時の自動例外ダンプ)を表示します。
Consoleはシミュレータと物理デバイスの両方で動作します。シミュレータでは、メッセージはローカルパイプを介して即座に届きます。デバイスでは、USB接続を介して1~3フレームの遅延で届きます。本番アプリでは、デバイス上のConsoleは利用できません。開発者はCrashlyticsやlog collectによるリモート収集を備えたUnified Loggingに依存します。
MacのシステムConsole.appとは異なり、XcodeのConsoleウィンドウは現在実行中のアプリのログのみを表示します(フィルタリング機能付き)。Console.appはiOSシミュレータを含むMac上のすべてのプロセスのログを収集します。ただし、iOSアプリのデバッグには、LLDBデバッガとの統合により、開発者は組み込みのXcode Consoleを使用します。
3つの主要なAPIがiOS開発者がConsoleに出力するために利用できます:NSLog(非推奨)、os_log(推奨)、print(Swiftのみ)。それぞれ、パフォーマンス、書式設定、Unified Logging Systemとの互換性において独自の特徴があります。
NSLogはFoundationの関数で、Objective-CとSwiftで利用できます。NSLogはタイムスタンプ、プロセス名、PIDとともにメッセージを出力します。欠点:NSLogは同期的にシステムバッファに書き込み、書き込み中に現在のスレッドをブロックします。頻繁な呼び出し(ループ内など)では、NSLogは顕著な遅延を引き起こします。Appleは新しいプロジェクトにNSLogを推奨していませんが、レガシーコードやサードパーティライブラリとの互換性は維持されています。
os_logはiOS 10で導入されたos.frameworkのAPIです。os_logは非同期で、メッセージはキューに入れられ、呼び出しスレッドをブロックせずにバッファに書き込まれます。WWDC 2016によると、高負荷シナリオではos_logはNSLogより50倍高速です。os_logは動的制御もサポートしています。DEBUGレベルのメッセージはDebugビルドでのみ収集され、Releaseではオーバーヘッドなしで無視されます。
print()はSwiftで最もシンプルな出力方法です。printはstdout(標準出力)に書き込み、XcodeがそれをConsoleにリダイレクトします。printはメタデータ(時刻、レベル)を追加しませんが、stdoutバッファリングをサポートします。簡単なデバッグにはprintは便利なツールですが、永続的なロギングでは機能性と制御の面でos_logに及びません。
import os.log
// NSLog — 非推奨、ブロッキング
NSLog("Application started")
// os_log — 推奨、非同期
let log = OSLog(
subsystem: "com.myapp",
category: "lifecycle"
)
os_log("Application started", log: log)
// print — 高速Swift出力
print("Application started")
Unified Logging System(ULS)はiOS 10とmacOS Sierraで導入されたAppleのエンドツーエンドのロギングインフラストラクチャです。ULSはすべてのシステムプロセスからのメッセージを単一のストレージに収集し、Macのlogコマンドラインツールを介したリモートアクセスを可能にします。開発者はULSへの書き込みにos_logを、読み取りにConsoleを使用します。
各OSLogはsubsystem(例:com.myapp.network)とcategory(例:http、websocket)のペアで識別されます。サブシステムはアプリケーションドメインです(1つのアプリは異なるモジュールに対して複数のサブシステムを持つことができます)。カテゴリはサブシステム内のコンポーネントです。subsystem + categoryの組み合わせにより、Consoleとlog collectで柔軟なログフィルタリングが可能になります。
| レベル | OSLogType | Console表示 | Release収集 |
|---|---|---|---|
| Default | .default | 常に | はい |
| Info | .info | os_log UI有効時 | はい |
| Debug | .debug | Debugビルドのみ | いいえ |
| Error | .error | 常に赤ラベル | はい |
| Fault | .fault | 常に紫ラベル | はい |
Macのlog collectコマンドは、接続されたiOSデバイスからアーカイブされたログを.logarchiveファイルに収集します。このファイルはMacのConsole.appで開いて詳細な分析が可能で、os_logメッセージ、クラッシュログ、システム診断が含まれます。デバイスでの収集を有効にするには、開発者モードを有効にし、USBでデバイスを接続する必要があります。
Consoleでの実践的な作業には、開発中のアクティブなロギング、クラッシュ後のクラッシュログ分析、.logarchiveによるリモート診断の3つの主要なシナリオがあります。各シナリオには最適なツールと設定があります。
各アプリケーションモジュールに対して、debug(詳細デバッグ)、info(主要な状態遷移)、error(例外と障害)のレベルで個別のOSLogを作成することをお勧めします。Xcode Consoleで、アプリケーションのサブシステムでフィルタリングを有効にし、ノイズを生み出しアプリのロジックから注意をそらすシステムメッセージを除外します。
アプリがクラッシュすると、Xcodeは自動的に実行を停止し、Consoleに完全なスタックトレースとともにクラッシュが発生したスレッドを表示します。クラッシュログの最初の行には、例外の種類(NSException、EXC_BAD_ACCESS)と理由が含まれています。スタックトレースを下から上に調べます。最後に呼び出されたメソッドがクラッシュの場所です。暗号化されたアドレス(Release)の場合は、dSYMによるシンボリケーションが必要です。
// OSLogのモジュール設定例
extension OSLog {
static let uiLifecycle = OSLog(
subsystem: "com.myapp.ui",
category: "lifecycle"
)
static let network = OSLog(
subsystem: "com.myapp.network",
category: "http"
)
static let database = OSLog(
subsystem: "com.myapp.data",
category: "core-data"
)
}
// レベルでの使用
os_log("View did load", log: .uiLifecycle, type: .debug)
os_log("HTTP 200 received", log: .network, type: .info)
os_log("Failed to save: \(error.localizedDescription)",
log: .database, type: .error)
Xcode Consoleは単純なロギングを超えるいくつかの高度な機能をサポートしています。ブレークポイントログは実行を停止せずにConsoleにメッセージを出力でき、Debugger CommandのLLDBコマンドは出力の書式設定を完全に制御できます。
Consoleにメッセージを出力して自動的に実行を続けるようにブレークポイントを設定できます。目的の行にブレークポイントを設定し、右クリック→Edit Breakpoint→Debugger Commandを追加:「po self」または「expr @import UIKit」+ Debugger Command:「po self.view」。Automatically continue after evaluatingにチェックを入れます。起動後、ブレークポイントは行に到達するたびにコマンド結果をConsoleに出力し、スレッドを中断しません。
Xcode Consoleはブレークポイントで停止中に任意のLLDBコマンドの実行をサポートしています。po(print object)はオブジェクトの説明を出力し、p(print)はプリミティブ値を出力し、exprはSwift/ObjC式を実行します。書式付き出力にはp/CGRectGetWidthを使用します。LLDB出力はブレークポイントに到達するとすぐにConsoleに表示されます。
func processUserData(user: User) {
// Debugger Commandのブレークポイント:
// po "User name: \(user.name)"
// expr user.age = 30
print("Processing user: \(user.name)")
}
// シーケンスを使ったカスタムロギングの例
func trackMethodCall(
file: String = #file,
function: String = #function
) {
os_log("[\(function)] called",
log: .uiLifecycle, type: .debug)
}
Xcode ConsoleはXcodeのプロファイリングツールであるInstrumentsと密接に統合されています。Product→ProfileからLoggingテンプレートでアプリを実行すると、すべてのos_logメッセージがタイムスタンプ付きでInstrumentsトレースに記録されます。これにより、単一のタイムラインでログ、パフォーマンス、システムイベントを同時に表示でき、競合状態やパフォーマンス低下の診断に重要です。
よくある質問
NSLogは同期的でスレッドをブロックし、常にメッセージを出力します。os_logは非同期で、高負荷シナリオで50倍高速で、カテゴリをサポートし、パフォーマンスを低下させることなくReleaseビルドでデバッグレベルを動的に無効にします。
ロギングレベルを確認してください:デフォルトでは、Consoleはdefault以上のみを表示します。infoとdebugを表示するには、Xcode Consoleでos_logメニューを開き、スキーム設定でInclude Info MessagesとInclude Debug Messagesを選択します(Edit Scheme→Run→Arguments→OS_ACTIVITY_MODE = debug)。
Consoleで目的のメッセージを選択し、コピー(Cmd + C)して任意のテキストエディタに貼り付けます。完全なダンプのには、ターミナルコマンドを使用します:sudo log collect --device --output /tmp/app_logs.logarchive — iOSデバイスからすべてのログを構造化形式で保存します。
os_logタイプ.defaultと.errorはデフォルトでReleaseで動作します。Releaseで.infoと.debugを有効にするには、Xcodeスキームに起動引数-OSLogPreferencesApp「$(PRODUCT_BUNDLE_IDENTIFIER):debug」を追加する必要があります。この引数がないと、デバッグメッセージはReleaseで収集されず、デバイスリソースを節約します。
XcodeでWindow→Organizer→Crashesを開きます。オーガナイザは、例外の種類でグループ化された、テスターのデバイスから収集されたすべてのクラッシュログを表示します。シンボリケーションには、クラッシュが発生したビルドの.dSYMファイルが必要です。Xcodeはアーカイブが利用可能な場合、自動的にそれを見つけます。
まとめ
ターンキー方式のモバイルアプリケーションを開発します
IT Sectrは2017年からスタートアップや企業向けにiOS・Androidアプリケーションを開発しています。私たちがご相談に乗り、最適なソリューションをご提案します。