システムログを取得してみた

##はじめに
こんにちは。NTTドコモ 3年目社員の百瀬です。
自分はサービスデザイン部という部署でコンシューマ向けのアプリ開発をしています。
アプリ開発を担当してから早１年半。まだまだ駆け出しの開発者ですが、沢山の方に便利に使ってもらえるアプリを目指して日々奮闘しております！！
今回はチームの悩みを解消する取り組みの中で、システムログ取得について調査する機会があったので、自分の備忘録もかねてこちらの記事を書くことにしました。


##チームの悩み
私たちのチームでは、より良いアプリにしていくために、アプリを社内の人に使ってもらって、改善点や問題点を洗い出す取り組みを始めました。
アプリ関係者よりもユーザに近い方の生の声を聞ける機会はすごくありがたく、アプリの改善に役立っていることを実感する一方でこちらの取り組みの課題も見えてきました。
下記のようなケースが度々現れていて、「**原因特定までに時間がかかってしまっている**」のです。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2286365/9b52c04b-fb0b-fd9d-13f4-41ab860224ea.png" width=100%>
事象の再現が出来て解析が進められればまだ良い方ですが、中には時間をかけてやり取りしたにも関わらず、事象再現ができずにそこまでの労力が無駄になってしまうこともあったり・・・
こちらの課題を解決するために、

■ 誰でも簡単に**「テスト時の利用ログや環境情報を収集できる」「収集した情報を報告できる」**
■ アプリ開発者が**「いつでも報告情報にアクセスし、解析に役立てることができる」**

上記仕組みを持ったSDK＋Webページを作成し、
こちらのSDKをテスト用のアプリに組み込むことで、アプリ不具合をいち早く見つけ、即時に解析できる環境を作成しました。

##システムログ取得について調査してみた
アプリがクラッシュした場合にも調査できるようにしたかったため、アプリログだけでなく、システムログまで取得したいぞという気持ちで調査を進めていましたが、こちらがなかなかに大変でした...
各OSでのシステムログ取得についてまとめます。
###Androidでのシステムログ取得処理
####ログ取得処理
■ `AndroidManifest.xml`　に`READ_LOGS`の権限を追加

```java
public static final String READ_LOGS
```
Allows an application to read the low-level system log files.
Not for use by third-party applications, because Log entries can contain the user's private information.
Constant Value: "android.permission.READ_LOGS"
<参考>https://developer.android.com/reference/android/Manifest.permission?authuser=1#READ_LOGS

■ [logcatコマンドラインツール](https://developer.android.com/studio/command-line/logcat?authuser=1#outputFormat)`logcat -v time`を使ってシステムログを取得
　Logcatコマンドは、デバイスが出力したシステムメッセージのログをダンプするコマンドラインツールです。

####作成したSDKでのログ取得の仕組み
実際に作成したSDKでは下記のような構成をとってシステムログ取得を実現しています！
ユーザデバイスにすでに存在するログデータをキャプチャしているイメージで、新たに端末内にファイルの保存は行っていません。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2286365/2c887fa3-e414-4817-b1b2-fd61519e2883.png" width=60%>


####Android ロギングの仕組み(参考)
Android ロギングシステムは、システムプロセスlogdによって維持される循環バッファ(リングバッファ)セット。
使用可能なバッファセットは固定され、システムによって定義されている。
各ログには、優先度(VERBOSE、DEBUG、INFO、WARNING、ERROR、FATAL)とログの発信元のタグ、ログメッセージが含まれる。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2286365/4f2ab87e-bf02-2399-4971-b85f6bc5e348.png" width=70%>
出典：https://dzone.com/articles/android-log-analysis
<参考>
・https://dzone.com/articles/android-log-analysis
・https://www.slideshare.net/tetsu.koba/logging-system-of-android-5111399
###iOSでのシステムログ取得処理
システムログを端末から抜き出す方法を探す旅、こちらが長旅でした。。
####ログ取得方法を検討
**手動でログを抜く**やり方として下記３つを最初考えました。
・Macにつないで、XCode経由で抜く
・Macにつないで、Console.app経由で抜く
・端末の電源ボタンと音量ボタンを長押ししてiPhone内にsysdiagnoseログを出力して送信してもらう(詳細は以下公式手順参照）
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2286365/eb5b522e-a14c-ef6f-f8ef-571952f94b9f.png" width=50%>
システムログ自体を抜き出すことは可能だと分かりましたが、開発知識０の方もユーザとして想定しているため、ユーザにやってもらう操作としてはどれもハードルが高すぎます。
他に良い方法はないのか調査を進めていくと・・・

####どうやらiOS15でシステムログ取得が可能になっているらしい！
別の方法としてアプリ内からシステムログを参照する方法がないか、AppleDeveloperのフォーラムを調べまわったところ、１つ出来そうな方法を発見しました。

```
[以下、超意訳]
質問者：　ヘイ！デバッグのためにアプリのログをテスターに取得してもらうのめんどくさすぎるんだけど何か良い方法はないのかい？
村人A：　 OSLogStoreクラスでログが取得できるようになったみたいですぜ
村人B：　 OSLogStoreはMacOSでしか動作しないよ、iOSには対応してない
Apple公式：　
　　　　　経緯を説明させてくれ
　　　　　　・OSLogStoreはmacOS10.15で実装
　　　　　　・この時はiOSには非対応
　　　　　　・iOS14ベータ版でiOSにも対応した
　　　　　　・ただ問題が見つかってベータ版の初期段階でこの機能は削除となった
　　　　　　・現在のところこの機能は削除されたままで、この先実装されるかも未定
　　　　　ただ開発チームはこの機能の需要が多いことはちゃんと理解してるぜ！

...それからしばらくして
村人C： iOS15ベータ版でOSLogStoreが復活したっぽいぞ！！
```

<参考>
https://developer.apple.com/forums/thread/650843
https://developer.apple.com/forums/thread/677068

というわけで、
2021/08/11にリリースされたIOS15ベータ版で`OSLogStore`というモジュールが追加されており、
これを利用することでアプリケーションから端末内部のログを取得できるようになったようです。
また、printログに関しては出力されていないようで、取得できるログの種類は以下です。

|ログの種類 |取得可否|
|:--------|:-----:|
|OSLog| ○|
|NSLog |○|
|print|×|
|アプリに関連するログ/BackgroundTask等|○|
|crashログ|○|

####作成したSDKでのログ取得の仕組み
■iOS15から追加になった`OSLogStore`モジュールを使ってシステムログを取得

```swift
class OSLogStore : NSObject
```
**Overview**
Instances of this class represent a fixed range of entries and may be backed by a logarchive or your Mac's local store. Use the getEntries(with:at :matching:) function to retrieve a filtered array of log entries.
<参考>https://developer.apple.com/documentation/oslog/oslogstore


OSLogStoreの仕組みとしては、
ログアーカイブに基づいてログストアを作成し、作成したログストアから指定された位置のログを取得することができます。

実際に作成したSDKでは下記のようにAndroidと同様の構成をとなっています。
iOSに関してはログの仕組みの公開が少ないため、実際の端末内でのログの仕組みは不明な部分がありますが、
すでに出ているログを取得するという意味では、Android側とログ取得方法は同じ考え方かなと思っています。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2286365/ef903cf0-0dff-05c9-7b67-fc5a2fff128d.png" width=60%>

##まとめ
β版に機能として載ったけど、最終版に載ってこない機能もあると思うので、今回OSLogStoreが追加されたのはラッキーでした。
ありがとう！Appleさん！
Androidに比べてiOSは公開されているログ周りの情報が少ないなぁと実感したので、この記事が少しでも誰かのお役に立てれば嬉しいです。
ここまで読んでいただきありがとうございました！