Unified Logging の出力をアプリから見られるようにする

Apple プラットフォームのアプリには Unified Logging というログの仕組みがあります。Unified Logging のログはユーザのデバイスに溜まるだけで開発者が見られるわけではないため、サーバサイドアプリケーションのログと比べると役立つ場面は限定的です。しかし、出力しておくとアプリが想定しない挙動をした時の調査などで助かることがあります。

以下の WWDC のセッションではログを不具合解決に役立てる様子が紹介されています。

developer.apple.com

個人的な経験としても、開発しているアプリの TestFlight 版を常用していて変な動作があったらログを見ることがあります。また、例えばデバッグビルドでは再現しなかったり、 QA エンジニアでの端末でのみ発生する不具合などを修正する際にはデバッガで動作を追うことができないのでログが唯一の手掛かりになり得ます。 しかし、 Unified Logging の出力を見るためにはデバイスMac に繋げて Console.app を開いて自分のアプリのログをフィルタする...という手順を踏む必要がありなかなか面倒です。わざわざログを見ないといけない状況になっているということはその時点で面倒が発生しているはずなので、調査のためにさらなる面倒を背負うのはやめたいものです。

OSLogStoregetEntries メソッドを呼ぶことで、 Unified Logging の出力を配列としてアプリ内から取得することができます。取得できるということはアプリ内のデバッグ用画面などにログを表示できるということで、そうなるとログへのアクセスがだいぶしやすくなります。

developer.apple.com

以下のコードでアプリの起動直後からのログを取得することができます。 entries の要素それぞれが、メッセージに加えてログレベルやカテゴリ、出力された日時の情報を持っています。

let store = try OSLogStore(scope: .currentProcessIdentifier)
let position = store.position(timeIntervalSinceLatestBoot: 1)

let entries = try store.getEntries(at: position)

取得したログは当然アプリで自由に操作できるので、例えば以下のようにログのカテゴリやメッセージでフィルタする UI を作ることができます。

ただし、この方法ではアプリ起動後のログしか取得できないため、アプリの前回起動中のログを見たい場合には Console.app を利用する必要があります。もしアプリから起動前のログを取得する方法をご存知の方は教えてください。

モバイルアプリのログによって開発のしやすさが爆増するということはあまりないと思うのですが、いざという時やふとした時に役立つこともあるし、アプリ内でログを見られるようにする手間はほとんどないので、やり得と思って自分はいつも見られるようにしています。

参考までに、上記の gif を実現するためのコードを載せておきます。自分が最近趣味で開発しているアプリのものをそのまま載せていますが、ログのカテゴリは当然アプリによって異なるだろうし、細かい検索の UI なども好みや用途に合わせてカスタマイズするとよさそうです。

gist.github.com