游戏项目信息打印还是很重要的,Unity引擎提供了基本Debug接口,但不是特别定制,为了更好地使用,需要做些简单封装。
using System.Diagnostics;
using System.Text;
using UnityEngine;
using Debug = UnityEngine.Debug;
namespace TEngine.Runtime
{
/// <summary>
/// 颜色工具
/// </summary>
public static class ColorUtils
{
#region ColorStr
public const string White = "FFFFFF";
public const string Black = "000000";
public const string Red = "FF0000";
public const string Green = "00FF18";
public const string Oringe = "FF9400";
public const string Exception = "FF00BD";
#endregion
public static string ToColor(this string str, string color)
{
if (string.IsNullOrEmpty(str))
{
return str;
}
return string.Format("<color=#{0}>{1}</color>", color, str);
}
}
/// <summary>
/// 日志工具
/// </summary>
public class TLogger : TSingleton<TLogger>
{
/// <summary>
/// 初始化
/// </summary>
protected override void Init()
{
_outputType = OutputType.EDITOR;
_logToFile = new LogToFile();
_logToFile.Init();
UnityEngine.Application.logMessageReceivedThreaded += OnLogMessageReceivedThreaded;
}
/// <summary>
/// 输出日志文件
/// </summary>
private LogToFile _logToFile;
private void OnLogMessageReceivedThreaded(string condition, string stackTrace, LogType type)
{
if (!condition.StartsWith("TLogger]"))
{
_stringBuilder.Clear();
_stringBuilder.AppendFormat("[System][{0}][{1}] {2}", type.ToString(), System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff"), condition);
if (type == LogType.Warning || type == LogType.Error || type == LogType.Exception)
{
_stringBuilder.AppendLine(stackTrace);
}
string strToWrite = _stringBuilder.ToString();
_logToFile.Write(strToWrite);
}
}
~TLogger()
{
}
/// <summary>
/// 释放
/// </summary>
public override void Release()
{
Application.logMessageReceivedThreaded -= OnLogMessageReceivedThreaded;
_logToFile.DeInit();
_logToFile = null;
base.Release();
}
/// <summary>
/// 修改输出日志方式
/// </summary>
/// <param name="type"></param>
private void ChangeOutputChannel(OutputType type)
{
if (type != _outputType)
{
_outputType = type;
}
}
/// <summary>
/// 设置信息打印类型
/// </summary>
/// <param name="filterLevel"></param>
public static void SetFilterLevel(LogLevel filterLevel)
{
Instance._filterLevel = filterLevel;
}
/// <summary>
/// 打印资源信息
/// </summary>
/// <param name="condition"></param>
/// <param name="logStr"></param>
[Conditional("UNITY_EDITOR"), Conditional("_DEVELOPMENT_BUILD_"), Conditional("ENABLE_LOG_ASSERT")]
public static void LogAssert(bool condition, string logStr = "")
{
if (!condition)
{
if (string.IsNullOrEmpty(logStr))
{
logStr = string.Format("{0}", "Assert Failed");
}
Instance.Log(LogLevel.ASSERT, logStr);
}
}
/// <summary>
/// 打印资源信息
/// </summary>
/// <param name="condition"></param>
/// <param name="format"></param>
/// <param name="args"></param>
[Conditional("UNITY_EDITOR"), Conditional("_DEVELOPMENT_BUILD_"), Conditional("ENABLE_LOG_ASSERT")]
public static void LogAssert(bool condition, string format, params System.Object[] args)
{
if (!condition)
{
string logStr = string.Format(format, args);
Instance.Log(LogLevel.ASSERT, logStr);
}
}
/// <summary>
/// 打印信息
/// </summary>
/// <param name="logStr"></param>
[Conditional("UNITY_EDITOR"), Conditional("_DEVELOPMENT_BUILD_"), Conditional("ENABLE_LOG_INFO")]
public static void LogInfo(string logStr)
{
Instance.Log(LogLevel.INFO, logStr);
}
/// <summary>
/// 打印信息
/// </summary>
/// <param name="format"></param>
/// <param name="args"></param>
[Conditional("UNITY_EDITOR"), Conditional("_DEVELOPMENT_BUILD_"), Conditional("ENABLE_LOG_INFO")]
public static void LogInfo(string format, params System.Object[] args)
{
string logStr = string.Format(format, args);
Instance.Log(LogLevel.INFO, logStr);
}
/// <summary>
/// 打印成功信息
/// </summary>
/// <param name="logStr"></param>
[Conditional("UNITY_EDITOR"), Conditional("_DEVELOPMENT_BUILD_"), Conditional("ENABLE_LOG_SUCCESS")]
public static void LogInfoSuccessd(string logStr)
{
Instance.Log(LogLevel.Successd, logStr);
}
/// <summary>
/// 打印成功信息
/// </summary>
/// <param name="format"></param>
/// <param name="args"></param>
[Conditional("UNITY_EDITOR"), Conditional("_DEVELOPMENT_BUILD_"), Conditional("ENABLE_LOG_SUCCESS")]
public static void LogInfoSuccessd(string format, params System.Object[] args)
{
string logStr = string.Format(format, args);
Instance.Log(LogLevel.Successd, logStr);
}
/// <summary>
/// 打印警告信息
/// </summary>
/// <param name="logStr"></param>
[Conditional("UNITY_EDITOR"), Conditional("_DEVELOPMENT_BUILD_"), Conditional("ENABLE_LOG_WARNING")]
public static void LogWarning(string logStr)
{
Instance.Log(LogLevel.WARNING, logStr);
}
/// <summary>
/// 打印警告信息
/// </summary>
/// <param name="format"></param>
/// <param name="args"></param>
[Conditional("UNITY_EDITOR"), Conditional("_DEVELOPMENT_BUILD_"), Conditional("ENABLE_LOG_WARNING")]
public static void LogWarning(string format, params System.Object[] args)
{
string logStr = string.Format(format, args);
Instance.Log(LogLevel.WARNING, logStr);
}
/// <summary>
/// 打印错误信息
/// </summary>
/// <param name="logStr"></param>
[Conditional("UNITY_EDITOR"), Conditional("_DEVELOPMENT_BUILD_"), Conditional("ENABLE_LOG_ERROR")]
public static void LogError(string logStr)
{
Instance.Log(LogLevel.ERROR, logStr);
}
/// <summary>
/// 打印错误信息
/// </summary>
/// <param name="format"></param>
/// <param name="args"></param>
[Conditional("UNITY_EDITOR"), Conditional("_DEVELOPMENT_BUILD_"), Conditional("ENABLE_LOG_ERROR")]
public static void LogError(string format, params System.Object[] args)
{
string logStr = string.Format(format, args);
Instance.Log(LogLevel.ERROR, logStr);
}
/// <summary>
/// 打印异常信息
/// </summary>
/// <param name="logStr"></param>
[Conditional("UNITY_EDITOR"), Conditional("_DEVELOPMENT_BUILD_"), Conditional("ENABLE_LOG_EXCEPTION")]
public static void LogException(string logStr)
{
Instance.Log(LogLevel.EXCEPTION, logStr);
}
/// <summary>
/// 打印异常信息
/// </summary>
/// <param name="format"></param>
/// <param name="args"></param>
[Conditional("UNITY_EDITOR"), Conditional("_DEVELOPMENT_BUILD_"), Conditional("ENABLE_LOG_EXCEPTION")]
public static void LogException(string format, params System.Object[] args)
{
string msg = string.Format(format, args);
Instance.Log(LogLevel.EXCEPTION, msg);
}
/// <summary>
/// 打印信息字符串处理
/// </summary>
/// <param name="logLevel"></param>
/// <param name="logString"></param>
/// <param name="bColor"></param>
/// <returns></returns>
private StringBuilder GetFormatedString(LogLevel logLevel, string logString, bool bColor)
{
_stringBuilder.Clear();
switch (logLevel)
{
case LogLevel.Successd:
if (UseCustomColor)
{
_stringBuilder.AppendFormat("[TLogger][SUCCESSED][{0}] - <color=#{2}>{1}</color>",
System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff"), logString, ColorUtils.Green);
}
else
{
_stringBuilder.AppendFormat(
bColor ? "[TLogger][INFO][{0}] - <color=#00FF18>{1}</color>" : "[TLogger][SUCCESSED][{0}] - {1}",
System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff"), logString);
}
break;
case LogLevel.INFO:
if (UseCustomColor)
{
_stringBuilder.AppendFormat("[TLogger][INFO][{0}] - <color=#{2}>{1}</color>" ,
System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff"), logString,ColorUtils.Black);
}
else
{
_stringBuilder.AppendFormat(
bColor ? "[TLogger][INFO][{0}] - <color=gray>{1}</color>" : "[TLogger][INFO][{0}] - {1}",
System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff"), logString);
}
break;
case LogLevel.ASSERT:
if (UseCustomColor)
{
_stringBuilder.AppendFormat("[TLogger][ASSERT][{0}] - <color=#{2}>{1}</color>",
System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff"), logString,ColorUtils.Exception);
}
else
{
_stringBuilder.AppendFormat(
bColor ? "[TLogger][ASSERT][{0}] - <color=green>{1}</color>" : "[TLogger][ASSERT][{0}] - {1}",
System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff"), logString);
}
break;
case LogLevel.WARNING:
if (UseCustomColor)
{
_stringBuilder.AppendFormat("[TLogger][WARNING][{0}] - <color=#{2}>{1}</color>",
System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff"), logString, ColorUtils.Oringe);
}
else
{
_stringBuilder.AppendFormat(
bColor
? "[TLogger][WARNING][{0}] - <color=yellow>{1}</color>"
: "[TLogger][WARNING][{0}] - {1}", System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff"),
logString);
}
break;
case LogLevel.ERROR:
if (UseCustomColor)
{
_stringBuilder.AppendFormat("[ERROR][WARNING][{0}] - <color=#{2}>{1}</color>",
System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff"), logString, ColorUtils.Red);
}
else
{
_stringBuilder.AppendFormat(
bColor ? "[TLogger][ERROR][{0}] - <color=red>{1}</color>" : "[TLogger][ERROR][{0}] - {1}",
System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff"), logString);
}
break;
case LogLevel.EXCEPTION:
if (UseCustomColor)
{
_stringBuilder.AppendFormat("[ERROR][EXCEPTION][{0}] - <color=#{2}>{1}</color>",
System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff"), logString, ColorUtils.Exception);
}
else
{
_stringBuilder.AppendFormat(
bColor
? "[TLogger][EXCEPTION][{0}] - <color=red>{1}</color>"
: "[TLogger][EXCEPTION][{0}] - {1}",
System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff"), logString);
}
break;
}
return _stringBuilder;
}
/// <summary>
/// 打印
/// </summary>
/// <param name="type"></param>
/// <param name="logString"></param>
private void Log(LogLevel type, string logString)
{
if (_outputType == OutputType.NONE)
{
return;
}
if (type < _filterLevel)
{
return;
}
StringBuilder infoBuilder = GetFormatedString(type, logString, UseSystemColor);
string logStr = infoBuilder.ToString();
//获取C#堆栈,Warning以上级别日志才获取堆栈
if (type == LogLevel.ERROR || type == LogLevel.WARNING || type == LogLevel.EXCEPTION)
{
StackFrame[] sf = new StackTrace().GetFrames();
for (int i = 0; i < sf.Length; i++)
{
StackFrame frame = sf[i];
string declaringTypeName = frame.GetMethod().DeclaringType.FullName;
string methodName = sf[i].GetMethod().Name;
infoBuilder.AppendFormat("[{0}::{1}\n", declaringTypeName, methodName);
}
}
if (type == LogLevel.INFO || type == LogLevel.Successd)
{
Debug.Log(logStr);
}
else if (type == LogLevel.WARNING)
{
Debug.LogWarning(logStr);
}
else if (type == LogLevel.ASSERT)
{
Debug.LogAssertion(logStr);
}
else if (type == LogLevel.ERROR)
{
Debug.LogError(logStr);
}
else if (type == LogLevel.EXCEPTION)
{
Debug.LogError(logStr);
}
}
#region Properties
public bool UseCustomColor = false;
public bool UseSystemColor = true;
/// <summary>
/// 信息打印类型枚举
/// </summary>
public enum LogLevel
{
INFO,//普通信息打印
Successd,//成功信息打印
ASSERT,//资源信息打印
WARNING,//警告信息打印
ERROR,//错误信息打印
EXCEPTION,//异常信息打印
}
/// <summary>
/// 输出日志方式枚举
/// </summary>
[System.Flags]
public enum OutputType
{
NONE = 0,
EDITOR = 0x1,//编辑器模式
GUI = 0x2,//UI模式
FILE = 0x4//文件模式
}
private LogLevel _filterLevel = LogLevel.INFO;
private OutputType _outputType = OutputType.EDITOR;
private StringBuilder _stringBuilder = new StringBuilder();
#endregion
}
}
上面是打印日志基本接口的封装,有时候我们需要把日运行日志输出到文件中,也可以设定日志文件最大保留的天数。
using System;
using System.Collections.Generic;
using System.IO;
namespace TEngine.Runtime
{
/// <summary>
/// 日志文件的处理
/// </summary>
public class LogToFile
{
private FileWriter _fileWriter = new FileWriter();
/// <summary>
/// 存储日志文件的根目录
/// </summary>
private static readonly string mLogRootPath = Path.Combine(FileSystem.PersistentDataPath, "Log").FixPath();
/// <summary>
/// 日志保留天数
/// </summary>
private static int MaxLogDays = 3;
private static string _currentLogName = string.Empty;
/// <summary>
/// 获得日志文件路径
/// </summary>
/// <param name="dt"></param>
/// <returns></returns>
private string GetLogPath(DateTime dt)
{
string dataDir = dt.ToString("yyyy_MM_dd");
string logPath = Path.Combine(mLogRootPath, dataDir);
return logPath.FixPath();
}
/// <summary>
/// 日志文件中断
/// </summary>
public void DeInit()
{
if (_fileWriter == null)
{
return;
}
_fileWriter.Flush();
_fileWriter.Shutdown();
}
/// <summary>
/// 初始化
/// </summary>
public void Init()
{
DateTime currentTime = DateTime.Now;
RemoveOldLogs(currentTime);
string logDir = GetLogPath(currentTime);
string logFileName = string.Format("Log_{0}.log", currentTime.ToString("yyyy_MM_dd-HH_mm_ss"));
_currentLogName = logFileName;
string fullPath = Path.Combine(logDir, logFileName).FixPath();
try
{
if (!Directory.Exists(logDir))
{
Directory.CreateDirectory(logDir);
}
if (File.Exists(fullPath))
{
File.Delete(fullPath);
}
_fileWriter.OpenFile(fullPath);
}
catch (Exception e)
{
TLogger.LogException( e.ToString());
}
}
/// <summary>
/// 写
/// </summary>
/// <param name="msg"></param>
public void Write(string msg)
{
if (_fileWriter == null)
{
return;
}
_fileWriter.Write(msg);
}
/// <summary>
/// 删除超出最大保留天数的旧日志文件
/// </summary>
/// <param name="now"></param>
private void RemoveOldLogs(DateTime now)
{
HashSet<string> foldersToKeep = new HashSet<string>();
for (int i = 0; i < MaxLogDays; i++)
{
DateTime current = now.AddDays(-i);
string folder = GetLogPath(current);
foldersToKeep.Add(folder);
}
if (Directory.Exists(mLogRootPath))
{
try
{
string[] allLogDir = Directory.GetDirectories(mLogRootPath);
foreach (string dir in allLogDir)
{
string fixedDir = dir.FixPath();
if (!foldersToKeep.Contains(fixedDir))
{
try
{
Directory.Delete(fixedDir, true);
}
catch (Exception e)
{
TLogger.LogException(e.ToString());
}
}
}
}
catch (Exception e)
{
TLogger.LogException(e.ToString());
}
}
}
}
}