📝

UnityでDebug.Logの内容をファイルに出力する

2021/08/25に公開

タイトルの内容に苦しんだらしき形跡を見かけたので「ググル・コピペ・ジツを使うのだ!」などと思っていたのですが、いざけんさくしたら案外出てこなかったので作りました。

LogWriter.cs
https://gist.github.com/nekomimi-daimao/b9baa2282cd548fe066cf44d2fd35e7d

Unity標準のDebug.Logクラスから出力されるログをコンストラクタのパスに指定されたファイルにひたすら追記していくクラスです。UniTaskに依存しています。[1]

使い方

こんな感じで使います。

usage
private void Start()
{
    // /Assets/StreamingAssets/log/example.txt
    var path = Path.Combine(Application.streamingAssetsPath, "log", "example.txt");
    var logWriter = new LogWriter(path, this.GetCancellationTokenOnDestroy());
}

private void Update()
{
    Debug.Log(UnityEngine.Random.onUnitSphere);
    Debug.LogWarning(UnityEngine.Random.ColorHSV());
    Debug.LogError(UnityEngine.Random.rotation);
}

これを動かすとこんな感じに出力されます。

example.txt
20210825022416 [L] (0.4, -0.8, -0.4)
20210825022416 [W] RGBA(0.545, 0.403, 0.468, 1.000)
20210825022416 [E] (0.4, 0.5, 0.5, 0.6)
20210825022416 [L] (-0.2, 0.9, -0.4)
20210825022416 [W] RGBA(0.078, 0.413, 0.256, 1.000)
20210825022416 [E] (0.0, -0.2, 0.7, 0.6)
20210825022417 [L] (0.6, 0.7, 0.3)
20210825022417 [W] RGBA(0.914, 0.453, 0.567, 1.000)
20210825022417 [E] (0.9, 0.0, 0.0, 0.3)
20210825022417 [L] (-0.1, -0.1, -1.0)
20210825022417 [W] RGBA(0.639, 0.688, 0.682, 1.000)
20210825022417 [E] (0.6, 0.3, 0.4, 0.7)
20210825022417 [L] (0.3, 0.0, 1.0)
20210825022417 [W] RGBA(0.274, 0.541, 0.482, 1.000)
20210825022417 [E] (0.0, -0.6, 0.2, 0.8)

コンストラクタに渡したCancellationTokenのキャンセルに反応してログの出力をやめますが、大抵の場合はアプリの起動から終了までログを残したいと思うので、DontDestroyOnLoadしたGameObjectからthis.GetCancellationTokenOnDestroy()で作ったtokenを渡してあげればいいと思います。

実装のポイント

Application.logMessageReceivedThreadedを使う

Debug.LogのコールバックはApplication.logMessageReceivedApplication.logMessageReceivedThreadedがありますが、Threadedがついていない方はメインスレッドからのログしか教えてくれません。わざわざファイルに書き出すからには、スレッド関係なしにログが欲しいだろうので、Threadedの方を使いましょう。

スレッドセーフなQueueに格納する

Application.logMessageReceivedThreadedはメインスレッド外からも飛んでくるのでスレッドセーフを考慮する必要があります。マルチスレッド処理は既存のクラスを使うに限るので、素直にBlockingCollectionに突っ込んで、別のところでループを回して中身を取り出してファイルに書き込みましょう。
本当ならBlockingCollection.GetConsumingEnumerableを使いたいところですが、なぜか必ずforeachの中でメインスレッドを停止させるのでTakeにしました。

スマートフォンでのログの取り出し方メモ

Android

  • AndroidStudioDeviceFileExplorerとかadbで取り出す

https://developer.android.com/studio/debug/device-file-explorer

  • X-ploreの見えるところに出力して端末をサーバにしてダウンロードする[2]

https://play.google.com/store/apps/details?id=com.lonelycatgames.Xplore

iOS

https://qiita.com/ShingoFukuyama/items/e85d34360f3f951ca612

この処理をした上でApplication.persistentDataPathにファイルを書き出す。
UnityEngine.iOS.Device.SetNoBackupFlagにもパスを渡しておかないとiCloudにバックアップされて面倒なことになるので注意。ログファイルの親ディレクトリを指定するべし。

まとめ

なんか毎回作っている気がするので、メモも兼ねて記事にしました。OnLogMessageReceivedThreadedでログのフォーマットを作っているので、分析のためにcsvにしたい場合などは適当にいじってください。
しかし調べても同じことをしている人の記事が出てこない。ほんとに? ほんとにないのか?

おしまい。

脚注
  1. まじめな話、UniTaskなしでUnity開発ってできるのか……? ↩︎

  2. このアプリQuestでも使えるAndroid最強のファイラなのでぜひインストールしてアプリ情報にある開発者の顔写真をタップしてください ↩︎

Discussion