しおメモ

雑多な技術系ブログです。ニッチな内容が多いです。

OSLogを利用したロギング

iOS開発でログを利用する場合、自前のロガーを利用したり、OSSを利用する選択肢が多いですが、標準のOSLogのAPIが新しくなり、iOS14以降で使いやすくなりそうなので、紹介します。

printと比べて何が良いか

Xcodeの使い勝手が原因でもあるのですが、printで出力された情報は他のログと混ざりやすく、検索もまともにできないので、ログを出力するのには向いていません。

OSLogは今まで通りXcode上のconsoleに出力をしつつ、Console.appで視覚的にログを追いやすくすることができます。

OSLogを利用した出力

iOS14以上では、新しいAPIを使って直感的な記法で記述することができますが、それ以下のiOSをサポートしている場合は古い方のAPIを利用する必要があります。(機能は同等です)

Loggerを用意する

iOS14からはLoggerインスタンスを用意します。

import os
let logger = Logger(subsystem: "com.flyingalpaca.sample", category: "Network")

subsystemを利用してどのアプリケーションから出力されたログ化を識別します。 他のアプリケーションと区別しやすくするために、上のような逆DNS記法で書くことが推奨されています。

categoryはアプリ内のどこから出力されたログかを識別するのに利用します。 こちらは、NetworkUIなど適当につけても大丈夫です。

iOS14以前の古いAPIでの記法はこちらです。

import os.log
let osLog = OSLog(subsystem: "com.flyingalpaca.sample", category: "Network")

共通で利用するものは、staticでどこかにインスタンスを作っておくと便利です。

import os

extension OSLog {
    static let network = Logger(subsystem: "com.flyingalpaca.sample", category: "Network")
}

ログを出力する

新しいAPIでは、出力のインターフェースが他の言語でもあるような形式に変更されました。

以下のような書き方で出力することができます。

logger.trace("trace")
logger.debug("debug")
logger.info("info")
logger.notice("notice")
logger.error("error")
logger.fault("fault")
logger.critical("critical")

詳しい解説がないのも含めれば、7種類ログレベルが存在します。 下に行くほど深刻度が高くなります。(詳しくは下のドキュメントや、docコメントを参照してください)

https://github.com/apple/swift-log/blob/1.2.0/Sources/Logging/Logging.swift#L323-L352

tracedebugはストレージへの書き込みをデフォルトでは行わないので、オーバーヘッドが少なくなっています。
infoはツールを使ってログを収集しているときのみ、ストレージにログを保持します。
criticalはデベロッパードキュメントには記載されていないですが、上のソースコードのdocコメントを参照すると、このログを送った場合、ロガーがスタックトレースのキャプチャなどの重い処理を行えるようになると書いてあります。(逆に言えばオーバーヘッドがあるので、名前の通り致命的な場合以外は使わないほうが良さそうです)

古いAPIでは、os_logというメソッドを使います。

os_log(.info, log: osLog, "info")
os_log(.error, log: osLog, "error")

ログの記法

新しいAPIではOSLogMessageを引数にとっていますが、このインスタンスを直接生成してはいけません。

OSLogInterpolationを介して独自のフォーマットで記述することで、より柔軟な出力を行うことができます。

logger.info("started: \(1000000, format: .secondsSince1970)")

let value: UInt32 = 3735928559
logger.info("address: \(value, format: .hex)")
2021-03-07 17:26:44.471594+0900 LoggerTest2[7455:334390] [view] started: 1970-01-12 22:46:40+0900
2021-03-07 17:26:44.471784+0900 LoggerTest2[7455:334390] [view] address: deadbeef

詳しくは、以下の"Format Custom Values in Message Strings"の部分や、各formatの実装を参照してください。

developer.apple.com

ここで出力される情報は、誰でもアクセスできるので、第三者に知られたくない重要な情報はマスクする必要があります。
デフォルトでは、数値はマスクされず、それ以外のオブジェクトはマスクされます。

let value: UInt32 = 3735928559
logger.info("address: \(value, format: .hex, privacy: .private(mask: .hash))")

古いAPIでは、以下のような記法になります。(情報が少なく、printf likeな書き方でここが使いづらかった部分の一つです。)

let value: UInt32 = 3735928559
os_log(.info, log: osLog, "address: %{private}x", value)

ログの確認

Xcodeのコンソールにも出力されますが、OSLogを経由するとログを確認する方法があります。

Console.appを利用した確認

Console.appを利用すると、GUIを通じてログを確認することができます。 また、先程設定したsubsystemcategoryを利用して、ログをフィルタリングすることができます。

f:id:scior:20210307181956p:plain

上の画像のように、右上にフィルターの条件を記述します。

infodebugのログは、初期設定では表示されないので、以下の部分にチェックを入れます。

f:id:scior:20210307182017p:plain

複数行のログもまとめて吐かれるので、printよりも検索しやすくなっています。

f:id:scior:20210307182051p:plain

logコマンドを使った確認

log collectlog showを使ってターミナル上でも確認することができます。

log collect --device 00008101-001E69993EC2001E --last 1h
log show --predicate '(subsystem == "com.flyingalpaca.sample")' --info --last 1h --archive ./system_logs.logarchive
2021-03-07 18:26:22.876033+0900 0x7a513    Info        0x25c42e             2997   0    LoggerTest2: [com.flyingalpaca.sample:view] info
2021-03-07 18:26:22.876050+0900 0x7a513    Default     0x25c42e             2997   0    LoggerTest2: [com.flyingalpaca.sample:view] notice
2021-03-07 18:26:22.876177+0900 0x7a513    Error       0x25c42e             2997   0    LoggerTest2: [com.flyingalpaca.sample:view] error
2021-03-07 18:26:22.876522+0900 0x7a513    Fault       0x25c42f             2997   14   LoggerTest2: [com.flyingalpaca.sample:view] fault
2021-03-07 18:26:22.876718+0900 0x7a513    Fault       0x25e510             2997   14   LoggerTest2: [com.flyingalpaca.sample:view] critical
2021-03-07 18:26:22.876840+0900 0x7a513    Info        0x25c42e             2997   0    LoggerTest2: [com.flyingalpaca.sample:view] started: 1970-01-12 22:46:40+0900
2021-03-07 18:26:22.876899+0900 0x7a513    Info        0x25c42e             2997   0    LoggerTest2: [com.flyingalpaca.sample:view] address: deadbeef

テキスト処理をしたい場合は、こちらも活用できます。 (あまりWWDCの動画などでは情報がないので、man logを参照すると良さそうです)

OSLogに関するドキュメントやWWDCのセッション

ぜひみてください