diff --git a/src/WinSW.Core/Configuration/XmlServiceConfig.cs b/src/WinSW.Core/Configuration/XmlServiceConfig.cs index 07021a5..5149e26 100644 --- a/src/WinSW.Core/Configuration/XmlServiceConfig.cs +++ b/src/WinSW.Core/Configuration/XmlServiceConfig.cs @@ -299,14 +299,24 @@ namespace WinSW throw new InvalidDataException("Time Based rolling policy is specified but no pattern can be found in configuration XML."); } + var timeBasedRollingKeepFiles = e.SelectSingleNode("keepFiles"); string? pattern = patternNode.InnerText; int period = SingleIntElement(e, "period", 1); - return new TimeBasedRollingLogAppender(this.LogDirectory, this.LogName, this.OutFileDisabled, this.ErrFileDisabled, this.OutFilePattern, this.ErrFilePattern, pattern, period); + return new TimeBasedRollingLogAppender( + this.LogDirectory, + this.LogName, + this.OutFileDisabled, + this.ErrFileDisabled, + this.OutFilePattern, + this.ErrFilePattern, + pattern, + period, + timeBasedRollingKeepFiles == null ? TimeBasedRollingLogAppender.DefaultFilesToKeep : int.Parse(timeBasedRollingKeepFiles.InnerText)); case "roll-by-size": sizeThreshold = SingleIntElement(e, "sizeThreshold", 10 * 1024) * SizeBasedRollingLogAppender.BytesPerKB; - int keepFiles = SingleIntElement(e, "keepFiles", SizeBasedRollingLogAppender.DefaultFilesToKeep); - return new SizeBasedRollingLogAppender(this.LogDirectory, this.LogName, this.OutFileDisabled, this.ErrFileDisabled, this.OutFilePattern, this.ErrFilePattern, sizeThreshold, keepFiles); + int sizeBasedRollingKeepFiles = SingleIntElement(e, "keepFiles", SizeBasedRollingLogAppender.DefaultFilesToKeep); + return new SizeBasedRollingLogAppender(this.LogDirectory, this.LogName, this.OutFileDisabled, this.ErrFileDisabled, this.OutFilePattern, this.ErrFilePattern, sizeThreshold, sizeBasedRollingKeepFiles); case "append": return new DefaultLogAppender(this.LogDirectory, this.LogName, this.OutFileDisabled, this.ErrFileDisabled, this.OutFilePattern, this.ErrFilePattern); diff --git a/src/WinSW.Core/LogAppenders.cs b/src/WinSW.Core/LogAppenders.cs index 59fe4d4..8cc2b00 100644 --- a/src/WinSW.Core/LogAppenders.cs +++ b/src/WinSW.Core/LogAppenders.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.IO.Compression; @@ -104,10 +105,13 @@ namespace WinSW protected string ErrFilePattern { get; } + protected string LogDirectory { get; private set; } + protected AbstractFileLogAppender(string logDirectory, string baseName, bool outFileDisabled, bool errFileDisabled, string outFilePattern, string errFilePattern) : base(outFileDisabled, errFileDisabled) { this.BaseLogFileName = Path.Combine(logDirectory, baseName); + this.LogDirectory = logDirectory; this.OutFilePattern = outFilePattern; this.ErrFilePattern = errFilePattern; } @@ -216,13 +220,18 @@ namespace WinSW { public string Pattern { get; } + public static int? DefaultFilesToKeep = null; + public int Period { get; } - public TimeBasedRollingLogAppender(string logDirectory, string baseName, bool outFileDisabled, bool errFileDisabled, string outFilePattern, string errFilePattern, string pattern, int period) + public int? FilesToKeep { get; private set; } + + public TimeBasedRollingLogAppender(string logDirectory, string baseName, bool outFileDisabled, bool errFileDisabled, string outFilePattern, string errFilePattern, string pattern, int period, int? filesToKeep) : base(logDirectory, baseName, outFileDisabled, errFileDisabled, outFilePattern, errFilePattern) { this.Pattern = pattern; this.Period = period; + this.FilesToKeep = filesToKeep; } protected override Task LogOutput(StreamReader outputReader) @@ -251,6 +260,40 @@ namespace WinSW { writer.Dispose(); copy.Writer = writer = new FileStream(this.BaseLogFileName + "_" + periodicRollingCalendar.Format + ext, FileMode.Create); + + if (this.FilesToKeep != null) + { + var logFiles = new List(); + + foreach (string file in Directory.GetFiles(this.LogDirectory, "*" + ext)) + { + DateTime createdAt = File.GetCreationTime(file); + + if (this.BaseLogFileName + "_" + periodicRollingCalendar.GetFormatForDateTime(createdAt) + ext == file) + { + logFiles.Add(file); + } + } + + logFiles.Sort((x, y) => File.GetCreationTime(x).CompareTo(File.GetCreationTime(y))); + try + { + while (this.FilesToKeep < logFiles.Count) + { + var filename = logFiles[0]; + if (File.Exists(filename)) + { + File.Delete(filename); + } + + logFiles.RemoveAt(0); + } + } + catch (IOException e) + { + this.EventLogger.WriteEntry("Failed to roll log: " + e.Message); + } + } } } diff --git a/src/WinSW.Core/PeriodicRollingCalendar.cs b/src/WinSW.Core/PeriodicRollingCalendar.cs index 4bd33c0..8192904 100644 --- a/src/WinSW.Core/PeriodicRollingCalendar.cs +++ b/src/WinSW.Core/PeriodicRollingCalendar.cs @@ -103,6 +103,8 @@ namespace WinSW } } - public string Format => this.currentRoll.ToString(this.format); + public string GetFormatForDateTime(DateTime datetime) => datetime.ToString(this.format); + + public string Format => this.GetFormatForDateTime(this.currentRoll); } }