Project_WL/Assets/WL/Island/WLErrorTrace.cs

62 lines
3.4 KiB
C#

// ─────────────────────────────────────────────────────────────────────────────
// WLErrorTrace.cs — 런타임 에러·예외·「Coroutine couldn't be started」 경고를 **메모리에 보관**한다(최근 40건 · 스택 포함).
//
// 2026-09-17 PD 「다리가 생성될 때 에러」 실측: 화면 팝업은 보였는데 에디터 콘솔(파이프라인 조회)은 비어 있어 원문·스택을 못 잡았다
// (Play 재시작·Clear 로 사라짐). 이후로는 Lead 프로브가 `WLErrorTrace.Dump()` 로 언제든 읽는다. 원본 코드 0줄 · 화면 출력 없음.
// ─────────────────────────────────────────────────────────────────────────────
using System.Collections.Generic;
using UnityEngine;
namespace WL.Island
{
public static class WLErrorTrace
{
public struct Entry { public float time; public LogType type; public string message; public string stack; }
static readonly List<Entry> s_entries = new List<Entry>(64);
static bool s_hooked;
public static int Total;
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
static void Hook()
{
if (s_hooked) return;
s_hooked = true;
Application.logMessageReceived += OnLog;
}
static void OnLog(string message, string stack, LogType type)
{
bool keep = type == LogType.Error || type == LogType.Exception || type == LogType.Assert
|| (type == LogType.Warning && message != null && message.IndexOf("Coroutine couldn't be started", System.StringComparison.Ordinal) >= 0);
if (!keep) return;
Total++;
if (s_entries.Count >= 40) s_entries.RemoveAt(0);
s_entries.Add(new Entry { time = Time.realtimeSinceStartup, type = type, message = message, stack = stack });
}
/// <summary>최근 항목을 한 문자열로(프로브용). 같은 메시지는 횟수만 센다.</summary>
public static string Dump(int maxEach = 400)
{
var sb = new System.Text.StringBuilder();
sb.Append("total=").Append(Total).Append(" kept=").Append(s_entries.Count);
var counts = new Dictionary<string, int>();
for (int i = 0; i < s_entries.Count; i++)
{
var e = s_entries[i];
string key = e.message.Length > 100 ? e.message.Substring(0, 100) : e.message;
int c; counts.TryGetValue(key, out c);
counts[key] = c + 1;
if (c > 0) continue;
sb.Append("\n[").Append(e.time.ToString("F1")).Append("s ").Append(e.type).Append("] ")
.Append(e.message.Length > maxEach ? e.message.Substring(0, maxEach) : e.message);
if (!string.IsNullOrEmpty(e.stack)) sb.Append("\n ").Append(e.stack.Length > maxEach ? e.stack.Substring(0, maxEach) : e.stack);
}
foreach (var kv in counts) if (kv.Value > 1) sb.Append("\n x").Append(kv.Value).Append(" ").Append(kv.Key);
return sb.ToString();
}
public static void Clear() { s_entries.Clear(); }
}
}