using System; using System.Collections; using System.IO; using System.Text; using UnityEngine; public class FileLog : MonoBehaviour { public enum LogLevels : byte { Log = 0x0, Warning = 0x1, Error = 0x2, Exception = 0x3, Assert = 0x4 } private static string _pathToLog = string.Empty; private static StringBuilder _items = new StringBuilder(); private static DateTime _now; private static FileLog _instance; private static bool _catchSystemLog; private static string _fileName = "log"; private static bool _stoped = true; private static bool _dateInFileName = true; private static bool _timeInEachRecord = true; private static LogLevels _minimumLevel = LogLevels.Log; private bool _writting; private static readonly object LOCKER = new object(); private static string FileName { get { if (!_dateInFileName) { return string.Format("{0}.nekkilog", _fileName); } return string.Format("{3} {0}.{1}.{2}.nekkilog", _now.Year.ToString("0000"), _now.Month.ToString("00"), _now.Day.ToString("00"), _fileName); } } private static string Path { get { if (string.IsNullOrEmpty(_pathToLog)) { return string.Format("{0}/{1}", Application.persistentDataPath, FileName); } return string.Format("{0}/{1}", _pathToLog, FileName); } } public static void Init(string pathToLog, string fileName, bool catchSystemLog, bool dateInFileName, bool timeInEachRecord, LogLevels minimumLevel) { if (_instance) { _instance.Write(); } _pathToLog = pathToLog.Trim('/').Trim('\\'); _minimumLevel = minimumLevel; _dateInFileName = dateInFileName; _timeInEachRecord = timeInEachRecord; _catchSystemLog = catchSystemLog; if (!string.IsNullOrEmpty(fileName)) { _fileName = fileName; } CheckPersistance(); _stoped = false; } private static void CheckPersistance() { if (_instance) { return; } var go = new GameObject("_log"); _instance = go.AddComponent(); DontDestroyOnLoad(go); _instance.Update(); _instance.StartCoroutine(_instance.SaveToFile()); Application.RegisterLogCallback(_unityLogCallback); } private void OnDestroy() { Stop(); } private void OnEnable() { StopAllCoroutines(); StartCoroutine(SaveToFile()); } private static void _unityLogCallback(string condition, string stacktrace, LogType type) { if (!_catchSystemLog) { return; } switch (type) { case LogType.Error: Error(condition,stacktrace); break; case LogType.Assert: Assert(condition,stacktrace); break; case LogType.Warning: Warning(condition,stacktrace); break; case LogType.Log: Log(condition,stacktrace); break; case LogType.Exception: Exception(condition,stacktrace); break; } } private void Update() { if (_timeInEachRecord || _dateInFileName) { _now = DateTime.Now; } } public static void Log(object message, string stacktrace = null) { PostMesage(LogLevels.Log, message, stacktrace); } public static void Warning(object message, string stacktrace = null) { PostMesage(LogLevels.Warning, message, stacktrace); } public static void Error(object message, string stacktrace = null) { PostMesage(LogLevels.Error, message, stacktrace); } public static void Exception(Exception ex) { PostMesage(LogLevels.Exception, ex.Message, ex.StackTrace); } private static void Exception(object message, string stacktrace) { PostMesage(LogLevels.Exception, message, stacktrace); } public static void Assert(object message, string stacktrace = null) { PostMesage(LogLevels.Assert, message, stacktrace); } public static void Stop() { _instance.Write(); _stoped = true; } private static string FormatMessage(LogLevels level, object condition, string stacktrace = null) { var message = string.IsNullOrEmpty(stacktrace) ? condition : string.Format("{0} at: {1}", condition, stacktrace); if (!_timeInEachRecord) { return string.Format("[{0}] {1}\n", level, message); } return string.Format("[{3}] [{0}:{1}:{2}] {4}\n", _now.Hour.ToString("00"), _now.Minute.ToString("00"), _now.Second.ToString("00"), level, message); } private static void PostMesage(LogLevels level, object message, string stacktrace = null) { if (_stoped) { Debug.LogWarning("you must init log system first!"); return; } if (level < _minimumLevel) { return; } CheckPersistance(); lock (LOCKER) { _items.Append(FormatMessage(level, message,stacktrace)); } } private IEnumerator SaveToFile() { while (transform) { yield return new WaitForSeconds(1); Write(); } } private void Write() { if (_writting) { return; } _writting = true; string contents; lock (LOCKER) { contents = _items.ToString(); _items = new StringBuilder(); } try { File.AppendAllText(Path, contents); } catch (Exception){ } _writting = false; } }