[Unity] 自定义日志系统 解决Unity Log的痛点

该博客介绍了一个优化的Unity日志系统,解决了原生日志的问题,如无时间戳、Log、Warning和Error区分不清等。新系统增加了时间戳、控制Log输出、按次生成日志文件、设备信息记录等功能,并在Error发生时自动显示之前的部分Log历史,便于错误跟踪。源码提供,可在项目初始化时调用以启用此日志系统。
摘要由CSDN通过智能技术生成

当前Unity日志存在的问题:

1.日志打印没有时间

2.日志文件中Log、Warning、和Error区分度不大

3.长时间没有清理容易产生动辄几十MB,几十万行的日志文件

本日志系统区别于Unity原生Log主要有以下几点:

1.日志打印添加时间戳

2.普通打印可忽略堆栈信息

3.每次启动生成一份日志文件

4.日志文件包含设备信息

5.关闭Log可自定义关闭内容,关闭Log默认情况下仅屏蔽普通打印,不屏蔽Warning和Error

6.关闭Log情况下出现Error自动打印前20条Log方便跟踪报错

效果展示:

使用方式:

需要在程序初始化时调用初始化日志系统,以便日志系统捕获系统报错

Editor:

日志文件:

源码:

using System;
using System.Collections.Generic;
using System.IO;
using UnityEngine;

namespace AuthorZhidai
{

    public class Log
    {

        private const int LOG_COUNT = 20;// 最多临时保存LOG_COUNT条日志
        private const int LOG_FILE_COUNT = 10;// 最多保存的日志文件数


        public static bool EnableLog = true;// 是否启用日志,仅可控制普通级别的日志的启用与关闭,LogError和LogWarn都是始终启用的。
        public static bool EnableSave = true;// 是否允许保存日志,即把日志写入到文件中

        public static string LogFileDir = Application.dataPath.Replace("Assets", "") + "Log";// 日志存放目录:和Assets同级目录下的Log
        public static string LogFileName = "";
        public static string Prefix = "> ";// 用于与Unity默认的系统日志做区分。本日志系统输出的日志头部都会带上这个标记。
        public static StreamWriter LogFileWriter = null;


        //日志列表,忽略Info时报错回溯使用
        public static List<string> ListLogs = new List<string>();

        //第一次执行打印log
        private static bool FirstLogTag = true;

        public static void Init()
        {
            Application.logMessageReceived += OnLogByUnity;
        }

        #region 日志
        public static void Info(object message, bool recordStackTrace = false)
        {
            string str = "[I]" + GetLogTime() + message;
            AddListLogs(str);
            if (!EnableLog)
                return;

            Debug.Log(Prefix + str, null);
            LogToFile(str, recordStackTrace);
        }

        public static void Warning(object message)
        {
            string str = "[W]" + GetLogTime() + message;
            AddListLogs(str);
            Debug.LogWarning(Prefix + str, null);
            LogToFile(str, true);
        }

        public static void Error(object message)
        {
            string str = "[E]" + GetLogTime() + message;
            Debug.LogError(Prefix + str, null);
            if (!EnableLog)
            {
                OutputListLogs(LogFileWriter);// 忽略Info时报错,自动将日志记录到文件中方便回溯
            }
            else
            {
                AddListLogs(str);
            }
            LogToFile(str, true);
        }

        /// <summary>
        /// 输出列表中所有日志
        /// 可能会造成卡顿,谨慎使用。
        /// </summary>
        /// <param name="sw"></param>
        public static void OutputListLogs(StreamWriter sw)
        {
            if (sw == null || ListLogs.Count < 1)
                return;
            sw.WriteLine($"---------------- Log History Start [以下是报错前{ListLogs.Count}条日志]---------------- ");
            foreach (var i in ListLogs)
            {
                sw.WriteLine(i);
            }
            sw.WriteLine($"---------------- Log History  End  [以上是报错前{ListLogs.Count}条日志]---------------- ");
            ListLogs.Clear();
        }
        #endregion

        public static void CloseLog()
        {
            if (LogFileWriter != null)
            {
                try
                {
                    LogFileWriter.Flush();
                    LogFileWriter.Close();
                    LogFileWriter.Dispose();
                    LogFileWriter = null;
                }
                catch (Exception)
                {
                }
            }
        }

        public static void CheckClearLog()
        {
            if (!Directory.Exists(LogFileDir))
            {
                return;
            }

            DirectoryInfo direction = new DirectoryInfo(LogFileDir);
            var files = direction.GetFiles("*");
            if (files.Length >= LOG_FILE_COUNT)
            {
                var oldfile = files[0];
                var lastestTime = files[0].CreationTime;
                foreach (var file in files)
                {
                    if (lastestTime > file.CreationTime)
                    {
                        oldfile = file;
                        lastestTime = file.CreationTime;
                    }

                }
                oldfile.Delete();
            }

        }

        private static void OnLogByUnity(string condition, string stackTrace, LogType type)
        {
            // 过滤自己的输出
            if (type == LogType.Log || condition.StartsWith(Prefix))
            {
                return;
            }
            var str = type == LogType.Warning ? "[W]" : "[E]" + GetLogTime() + condition + "\n" + stackTrace;
            if (!EnableLog && type != LogType.Warning)
                OutputListLogs(LogFileWriter);// 忽略Info时报错,自动将日志记录到文件中方便回溯
            else
                AddListLogs(str);
            LogToFile(str);
        }

        private static void AddListLogs(string str)
        {
            if (ListLogs.Count > LOG_COUNT)
            {
                ListLogs.RemoveAt(0);
            }
            ListLogs.Add(str);
        }

        private static string GetLogTime()
        {
            string str = "";

            str = DateTime.Now.ToString("HH:mm:ss.fff") + " ";


            return str;
        }

        /// <summary>
        /// 将日志写入到文件中
        /// </summary>
        /// <param name="message"></param>
        /// <param name="EnableStack"></param>
        private static void LogToFile(string message, bool EnableStack = false)
        {
            if (!EnableSave)
                return;

            if (LogFileWriter == null)
            {
                CheckClearLog();
                LogFileName = DateTime.Now.GetDateTimeFormats('s')[0].ToString();
                LogFileName = LogFileName.Replace("-", "_");
                LogFileName = LogFileName.Replace(":", "_");
                LogFileName = LogFileName.Replace(" ", "");
                LogFileName = LogFileName.Replace("T", "_");
                LogFileName = LogFileName + ".log";
                if (string.IsNullOrEmpty(LogFileDir))
                {
                    try
                    {
                        if (!Directory.Exists(LogFileDir))
                        {
                            Directory.CreateDirectory(LogFileDir);
                        }
                    }
                    catch (Exception exception)
                    {
                        Debug.Log(Prefix + "获取 Application.streamingAssetsPath 报错!" + exception.Message, null);
                        return;
                    }
                }
                string path = LogFileDir + "/" + LogFileName;

                Debug.Log("Log Path :" + LogFileDir + "\nLog Name :" + LogFileName);
                try
                {
                    if (!Directory.Exists(LogFileDir))
                    {
                        Directory.CreateDirectory(LogFileDir);
                    }
                    LogFileWriter = File.AppendText(path);
                    LogFileWriter.AutoFlush = true;
                }
                catch (Exception exception2)
                {
                    LogFileWriter = null;
                    Debug.Log("LogToCache() " + exception2.Message + exception2.StackTrace, null);
                    return;
                }
            }
            if (LogFileWriter != null)
            {
                try
                {
                    if (FirstLogTag)
                    {
                        FirstLogTag = false;
                        PhoneSystemInfo(LogFileWriter);
                    }
                    LogFileWriter.WriteLine(message);
                    if (EnableStack)
                    {
                        //把无关的log去掉
                        var st = StackTraceUtility.ExtractStackTrace();
#if UNITY_EDITOR
                        for (int i = 0; i < 3; i++)
#else
                        for (int i = 0; i < 2; i++)
#endif
                        {
                            st = st.Remove(0, st.IndexOf('\n') + 1);
                        }
                        LogFileWriter.WriteLine(st);
                    }
                }
                catch (Exception)
                {
                }
            }
        }

        private static void PhoneSystemInfo(StreamWriter sw)
        {
            sw.WriteLine("*********************************************************************************************************start");
            sw.WriteLine("By " + SystemInfo.deviceName);
            DateTime now = DateTime.Now;
            sw.WriteLine(string.Concat(new object[] { now.Year.ToString(), "年", now.Month.ToString(), "月", now.Day, "日  ", now.Hour.ToString(), ":", now.Minute.ToString(), ":", now.Second.ToString() }));
            sw.WriteLine();
            sw.WriteLine("操作系统:  " + SystemInfo.operatingSystem);
            sw.WriteLine("系统内存大小:  " + SystemInfo.systemMemorySize);
            sw.WriteLine("设备模型:  " + SystemInfo.deviceModel);
            sw.WriteLine("设备唯一标识符:  " + SystemInfo.deviceUniqueIdentifier);
            sw.WriteLine("处理器数量:  " + SystemInfo.processorCount);
            sw.WriteLine("处理器类型:  " + SystemInfo.processorType);
            sw.WriteLine("显卡标识符:  " + SystemInfo.graphicsDeviceID);
            sw.WriteLine("显卡名称:  " + SystemInfo.graphicsDeviceName);
            sw.WriteLine("显卡标识符:  " + SystemInfo.graphicsDeviceVendorID);
            sw.WriteLine("显卡厂商:  " + SystemInfo.graphicsDeviceVendor);
            sw.WriteLine("显卡版本:  " + SystemInfo.graphicsDeviceVersion);
            sw.WriteLine("显存大小:  " + SystemInfo.graphicsMemorySize);
            sw.WriteLine("显卡着色器级别:  " + SystemInfo.graphicsShaderLevel);
            sw.WriteLine("是否图像效果:  " + SystemInfo.supportsImageEffects);
            sw.WriteLine("是否支持内置阴影:  " + SystemInfo.supportsShadows);
            sw.WriteLine("*********************************************************************************************************end");
            sw.WriteLine("LogInfo:");
            sw.WriteLine();
        }

    }

}

评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值