using System; using System.IO; using System.Text; using UnityEngine; namespace IchniOnline.Online.Util { public class PersistentFileLogger : MonoBehaviour { private static StreamWriter _writer; private static readonly object LockObj = new object(); private string _logFilePath; [Header("日志文件夹名称")] public string logFolderName = "Logs"; [Header("启动时打印日志路径")] public bool printLogPath = true; private void Awake() { DontDestroyOnLoad(gameObject); InitializeLogger(); } private void InitializeLogger() { if (_writer != null) return; string logDir = Path.Combine( Application.persistentDataPath, logFolderName); Directory.CreateDirectory(logDir); string fileName = $"log_{DateTime.Now:yyyyMMdd_HHmmss}.txt"; _logFilePath = Path.Combine(logDir, fileName); _writer = new StreamWriter( new FileStream( _logFilePath, FileMode.Create, FileAccess.Write, FileShare.ReadWrite, 4096, FileOptions.WriteThrough), Encoding.UTF8); _writer.AutoFlush = true; Application.logMessageReceivedThreaded += OnLogReceived; WriteRaw("=================================================="); WriteRaw($"Unity Version : {Application.unityVersion}"); WriteRaw($"Platform : {Application.platform}"); WriteRaw($"Start Time : {DateTime.Now:yyyy-MM-dd HH:mm:ss.fff}"); WriteRaw($"Log File : {_logFilePath}"); WriteRaw("=================================================="); if (printLogPath) { Debug.Log($"Log file: {_logFilePath}"); } } private void OnDestroy() { ShutdownLogger(); } private void OnApplicationQuit() { ShutdownLogger(); } private void ShutdownLogger() { Application.logMessageReceivedThreaded -= OnLogReceived; lock (LockObj) { if (_writer != null) { WriteRaw("Application Exit"); _writer.Flush(); _writer.Close(); _writer.Dispose(); _writer = null; } } } private static void OnLogReceived( string condition, string stackTrace, LogType type) { lock (LockObj) { if (_writer == null) return; string timestamp = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"); _writer.WriteLine( $"[{timestamp}] [{type}] {condition}"); if (type == LogType.Error || type == LogType.Exception || type == LogType.Assert) { if (!string.IsNullOrWhiteSpace(stackTrace)) { _writer.WriteLine(stackTrace); } } _writer.Flush(); } } private static void WriteRaw(string message) { lock (LockObj) { if (_writer == null) return; _writer.WriteLine(message); _writer.Flush(); } } } }