using System; using System.Collections; using System.IO; namespace Avanade.Baz.Logging.Sinks { /// /// Used internally by the RollingFileSink to evaluate rollover thresholds. /// Also is used to rename a log file that has exceeded thresholds. /// internal class LogRoller { private RollingFileSinkData _data; private FileInfo _info; private FilenameBuilder _builder; /// /// Create an instance of the LogRoller. /// /// Rolling File Sink configuration data. public LogRoller(RollingFileSinkData data) { _data = data; _builder = new FilenameBuilder(_data); string existingFileWithFullPath = _builder.FormatCurrentFilename(); _info = new FileInfo(existingFileWithFullPath); } /// /// Archive the current log file by renaming it with today's timestamp. /// Generate a new filename for the current log file using a . /// public void PerformRenameRollover() { Purge(); if (File.Exists(_info.FullName)) { string newName = _builder.CreateNewFilename(); File.Move(_info.FullName, newName); CreateNewLogFile(); } } /// /// Evaluate the age and size threshold. /// /// Return true if the file has exceeded the thresholds. public bool CheckExceededThresholds() { if (!File.Exists(_info.FullName)) return false; return CheckExceededByteThreshold() || CheckExceededAgeThreshold(); } /// /// Creates a new current log file and explicitly sets its creation to . /// /// Explicitly creating the new file and explicitly setting its creation is /// necessary due to file system tunneling. Due the file system tunneling a new file will get the creation /// of an older file that existed with the same name but that was deleted or renamed within 15 seconds of /// the creation operation. private void CreateNewLogFile() { FileStream newLogFileStream = File.Create(_info.FullName, 1); newLogFileStream.Close(); File.SetCreationTime(_info.FullName, DateTime.Now); } /// /// Evaluate the file size threshold. /// /// Returns true if the file has grown larger than the AgeThreshold. private bool CheckExceededByteThreshold() { bool exceed = false; if (_data.ByteThreshold > 0) { long threshold = _data.ByteThreshold * Convert.ToInt32(_data.ByteUnit); if (_info.Length >= threshold) { exceed = true; } } return exceed; } /// /// Evaluate the age threshold by comparing the file's creation date against today. /// /// Returns true if the file has grown larger than the AgeThreshold. private bool CheckExceededAgeThreshold() { bool exceed = false; if (_data.AgeThreshold > 0) { double elapsedValue = GetElapsedAgeValue(); if (elapsedValue >= _data.AgeThreshold) { exceed = true; } } return exceed; } private double GetElapsedAgeValue() { TimeSpan age = DateTime.Now.Subtract(_info.CreationTime); double elapsedValue = 0; switch (_data.AgeUnit) { case (AgeThresholdUnit.Minutes): elapsedValue = age.TotalMinutes; break; case (AgeThresholdUnit.Hours): elapsedValue = age.TotalHours; break; case (AgeThresholdUnit.Days): elapsedValue = age.TotalDays; break; case (AgeThresholdUnit.Weeks): elapsedValue = age.TotalDays / 7; break; case (AgeThresholdUnit.Months): elapsedValue = age.TotalDays / 30; break; default: break; } return elapsedValue; } private void Purge() { if (_data.MaximumLogFilesBeforePurge > 0) { ArrayList sortedFiles = _builder.GetSortedFiles(); DeleteFiles(sortedFiles); } } private void DeleteFiles(ArrayList sortedFiles) { int numFilesToDelete = sortedFiles.Count - _data.MaximumLogFilesBeforePurge; if (numFilesToDelete > 0) { int start = 0; if (sortedFiles[0].ToString().IndexOf(_data.BaseFilename) > -1) { start = 1; } for (int i = start; i < numFilesToDelete + start; i++) { File.Delete(sortedFiles[i] as string); } } } } }