Index: RollingFileAppender.cs =================================================================== --- RollingFileAppender.cs (revision 425395) +++ RollingFileAppender.cs (working copy) @@ -477,6 +477,26 @@ set { m_staticLogFileName = value; } } + /// + /// Gets or sets a value indicating whether to preserve the file name extension when rolling. + /// + /// + /// true if the file name extension should be preserved. + /// + /// + /// + /// By default file.log is rolled to file.log.yyyy-mm-dd or file.log.curSizeRollBackup. + /// However, under Windows the new file name will loose any program associations as the + /// extension is changed. Optionally file.log can be renamed to file.yyyy-mm-dd.log or + /// file.curSizeRollBackup.log to maintain any program associations. + /// + /// + public bool PreserveLogFileNameExtension + { + get { return m_preserveLogFileNameExtension; } + set { m_preserveLogFileNameExtension = value; } + } + #endregion Public Instance Properties #region Override implementation of FileAppender @@ -679,9 +699,15 @@ /// that are similar to the base file name. /// /// + /// /// - private static string GetWildcardPatternForFile(string baseFileName) + private static string GetWildcardPatternForFile(string baseFileName, bool preserveLogFileNameExtension) { + if (preserveLogFileNameExtension == true) + { + string pp = Path.GetFileNameWithoutExtension(baseFileName) + "*" + Path.GetExtension(baseFileName); + return (pp); + } return baseFileName + '*'; } @@ -691,9 +717,10 @@ /// /// /// - private ArrayList GetExistingFiles(string baseFilePath) + private ArrayList GetExistingFiles(string baseFilePath) { ArrayList alFiles = new ArrayList(); + string bfn = ""; string directory = null; @@ -706,25 +733,65 @@ { string baseFileName = Path.GetFileName(fullPath); - string[] files = Directory.GetFiles(directory, GetWildcardPatternForFile(baseFileName)); - - if (files != null) - { - for (int i = 0; i < files.Length; i++) - { - string curFileName = Path.GetFileName(files[i]); - if (curFileName.StartsWith(baseFileName)) - { - alFiles.Add(curFileName); - } - } - } + string t = GetWildcardPatternForFile(baseFileName, PreserveLogFileNameExtension); + string[] files = Directory.GetFiles(directory, GetWildcardPatternForFile(baseFileName, PreserveLogFileNameExtension)); + + if (files != null) + { + if (PreserveLogFileNameExtension) + { + bfn = Path.GetFileNameWithoutExtension(baseFileName); + } + for (int i = 0; i < files.Length; i++) + { + string curFileName = Path.GetFileName(files[i]); + if (PreserveLogFileNameExtension) + { + string fnext = Path.GetFileNameWithoutExtension(curFileName); + + // if it's a log file we've generated, the name from the directory will either be + // the basefilename (with extension) + // or will end with a period followed by the file's serial number + // followed by the basefilename's extension + // the last point is guaranteed by the wild card pattern used to look for files + + if ((fnext==bfn) + || (fnext.LastIndexOf(".") >0) && (IsNumber(fnext.Substring(fnext.LastIndexOf(".")+1)))) + { + alFiles.Add(curFileName); + } + } + else + { + if (curFileName.StartsWith(baseFileName)) + { + alFiles.Add(curFileName); + } + } + } + } } } LogLog.Debug("RollingFileAppender: Searched for existing files in ["+directory+"]"); return alFiles; } + // see Justin Rogers comparison of testing for numeric strings http://weblogs.asp.net/justin_rogers/archive/2004/03/29/100982.aspx + + private static bool IsNumber(string testee) + { + for (int i = 0; i < testee.Length; i++) + { + if (!char.IsNumber(testee[i])) + { + return false; + } + } + + return true; + } + + /// /// Initiates a roll over if needed for crossing a date boundary since the last run. /// @@ -743,7 +810,16 @@ if (!(last.ToString(m_datePattern,System.Globalization.DateTimeFormatInfo.InvariantInfo).Equals(m_now.ToString(m_datePattern, System.Globalization.DateTimeFormatInfo.InvariantInfo)))) { - m_scheduledFilename = m_baseFileName + last.ToString(m_datePattern, System.Globalization.DateTimeFormatInfo.InvariantInfo); + m_scheduledFilename = ""; + if (PreserveLogFileNameExtension) + { + m_scheduledFilename = Path.GetDirectoryName(m_baseFileName) + "\\" + Path.GetFileNameWithoutExtension(m_baseFileName); + } + else + { + m_scheduledFilename = m_baseFileName; + } + m_scheduledFilename += last.ToString(m_datePattern, System.Globalization.DateTimeFormatInfo.InvariantInfo); LogLog.Debug("RollingFileAppender: Initial roll over to ["+m_scheduledFilename+"]"); RollOverTime(false); LogLog.Debug("RollingFileAppender: curSizeRollBackups after rollOver at ["+m_curSizeRollBackups+"]"); @@ -808,7 +884,9 @@ /// private void InitializeFromOneFile(string baseFile, string curFileName) { - if (! curFileName.StartsWith(baseFile) ) + int seqNoLength = 0; // length of the logfile sequence # in the filename (including delimiting period) + if (!(curFileName.StartsWith(baseFile) + || (PreserveLogFileNameExtension && curFileName.StartsWith(Path.GetFileNameWithoutExtension(baseFile))) )) { // This is not a log file, so ignore return; @@ -828,10 +906,23 @@ if (m_staticLogFileName) { - int endLength = curFileName.Length - index; - if (baseFile.Length + endLength != curFileName.Length) + seqNoLength = curFileName.Length - index; // length of the logfile sequence # in the filename + // (sequence # normally last part of the filename) + if (PreserveLogFileNameExtension) // if we are preserving file extension, sequence # + // is the second last part of the filename + { // (between the second last "." and the last one) + int lastPeriodIndex = index; + int secondLastPeriodIndex = curFileName.Substring(0, index - 1).LastIndexOf("."); + string seqNo = curFileName.Substring(secondLastPeriodIndex, lastPeriodIndex - secondLastPeriodIndex); + seqNoLength = lastPeriodIndex - secondLastPeriodIndex; + index = curFileName.Substring(0, index - 1).LastIndexOf("."); + } + // if the file is in the current log set, it's length must be + // the length of the basefilename + the length of the sequence numbber + if ((baseFile.Length + seqNoLength != curFileName.Length) ) { - // file is probably scheduledFilename + .x so I don't care + // filename must have more than the base filename and sequence number + // likely a date. In any event not part of the current log set return; } } @@ -850,7 +941,7 @@ { // Bump the counter up to the highest count seen so far int backup; - if (SystemInfo.TryParse(curFileName.Substring(index + 1), out backup)) + if (SystemInfo.TryParse(curFileName.Substring(index + 1, seqNoLength - 1), out backup)) { if (backup > m_curSizeRollBackups) { @@ -1032,6 +1123,19 @@ #region Roll File + private string CombinePath(string path1, string path2) + { + string extension = Path.GetExtension(path1); + if (m_preserveLogFileNameExtension && extension.Length > 0) + { + return Path.GetDirectoryName(path1) + "\\" + Path.GetFileNameWithoutExtension(path1) + path2 + extension; + } + else + { + return path1 + path2; + } + } + /// /// Rollover the file(s) to date/time tagged file(s). /// @@ -1045,47 +1149,64 @@ /// protected void RollOverTime(bool fileIsOpen) { - if (m_staticLogFileName) - { - // Compute filename, but only if datePattern is specified - if (m_datePattern == null) - { - ErrorHandler.Error("Missing DatePattern option in rollOver()."); - return; - } - - //is the new file name equivalent to the 'current' one - //something has gone wrong if we hit this -- we should only - //roll over if the new file will be different from the old - string dateFormat = m_now.ToString(m_datePattern, System.Globalization.DateTimeFormatInfo.InvariantInfo); - if (m_scheduledFilename.Equals(File + dateFormat)) - { - ErrorHandler.Error("Compare " + m_scheduledFilename + " : " + File + dateFormat); - return; - } - - if (fileIsOpen) - { - // close current file, and rename it to datedFilename - this.CloseFile(); - } - - //we may have to roll over a large number of backups here - for (int i = 1; i <= m_curSizeRollBackups; i++) - { - string from = File + '.' + i; - string to = m_scheduledFilename + '.' + i; - RollFile(from, to); - } - - RollFile(File, m_scheduledFilename); - } + if (m_staticLogFileName) + { + // Compute filename, but only if datePattern is specified + if (m_datePattern == null) + { + ErrorHandler.Error("Missing DatePattern option in rollOver()."); + return; + } + + //is the new file name equivalent to the 'current' one + //something has gone wrong if we hit this -- we should only + //roll over if the new file will be different from the old + string dateFormat = m_now.ToString(m_datePattern, System.Globalization.DateTimeFormatInfo.InvariantInfo); + if (m_scheduledFilename.Equals(CombinePath(File, dateFormat))) + { + ErrorHandler.Error("Compare " + m_scheduledFilename + " : " + CombinePath(File, dateFormat)); + return; + } + + if (fileIsOpen) + { + // close current file, and rename it to datedFilename + this.CloseFile(); + } + + int maxSerial = 0; // keep trakc of the largest file used on the date being rolled + + // roll over the archived files + //we may have to roll over a large number of backups here + for (int i = 1; i <= m_curSizeRollBackups; i++) + { + string from = CombinePath(File, "." + i); + string to = CombinePath(m_scheduledFilename + (PreserveLogFileNameExtension? Path.GetExtension(File): ""), "." + i); + + if (FileExists(from)) + { + RollFile(from, to); + maxSerial = i; + } + } + // roll the newest one + if (PreserveLogFileNameExtension) + { + // the Serial for the last file on a date/time is one more than + // the largest used in the ones we've already rolled + RollFile(File, CombinePath(m_scheduledFilename + Path.GetExtension(File), "." + (maxSerial + 1))); + } + else + { + RollFile(File, m_scheduledFilename); + } + } //We've cleared out the old date and are ready for the new m_curSizeRollBackups = 0; //new scheduled name - m_scheduledFilename = File + m_now.ToString(m_datePattern, System.Globalization.DateTimeFormatInfo.InvariantInfo); + m_scheduledFilename = CombinePath(File, m_now.ToString(m_datePattern, System.Globalization.DateTimeFormatInfo.InvariantInfo)); if (fileIsOpen) { @@ -1294,20 +1415,20 @@ // Delete the oldest file, to keep Windows happy. if (m_curSizeRollBackups == m_maxSizeRollBackups) { - DeleteFile(baseFileName + '.' + m_maxSizeRollBackups); + DeleteFile(CombinePath(baseFileName , "." + m_maxSizeRollBackups)); m_curSizeRollBackups--; } // Map {(maxBackupIndex - 1), ..., 2, 1} to {maxBackupIndex, ..., 3, 2} for (int i = m_curSizeRollBackups; i >= 1; i--) { - RollFile((baseFileName + "." + i), (baseFileName + '.' + (i + 1))); + RollFile((CombinePath(baseFileName, "." + i)), (CombinePath(baseFileName, "." + (i + 1)))); } m_curSizeRollBackups++; // Rename fileName to fileName.1 - RollFile(baseFileName, baseFileName + ".1"); + RollFile(baseFileName, CombinePath(baseFileName, ".1")); } else { @@ -1343,7 +1464,7 @@ if (m_staticLogFileName) { m_curSizeRollBackups++; - RollFile(baseFileName, baseFileName + '.' + m_curSizeRollBackups); + RollFile(baseFileName, CombinePath(baseFileName, "." + m_curSizeRollBackups)); } } } @@ -1515,6 +1636,11 @@ private bool m_staticLogFileName = true; /// + /// Value indicating whether to preserve the file name extension when rolling. + /// + private bool m_preserveLogFileNameExtension = false; + + /// /// FileName provided in configuration. Used for rolling properly /// private string m_baseFileName;