Unity - 带耗时 begin ... end 的耗时统计的Log - TSLog

该代码示例展示了如何在UnityEditor中创建一个自定义的日志系统,用于记录带有TimeSpan的日志数据,包括开始和结束时间、函数调用描述等信息。类TSLog实现了开始和结束标签功能,用于追踪代码执行时间,生成的数据可以导出为CSV格式。然而,它不包含Profiler的调用次数和堆栈跟踪功能。

CSharp Code

// jave.lin 2023/04/21 带 timespan 的日志 (不帶 log hierarchy 结构要求,即: 不带 stack 要求)

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

public class TSLog
{
    // ts == time span
    public class WithTimeSpanLogData
    {
        public int idx;
        public string tag;
        public TimeSpan timeSpan; // (DateTime)start - (DateTime)end

        public string startDesc;
        public string endDesc;
        public DateTime startDateTime;
        public DateTime endDateTime;
        public string classNameStart;
        public int lineStart;
        public string classNameEnd;
        public int lineEnd;

        public static string GetCSVTitle()
        {
            return $"编号, 标记, 耗时, 开始描述, 结束描述, 开始时间, 结束时间, 开始文件, 开始行, 结束文件, 结束行\n";
        }

        public override string ToString()
        {
            return $"{idx}, {tag}, {timeSpan}, {startDesc}, {endDesc}, {startDateTime}, {endDateTime}, {classNameStart}, {lineStart}, {classNameEnd}, {lineEnd}";
        }
    }

    // clog == custom log
    public static void CLog(string content)
    {
        Debug.Log($"[{DateTime.Now}] {content}");
    }

    private static void GetCodeLineNum(out string fileName, out int lineNum)
    {
        System.Diagnostics.StackTrace st = new System.Diagnostics.StackTrace(0, true);
        System.Diagnostics.StackFrame frame = st.GetFrame(st.FrameCount - 1);
        fileName = frame.GetFileName();
        lineNum = frame.GetFileLineNumber();
    }

    //=== DEMO START ======================

    private static void Test()
    {
        System.Threading.Thread.Sleep(2000);
        CLog("Test Func Testing with date time Log");
    }

    private static void Test2()
    {
        System.Threading.Thread.Sleep(1000);
        CLog("Test2 Func Testing with date time Log");
    }

    [MenuItem("实用工具/测试/测试TSLog并写日志结果")]
    private static void Usage()
    {
        var tslog = new TSLog();

        tslog.Clear();

        tslog.BeginTag("Test", "开始Test函数,并标记");
        Test();
        tslog.EndTag("Test", "结束Test函数,并统计消耗");

        tslog.BeginTag("Test2", "开始Test2函数,并标记");
        Test2();
        tslog.EndTag("Test2", "结束Test2函数,并统计耗时");

        tslog.WriteTagLogs();

        /*

        测试输出:

编号, 标记, 耗时, 开始描述, 结束描述, 开始时间, 结束时间, 开始文件, 开始行, 结束文件, 结束行
0, Test, 00:00:02.0112773, 开始Test函数,并标记, 结束Test函数,并统计消耗, 2023/4/21 15:36:10, 2023/4/21 15:36:12, C:\SuoguoProject\Client\Assets\Editor\TSLog.cs, 73, C:\SuoguoProject\Client\Assets\Editor\TSLog.cs, 75
1, Test2, 00:00:01.0104517, 开始Test2函数,并标记, 结束Test2函数,并统计耗时, 2023/4/21 15:36:12, 2023/4/21 15:36:13, C:\SuoguoProject\Client\Assets\Editor\TSLog.cs, 77, C:\SuoguoProject\Client\Assets\Editor\TSLog.cs, 79


         * */
    }

    //=== DEMO END ======================

    // WTSL ==> With TimeSpan Log
    private int WTSLDataIDXCounter = 0;

    private List<WithTimeSpanLogData> logTag_List = new List<WithTimeSpanLogData>();

    private Dictionary<string, WithTimeSpanLogData> logTag_Dict = new Dictionary<string, WithTimeSpanLogData>();

    public void Clear()
    {
        WTSLDataIDXCounter = 0;
        logTag_List.Clear();
        logTag_Dict.Clear();
    }

    public void BeginTag(string tag, string description = null)
    {
        tag = tag.Replace(",", "_");
        if (description != null)
            description = description.Replace(",", "_");

        var alreadyBeginTag = logTag_Dict.TryGetValue(tag, out var data);
        var nowDateTime = DateTime.Now;
        if (alreadyBeginTag)
        {
            Debug.LogWarning($"[{nowDateTime}] W BeginTag : {tag}, but alreadyBeginTag at time : {data}");
        }
        else
        {
            GetCodeLineNum(out string fileName, out int lineNum);

            Debug.Log($"[{nowDateTime}] D BeginTag : {tag}");
            logTag_Dict[tag] = new WithTimeSpanLogData
            {
                idx = WTSLDataIDXCounter++,
                tag = tag,
                startDesc = description,
                startDateTime = nowDateTime,
                classNameStart = fileName,
                lineStart = lineNum,
            };
        }
    }

    public void EndTag(string tag, string description = null)
    {
        tag = tag.Replace(",", "_");
        if (description != null)
            description = description.Replace(",", "_");

        var hasBeginTag = logTag_Dict.TryGetValue(tag, out var data);
        var nowDateTime = DateTime.Now;
        if (hasBeginTag)
        {
            var ts = nowDateTime - data.startDateTime;
            Debug.Log($"[{nowDateTime}] D EndTag : {tag}, Timespan : {ts}");
            logTag_Dict.Remove(tag);

            GetCodeLineNum(out string fileName, out int lineNum);

            data.endDesc = description;
            data.endDateTime = nowDateTime;
            data.classNameEnd = fileName;
            data.lineEnd = lineNum;
            data.timeSpan = ts;

            logTag_List.Add(data);
        }
        else
        {
            Debug.LogWarning($"[{nowDateTime}] W EndTag : {tag}, have no Timespan");
        }
    }

    public bool WriteTagLogs()
    {
        var ret = false;
        var error = string.Empty;
        try
        {
            using (var streamWriter = new StreamWriter("BuildingTagLogs.csv", false))
            {
                // 标题
                streamWriter.Write(WithTimeSpanLogData.GetCSVTitle());

                // 内容

                var list = logTag_List;
                list.Sort((a, b) => a.idx - b.idx);

                foreach (var data in list)
                {
                    streamWriter.Write($"{data}\n");
                }

                streamWriter.Close();
            }
            Debug.Log("WriteTagLogs : BuildingTagLogs.csv Successfully!");

            ret = true;
            error = string.Empty;
        }
        catch (System.Exception er)
        {
            ret = false;
            error = er.ToString();
        }
        finally
        {
            if (!ret)
            {
                Debug.LogError($"WriteTagLogs : BuildingTagLogs.csv Failured, error : {error}");
            }
        }
        return ret;
    }
}

CSV Output

编号, 标记, 耗时, 开始描述, 结束描述, 开始时间, 结束时间, 开始文件, 开始行, 结束文件, 结束行
0, Test, 00:00:02.0112773, 开始Test函数,并标记, 结束Test函数,并统计消耗, 2023/4/21 15:36:10, 2023/4/21 15:36:12, C:\SuoguoProject\Client\Assets\Editor\TSLog.cs, 73, C:\SuoguoProject\Client\Assets\Editor\TSLog.cs, 75
1, Test2, 00:00:01.0104517, 开始Test2函数,并标记, 结束Test2函数,并统计耗时, 2023/4/21 15:36:12, 2023/4/21 15:36:13, C:\SuoguoProject\Client\Assets\Editor\TSLog.cs, 77, C:\SuoguoProject\Client\Assets\Editor\TSLog.cs, 79

在这里插入图片描述


另外,上面的 Log 并没有实现类似 profiler 中的 call times (单帧的调佣次数) 和嵌套的栈调用管理,如果要有这些功能,上面的代码是不满足的,需要重现封装

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值