From efed24de2011eb9aad6fbeac38697eb9a7c37e3f Mon Sep 17 00:00:00 2001 From: Syntriax Date: Fri, 8 Aug 2025 16:28:08 +0300 Subject: [PATCH] feat: rotating file logger added --- Engine.Core/Debug/RotatingFileLogger.cs | 71 +++++++++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 Engine.Core/Debug/RotatingFileLogger.cs diff --git a/Engine.Core/Debug/RotatingFileLogger.cs b/Engine.Core/Debug/RotatingFileLogger.cs new file mode 100644 index 0000000..ec3e007 --- /dev/null +++ b/Engine.Core/Debug/RotatingFileLogger.cs @@ -0,0 +1,71 @@ +using System; +using System.IO; +using System.Linq; + +namespace Engine.Core.Debug; + +public class RotatingFileLogger : ILogger +{ + public readonly FileLogger FileLogger = null!; + public readonly string Directory = string.Empty; + public readonly int RotateLength = 3; + + public RotatingFileLogger(string directory, string namePrefix, string nameSuffix = "", int rotateLength = 3) + { + RotateLength = rotateLength; + + string fileName = Path.Combine(directory, namePrefix); + if (!string.IsNullOrWhiteSpace(nameSuffix)) + fileName += $"_{nameSuffix}"; + + bool isRelativePath = Path.GetFullPath(fileName).CompareTo(fileName) != 0; + + if (isRelativePath) + fileName = Path.GetFullPath(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, fileName)); + + if (File.Exists($"{fileName}.log")) + RenameExistingLogs(fileName, RotateLength); + + FileLogger = new(fileName); + + Directory = Path.GetDirectoryName(fileName) ?? throw new("Unexpected error on getting directory of logger path"); + RotateLastLogs(Directory, namePrefix, RotateLength); + } + + private static void RenameExistingLogs(string filePath, int rotateLength) + { + for (int i = rotateLength - 1; i >= 0; i--) + { + string source = i == 0 + ? $"{filePath}.log" + : $"{filePath}_{i}.log"; + + string dest = $"{filePath}_{i + 1}.log"; + + if (!File.Exists(source)) + continue; + + if (File.Exists(dest)) + File.Delete(dest); + + File.Move(source, dest); + } + } + + private static void RotateLastLogs(string directory, string prefix, int rotateLength) + { + IOrderedEnumerable logs = System.IO.Directory.GetFiles(directory, $"{prefix}*.log") + .OrderBy(File.GetCreationTime); + + foreach (string file in logs.Skip(rotateLength)) + try + { + ILogger.Shared.Log($"Removing log file located at \"{file}\" during rotation."); + File.Delete(file); + } + catch (Exception e) { ILogger.Shared.LogException($"Failed to rotate log file at \"{file}\"", e); } + } + + public ILogger.Level FilterLevel { get => FileLogger.FilterLevel; set => FileLogger.FilterLevel = value; } + public void Log(string message, ILogger.Level level = ILogger.Level.Info, bool force = false) => FileLogger.Log(message, level, force); +}