U3D客户端框架之日志写入器 把Log日志写入到可写区 方便调试

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介: U3D客户端框架之日志写入器 把Log日志写入到可写区 方便调试

1 日志写入器概要


设计目的


有一段时间游戏战斗系统里出现了一个不是必现的BUG,偶尔出现偶尔不出现,Unity虽然安装了Reporter调试插件,但是日志还是无法写入本地,就很蛋疼。同事说可以连接logcat做定位,可是logcat用过的小伙伴都知道,总是会输出一大堆不需要的log,容易遗漏关键信息。最麻烦的是需要插着线调试非常麻烦。定位一些不是很好复现的BUG的时候,很麻烦。 unity3d打印出来的日志不会写入本地,有时候移动端开发如果没有log很难定位BUG。所以搭这套框架的时候考虑到了这点,加了日志写入器。


2 代码设计


为了避免频繁写入,文件频繁IO影响程序性能,根据数量策略向用户可写区Append日志数据。好困,想到再写~


LoggerManager.cs代码


using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UnityEngine;
using YouYou;
namespace Myh
{
    public class LoggerManager : ManagerBase, IDisposable
    {
        //日志数组
        private List<string> m_LogArray;
        //记录(写入)日志的路径
        private string m_LogPath = null;
        //单个日志文件最大日志数量
        private int m_LogMaxCapacity = 500;
        //当前日志数量(当前日志文件写入的日志数量)
        private int m_CurrLogCount = 0;
        //日志缓存的数量(内存中有多少条log会写入磁盘一次,应该叫落地数量吧)
        private int m_LogBufferMaxNumber = 10;
        public override void Init()
        {
            m_LogArray = new List<string>();
            if (string.IsNullOrEmpty(m_LogPath))
            {
                //在可写区(persistent data path 也叫local path)创建日志文件
                //文件格式以年-月-日-时-分-秒+Start.txt 命名
                m_LogPath = Application.persistentDataPath + "//" + "MYH_LOG_"+DateTime.Now.ToString("yyyy-MM-dd_hh.mm.ss") + "-Start.txt";
            }
            GameEntry.Log(LogCategory.Normal, "LoggerManager.Init LogPath{0}", m_LogPath);
        }
        //写入日志,并且检查是否存在日志文件,弱不存在则创建日志文件
        private void CreateFile(string pathAndName, string info)
        {
            StreamWriter sw;
            FileInfo fileInfo = new FileInfo(pathAndName);
            if (!fileInfo.Exists)
            {
                //CreateText方法限定了文本文件,只能创建文本文件
                //Create应该可以创建任何类型的文件
                sw = fileInfo.CreateText();
            }
            else
            {
                sw = fileInfo.AppendText();
            }
            //写入一行
            sw.WriteLine(info);
            //关闭流
            sw.Close();
            //销毁?
            sw.Dispose();
        }
        //同步日志(写入磁盘)
        public void SyncLog()
        {
            if (!string.IsNullOrEmpty(m_LogPath))
            {
                int iLen = m_LogArray.Count;
                for (int i = 0; i < iLen; ++i)
                {
                    //写入日志
                    CreateFile(m_LogPath, m_LogArray[i]);
                }
                ClearLogArray();
            }
        }
        //附加日志到文件尾部
        public void AppendDataToFile(string writerFileData)
        {
            if (!string.IsNullOrEmpty(writerFileData))
            {
                m_LogArray.Add(writerFileData);
            }
            if (m_LogArray.Count % m_LogBufferMaxNumber == 0)
            {
                SyncLog();
            }
        }
        //写入日志
        public void Write(string strWriteFileData, LogType logType)
        {
            //判断单个文件写入数量是否超过上限,如果超过上限用当前时间新创建一个日志文件
            if (m_CurrLogCount >= m_LogMaxCapacity)
            {
                m_LogPath = Application.persistentDataPath + "//" + "MYH_LOG_" + DateTime.Now.ToString("yyyy-MM-dd_hh.mm.ss") + ".txt";
                m_CurrLogCount = 0;
            }
            ++m_CurrLogCount;
            if (!string.IsNullOrEmpty(strWriteFileData))
            {
                //拼接写入的时间
                strWriteFileData = "[" + DateTime.Now.ToString("yyyy-MM-dd hh.mm.ss") + "] [" + logType + "] " + strWriteFileData;
                AppendDataToFile(strWriteFileData);
            }
        }
        //清理Log数组
        private void ClearLogArray()
        {
            if (null != m_LogArray)
            {
                m_LogArray.Clear();
            }
        }
        public void Dispose()
        {
            m_LogArray.Clear();
        }
    }
}


3 测试


设计完之后,最重要的是测试并且验证实现过的功能。在Win32平台测试后,日志可以正常写入到可写区。


测试代码


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using YouYou;
using UnityEngine;
public class TestUtils : ITest
{
    private void TestLogger()
    {
        GameEntry.Log(LogCategory.Normal, "TestLogger start");
        //int iLen = 0;
        for (int i = 0; i < 400; ++i)
        {
            GameEntry.Logger.Write("我是一般Log:" + i.ToString(), LogType.Log);
            GameEntry.Logger.Write("我是警告Log:" + i.ToString(), LogType.Warning);
            GameEntry.Logger.Write("我是断言Log:" + i.ToString(), LogType.Assert);
            GameEntry.Logger.Write("我是错误Log:" + i.ToString(), LogType.Error);
            GameEntry.Logger.Write("我是异常Log:" + i.ToString(), LogType.Exception);
        }
        GameEntry.Log(LogCategory.Normal, "TestLogger end");
    }
    private void TestLog()
    {
        GameEntry.Log(LogCategory.Normal, "这是一个Normal测试日志 value:{0} {1}", "xx", 1);
        GameEntry.Log(LogCategory.Procedure, "这是一个Procedure测试日志 value:{0} {1}", "xx", 2);
        GameEntry.Log(LogCategory.Proto, "这是一个Proto测试日志 value:{0} {1}", "xx", 3);
        GameEntry.Log(LogCategory.Resource, "这是一个Resource测试日志 value:{0} {1}", "xx", 4);
    }
    public void OnTestStart()
    {
        //TestLog();
        //TestLogger();
    }
    public void OnTestUpdate()
    {
    }
}
相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
相关文章
|
11天前
|
XML 安全 Java
【日志框架整合】Slf4j、Log4j、Log4j2、Logback配置模板
本文介绍了Java日志框架的基本概念和使用方法,重点讨论了SLF4J、Log4j、Logback和Log4j2之间的关系及其性能对比。SLF4J作为一个日志抽象层,允许开发者使用统一的日志接口,而Log4j、Logback和Log4j2则是具体的日志实现框架。Log4j2在性能上优于Logback,推荐在新项目中使用。文章还详细说明了如何在Spring Boot项目中配置Log4j2和Logback,以及如何使用Lombok简化日志记录。最后,提供了一些日志配置的最佳实践,包括滚动日志、统一日志格式和提高日志性能的方法。
116 30
【日志框架整合】Slf4j、Log4j、Log4j2、Logback配置模板
|
1月前
|
XML JSON Java
Logback 与 log4j2 性能对比:谁才是日志框架的性能王者?
【10月更文挑战第5天】在Java开发中,日志框架是不可或缺的工具,它们帮助我们记录系统运行时的信息、警告和错误,对于开发人员来说至关重要。在众多日志框架中,Logback和log4j2以其卓越的性能和丰富的功能脱颖而出,成为开发者们的首选。本文将深入探讨Logback与log4j2在性能方面的对比,通过详细的分析和实例,帮助大家理解两者之间的性能差异,以便在实际项目中做出更明智的选择。
216 3
|
1月前
|
Java 程序员 应用服务中间件
「测试线排查的一些经验-中篇」&& 调试日志实战
「测试线排查的一些经验-中篇」&& 调试日志实战
22 1
「测试线排查的一些经验-中篇」&& 调试日志实战
|
21天前
|
Java 程序员 API
Android|集成 slf4j + logback 作为日志框架
做个简单改造,统一 Android APP 和 Java 后端项目打印日志的体验。
83 1
|
1月前
|
Python
log日志学习
【10月更文挑战第9天】 python处理log打印模块log的使用和介绍
30 0
|
1月前
|
数据可视化
Tensorboard可视化学习笔记(一):如何可视化通过网页查看log日志
关于如何使用TensorBoard进行数据可视化的教程,包括TensorBoard的安装、配置环境变量、将数据写入TensorBoard、启动TensorBoard以及如何通过网页查看日志文件。
193 0
|
1月前
|
SQL XML 监控
SpringBoot框架日志详解
本文详细介绍了日志系统的重要性及其在不同环境下的配置方法。日志用于记录系统运行时的问题,确保服务的可靠性。文章解释了各种日志级别(如 info、warn、error 等)的作用,并介绍了常用的日志框架如 SLF4J 和 Logback。此外,还说明了如何在 SpringBoot 中配置日志输出路径及日志级别,包括控制台输出与文件输出的具体设置方法。通过这些配置,开发者能够更好地管理和调试应用程序。
|
3月前
|
Kubernetes Ubuntu Windows
【Azure K8S | AKS】分享从AKS集群的Node中查看日志的方法(/var/log)
【Azure K8S | AKS】分享从AKS集群的Node中查看日志的方法(/var/log)
131 3
|
1月前
|
存储 缓存 关系型数据库
MySQL事务日志-Redo Log工作原理分析
事务的隔离性和原子性分别通过锁和事务日志实现,而持久性则依赖于事务日志中的`Redo Log`。在MySQL中,`Redo Log`确保已提交事务的数据能持久保存,即使系统崩溃也能通过重做日志恢复数据。其工作原理是记录数据在内存中的更改,待事务提交时写入磁盘。此外,`Redo Log`采用简单的物理日志格式和高效的顺序IO,确保快速提交。通过不同的落盘策略,可在性能和安全性之间做出权衡。
1625 14
|
1月前
|
存储 分布式计算 NoSQL
大数据-136 - ClickHouse 集群 表引擎详解1 - 日志、Log、Memory、Merge
大数据-136 - ClickHouse 集群 表引擎详解1 - 日志、Log、Memory、Merge
40 0