using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.IO; namespace Neumont { /// /// author: pedroliska.com /// creation-date: 2009-05-01 /// /// This class handles writing to a log file and rolling it based on /// the file size. Currently you only need to send one parameter to the /// constructor: the logFullFilePath /// /// From the logFullFilePath, this class will determine the folder location where /// to place all logs and the file names for the log files. Log files will be /// rolled when the file hits 5MB; this will be customizable in the future via /// constructor parameters or public properties. /// /// For a logFullFilePath like this one: C:\dir1\dir2\log-file-name.log /// /// All of the log files will be located in C:\dir1\dir2 , the most recent /// log file will always be log-file-name.log and once log-file-name.log hits 5MB, /// it will be renamed log-file-name-01.log and a new log-file-name.log file will /// be created. Then when log-file-name.log hits 5MB again, log-file-name-01.log /// will become log-file-name-02.log, log-file-name.log will become log-file-name-01.log /// and a new log-file-name.log file will be created. And so on... /// /// Currently you will have 15 log-file-name-NN.log files; but this will be /// customizeable in the future via constructor parameters or public properties. /// public class LogRoller { // The amount of numbered file logs private int numberedFileMax = 15; private int maxFileSizeInMB = 5; private string logFullFilePath = ""; private string logDirectoryWithSlash = ""; private string logFileName = ""; private string logFileExtensionWithDot = ""; public LogRoller(string logFullFilePath) { int slashIndex = logFullFilePath.LastIndexOf(@"\"); if (slashIndex == -1) slashIndex = logFullFilePath.LastIndexOf(@"/"); if (slashIndex == -1) throw new ApplicationException(@"The fullFilePath must have at least one backslash ('\') or slash ('/')"); int dotIndex = logFullFilePath.LastIndexOf(@"."); if (dotIndex == -1 || dotIndex >= logFullFilePath.Length - 1) throw new ApplicationException(@"The fullFilePath must have a dot before its extension"); this.logFullFilePath = logFullFilePath; this.logDirectoryWithSlash = logFullFilePath.Substring(0, slashIndex + 1); this.logFileName = logFullFilePath.Substring(slashIndex + 1, dotIndex - slashIndex - 1); this.logFileExtensionWithDot = logFullFilePath.Substring(dotIndex); } public void LogMessage(string message) { FileInfo logFileInfo = new FileInfo(this.logFullFilePath); if (!logFileInfo.Exists) { if (!Directory.Exists(logFileInfo.DirectoryName)) Directory.CreateDirectory(logFileInfo.DirectoryName); } else { // The log file exists, see if we need to roll if (logFileInfo.Length / 1024 / 1024 > this.maxFileSizeInMB) { // We need to roll the files string currentLogFullFilePath = ""; string previousEachLogFullFilePath = ""; for (int i = this.numberedFileMax - 1; i > 0; i--) { currentLogFullFilePath = this.GetLogFullFileNameFromNumber(i); FileInfo errorLog = new FileInfo(currentLogFullFilePath); if (errorLog.Exists) { // This will happen at most one time per method call, if any. if (previousEachLogFullFilePath == "") previousEachLogFullFilePath = this.GetLogFullFileNameFromNumber(i + 1); // You cannot move and do an overwrite. So lets use the copy command, this // one can overwrite. //File.Move(currentLogFullFilePath, previousEachLogFullFilePath); File.Copy(currentLogFullFilePath, previousEachLogFullFilePath, true); } previousEachLogFullFilePath = currentLogFullFilePath; } File.Copy(this.logFullFilePath, currentLogFullFilePath, true); File.Delete(this.logFullFilePath); } } // Write to the log. // // In the future you might want to deal with the scenario where // two LogRollers are trying to write to the same file at the same time. I'm not // dealing with this right now because this will never happen in my current application // and I do not want to hinder performace. // // There are two options to deal with this. 1) Making this code be thread safe. 2) Somehow // catching the IOException and trying several times after waiting a time interval? System.IO.StreamWriter writer = new System.IO.StreamWriter(this.logFullFilePath, true); writer.WriteLine("[" + DateTime.Now + "] " + message); writer.Close(); } public void LogException(Exception ex) { this.LogMessage("\n" + PLiska.EventDealer.ExceptionToString(ex)); } private string GetLogFullFileNameFromNumber(int number) { return this.logDirectoryWithSlash + this.logFileName + "-" + number.ToString().PadLeft(2,'0') + this.logFileExtensionWithDot; } } }