分享一个我用的 unity 日志系统

Posted 勥小透明

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了分享一个我用的 unity 日志系统相关的知识,希望对你有一定的参考价值。

我们在开发中,往往会觉得unity自带的日志系统不是那么好用,比如,不能筛选日志,不能打印在屏幕上,想生成自己的日志文件,等等等等的需求,这时候就需要自己来扩展编辑器的相关功能了。
我这里实现的需求比较简单,就是给日志加了个key,可以根据这个key来对暂时不需要显示的日志进行过滤,还有就是将我们的日志打印到屏幕上去。

打印屏幕的类参考了由 Jeremy Hollingsworth 和 Simon Waite 这2人写的一个 DebugConsole.cs 类,不过他们2个的版本实在是太早了,而且还有错误和啰嗦的地方,有兴趣的话你可以去搜来看看。外加老外真的很喜欢用while循环呀,好多能用for的地方也是while,是因为这样写字比较少吗?看来大家都是懒癌晚期患者,(:зゝ∠)

一直犯懒,终于把它给写了。。。有时间我也给它扔到 github 上去。。。
外加如果想要输出日志文件,或者其它什么功能的,你就自己加就好了,我当前的需求还是挺简单的~

效果如图:

这样用
这里写图片描述

或者这样用
这里写图片描述

一共由2个类组成,一个负责控制台打印,一个负责屏幕打印

using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System.Text;

namespace GameFramework
{
    /// <summary>
    /// 日志管理器
    /// </summary>
    public class DebugMgr
    {
        #region 日志结构

        /// <summary>
        /// 日志基类
        /// </summary>
        protected abstract class LogDataBase
        {
            /// <summary>
            /// key
            /// </summary>
            public string key;
            /// <summary>
            /// 日志
            /// </summary>
            public string log;

            /// <summary>
            /// 构造
            /// </summary>
            /// <param name="_key">key</param>
            /// <param name="_log">日志</param>
            public LogDataBase(string _key, string _log)
            {
                key = _key;
                log = _log;
            }

            /// <summary>
            /// 获取log
            /// </summary>
            /// <param name="format">格式</param>
            /// <returns>log</returns>
            protected string GetLog(string format)
            {
                string txt = string.Format(format, key, log);
                return txt;
            }

            /// <summary>
            /// 打印
            /// </summary>
            /// <param name="format">格式</param>
            /// <returns>日志</returns>
            public abstract string Print(string format);
        }

        /// <summary>
        /// 日志类
        /// </summary>
        protected class LogData : LogDataBase
        {
            public LogData(string key, string message)
                : base(key, message)
            { }

            public override string Print(string format)
            {
                string logTxt = base.GetLog(format);
                Debug.Log(logTxt);
                return logTxt;
            }
        }

        /// <summary>
        /// 警告类
        /// </summary>
        protected class LogWarningData : LogDataBase
        {
            public LogWarningData(string key, string message)
                : base(key, message)
            { }

            public override string Print(string format)
            {
                string logTxt = base.GetLog(format);
                Debug.LogWarning(logTxt);
                return logTxt;
            }
        }

        /// <summary>
        /// 错误类
        /// </summary>
        protected class LogErrorData : LogDataBase
        {
            public LogErrorData(string key, string message)
                : base(key, message)
            { }

            public override string Print(string format)
            {
                string logTxt = base.GetLog(format);
                Debug.LogError(logTxt);
                return logTxt;
            }
        }

        #endregion 日志结构类 ------------------------------------


        /// <summary>
        /// 日志格式
        /// </summary>
        public static string format = "{0}:{1}";

        /// <summary>
        /// 屏幕显示
        /// </summary>
        public static bool screenDisplay = false;

        // 过滤key集合
        private static List<string> s_filterKeyList = new List<string>();

        /// <summary>
        /// 清除所有key
        /// </summary>
        public static void ClearFilterKey()
        {
            s_filterKeyList.Clear();
        }
        /// <summary>
        /// 增加key
        /// </summary>
        /// <param name="key">key</param>
        public static void AddFilterKey(string key)
        {
            // 不加重复的key
            if (s_filterKeyList.Contains(key))
                return;
            s_filterKeyList.Add(key);
        }
        /// <summary>
        /// 移除key
        /// </summary>
        /// <param name="key">key</param>
        public static void RemoveFilterKey(string key)
        {
            if (s_filterKeyList.Contains(key))
                s_filterKeyList.Remove(key);
        }

        // 打印
        private static string Print(LogDataBase ld)
        {
            // 日志不能为空
            if (ld == null)
                return "";

            // 日志key是被过滤的
            if (s_filterKeyList.Contains(ld.key))
                return "";

            // 打印日志
            string logTxt = ld.Print(format);
            return logTxt;
        }

        /// <summary>
        /// 日志
        /// </summary>
        /// <param name="log">日志</param>
        /// <param name="key">key</param>
        public static void Log(string log, string key = "日志")
        {
            LogData ld = new LogData(key, log);
            string logTxt = DebugMgr.Print(ld);

            if (screenDisplay)
                DebugConsole.Log(logTxt);
            else
                DebugConsole.Clear();
        }
        /// <summary>
        /// 警告
        /// </summary>
        /// <param name="log">日志</param>
        /// <param name="key">key</param>
        public static void LogWarning(string log, string key = "警告")
        {
            LogWarningData ld = new LogWarningData(key, log);
            string logTxt = DebugMgr.Print(ld);

            if (screenDisplay)
                DebugConsole.LogWarning(logTxt);
            else
                DebugConsole.Clear();
        }
        /// <summary>
        /// 错误
        /// </summary>
        /// <param name="log">日志</param>
        /// <param name="key">key</param>
        public static void LogError(string log, string key = "错误")
        {
            LogErrorData ld = new LogErrorData(key, log);
            string logTxt = DebugMgr.Print(ld);

            if (screenDisplay)
                DebugConsole.LogError(logTxt);
            else
                DebugConsole.Clear();
        }
    }
}
using UnityEngine;
using System.Collections;
using System.Collections.Generic;

namespace GameFramework
{
    public class DebugConsole : MonoBehaviour
    {
        /// <summary>
        /// 日志颜色枚举
        /// </summary>
        public enum LogColor
        {
            NORMAL, WARNING, ERROR
        }

        /// <summary>
        /// 普通颜色
        /// </summary>
        public Color normalColor = Color.green;
        /// <summary>
        /// 警告颜色
        /// </summary>
        public Color warningColor = Color.yellow;
        /// <summary>
        /// 错误颜色
        /// </summary>
        public Color errorColor = Color.red;

        /// <summary>
        /// 第一个gui组件
        /// </summary>
        public GameObject debugGui = null;
        /// <summary>
        /// 默认gui位置
        /// </summary>
        public Vector3 defaultGuiPosition = new Vector3(0.01f, 0.98f, 0f);

        /// <summary>
        /// 显示最大日志数
        /// </summary>
        public int maxLogs = 30;
        /// <summary>
        /// 行间距
        /// </summary>
        public float lineSpacing = 0.03f;

        /// <summary>
        /// 能拖动
        /// </summary>
        public bool draggable = true;
        /// <summary>
        /// 是否显示
        /// </summary>
        public bool visible = true;


        // 集合
        private List<GUIText> m_guiList = new List<GUIText>();
        private List<string> m_logList = new List<string>();
        private List<LogColor> m_colorList = new List<LogColor>();


        // 单例
        private static DebugConsole s_instance = null;
        /// <summary>
        /// 获取单例
        /// </summary>
        /// <returns>单例</returns>
        public static DebugConsole GetInstance()
        {
            if (s_instance == null)
            {
                s_instance = (DebugConsole)FindObjectOfType(typeof(DebugConsole));
                if (s_instance == null)
                {
                    GameObject console = new GameObject();
                    console.name = "DebugConsole";
                    console.AddComponent<DebugConsole>();

                    s_instance = (DebugConsole)FindObjectOfType(typeof(DebugConsole));
                }
            }

            return s_instance;
        }

        void Awake()
        {
            DontDestroyOnLoad(this);
            s_instance = this;
            this.InitGuis();
        }

        private void InitGuis()
        {
            // 初始化第一个gui
            if (debugGui == null)
            {
                debugGui = new GameObject();
                debugGui.name = "DebugGUI(0)";
                debugGui.transform.SetParent(this.transform, false);
                debugGui.transform.position = defaultGuiPosition;

                GUIText gt = debugGui.AddComponent<GUIText>();
                m_guiList.Add(gt);
            }

            // 创建其它的gui
            Vector3 position = debugGui.transform.position;
            int guiCount = 1;
            while (guiCount < maxLogs)
            {
                position.y -= lineSpacing;

                GameObject clone = (GameObject)Instantiate(debugGui, position, transform.rotation);
                clone.name = string.Format("DebugGUI({0})", guiCount);
                GUIText gt = clone.GetComponent<GUIText>();
                m_guiList.Add(gt);

                position = clone.transform.position;

                ++guiCount;
            }
            // 设置父节点
            guiCount = 0;
            while (guiCount < m_guiList.Count)
            {
                GUIText temp = (GUIText)m_guiList[guiCount];
                temp.transform.parent = debugGui.transform;

                ++guiCount;
            }
        }


        // 连接到手指
        private bool connectedToMouse = false;
        void Update()
        {
            // 拖拽移动
            if (draggable)
            {
                if (Input.GetMouseButtonDown(0))
                {
                    if (connectedToMouse)
                    {
                        connectedToMouse = false;
                    }
                    else if (connectedToMouse == false && debugGui.GetComponent<GUIText>().HitTest((Vector3)Input.mousePosition))
                    {
                        connectedToMouse = true;
                    }
                }

                if (connectedToMouse)
                {
                    float posX = Input.mousePosition.x / Screen.width;
                    float posY = Input.mousePosition.y / Screen.height;
                    debugGui.transform.position = new Vector3(posX, posY, 0F);
                }
            }
        }


        /// <summary>
        /// 清屏
        /// </summary>
        private void ClearScreen()
        {
            // 对象还没创建全的情况下不清
            if (m_guiList.Count < maxLogs)
                return;

            int count = 0;
            while (count < m_guiList.Count)
            {
                GUIText gt = m_guiList[count];
                gt.text = "";

                ++count;
            }
        }

        /// <summary>
        /// 精简多出来的消息
        /// </summary>
        private void Prune()
        {
            if (m_logList.Count <= maxLogs)
                return;

            int diff = m_logList.Count - maxLogs;

            m_logList.RemoveRange(0, diff);
            m_colorList.RemoveRange(0, diff);
        }

        /// <summary>
        /// 显示
        /// </summary>
        private void Display()
        {
            if (visible)
            {
                // 先尝试是否能精简
                this.Prune();

                // gui不够
                if (m_guiList.Count < maxLogs)
                    return;

                // 显示
                int guiCount = 0;
                while (guiCount < m_guiList.Count && guiCount < m_logList.Count)
                {
                    GUIText gt = m_guiList[guiCount];

                    // 文本
                    gt.text = m_logList[guiCount];

                    // 颜色
                    LogColor lc = m_colorList[guiCount];
                    switch (lc)
                    {
                        case LogColor.NORMAL:
                            {
                                gt.material.color = this.normalColor;
                            }
                            break;
                        case LogColor.WARNING:
                            {
                                gt.material.color = this.warningColor;
                            }
                            break;
                        case LogColor.ERROR:
                            {
                                gt.material.color = this.errorColor;
                            }
                            break;
                    }

                    // 循环
                    ++guiCount;
                }
            }
            else
            {
                // 清屏
                this.ClearScreen();
            }
        }

        // 加日志
        private void AddLog(string log, LogColor color = LogColor.NORMAL)
        {
            m_logList.Add(log);
            m_colorList.Add(color);
            this.Display();
        }
        // 清日志
        private void ClearLog()
        {
            m_logList.Clear();
            m_colorList.Clear();
            this.ClearScreen();
        }

        /// <summary>
        /// 日志
        /// </summary>
        /// <param name="log">日志</param>
        public static void Log(string log)
        {
            DebugConsole.GetInstance().AddLog(log, LogColor.NORMAL);
        }
        /// <summary>
        /// 警告
        /// </summary>
        /// <param name="log">日志</param>
        public static void LogWarning(string log)
        {
            DebugConsole.GetInstance().AddLog(log, LogColor.WARNING);
        }
        /// <summary>
        /// 错误
        /// </summary>
        /// <param name="log">日志</param>
        public static void LogError(string log)
        {
            DebugConsole.GetInstance().AddLog(log, LogColor.ERROR);
        }
        /// <summary>
        /// 清除
        /// </summary>
        public static void Clear()
        {
            DebugConsole.GetInstance().ClearLog();
        }
    }
}

测试类:

using UnityEngine;
using System.Collections;

using GameFramework;

public class Test : MonoBehaviour
{
    public bool screenDisplay = false;

    // Use this for initialization
    void Start()
    {
        DebugMgr.Log("开始了");
    }

    private int m_count = 0;

    void OnGUI()
    {
        if (GUI.Button(new Rect(500, 0, 100, 100), "加log"))
        {
            DebugMgr.screenDisplay = screenDisplay;

            string log = "count = " + m_count;
            DebugMgr.Log(log);
            DebugMgr.LogWarning(log);
            DebugMgr.LogError(log);

            ++m_count;
        }
    }
}

友情提示一下,你可能发现了,现在你左键点一下 Console 窗口下的日志,系统会给你跳转到 DebugMgr 类里,而不是真正打日志的地方,想要解决这个问题也很简单。你就把这2个类编译封装成一个单独的c#类库项目,生成dll后,再导入项目中就可以了,这样 unity 在追踪程序的堆栈调用时,跳转的位置就会指向你真正打日志的地方了,轻松又愉快~

以上是关于分享一个我用的 unity 日志系统的主要内容,如果未能解决你的问题,请参考以下文章

几个可以直接拿来用的jQuery代码片段

操作日志记录

unity3d游戏开发学习分享之表面着色器讲解

log4j2文件配置

ELK日志系统+x-pack安全验证

iOS和unity的交互问题