実機でUnityの出力するログを見たいときは
Application.logMessageReceived
にイベントを登録することでログをハンドルすることができます
Console を自作するときにも利用できますが、スクリプトコンパイル時の warning
の管理が面倒なので
既存の Console の代わりとして利用することはあまりおすすめしません
using System.Collections.Generic; using UnityEngine; public class SampleBehaviour : MonoBehaviour { private List<LogData> _logData = new List<LogData>(); private void OnEnable() { Application.logMessageReceived += HandleLog; } private void OnDisable() { Application.logMessageReceived -= HandleLog; } private void HandleLog(string message, string stackTrace, LogType type) { _logData.Add(new LogData(message, stackTrace, type)); } private class LogData { public string Message; public string StackTrace; public LogType Type; public LogData(string message, string stackTrace, LogType type) { Message = message; StackTrace = stackTrace; Type = type; } } }
ログを解析するクラス
ログデータからスタックトレースを解析できるクラスもついでに記述
ログを受け取った際に利用するとstring周りの処理でゴミが出るので
表示するときに解析するようにするといい感じになります
using System; using System.Collections.Generic; using UnityEngine; using System.Text.RegularExpressions; [Serializable] public class LogInfo { public readonly string Message; public readonly string DisplayMessage; public readonly LogType LogType; public readonly List<StackFrame> StackTraces; public readonly bool IsCompileError; // Unityのエラーメッセージ形式 private static readonly Regex UnityMessageRegex = new Regex(@"(.*)\((\d+).*\)"); public LogInfo(string logString, string stackTrace, LogType type) { Message = new Regex("\r|\n|\r\n").Replace("\n", logString); LogType = type; StackTraces = GetStackTraces(stackTrace); var lines = Message.Split('\n'); var match = UnityMessageRegex.Matches(logString); if (match.Count > 0 && lines.Length < 3) { var filename = match[0].Groups[1].Value; var lineNumber = Convert.ToInt32(match[0].Groups[2].Value); IsCompileError = true; StackTraces.Add(new StackFrame(logString, filename, lineNumber)); } DisplayMessage = GetDisplayMessage(lines); } private string GetDisplayMessage(string[] lines) { if (IsCompileError) return Message; if (!Message.Contains("\n") && StackTraces != null && StackTraces.Count >= 1) return string.Format("{0}\n{1}", Message, StackTraces[0].FormattedMethodName); if (lines != null && lines.Length >= 2) return lines[0] + "\n" + lines[1]; if (lines != null && lines.Length >= 1) return lines[0]; return string.Empty; } private List<StackFrame> GetStackTraces(string stackTrace) { var lines = Regex.Split(stackTrace, System.Environment.NewLine); var stacks = new List<StackFrame>(lines.Length + 1); foreach (var l in lines) { var frame = new StackFrame(l); if (string.IsNullOrEmpty(frame.FormattedMethodName)) continue; stacks.Add(frame); } return stacks; } } [Serializable] public class StackFrame { public readonly string MethodName; public readonly string FormattedMethodName; public readonly string DeclaringType; public readonly string ParameterSig; public readonly int LineNumber; public readonly string FileName; private static readonly Regex StackTraceRegex = new Regex(@"(.*)\:(.*)\s*\(.*\(at (.*):(\d+)"); public StackFrame(string message, string filename, int lineNumber) { FileName = filename; LineNumber = lineNumber; FormattedMethodName = message; } public StackFrame(string stackFrame) { var match = StackTraceRegex.Matches(stackFrame); FormattedMethodName = stackFrame; if (match.Count <= 0) return; DeclaringType = match[0].Groups[1].Value; MethodName = match[0].Groups[2].Value; FileName = match[0].Groups[3].Value; LineNumber = Convert.ToInt32(match[0].Groups[4].Value); string filename = FileName; if (!String.IsNullOrEmpty(FileName)) { var startSubNameIndex = FileName.IndexOf("Assets", StringComparison.OrdinalIgnoreCase); if (startSubNameIndex > 0) filename = FileName.Substring(startSubNameIndex); } FormattedMethodName = String.Format("{0}.{1}({2}) (at {3}:{4})", DeclaringType, MethodName, ParameterSig, filename, LineNumber); } }