优化Unity日志系统的消耗及在ILRuntime模式下双击能跳转到对应的文件行号

这篇具有很好参考价值的文章主要介绍了优化Unity日志系统的消耗及在ILRuntime模式下双击能跳转到对应的文件行号。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

方案:

Unity的日志控制:
日志系统打开,但是只打印错误日志。这样其他级别的日志就不会有打印消耗。

UnityEngine.Debug.unityLogger.logEnabled = true;
Debug.unityLogger.filterLogType = LogType.Error;

但是还是有字符串拼接的消耗。
Conditional属性是一个C#特性,它允许你根据预处理器指令的定义来有条件地执行方法。例如下面的代码:

[Conditional("OPEN_MAIN_LOG_LOGWARNING")]
public static void Log(object message,Object context)
{
    UnityEngine.Debug.Log(message,context);
}

如果没有OPEN_MAIN_LOG_LOGWARNING宏,编译的时候,所有调用Log的方法都会从Dll里去除。因此就没有了字符串拼接的消耗。文章来源地址https://www.toymoban.com/news/detail-508968.html

检查发现的问题:

  1. Unity Editor下的Debug函数不应该被替换
  2. 给ProjectStttings.asset文件修改宏的时候,应该全平台替换。
  3. 双击日志,非ILRuntime下和ILRuntime都能跳转到对应代码的行号。注意如果ILRuntime下加了
    DISABLE_ILRUNTIME_DEBUG就不会有行号的打印。
using System.IO;
using System.Reflection;
using System.Text.RegularExpressions;
using UnityEditor;
using UnityEditor.Callbacks;
using UnityEditorInternal;
using UnityEngine;

/// <summary>
/// 日志重定向相关的实用函数。
/// </summary>
internal static class LogRedirection
{
    private static readonly Regex LogRegex = new Regex(@" \(at (.+)\:(\d+)\)\r?\n");

    [OnOpenAsset(0)]
    private static bool OnOpenAsset(int instanceId, int line)
    {
        var scriptComponent = EditorUtility.InstanceIDToObject(instanceId);
        string selectedStackTrace = GetSelectedStackTrace();
        if (string.IsNullOrEmpty(selectedStackTrace))
        {
            return false;
        }

        //是ILRuntime下日志
        if (selectedStackTrace.Contains("ILRuntime StackTrace"))
        {
            //如果跳转的不是我们的GalaDebugger,证明打开的不是第一行的url,让系统跳转
            if (!scriptComponent.name.Contains("GalaDebugger"))
            {
                return false;
            }

            Match match = LogRegex.Match(selectedStackTrace);
            if (!match.Success)
            {
                return false;
            }

            InternalEditorUtility.OpenFileAtLineExternal(match.Groups[1].Value, int.Parse(match.Groups[2].Value));
            return true;
        }
        else
        {
            //操作本质就是
            //1,拿到堆栈 取得堆栈内容判断 找出正确的打开行
            //2,每一个Groups实际上就是一行 
            //3, Groups[1]取得正好是代码路径
            //4 当然自己根据实际的封装路径来搜寻正确的路径
            //5,因为目前日志内容带有url属性,可以直接跳转了,因此只要跳转的路径不是默认的路径(也就是第一个路径日志),都按其系统跳转
            if (!selectedStackTrace.Contains("GalaDebugger:"))
            {
                return false;
            }

            Match match = LogRegex.Match(selectedStackTrace);
            if (!match.Success)
            {
                return false;
            }

            //此时找到了第一个,如果跳转的不是第一个,证明我们手动选中了其它url  ---注意这里存在一个缺陷,如果选中的跳转url正好和默认路径的line一致,则会仍然跳转日志打印处
            //理论上可以判断脚本的instanceId
            int targetLine = int.Parse(match.Groups[2].Value);
            if (targetLine != line)
            {
                return false;
            }

            if (!match.Groups[1].Value.Contains("GalaDebugger.cs"))
            {
                return false;
            }

            match = match.NextMatch();
            if (!match.Success)
            {
                return false;
            }

            if (match.Groups[1].Value.Contains("GalaDebugger.cs"))
            {
                match = match.NextMatch();
                if (!match.Success)
                {
                    return false;
                }
            }

            InternalEditorUtility.OpenFileAtLineExternal(
                Path.Combine(Application.dataPath, match.Groups[1].Value.Substring(7)),
                int.Parse(match.Groups[2].Value));
            return true;
        }
    }

    private static string GetSelectedStackTrace()
    {
        Assembly editorWindowAssembly = typeof(EditorWindow).Assembly;
        if (editorWindowAssembly == null)
        {
            return null;
        }

        System.Type consoleWindowType = editorWindowAssembly.GetType("UnityEditor.ConsoleWindow");
        if (consoleWindowType == null)
        {
            return null;
        }

        FieldInfo consoleWindowFieldInfo =
            consoleWindowType.GetField("ms_ConsoleWindow", BindingFlags.Static | BindingFlags.NonPublic);
        if (consoleWindowFieldInfo == null)
        {
            return null;
        }

        EditorWindow consoleWindow = consoleWindowFieldInfo.GetValue(null) as EditorWindow;
        if (consoleWindow == null)
        {
            return null;
        }

        if (consoleWindow != EditorWindow.focusedWindow)
        {
            return null;
        }

        //目的就是要拿到当前选中的文本
        FieldInfo activeTextFieldInfo =
            consoleWindowType.GetField("m_ActiveText", BindingFlags.Instance | BindingFlags.NonPublic);
        if (activeTextFieldInfo == null)
        {
            return null;
        }

        return (string)activeTextFieldInfo.GetValue(consoleWindow);
    }
}
  1. 打底包和打热更的时候都应该加入Jenkins参数控制宏。
  2. 增加了新的日志系统,需要显示ILRuntime的堆栈,需要加上CLR重定向。
unsafe static void CLRRedirection(ILRuntime.Runtime.Enviorment.AppDomain appdomain)
        {
            Type debugType = typeof(DebugEX);
            var logMethod = debugType.GetMethod("Log", new[] { typeof(object) });
            appdomain.RegisterCLRMethodRedirection(logMethod, Log);
            var logWarningMethod = debugType.GetMethod("LogWarning", new[] { typeof(object) });
            appdomain.RegisterCLRMethodRedirection(logWarningMethod, LogWarning);
            var logErrorMethod = debugType.GetMethod("LogError", new[] { typeof(object) });
            appdomain.RegisterCLRMethodRedirection(logErrorMethod, LogError);
        }

        /// <summary>
        /// DebugEX.Log 实现
        /// </summary>
        /// <param name="__intp"></param>
        /// <param name="__esp"></param>
        /// <param name="__mStack"></param>
        /// <param name="__method"></param>
        /// <param name="isNewObj"></param>
        /// <returns></returns>
        unsafe static StackObject* Log(ILIntepreter __intp, StackObject* __esp, IList<object> __mStack,
            CLRMethod __method, bool isNewObj)
        {
            ILRuntime.Runtime.Enviorment.AppDomain __domain = __intp.AppDomain;
            StackObject* ptr_of_this_method;
            StackObject* __ret = ILIntepreter.Minus(__esp, 1);
            ptr_of_this_method = ILIntepreter.Minus(__esp, 1);

            object message = typeof(object).CheckCLRTypes(StackObject.ToObject(ptr_of_this_method, __domain, __mStack));
            __intp.Free(ptr_of_this_method);

            var stacktrace = __domain.DebugService.GetStackTrace(__intp);
            DebugEX.Log(message + "\n\n==========ILRuntime StackTrace==========\n" + stacktrace);
            return __ret;
        }

        /// <summary>
        /// DebugEX.LogError 实现
        /// </summary>
        /// <param name="__intp"></param>
        /// <param name="__esp"></param>
        /// <param name="__mStack"></param>
        /// <param name="__method"></param>
        /// <param name="isNewObj"></param>
        /// <returns></returns>
        unsafe static StackObject* LogError(ILIntepreter __intp, StackObject* __esp, IList<object> __mStack,
            CLRMethod __method, bool isNewObj)
        {
            ILRuntime.Runtime.Enviorment.AppDomain __domain = __intp.AppDomain;
            StackObject* ptr_of_this_method;
            StackObject* __ret = ILIntepreter.Minus(__esp, 1);
            ptr_of_this_method = ILIntepreter.Minus(__esp, 1);

            object message = typeof(object).CheckCLRTypes(StackObject.ToObject(ptr_of_this_method, __domain, __mStack));
            __intp.Free(ptr_of_this_method);

            var stacktrace = __domain.DebugService.GetStackTrace(__intp);
            DebugEX.LogError(message + "\n\n==========ILRuntime StackTrace==========\n" + stacktrace);
            return __ret;
        }

        /// <summary>
        /// DebugEX.LogWarning 实现
        /// </summary>
        /// <param name="__intp"></param>
        /// <param name="__esp"></param>
        /// <param name="__mStack"></param>
        /// <param name="__method"></param>
        /// <param name="isNewObj"></param>
        /// <returns></returns>
        unsafe static StackObject* LogWarning(ILIntepreter __intp, StackObject* __esp, IList<object> __mStack,
            CLRMethod __method, bool isNewObj)
        {
            ILRuntime.Runtime.Enviorment.AppDomain __domain = __intp.AppDomain;
            StackObject* ptr_of_this_method;
            StackObject* __ret = ILIntepreter.Minus(__esp, 1);
            ptr_of_this_method = ILIntepreter.Minus(__esp, 1);

            object message = typeof(object).CheckCLRTypes(StackObject.ToObject(ptr_of_this_method, __domain, __mStack));
            __intp.Free(ptr_of_this_method);

            var stacktrace = __domain.DebugService.GetStackTrace(__intp);
            DebugEX.LogWarning(message + "\n\n==========ILRuntime StackTrace==========\n" + stacktrace);
            return __ret;
        }

到了这里,关于优化Unity日志系统的消耗及在ILRuntime模式下双击能跳转到对应的文件行号的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Unity中的热更新的基础知识,Xlua与ILRuntime基础知识

    热更新是指在不需要重新编译打包游戏的情况下,在线更新游戏中的一些非核心代码和资源,比如活动运营和打补丁。热更新分为资源热更新和代码热更新两种,代码热更新实际上也是把代码当成资源的一种热更新,但通常所说的热更新一般是指代码热更新。资源热更新主要

    2023年04月09日
    浏览(72)
  • 从0-1优化C++类对象创建资源消耗 (附源码)

    本文是C/C++常用功能代码封装专栏的导航贴。部分来源于实战项目中的部分功能提炼,希望能够达到你在自己的项目中拿来就用的效果,这样更好的服务于工作实践。 专栏介绍:专栏讲本人近10年后端开发常用的案例,以高质量的代码提取出来,并对其进行了介绍。代码拿去

    2023年04月13日
    浏览(28)
  • 【DOM】重绘与重排详解及在性能优化中的应用

    表示页面结构 表示DOM节点如何展示 DOM树中需要展示的节点在渲染树中至少存在一个对应的节点(隐藏的DOM元素在渲染树中没有对应的节点)。渲染树中的节点被称为“帧(frames)”或“盒(boxes)”。符合CSS模型的定义。理解页面元素为一个具有内边距、外边距、边框、位置

    2024年04月10日
    浏览(30)
  • Unity - 搬砖日志 - UGUI合批优化 - Overlap(UI AABB 有重叠), Z != 0 照样合批的方案

    Unity : 2020.3.37f1 Pipeline : BRP (另一个项目在 2021.1.xx 的 LTS 下的 URP 管线同样如此,目测:因为 UGUI 不受渲染管线切换而变化) 便于索引,记录搬砖 可以看到,下图 Canvas 的 Render Mode 在使用: Screen Space - Overlay 模式下的DC为 8 这里导致合批失败的有两个问题: 图片显示有相互的

    2024年02月13日
    浏览(30)
  • C++项目实战——基于多设计模式下的同步&异步日志系统-④-日志系统框架设计

    🌸作者简介: 花想云 ,在读本科生一枚,C/C++领域新星创作者,新星计划导师,阿里云专家博主,CSDN内容合伙人…致力于 C/C++、Linux 学习。 🌸 专栏简介:本文收录于 C++项目——基于多设计模式下的同步与异步日志系统 🌸 相关专栏推荐: C语言初阶系列 、 C语言进阶系列

    2024年02月09日
    浏览(31)
  • Unity 之 Mac App Store 内购过程解析(购买非消耗道具 | 恢复购买 | 支付验证)

    苹果后台设置 创建工程导入内购插件 需要详细步骤请查看: Unity 之 接入IOS内购过程解析 Unity内购官方文档 Mac支付和IOS逻辑基本一致,这是我之前做IOS内购时的思维导图,可以看下,先有个概念: 创建四个按钮,分别为 购买道具 , 清空日志 , 购买非消耗道具 , 恢复购买

    2023年04月08日
    浏览(26)
  • 运用多设计模式的同步&异步滚动日志系统

    还有使用样例代码 和扩展样例代码(test.cc以及写的很详细了,后续补充) 以及性能测试代码

    2024年02月19日
    浏览(27)
  • Windows系统C盘空间优化进阶:磁盘清理与Docker日志管理

    Windows系统C盘空间优化进阶:磁盘清理与Docker日志管理 当您的Windows系统C盘空间告急时,除了深入挖掘并清理隐藏的大文件,如Docker日志外,不要忽视了Windows自带的“磁盘清理”工具。这是一个强大的工具,可以帮助您释放磁盘空间,让系统运行更加流畅。以下是如何结合使

    2024年04月09日
    浏览(46)
  • 【实例项目:基于多设计模式下的日志系统(同步&异步)】

    本项目涉及的到所有源码见以下链接: https://gitee.com/ace-zhe/wz_log        日志类似于日记,通常是指对完成某件事情的过程中状态等的记录,而计算机中的日志是指日志数据,是有价值的信息宝库,各种操作系统、应用程序、设备和安全产品的日志数据能够帮助你提前发现和

    2024年02月09日
    浏览(34)
  • 【C++基于多设计模式下的同步&异步日志系统】

    本项⽬主要实现⼀个⽇志系统, 其主要⽀持以下功能: 1️⃣⽀持多级别⽇志消息; 2️⃣⽀持同步⽇志和异步⽇志; 3️⃣⽀持可靠写⼊⽇志到控制台、⽂件以及滚动⽂件中; 4️⃣⽀持多线程程序并发写⽇志; 5️⃣⽀持扩展不同的⽇志落地⽬标. 1️⃣CentOS 7.6(2核,内存2GB,SSD云硬盘

    2024年02月08日
    浏览(71)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包