using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Text;
using UnityEngine;
namespace XCharts.Runtime
{
///
/// Log system. Used to output logs with date and log type, support output to file, support custom output log type.
/// ||日志系统。用于输出带日期和日志类型的日志,支持输出到文件,支持自定义输出的日志类型。
///
public class XLog : MonoBehaviour
{
public const int ALL = 0;
public const int WARNING = 1;
public const int DEBUG = 2;
public const int INFO = 3;
public const int PROTO = 4;
public const int VITAL = 5;
public const int ERROR = 6;
public const int EXCEPTION = 7;
private const int MAX_ERROR_LOG = 20;
public static bool isReportBug = false;
public static bool isOutputLog = false;
public static bool isUploadLog = false;
public static bool isCloseOutLog = false;
public static int errorCount = 0;
public static int exceptCount = 0;
public static int uploadTick = 20;
public static int reportTick = 10;
private static bool initFileSuccess = false;
private static bool[] levelList = new bool[] { true, true, true, true, true, true, true, true };
private static List writeList = new List();
private static float uploadTime = 0;
private static float reportTime = 0;
private string outpath;
private StreamWriter writer;
private string[] temp;
public int logCount = 0;
public static List errorList = new List();
private static object m_Lock = new object();
private static XLog m_Instance;
public static XLog Instance
{
get
{
// if (m_Instance == null)
// {
// GameObject go = new GameObject("XLog");
// m_Instance = go.AddComponent();
// DontDestroyOnLoad(go);
// }
return m_Instance;
}
}
void Awake()
{
if (m_Instance != null)
{
Destroy(gameObject);
return;
}
m_Instance = this;
InitLogFile();
// Application.logMessageReceived += HandleLog;
Application.logMessageReceivedThreaded += HandleLog;
}
void OnDestroy()
{
if (writer != null)
{
writer.Close();
writer.Dispose();
}
// Application.logMessageReceived -= HandleLog;
Application.logMessageReceivedThreaded -= HandleLog;
}
void Update()
{
uploadTime += Time.deltaTime;
reportTime += Time.deltaTime;
lock (m_Lock)
{
if (writeList.Count > 0)
{
logCount = writeList.Count;
if (!initFileSuccess)
{
writeList.Clear();
return;
}
try
{
temp = writeList.ToArray();
int count = 0;
foreach (var str in temp)
{
count++;
writer.WriteLine(str);
writeList.Remove(str);
if (count > 10) break;
}
writer.Flush();
}
catch (Exception e)
{
initFileSuccess = false;
//Application.logMessageReceived -= HandleLog;
Application.logMessageReceivedThreaded -= HandleLog;
UnityEngine.Debug.LogError("write outlog.txt error:" + e.Message);
}
}
}
}
private void InitLogFile()
{
ClearAllLog();
XLog.EnableLog(ALL);
if (Application.platform == RuntimePlatform.Android || Application.platform == RuntimePlatform.IPhonePlayer)
{
XLog.ClearAllLog();
XLog.EnableLog(VITAL);
XLog.EnableLog(ERROR);
XLog.isReportBug = true;
XLog.isUploadLog = true;
}
else
{
XLog.isUploadLog = false;
XLog.isReportBug = false;
}
outpath = GetLogOutputPath();
try
{
if (File.Exists(outpath))
{
File.Delete(outpath);
}
writer = new StreamWriter(outpath, false, Encoding.UTF8);
writer.WriteLine(GetNowTime() + "init file success!!");
UnityEngine.Debug.Log(GetNowTime() + "init file success:" + outpath);
writer.Flush();
initFileSuccess = true;
}
catch (Exception e)
{
initFileSuccess = false;
Application.logMessageReceived -= HandleLog;
UnityEngine.Debug.LogError("write outlog.txt error:" + e.Message);
}
}
private static string GetLogOutputPath()
{
#if UNITY_EDITOR
string path = Application.dataPath + "/../outlog.txt";
#else
string path = Application.persistentDataPath + "/outlog.txt";
if (Application.platform == RuntimePlatform.Android || Application.platform == RuntimePlatform.IPhonePlayer)
{
path = Application.persistentDataPath + "/outlog.txt";
}
else
{
path = Application.dataPath + "/../outlog.txt";
}
#endif
return path;
}
private void HandleLog(string logString, string stackTrace, LogType type)
{
lock (m_Lock)
{
if (!initFileSuccess) return;
int index = logString.IndexOf("stack traceback");
if (index > 0)
{
string log = logString.Substring(0, index);
string trace = logString.Substring(index, logString.Length - index);
logString = log;
stackTrace = trace;
}
if (type == LogType.Log)
{
}
else if (type == LogType.Error)
{
if (logString.IndexOf("LUA ERROR") > 0 || logString.IndexOf("stack traceback") > 0) exceptCount++;
else errorCount++;
writeList.Add(logString);
//writeList.Add(stackTrace + "\n");
if (errorList.Count >= MAX_ERROR_LOG)
{
errorList.RemoveAt(1);
}
if (errorList.Count < MAX_ERROR_LOG)
{
errorList.Add(logString);
// errorList.Add(stackTrace + "\n");
}
}
else if (type == LogType.Exception)
{
exceptCount++;
writeList.Add(logString);
writeList.Add(stackTrace + "\n");
if (errorList.Count >= MAX_ERROR_LOG)
{
errorList.RemoveAt(1);
}
if (errorList.Count < MAX_ERROR_LOG)
{
errorList.Add(logString);
errorList.Add(stackTrace + "\n");
}
}
}
}
public static void FlushLog()
{
var instance = XLog.Instance;
if (instance != null && instance.writer != null)
{
for (int i = 0; i < writeList.Count; i++)
{
instance.writer.WriteLine(writeList[i]);
}
instance.writer.Flush();
writeList.Clear();
}
}
public static void EnableLog(int logType)
{
if (logType < 0 || logType >= levelList.Length) return;
levelList[logType] = true;
}
public static void ClearAllLog()
{
for (int i = 0; i < levelList.Length; i++)
{
levelList[i] = false;
}
}
public static bool CanLog(int level)
{
if (level < 0 || level >= levelList.Length) return false;
return levelList[level] || levelList[0];
}
public static void Log(string log)
{
Debug(log);
}
public static void LogError(string log)
{
Error(log);
}
public static void LogWarning(string log)
{
Warning(log);
}
public static void Debug(string log)
{
if (!CanLog(DEBUG)) return;
UnityEngine.Debug.Log(GetNowTime() + "[DEBUG]\t" + log);
}
public static void Vital(string log)
{
if (!CanLog(INFO)) return;
UnityEngine.Debug.Log(GetNowTime() + "[VITAL]\t" + log);
}
public static void Info(string log)
{
if (!CanLog(INFO)) return;
UnityEngine.Debug.Log(GetNowTime() + "[INFO]\t" + log);
}
public static void Proto(string log)
{
if (!CanLog(PROTO)) return;
UnityEngine.Debug.Log(GetNowTime() + "[PROTO]\t" + log);
}
public static void Warning(string log)
{
if (!CanLog(WARNING)) return;
UnityEngine.Debug.LogWarning(GetNowTime() + "[WARN]\t" + log);
}
public static void Error(string log)
{
if (!CanLog(ERROR)) return;
UnityEngine.Debug.LogError(GetNowTime() + "[ERROR]\t" + log);
}
public static string GetNowTime(string formatter = null)
{
DateTime now = DateTime.Now;
if (formatter == null)
return now.ToString("[HH:mm:ss fff]", DateTimeFormatInfo.InvariantInfo);
else
return now.ToString(formatter, DateTimeFormatInfo.InvariantInfo);
}
public static ulong GetTimestamp()
{
return (ulong)(DateTime.Now - new DateTime(190, 1, 1, 0, 0, 0, 0)).TotalSeconds;
}
}
}