using Cysharp.Text; using UnityEngine; namespace AlicizaX.Runtime { public static class LogReportUtil { private static LogDetails LastReportedDetails = new LogDetails(); public static bool ForceDisableReport = true; internal static void RedirectLog() { Application.logMessageReceived += HandleLog; } internal static void UnRedirectLog() { Application.logMessageReceived -= HandleLog; } private static void HandleLog(string logMessage, string stackTrace, LogType logType) { GameFrameworkLogLevel logLevel = GameFrameworkLogLevel.Info; switch (logType) { case LogType.Error: logLevel = GameFrameworkLogLevel.Error; break; case LogType.Assert: case LogType.Exception: logLevel = GameFrameworkLogLevel.Fatal; break; case LogType.Warning: logLevel = GameFrameworkLogLevel.Warning; break; case LogType.Log: logLevel = GameFrameworkLogLevel.Info; break; } ProcessLogMessage(logLevel, logMessage, stackTrace); } private static void ProcessLogMessage(GameFrameworkLogLevel logLevel, string message, string stackTrace) { if (logLevel == GameFrameworkLogLevel.Fatal || logLevel == GameFrameworkLogLevel.Error) { string formattedMessage = ""; using (var sb = ZString.CreateStringBuilder()) { sb.Append(message); sb.Append(GetStackTrace(stackTrace)); formattedMessage = sb.ToString(); } if (!ForceDisableReport && ShouldReport(logLevel, formattedMessage)) { _ = WebHookUtils.SendLogToServerAsync(formattedMessage); } } } private static string GetStackTrace(string stackTrace) { return string.IsNullOrEmpty(stackTrace) ? string.Empty : $"\nStackTrace:\n{SimplifyStackTrace(stackTrace)}"; } private static string SimplifyStackTrace(string stackTrace) { var sb = ZString.CreateStringBuilder(); var lines = stackTrace.Split('\n'); bool skipLine = false; foreach (var line in lines) { if (line.Contains("Log") || line.Contains("Sirenix")) { skipLine = true; } else { if (skipLine) { if (!string.IsNullOrWhiteSpace(line) && !line.Contains("Log") && !line.Contains("Sirenix")) { skipLine = false; } else { continue; } } if (!string.IsNullOrWhiteSpace(line)) { sb.Append(line); sb.Append('\n'); } } } string result = sb.ToString().Trim(); return !string.IsNullOrEmpty(result) ? result : "Stack trace not available."; } private static bool ShouldReport(GameFrameworkLogLevel logLevel, string message) { if (LastReportedDetails.Level == logLevel && LastReportedDetails.Message.Equals(message)) { return false; } LastReportedDetails.Update(logLevel, message); return true; } private struct LogDetails { public GameFrameworkLogLevel Level; public string Message; public void Update(GameFrameworkLogLevel level, string message) { Level = level; Message = message; } } } }