Unity 日志存储及上传工具

记录一下学习工具

using UnityEngine;
using System.IO;
using System.Text;

namespace GameLogger
{
    /// <summary>
    /// 封装Debug日志打印,实现日志开关控制、彩色日志打印、日志文件存储等功能
    /// </summary>
    public class XxLogger
    {
        // 普通日志开关
        private static bool debugLogEnable = true;
        // 警告日志开关
        private static bool warningLogEnable = true;
        // 错误日志开关
        private static bool errorLogEnable = true;

        // 使用StringBuilder来优化字符串的重复构造
        private static StringBuilder _logStr = new StringBuilder();
        // 日志储存位置
        public static string _logFilePath;

        /// <summary>
        /// 初始化,在App启动的入口脚本Awake中调用
        /// </summary>
        public static void Init()
        {
            var t = System.DateTime.Now.ToString("yyyyMMddhhmmss");
            _logFilePath = string.Format("{0}/output_{1}.log", Application.persistentDataPath, t);
            Application.logMessageReceived += OnLogCallBack;
        }

        /// <summary>
        /// 打印日志
        /// </summary>
        /// <param name="condition"> 日志文本 </param>
        /// <param name="stackTrace"> 调用堆栈 </param>
        /// <param name="type"> 日志类型 </param>
        private static void OnLogCallBack(string condition, string stackTrace, LogType type)
        {
            _logStr.Append(condition);
            _logStr.Append("\n");
            _logStr.Append(stackTrace);
            _logStr.Append("\n");

            if (_logStr.Length <= 0)
                return;

            if (!File.Exists(_logFilePath))
            {
                var fs = File.Create(_logFilePath);
                fs.Close();
            }

            using (var sw = File.AppendText(_logFilePath))
            {
                sw.WriteLine(_logStr.ToString());
            }

            _logStr.Remove(0, _logStr.Length);
        }

        /// <summary>
        /// 上传日志到服务端
        /// </summary>
        /// <param name="desc"></param>
        public static void UpLoadLog(string desc)
        {
            
        }

        /// <summary>
        /// 格式化打印日志
        /// </summary>
        /// <param name="format"></param>
        /// <param name="args"></param>
        public static void LogFormat(string format, params object[] args)
        {
            Debug.LogFormat(format,args);
        }
        
        /// <summary>
        /// 普通日志打印
        /// </summary>
        /// <param name="message"></param>
        /// <param name="context"></param>
        public static void Log(object message, Object context = null)
        {
            if (!debugLogEnable) return;
            
            Debug.Log(message,context);
        }

        /// <summary>
        /// 警告日志打印
        /// </summary>
        /// <param name="message"></param>
        /// <param name="context"></param>
        public static void WarningLog(object message, Object context = null)
        {
            if(!warningLogEnable) return;
            
            Debug.LogWarning(message,context);
        }
        
        /// <summary>
        /// 错误日志打印
        /// </summary>
        /// <param name="message"></param>
        /// <param name="context"></param>
        public static void ErrorLog(object message, Object context = null)
        {
            if (!errorLogEnable) return;
            
            Debug.LogError(message,context);
        }

        /// <summary>
        /// 带颜色的普通日志
        /// </summary>
        /// <param name="message"></param>
        /// <param name="color"></param>
        /// <param name="context"></param>
        public static void LogWithColor(string message, string color, Object context = null)
        {
            Debug.Log(FmtColor(color, message),context);
        }

        /// <summary>
        /// 格式化带颜色的日志
        /// </summary>
        /// <param name="color"></param>
        /// <param name="obj"></param>
        /// <returns></returns>
        private static object FmtColor(string color, string msg)
        {
#if !UNITY_EDITOR
            return msg;
#else
            int p = msg.IndexOf('\n');
            if (p >= 0) p = msg.IndexOf('\n', p + 1);// 可以同时显示两行
            if (p < 0 || p >= msg.Length - 1) return string.Format("<color={0}>{1}</color>", color, msg);
            if (p > 2 && msg[p - 1] == '\r') p--;
            return string.Format("<color={0}>{1}</color>{2}", color, msg.Substring(0, p), msg.Substring(p));
#endif
        }

        #region 解决日志双击溯源问题
#if UNITY_EDITOR
        [UnityEditor.Callbacks.OnOpenAssetAttribute(0)]
        static bool OnOpenAsset(int instanceID, int line)
        {
            string stackTrace = GetStackTrace();
            if (!string.IsNullOrEmpty(stackTrace) && stackTrace.Contains("XxLogger:Log"))
            {
                //使用正则表达式匹配at的哪一个脚本
                var matches = System.Text.RegularExpressions.Regex.Match(stackTrace, @"\(at (.+)\)",
                    System.Text.RegularExpressions.RegexOptions.IgnoreCase);
                string pathLine = "";
                while (matches.Success)
                {
                    pathLine = matches.Groups[1].Value;

                    if (!pathLine.Contains("XxLogger.cs"))
                    {
                        int splitIndex = pathLine.LastIndexOf(":");
                        //脚本路径
                        string path = pathLine.Substring(0, splitIndex);
                        //行号
                        line = System.Convert.ToInt32(pathLine.Substring(splitIndex + 1));
                        string fullPath = Application.dataPath.Substring(0, Application.dataPath.LastIndexOf("Assets"));
                        fullPath = fullPath + path;
                        //跳转到目标代码特定行
                        UnityEditorInternal.InternalEditorUtility.OpenFileAtLineExternal(fullPath.Replace('/', '\\'),
                            line);
                        break;
                    }
                    matches = matches.NextMatch();
                }
                return true;
            }

            return false;
        }

        static string GetStackTrace()
        {
            // 通过反射获取ConsoleWindow类
            var ConsoleWindowType = typeof(UnityEditor.EditorWindow).Assembly.GetType("UnityEditor.ConsoleWindow");
            //获取窗口实例
            var fieldInfo = ConsoleWindowType.GetField("ms_ConsoleWindow",
                System.Reflection.BindingFlags.Static |
                System.Reflection.BindingFlags.NonPublic);
            var consoleInstance = fieldInfo.GetValue(null);
            if (consoleInstance != null)
            {
                if ((object) UnityEditor.EditorWindow.focusedWindow == consoleInstance)
                {
                    //获取成员
                    fieldInfo = ConsoleWindowType.GetField("m_ActiveText",
                        System.Reflection.BindingFlags.Instance |
                        System.Reflection.BindingFlags.NonPublic);
                    //获取值
                    string activeText = fieldInfo.GetValue(consoleInstance).ToString();
                    return activeText;
                }
            }

            return null;
        }
#endif
        #endregion
    }
}
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Runtime.CompilerServices;
using UnityEngine;
using UnityEngine.Networking;

namespace GameLogger
{
    public class LogUpLoad : MonoBehaviour
    {
        public void StartUpLoadLog()
        {
            StartCoroutine(UploadLog());
        }

        private IEnumerator UploadLog()
        {
            //一般是固定路径
            string logFilePath = XxLogger._logFilePath;
            //固定URL
            string url = "http://127.0.0.1";
            //日志描述
            string desc = "Xx日志";
            var fileName = Path.GetFileName(logFilePath);
            var data = ReadLogFile(logFilePath);

            WWWForm form = new WWWForm();
            //塞入字段描述。字段名与服务端约定好
            form.AddField("desc",desc);
            //塞入日志字节流字段,字段名与服务端约定好
            form.AddBinaryData("logfile",data,fileName,"application/x-gzip");
            //使用unitywebrequest
            UnityWebRequest request = UnityWebRequest.Post(url,form);
            var result = request.SendWebRequest();

            while (!result.isDone)
            {
                XxLogger.Log($"上传进度:{request.uploadProgress}");
                yield return null;
            }

            if (!string.IsNullOrEmpty(request.error))
            {
                XxLogger.Log(request.error);
            }
            else
            {
                XxLogger.Log($"日志上传完成,服务器返回信息:{request.downloadHandler.text}");
            }
            request.Dispose();
        }

        private byte[] ReadLogFile(string logFilePath)
        {
            byte[] data = null;

            using (FileStream fs = File.OpenRead(logFilePath))
            {
                int index = 0;
                long len = fs.Length;
                data = new byte[len];
                //根据需求限流读取
                int offset = data.Length > 1024 ? 1024 : data.Length;
                while (index < len)
                {
                    int readByteCnt = fs.Read(data, index, offset);
                    index += readByteCnt;
                    long leftByteCnt = len - index;
                    offset = leftByteCnt > offset ? offset : (int) leftByteCnt;
                }
            }

            return data;
        }
    }
}
using System;
using System.Collections;
using System.Collections.Generic;
using GameLogger;
using UnityEngine;

public class AppDebugMoudle : MonoBehaviour
{
    private void Awake()
    {
        XxLogger.Init();

        Application.logMessageReceived += (string condition, string trace, LogType type) =>
        {

        };
        
        XxLogger.Log("123");
        XxLogger.WarningLog("456");
        XxLogger.ErrorLog("789");
        XxLogger.LogWithColor("111","green");
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值