在Unity中使用Serilog作为日志系统
前言
接上一篇Unity中日志系统的配置与使用 - 非法关键字 - 博客园,文章中使用的是Package Manager中Unity Registry下的包Unity.Logging, 和Unity内置的Debug结合比较好,可以很方便的扩展一些支持的Sinks,但是某些方便还是有比较大的限制,也可能是我不够熟悉,查看了Unity.Logging的文档,文档中的某些特性实际上使用也存在偏差,例如我需要日志是以日期滚动(跨天自动处理)记录的、超过多少天的自动清理、在编辑器模式下支持。
使用场景
写了一个通信的工具,也需要在Editor模式下进行一些简单的调试,也希望日志能形成持久化的记录

使用Serilog
- 
首先在 Edit/Project Settings/Package Manager,添加Scoped RegisteriesName: xxxx URL: https://unitynuget-registry.openupm.com Scope(s): org.nuget 
- 
然后在Package Manager中就能看到My Registries节点下添加的Regitstry,然后安装 Serilog.Sinks.File,它能很棒的处理依赖 
- 
不啰嗦了,注释比较完整,直接贴 using System.IO; using Serilog; using UnityEngine; #if UNITY_EDITOR using UnityEditor; using UnityEditor.Callbacks; #endif /// <summary> /// 此脚本不需要挂载在任何GameObject上 /// 在编辑器和运行时都能拦截日志并写入文件 /// </summary> #if UNITY_EDITOR // 确保脚本加载或域重载后立刻触发静态构造 [InitializeOnLoad] #endif public static class UnitySerilogging/* : MonoBehaviour*/ { private static bool _initialized = false; private static readonly object _initLock = new object(); /// <summary> /// 检查日志系统是否初始化 /// </summary> public static bool IsInitialized => _initialized; static UnitySerilogging() { // 编辑器环境下:脚本编译完毕、打开项目、域重载后都会调用这里 InitializeLogging(); #if UNITY_EDITOR // 监听从编辑模式到播放模式、播放回编辑模式的切换 EditorApplication.playModeStateChanged += OnPlayModeStateChanged; #endif } /// <summary> /// RuntimeInitializeOnLoadMethod 确保在游戏运行时调用静态构造函数 /// RuntimeInitializeLoadType.BeforeSceneLoad 在任何场景加载前完成调用静态构造函数 /// </summary> [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)] private static void InitializeOnRuntime() { if (!_initialized) { InitializeLogging(); // 在运行时注册应用程序退出事件 Application.quitting += OnApplicationQuitting; } } private static void OnApplicationQuitting() { // 清理旧的日志器 CleanupLogging(); } #if UNITY_EDITOR private static void OnPlayModeStateChanged(PlayModeStateChange state) { switch (state) { case PlayModeStateChange.EnteredPlayMode: case PlayModeStateChange.EnteredEditMode: InitializeLogging(); break; case PlayModeStateChange.ExitingPlayMode: CleanupLogging(); break; } } /// <summary> /// 打包后进行清理 /// </summary> /// <param name="target"></param> /// <param name="pathToBuiltProject"></param> [PostProcessBuild(1)] private static void OnPostprocessBuild(BuildTarget target, string pathToBuiltProject) { // 清理旧的日志器 CleanupLogging(); } #endif private static void InitializeLogging() { lock (_initLock) { if (_initialized) return; // 基础路径配置 string basePath = Application.isEditor ? Path.GetFullPath(Path.Combine(Application.dataPath, "..")) : Application.persistentDataPath; // 创建日志目录 string logsFolder = Path.Combine(basePath, "Logs"); if (!Directory.Exists(logsFolder)) Directory.CreateDirectory(logsFolder); Log.Logger = new LoggerConfiguration() #if UNITY_EDITOR .MinimumLevel.Debug() .MinimumLevel.Override("Unity", Serilog.Events.LogEventLevel.Debug) // 过滤Unity的日志 .MinimumLevel.Override("UnityEngine", Serilog.Events.LogEventLevel.Debug) // 过滤UnityEngine的日志 .MinimumLevel.Override("UnityEditor", Serilog.Events.LogEventLevel.Debug) // 过滤UnityEditor的日志 #else .MinimumLevel.Warning() .MinimumLevel.Override("Unity", Serilog.Events.LogEventLevel.Warning) // 过滤Unity的日志 .MinimumLevel.Override("UnityEngine", Serilog.Events.LogEventLevel.Warning) // 过滤UnityEngine的日志 .MinimumLevel.Override("UnityEditor", Serilog.Events.LogEventLevel.Warning) // 过滤UnityEditor的日志 #endif .WriteTo.File($"{logsFolder}/log-.txt", rollingInterval: RollingInterval.Day, rollOnFileSizeLimit: true, fileSizeLimitBytes: 10 * 1024 * 1024, // 10MB retainedFileCountLimit: 15, // 保留15天的日志文件 outputTemplate: "[{Timestamp:HH:mm:ss.fff} {Level:u3}] {Message:lj}{NewLine}{Exception}") // 日志文件路径和滚动设置 .CreateLogger(); Application.logMessageReceived += HandleUnityLog; // 订阅Unity日志回调 _initialized = true; } } private static void HandleUnityLog(string message, string stackTrace, LogType type) { var severity = type switch { LogType.Assert => Serilog.Events.LogEventLevel.Debug, LogType.Log => Serilog.Events.LogEventLevel.Information, LogType.Warning => Serilog.Events.LogEventLevel.Warning, LogType.Error => Serilog.Events.LogEventLevel.Error, LogType.Exception => Serilog.Events.LogEventLevel.Fatal, _ => Serilog.Events.LogEventLevel.Debug, }; Log.Write(severity, "{message}\n{stackTrace}", message, stackTrace); } private static void CleanupLogging() { lock (_initLock) { if (!_initialized) return; // 取消订阅Unity日志回调 Application.logMessageReceived -= HandleUnityLog; Application.quitting -= OnApplicationQuitting; // 关闭并刷新Serilog日志 Log.CloseAndFlush(); // 重置标志 _initialized = false; } } /// <summary> /// 获取当前日志文件路径 /// </summary> /// <returns>日志文件路径,如果未初始化则返回null</returns> public static string GetLogDirectory() { if (!_initialized) return null; string basePath = Application.isEditor ? Path.GetFullPath(Path.Combine(Application.dataPath, "..")) : Application.persistentDataPath; return Path.Combine(basePath, "Logs"); } /// <summary> /// 手动刷新日志缓冲区 /// </summary> public static void FlushLogs() { if (_initialized) Log.CloseAndFlush(); } }
 
                    
                     
                    
                 
                    
                
 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号