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);
}
}
}
}
}