【Unity】【C#】Android実機でエラーログをファイルに書き出す 
2017/04/14 Fri [edit]
本来なら Android 実機のエラーは「Unity Performance Reporting」(※Unity Plus/Pro 用)を使ったり、Android SDK の「DDMS」(※PCとAndroid端末をUSBで繋ぐ)を使うべきなのかも知れないが、以前「Java で書いたエラー書き出し」のような簡単なものが Unity で欲しかったので、資料を色々組合せて作ってみた。
(※) Unity 5.6.0f3 / Windows10(x64) で確認
●実機でエラーログをファイルに書き出す
using System;
using System.IO;
using UnityEngine;
/// <summary>
/// エラーログをファイルに出力する
///・空の GameObject にアタッチして使う(DontDestroyOnLoad によりシーン変更でも残る[※本来はシングルトンモデルにした方が良い])。
///・ログは内部ストレージの "Android/data/[PackageName]/files/~" に出力
///(機種によっては外部ストレージになることもあるらしい)。
///・Debug.LogError() も保存される(LogType が Error または Exception で判断する)。
///・「Build Settings」の「Development Build」「Script Debugging」オンにすれば行番号も出力できる。
/// </summary>
public class ErrorReporter : MonoBehaviour {
public string reportFileName = "error_report.txt"; //出力するファイル名(任意)
public bool addDateTime = false; //ファイル名に日時を付加する
public bool typeException = true; //Exception のスタックトレースを保存する
public bool typeError = true; //Debug.LogError() を保存する
void OnEnable()
{
//Application.RegisterLogCallback(HandleLog); //obsolute
Application.logMessageReceived += HandleLog;
}
void OnDisable()
{
//Application.RegisterLogCallback(null); //obsolute
Application.logMessageReceived -= HandleLog;
}
//ログハンドリンング
void HandleLog(string condition, string stackTrace, LogType type)
{
if ((typeException && type == LogType.Exception) || (typeError && type == LogType.Error))
{
DateTime dt = DateTime.Now;
string text = dt.ToString("[yyyy-MM-dd HH:mm:ss]")
+ "\ncondition : " + condition + "\nstackTrace : " + stackTrace.Trim() + "\ntype : "
+ type.ToString() + "\n";
string outfile = reportFileName;
if (addDateTime)
{
string file = Path.GetFileNameWithoutExtension(reportFileName);
string ext = Path.GetExtension(reportFileName); //"."を含む拡張子
outfile = file + "_" + dt.ToString("yyyyMMddHHmmss") + ext;
}
SaveText(text, Path.Combine(Application.persistentDataPath, outfile));
}
}
// Use this for initialization
void Start () {
DontDestroyOnLoad(this);
}
// テキストファイルファイル保存
public static bool SaveText(string text, string path)
{
try
{
using (StreamWriter writer = new StreamWriter(path, true))
{
writer.Write(text);
writer.Flush();
writer.Close();
}
}
catch (Exception e)
{
Debug.Log(e.Message);
return false;
}
return true;
}
}

使い方は空の GameObject を作って、それにアタッチしておくだけでOK。DontDestroyOnLoad によりシーン変更でも残る(※本来はシングルトンモデルにした方が良い)。
インスペクタでは「Add Date Time」がオンでファイル名に日時を付加する(例:"error_report_20170414171928.txt" のようになる)。つまり1秒単位で小分けにファイル保存することになる。
●「error_report.txt」出力例
condition : IndexOutOfRangeException: Array index is out of range.
stackTrace : TestScript.ExceptionTest () (at D:/unity5/ErrorReportTest/Assets/Scripts/TestScript.cs:8)
UnityEngine.Events.InvokableCall.Invoke (System.Object[] args) (at /Users/builduser/buildslave/unity/build/Runtime/Export/UnityEvent.cs:154)
UnityEngine.Events.InvokableCallList.Invoke (System.Object[] parameters) (at /Users/builduser/buildslave/unity/build/Runtime/Export/UnityEvent.cs:637)
UnityEngine.Events.UnityEventBase.Invoke (System.Object[] parameters) (at /Users/builduser/buildslave/unity/build/Runtime/Export/UnityEvent.cs:773)
UnityEngine.Events.UnityEvent.Invoke () (at /Users/builduser/buildslave/unity/build/Runtime/Export/UnityEvent_0.cs:52)
UnityEngine.UI.Button.Press () (at C:/buildslave/unity/build/Extensions/guisystem/UnityEngine.UI/UI/Core/Button.cs:35)
UnityEngine.UI.Button.OnPointerClick (UnityEngine.EventSystems.PointerEventData eventData) (at C:/buildslave/unity/build/Extensions/guisystem/UnityEngine.UI/UI/Core/Button.cs:44)
UnityEngine.EventSystems.ExecuteEvents.Execute (IPointerClickHandler handler, UnityEngine.EventSystems.BaseEventData eventData) (at C:/buildslave/unity/build/Extensions/guisystem/UnityEngine.UI/EventSystem/ExecuteEvents.cs:50)
UnityEngine.EventSystems.ExecuteEvents.Execute[IPointerClickHandler] (UnityEngine.GameObject target, UnityEngine.EventSystems.BaseEventData eventData, UnityEngine.EventSystems.EventFunction`1 functor) (at C:/buildslave/unity/build/Extensions/guisystem/UnityEngine.UI/EventSystem/ExecuteEvents.cs:261)
UnityEngine.EventSystems.EventSystem:Update()
type : Exception
[2017-04-14 17:24:56]
condition : Debug.LogError Test!
stackTrace : UnityEngine.Debug:LogError(Object)
TestScript:ErrorTest() (at D:/unity5/ErrorReportTest/Assets/Scripts/TestScript.cs:18)
UnityEngine.EventSystems.EventSystem:Update()
type : Error
(※)「Build Settings」の「Development Build」「Script Debugging」オンの時
ログの出力場所は「Application.persistentDataPath」を使っているのでプラットフォームごとに異なるが、Android の場合、主に内部ストレージの "Android/data/[PackageName]/files/~" のようになる(機種によって微妙に異なる)。端末に付属している「マイファイル」などのアプリで覗くと良いだろう。また Android の場合、機種によっては外部ストレージになることもあるらしいので注意。以下に参考資料を載せておく。
(参考)
・AndroidのpersistentDataPathがカオス
・Unity,Androidのデータ保存領域まとめ
ちなみにこのスクリプトは「Java で書いたエラー書き出し」と違い、例外捕捉のコールバックではなくて、ログ受信のコールバック「Application.logMessageReceived」となっている。なので、コールバックハンドラ:HandleLog 内の条件を修正すれば Warning なども保存できる(引数の LogType(Enum型)で判別してるだけ)。ただしあまり出力し過ぎると、ファイルが巨大になるので気をつけた方が良いだろう。
ただ、これは Unity スクリプト内で発生したエラーしか捕捉できないので注意。OS による強制終了やグラフィックAPIなどで直接落ちたときなどにはコールバック自体が発生しないので無効になる。徹底的にログをトレースしたいのなら、冒頭に書いた「DDMS」や「Unity Performance Reporting」を使った方が良いかも知れない。ちょっとした確認用程度のものと思って欲しい。
(参考)
・[Unity][Unity3d]例外発生時にコールバック関数が呼ばれる様にする方法
・Unityでテキストデータを保存,取得
・Androidの実機ログを調査しやすくするTips
(関連記事)
【Unity】アイコン画像のフォーマット警告:Compressed texture XXX is used as icon. This might compromise visual quality of~ を消す
【Unity】5.6 の Canvas の警告:Shader channels Normal and Tangent are most often used with lighting~ を消す
【Unity】InitializeUnityExtensions: Must have a valid path for the plugin [XX] (XX:番号) というエラーの修正方法
【Unity】"~\Temp\Assembly-CSharp.dll.mdb" is denied. と出たら…
- 関連記事
トラックバック
トラックバックURL
→http://fantom1x.blog130.fc2.com/tb.php/239-ae8e8c7a
この記事にトラックバックする(FC2ブログユーザー)
| h o m e |