From fc828dc1d21450882dc6a6dc2fa8d22bfe953547 Mon Sep 17 00:00:00 2001 From: jmartin Date: Thu, 29 Sep 2016 17:10:56 +0200 Subject: [PATCH 1/7] Added {Hour} and {HalfHour} specifiers. --- .../Sinks/RollingFile/RollingFileSink.cs | 13 +- .../Sinks/RollingFile/RollingLogFile.cs | 6 +- .../Sinks/RollingFile/TemplatedPathRoller.cs | 131 +++++++++++++++--- 3 files changed, 125 insertions(+), 25 deletions(-) diff --git a/src/Serilog.Sinks.RollingFile/Sinks/RollingFile/RollingFileSink.cs b/src/Serilog.Sinks.RollingFile/Sinks/RollingFile/RollingFileSink.cs index 9e5d745..35d1bc4 100644 --- a/src/Serilog.Sinks.RollingFile/Sinks/RollingFile/RollingFileSink.cs +++ b/src/Serilog.Sinks.RollingFile/Sinks/RollingFile/RollingFileSink.cs @@ -126,11 +126,12 @@ void AlignCurrentFileTo(DateTime now) void OpenFile(DateTime now) { - var date = now.Date; + var currentCheckpoint = _roller.GetCurrentCheckpoint(now); // We only take one attempt at it because repeated failures // to open log files REALLY slow an app down. - _nextCheckpoint = date.AddDays(1); + + _nextCheckpoint = _roller.GetNextCheckpoint(now); var existingFiles = Enumerable.Empty(); try @@ -140,13 +141,13 @@ void OpenFile(DateTime now) } catch (DirectoryNotFoundException) { } - var latestForThisDate = _roller + var latestForThisDateTime = _roller .SelectMatches(existingFiles) - .Where(m => m.Date == date) + .Where(m => m.DateTime == currentCheckpoint) .OrderByDescending(m => m.SequenceNumber) .FirstOrDefault(); - var sequence = latestForThisDate != null ? latestForThisDate.SequenceNumber : 0; + var sequence = latestForThisDateTime != null ? latestForThisDateTime.SequenceNumber : 0; const int maxAttempts = 3; for (var attempt = 0; attempt < maxAttempts; attempt++) @@ -196,7 +197,7 @@ void ApplyRetentionPolicy(string currentFilePath) var newestFirst = _roller .SelectMatches(potentialMatches) - .OrderByDescending(m => m.Date) + .OrderByDescending(m => m.DateTime) .ThenByDescending(m => m.SequenceNumber) .Select(m => m.Filename); diff --git a/src/Serilog.Sinks.RollingFile/Sinks/RollingFile/RollingLogFile.cs b/src/Serilog.Sinks.RollingFile/Sinks/RollingFile/RollingLogFile.cs index 20d1a69..9b35251 100644 --- a/src/Serilog.Sinks.RollingFile/Sinks/RollingFile/RollingLogFile.cs +++ b/src/Serilog.Sinks.RollingFile/Sinks/RollingFile/RollingLogFile.cs @@ -18,16 +18,16 @@ namespace Serilog.Sinks.RollingFile { class RollingLogFile { - public RollingLogFile(string filename, DateTime date, int sequenceNumber) + public RollingLogFile(string filename, DateTime dateTime, int sequenceNumber) { Filename = filename; - Date = date; + DateTime = dateTime; SequenceNumber = sequenceNumber; } public string Filename { get; } - public DateTime Date { get; } + public DateTime DateTime { get; } public int SequenceNumber { get; } } diff --git a/src/Serilog.Sinks.RollingFile/Sinks/RollingFile/TemplatedPathRoller.cs b/src/Serilog.Sinks.RollingFile/Sinks/RollingFile/TemplatedPathRoller.cs index 945281e..00fb69b 100644 --- a/src/Serilog.Sinks.RollingFile/Sinks/RollingFile/TemplatedPathRoller.cs +++ b/src/Serilog.Sinks.RollingFile/Sinks/RollingFile/TemplatedPathRoller.cs @@ -29,18 +29,42 @@ class TemplatedPathRoller const string OldStyleDateSpecifier = "{0}"; const string DateSpecifier = "{Date}"; const string DateFormat = "yyyyMMdd"; + const string HourSpecifier = "{Hour}"; + const string HourFormat = "yyyyMMddHH"; + const string HalfHourSpecifier = "{HalfHour}"; + const string HalfHourFormat = "yyyyMMddHHmm"; const string DefaultSeparator = "-"; + const string MatcherMarkSpecifier = "date"; + const string MatcherMarkInc = "inc"; + readonly string _pathTemplate; readonly Regex _filenameMatcher; + readonly SpecifierTypeEnum _specifierType = SpecifierTypeEnum.None; + // Concret used Date or Hour specifier. + readonly string _usedSpecifier = string.Empty; + readonly string _usedFormat = string.Empty; public TemplatedPathRoller(string pathTemplate) { if (pathTemplate == null) throw new ArgumentNullException(nameof(pathTemplate)); + if (pathTemplate.Contains(OldStyleDateSpecifier)) throw new ArgumentException("The old-style date specifier " + OldStyleDateSpecifier + " is no longer supported, instead please use " + DateSpecifier); + int numSpecifiers = 0; + if (pathTemplate.Contains(DateSpecifier)) + numSpecifiers++; + if (pathTemplate.Contains(HourSpecifier)) + numSpecifiers++; + if (pathTemplate.Contains(HalfHourSpecifier)) + numSpecifiers++; + if (numSpecifiers > 1) + throw new ArgumentException("The date, hour and half-hour specifiers (" + + DateSpecifier + "," + HourSpecifier + "," + HalfHourSpecifier + + ") cannot be used at the same time"); + var directory = Path.GetDirectoryName(pathTemplate); if (string.IsNullOrEmpty(directory)) { @@ -51,26 +75,57 @@ public TemplatedPathRoller(string pathTemplate) if (directory.Contains(DateSpecifier)) throw new ArgumentException("The date cannot form part of the directory name"); + if (directory.Contains(HourSpecifier)) + throw new ArgumentException("The hour specifiers cannot form part of the directory name"); + if (directory.Contains(HalfHourSpecifier)) + throw new ArgumentException("The half-hour specifiers cannot form part of the directory name"); var filenameTemplate = Path.GetFileName(pathTemplate); - if (!filenameTemplate.Contains(DateSpecifier)) + if (!filenameTemplate.Contains(DateSpecifier) && + !filenameTemplate.Contains(HourSpecifier) && + !filenameTemplate.Contains(HalfHourSpecifier)) { + // If the file name doesn't use any of the admitted specifiers then it is added the date specifier + // as de default one. filenameTemplate = Path.GetFileNameWithoutExtension(filenameTemplate) + DefaultSeparator + DateSpecifier + Path.GetExtension(filenameTemplate); } - var indexOfSpecifier = filenameTemplate.IndexOf(DateSpecifier, StringComparison.Ordinal); + //--- + // From this point forward we don't reference the Date or Hour concret specifiers and formats : + // we will reference only the one set as "used" (_usedSpecifier and _usedFormat). + + if (filenameTemplate.Contains(DateSpecifier)) + { + _usedSpecifier = DateSpecifier; + _usedFormat = DateFormat; + _specifierType = SpecifierTypeEnum.Date; + } + else if (filenameTemplate.Contains(HourSpecifier)) + { + _usedSpecifier = HourSpecifier; + _usedFormat = HourFormat; + _specifierType = SpecifierTypeEnum.Hour; + } + else if (filenameTemplate.Contains(HalfHourSpecifier)) + { + _usedSpecifier = HalfHourSpecifier; + _usedFormat = HalfHourFormat; + _specifierType = SpecifierTypeEnum.HalfHour; + } + + var indexOfSpecifier = filenameTemplate.IndexOf(_usedSpecifier, StringComparison.Ordinal); var prefix = filenameTemplate.Substring(0, indexOfSpecifier); - var suffix = filenameTemplate.Substring(indexOfSpecifier + DateSpecifier.Length); + var suffix = filenameTemplate.Substring(indexOfSpecifier + _usedSpecifier.Length); _filenameMatcher = new Regex( "^" + Regex.Escape(prefix) + - "(?\\d{" + DateFormat.Length + "})" + - "(?_[0-9]{3,}){0,1}" + + "(?<" + MatcherMarkSpecifier + ">\\d{" + _usedFormat.Length + "})" + + "(?<" + MatcherMarkInc + ">_[0-9]{3,}){0,1}" + Regex.Escape(suffix) + "$"); - DirectorySearchPattern = filenameTemplate.Replace(DateSpecifier, "*"); + DirectorySearchPattern = filenameTemplate.Replace(_usedSpecifier, "*"); LogFileDirectory = directory; _pathTemplate = Path.Combine(LogFileDirectory, filenameTemplate); } @@ -81,12 +136,14 @@ public TemplatedPathRoller(string pathTemplate) public void GetLogFilePath(DateTime date, int sequenceNumber, out string path) { - var tok = date.ToString(DateFormat, CultureInfo.InvariantCulture); + DateTime currentCheckpoint = GetCurrentCheckpoint(date); + + var tok = currentCheckpoint.ToString(_usedFormat, CultureInfo.InvariantCulture); if (sequenceNumber != 0) tok += "_" + sequenceNumber.ToString("000", CultureInfo.InvariantCulture); - path = _pathTemplate.Replace(DateSpecifier, tok); + path = _pathTemplate.Replace(_usedSpecifier, tok); } public IEnumerable SelectMatches(IEnumerable filenames) @@ -97,26 +154,68 @@ public IEnumerable SelectMatches(IEnumerable filenames) if (match.Success) { var inc = 0; - var incGroup = match.Groups["inc"]; + var incGroup = match.Groups[MatcherMarkInc]; if (incGroup.Captures.Count != 0) { var incPart = incGroup.Captures[0].Value.Substring(1); inc = int.Parse(incPart, CultureInfo.InvariantCulture); } - DateTime date; - var datePart = match.Groups["date"].Captures[0].Value; + DateTime dateTime; + var dateTimePart = match.Groups[MatcherMarkSpecifier].Captures[0].Value; if (!DateTime.TryParseExact( - datePart, - DateFormat, + dateTimePart, + _usedFormat, CultureInfo.InvariantCulture, DateTimeStyles.None, - out date)) + out dateTime)) continue; - yield return new RollingLogFile(filename, date, inc); + yield return new RollingLogFile(filename, dateTime, inc); } } } + + public DateTime GetCurrentCheckpoint(DateTime date) + { + if (_specifierType == SpecifierTypeEnum.Hour) + { + return date.Date.AddHours(date.Hour); + } + else if (_specifierType == SpecifierTypeEnum.HalfHour) + { + DateTime auxDT = date.Date.AddHours(date.Hour); + if (date.Minute >= 30) + auxDT = auxDT.AddMinutes(30); + return auxDT; + } + + return date.Date; + } + + public DateTime GetNextCheckpoint(DateTime date) + { + DateTime currentCheckpoint = GetCurrentCheckpoint(date); + + if (_specifierType == SpecifierTypeEnum.Hour) + { + return currentCheckpoint.AddHours(1); + } + else if (_specifierType == SpecifierTypeEnum.HalfHour) + { + return currentCheckpoint.AddMinutes(30); + } + + return currentCheckpoint.AddDays(1); + } } -} \ No newline at end of file + + enum SpecifierTypeEnum + { + None, + Date, + Hour, + HalfHour + } + +} \ No newline at end of file From c7062a0a510bf7d38ff5e54ab31e13e07b7a7600 Mon Sep 17 00:00:00 2001 From: jmartin Date: Thu, 29 Sep 2016 17:34:25 +0200 Subject: [PATCH 2/7] Update of test sources. --- .../Serilog.Sinks.RollingFile.Tests/TemplatedPathRollerTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/Serilog.Sinks.RollingFile.Tests/TemplatedPathRollerTests.cs b/test/Serilog.Sinks.RollingFile.Tests/TemplatedPathRollerTests.cs index 6bc4083..c8cf6d9 100644 --- a/test/Serilog.Sinks.RollingFile.Tests/TemplatedPathRollerTests.cs +++ b/test/Serilog.Sinks.RollingFile.Tests/TemplatedPathRollerTests.cs @@ -121,7 +121,7 @@ public void MatchingParsesDates() var roller = new TemplatedPathRoller("log-{Date}.txt"); const string newer = "log-20150101.txt"; const string older = "log-20141231.txt"; - var matched = roller.SelectMatches(new[] { older, newer }).OrderByDescending(m => m.Date).Select(m => m.Filename).ToArray(); + var matched = roller.SelectMatches(new[] { older, newer }).OrderByDescending(m => m.DateTime).Select(m => m.Filename).ToArray(); Assert.Equal(new[] { newer, older }, matched); } } From 5564c62fc841aa852dbc179055cd9ba2ba5f6516 Mon Sep 17 00:00:00 2001 From: jmartin Date: Wed, 5 Oct 2016 12:55:49 +0200 Subject: [PATCH 3/7] Changes. --- .../Sinks/RollingFile/RollingFileSink.cs | 4 +- .../Sinks/RollingFile/Specifier.cs | 118 ++++++++++++++++ .../Sinks/RollingFile/TemplatedPathRoller.cs | 131 +++++------------- 3 files changed, 158 insertions(+), 95 deletions(-) create mode 100644 src/Serilog.Sinks.RollingFile/Sinks/RollingFile/Specifier.cs diff --git a/src/Serilog.Sinks.RollingFile/Sinks/RollingFile/RollingFileSink.cs b/src/Serilog.Sinks.RollingFile/Sinks/RollingFile/RollingFileSink.cs index 35d1bc4..6e3ba15 100644 --- a/src/Serilog.Sinks.RollingFile/Sinks/RollingFile/RollingFileSink.cs +++ b/src/Serilog.Sinks.RollingFile/Sinks/RollingFile/RollingFileSink.cs @@ -141,13 +141,13 @@ void OpenFile(DateTime now) } catch (DirectoryNotFoundException) { } - var latestForThisDateTime = _roller + var latestForThisCheckpoint = _roller .SelectMatches(existingFiles) .Where(m => m.DateTime == currentCheckpoint) .OrderByDescending(m => m.SequenceNumber) .FirstOrDefault(); - var sequence = latestForThisDateTime != null ? latestForThisDateTime.SequenceNumber : 0; + var sequence = latestForThisCheckpoint != null ? latestForThisCheckpoint.SequenceNumber : 0; const int maxAttempts = 3; for (var attempt = 0; attempt < maxAttempts; attempt++) diff --git a/src/Serilog.Sinks.RollingFile/Sinks/RollingFile/Specifier.cs b/src/Serilog.Sinks.RollingFile/Sinks/RollingFile/Specifier.cs new file mode 100644 index 0000000..ee28613 --- /dev/null +++ b/src/Serilog.Sinks.RollingFile/Sinks/RollingFile/Specifier.cs @@ -0,0 +1,118 @@ +using System; + +namespace Serilog.Sinks.RollingFile.Sinks.RollingFile +{ + internal class Specifier + { + internal const string OldStyleDateToken = "{0}"; + + internal const string DateToken = "{Date}"; + internal const string HourToken = "{Hour}"; + internal const string HalfHourToken = "{HalfHour}"; + + internal const string DateFormat = "yyyyMMdd"; + internal const string HourFormat = "yyyyMMddHH"; + internal const string HalfHourFormat = "yyyyMMddHHmm"; + + internal static readonly TimeSpan DateInterval = TimeSpan.FromDays(1); + internal static readonly TimeSpan HourInterval = TimeSpan.FromHours(1); + internal static readonly TimeSpan HalfHourInterval = TimeSpan.FromMinutes(30); + + //------------------- + + public static readonly Specifier Date = new Specifier(SpecifierType.Date); + public static readonly Specifier Hour = new Specifier(SpecifierType.Hour); + public static readonly Specifier HalfHour = new Specifier(SpecifierType.HalfHour); + + //------------------- + + + public SpecifierType Type { get; } + public string Name { get; } + public string Token { get; } + public string Format { get; } + public TimeSpan Interval { get; } + + Specifier(SpecifierType type) + { + switch (type) + { + case SpecifierType.Date: + Token = Specifier.DateToken; + Format = Specifier.DateFormat; + Interval = Specifier.DateInterval; + break; + + case SpecifierType.Hour: + Token = Specifier.HourToken; + Format = Specifier.HourFormat; + Interval = Specifier.HourInterval; + break; + + case SpecifierType.HalfHour: + Token = Specifier.HalfHourToken; + Format = Specifier.HalfHourFormat; + Interval = Specifier.HalfHourInterval; + break; + } + + Type = type; + Name = (Token != null ? Token.Replace("{", string.Empty).Replace("}", string.Empty) : Token); + } + + public DateTime GetCurrentCheckpoint(DateTime instant) + { + if (Type == SpecifierType.Hour) + { + return instant.Date.AddHours(instant.Hour); + } + else if (Type == SpecifierType.HalfHour) + { + DateTime auxDT = instant.Date.AddHours(instant.Hour); + if (instant.Minute >= 30) + auxDT = auxDT.AddMinutes(30); + return auxDT; + } + + return instant.Date; + } + + public DateTime GetNextCheckpoint(DateTime instant) + { + DateTime currentCheckpoint = GetCurrentCheckpoint(instant); + return currentCheckpoint.Add(Interval); + } + + //------------- + + internal static Specifier GetFromTemplate(string template) + { + if (!string.IsNullOrWhiteSpace(template)) + { + if (template.Contains(Specifier.DateToken)) + { + return Specifier.Date; + } + else if (template.Contains(Specifier.HourToken)) + { + return Specifier.Hour; + } + else if (template.Contains(Specifier.HalfHourToken)) + { + return Specifier.HalfHour; + } + } + + return null; + } + + //------------- + + internal enum SpecifierType + { + Date, + Hour, + HalfHour + } + } +} diff --git a/src/Serilog.Sinks.RollingFile/Sinks/RollingFile/TemplatedPathRoller.cs b/src/Serilog.Sinks.RollingFile/Sinks/RollingFile/TemplatedPathRoller.cs index 00fb69b..f96cb01 100644 --- a/src/Serilog.Sinks.RollingFile/Sinks/RollingFile/TemplatedPathRoller.cs +++ b/src/Serilog.Sinks.RollingFile/Sinks/RollingFile/TemplatedPathRoller.cs @@ -11,7 +11,8 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. - + +using Serilog.Sinks.RollingFile.Sinks.RollingFile; using System; using System.Collections.Generic; using System.Globalization; @@ -26,43 +27,34 @@ namespace Serilog.Sinks.RollingFile // class TemplatedPathRoller { - const string OldStyleDateSpecifier = "{0}"; - const string DateSpecifier = "{Date}"; - const string DateFormat = "yyyyMMdd"; - const string HourSpecifier = "{Hour}"; - const string HourFormat = "yyyyMMddHH"; - const string HalfHourSpecifier = "{HalfHour}"; - const string HalfHourFormat = "yyyyMMddHHmm"; + const string DefaultSeparator = "-"; - const string MatcherMarkSpecifier = "date"; - const string MatcherMarkInc = "inc"; + const string SpecifierMatchGroup = "specifier"; + const string SequenceNumberMatchGroup = "sequence"; readonly string _pathTemplate; readonly Regex _filenameMatcher; - readonly SpecifierTypeEnum _specifierType = SpecifierTypeEnum.None; - // Concret used Date or Hour specifier. - readonly string _usedSpecifier = string.Empty; - readonly string _usedFormat = string.Empty; + readonly Specifier _specifier = null; public TemplatedPathRoller(string pathTemplate) { if (pathTemplate == null) throw new ArgumentNullException(nameof(pathTemplate)); - if (pathTemplate.Contains(OldStyleDateSpecifier)) - throw new ArgumentException("The old-style date specifier " + OldStyleDateSpecifier + - " is no longer supported, instead please use " + DateSpecifier); + if (pathTemplate.Contains(Specifier.OldStyleDateToken)) + throw new ArgumentException("The old-style date specifier " + Specifier.OldStyleDateToken + + " is no longer supported, instead please use " + Specifier.DateToken); int numSpecifiers = 0; - if (pathTemplate.Contains(DateSpecifier)) + if (pathTemplate.Contains(Specifier.DateToken)) numSpecifiers++; - if (pathTemplate.Contains(HourSpecifier)) + if (pathTemplate.Contains(Specifier.HourToken)) numSpecifiers++; - if (pathTemplate.Contains(HalfHourSpecifier)) + if (pathTemplate.Contains(Specifier.HalfHourToken)) numSpecifiers++; if (numSpecifiers > 1) - throw new ArgumentException("The date, hour and half-hour specifiers (" + - DateSpecifier + "," + HourSpecifier + "," + HalfHourSpecifier + + throw new ArgumentException("The date, hour and half-hour specifiers (" + + Specifier.DateToken + "," + Specifier.HourToken + "," + Specifier.HalfHourToken + ") cannot be used at the same time"); var directory = Path.GetDirectoryName(pathTemplate); @@ -73,59 +65,42 @@ public TemplatedPathRoller(string pathTemplate) directory = Path.GetFullPath(directory); - if (directory.Contains(DateSpecifier)) + if (directory.Contains(Specifier.DateToken)) throw new ArgumentException("The date cannot form part of the directory name"); - if (directory.Contains(HourSpecifier)) + if (directory.Contains(Specifier.HourToken)) throw new ArgumentException("The hour specifiers cannot form part of the directory name"); - if (directory.Contains(HalfHourSpecifier)) + if (directory.Contains(Specifier.HalfHourToken)) throw new ArgumentException("The half-hour specifiers cannot form part of the directory name"); var filenameTemplate = Path.GetFileName(pathTemplate); - if (!filenameTemplate.Contains(DateSpecifier) && - !filenameTemplate.Contains(HourSpecifier) && - !filenameTemplate.Contains(HalfHourSpecifier)) + if (!filenameTemplate.Contains(Specifier.DateToken) && + !filenameTemplate.Contains(Specifier.HourToken) && + !filenameTemplate.Contains(Specifier.HalfHourToken)) { // If the file name doesn't use any of the admitted specifiers then it is added the date specifier // as de default one. filenameTemplate = Path.GetFileNameWithoutExtension(filenameTemplate) + DefaultSeparator + - DateSpecifier + Path.GetExtension(filenameTemplate); + Specifier.DateToken + Path.GetExtension(filenameTemplate); } //--- - // From this point forward we don't reference the Date or Hour concret specifiers and formats : - // we will reference only the one set as "used" (_usedSpecifier and _usedFormat). + // From this point forward we don't reference the Date, Hour or HalfHour concret tokens and formats : + // we will reference only the one configured as _specifier. - if (filenameTemplate.Contains(DateSpecifier)) - { - _usedSpecifier = DateSpecifier; - _usedFormat = DateFormat; - _specifierType = SpecifierTypeEnum.Date; - } - else if (filenameTemplate.Contains(HourSpecifier)) - { - _usedSpecifier = HourSpecifier; - _usedFormat = HourFormat; - _specifierType = SpecifierTypeEnum.Hour; - } - else if (filenameTemplate.Contains(HalfHourSpecifier)) - { - _usedSpecifier = HalfHourSpecifier; - _usedFormat = HalfHourFormat; - _specifierType = SpecifierTypeEnum.HalfHour; - } + _specifier = Specifier.GetFromTemplate(filenameTemplate); - var indexOfSpecifier = filenameTemplate.IndexOf(_usedSpecifier, StringComparison.Ordinal); + var indexOfSpecifier = filenameTemplate.IndexOf(_specifier.Token, StringComparison.Ordinal); var prefix = filenameTemplate.Substring(0, indexOfSpecifier); - var suffix = filenameTemplate.Substring(indexOfSpecifier + _usedSpecifier.Length); + var suffix = filenameTemplate.Substring(indexOfSpecifier + _specifier.Token.Length); _filenameMatcher = new Regex( "^" + Regex.Escape(prefix) + - "(?<" + MatcherMarkSpecifier + ">\\d{" + _usedFormat.Length + "})" + - "(?<" + MatcherMarkInc + ">_[0-9]{3,}){0,1}" + + "(?<" + SpecifierMatchGroup + ">\\d{" + _specifier.Format.Length + "})" + + "(?<" + SequenceNumberMatchGroup + ">_[0-9]{3,}){0,1}" + Regex.Escape(suffix) + "$"); - DirectorySearchPattern = filenameTemplate.Replace(_usedSpecifier, "*"); + DirectorySearchPattern = filenameTemplate.Replace(_specifier.Token, "*"); LogFileDirectory = directory; _pathTemplate = Path.Combine(LogFileDirectory, filenameTemplate); } @@ -138,12 +113,12 @@ public void GetLogFilePath(DateTime date, int sequenceNumber, out string path) { DateTime currentCheckpoint = GetCurrentCheckpoint(date); - var tok = currentCheckpoint.ToString(_usedFormat, CultureInfo.InvariantCulture); + var tok = currentCheckpoint.ToString(_specifier.Format, CultureInfo.InvariantCulture); if (sequenceNumber != 0) tok += "_" + sequenceNumber.ToString("000", CultureInfo.InvariantCulture); - path = _pathTemplate.Replace(_usedSpecifier, tok); + path = _pathTemplate.Replace(_specifier.Token, tok); } public IEnumerable SelectMatches(IEnumerable filenames) @@ -154,7 +129,7 @@ public IEnumerable SelectMatches(IEnumerable filenames) if (match.Success) { var inc = 0; - var incGroup = match.Groups[MatcherMarkInc]; + var incGroup = match.Groups[SequenceNumberMatchGroup]; if (incGroup.Captures.Count != 0) { var incPart = incGroup.Captures[0].Value.Substring(1); @@ -162,10 +137,10 @@ public IEnumerable SelectMatches(IEnumerable filenames) } DateTime dateTime; - var dateTimePart = match.Groups[MatcherMarkSpecifier].Captures[0].Value; + var dateTimePart = match.Groups[SpecifierMatchGroup].Captures[0].Value; if (!DateTime.TryParseExact( dateTimePart, - _usedFormat, + _specifier.Format, CultureInfo.InvariantCulture, DateTimeStyles.None, out dateTime)) @@ -176,46 +151,16 @@ public IEnumerable SelectMatches(IEnumerable filenames) } } - public DateTime GetCurrentCheckpoint(DateTime date) + public DateTime GetCurrentCheckpoint(DateTime instant) { - if (_specifierType == SpecifierTypeEnum.Hour) - { - return date.Date.AddHours(date.Hour); - } - else if (_specifierType == SpecifierTypeEnum.HalfHour) - { - DateTime auxDT = date.Date.AddHours(date.Hour); - if (date.Minute >= 30) - auxDT = auxDT.AddMinutes(30); - return auxDT; - } - - return date.Date; + return _specifier.GetCurrentCheckpoint(instant); } - public DateTime GetNextCheckpoint(DateTime date) + public DateTime GetNextCheckpoint(DateTime instant) { - DateTime currentCheckpoint = GetCurrentCheckpoint(date); - - if (_specifierType == SpecifierTypeEnum.Hour) - { - return currentCheckpoint.AddHours(1); - } - else if (_specifierType == SpecifierTypeEnum.HalfHour) - { - return currentCheckpoint.AddMinutes(30); - } - - return currentCheckpoint.AddDays(1); + return _specifier.GetNextCheckpoint(instant); } } - enum SpecifierTypeEnum - { - None, - Date, - Hour, - HalfHour - } } \ No newline at end of file From bbcfb67c0a98f7e7b518780c7c5d4bd283976c12 Mon Sep 17 00:00:00 2001 From: jmartin Date: Thu, 6 Oct 2016 11:33:39 +0200 Subject: [PATCH 4/7] Second revision. --- .../Sinks/RollingFile/RollingFileSink.cs | 1 - .../Sinks/RollingFile/Specifier.cs | 101 ++++++------------ .../Sinks/RollingFile/TemplatedPathRoller.cs | 38 +++---- 3 files changed, 48 insertions(+), 92 deletions(-) diff --git a/src/Serilog.Sinks.RollingFile/Sinks/RollingFile/RollingFileSink.cs b/src/Serilog.Sinks.RollingFile/Sinks/RollingFile/RollingFileSink.cs index 6e3ba15..4fca1db 100644 --- a/src/Serilog.Sinks.RollingFile/Sinks/RollingFile/RollingFileSink.cs +++ b/src/Serilog.Sinks.RollingFile/Sinks/RollingFile/RollingFileSink.cs @@ -130,7 +130,6 @@ void OpenFile(DateTime now) // We only take one attempt at it because repeated failures // to open log files REALLY slow an app down. - _nextCheckpoint = _roller.GetNextCheckpoint(now); var existingFiles = Enumerable.Empty(); diff --git a/src/Serilog.Sinks.RollingFile/Sinks/RollingFile/Specifier.cs b/src/Serilog.Sinks.RollingFile/Sinks/RollingFile/Specifier.cs index ee28613..d6faf7e 100644 --- a/src/Serilog.Sinks.RollingFile/Sinks/RollingFile/Specifier.cs +++ b/src/Serilog.Sinks.RollingFile/Sinks/RollingFile/Specifier.cs @@ -2,71 +2,44 @@ namespace Serilog.Sinks.RollingFile.Sinks.RollingFile { - internal class Specifier + class Specifier { - internal const string OldStyleDateToken = "{0}"; + public const string OldStyleDateToken = "{0}"; + + const string DateToken = "{Date}"; + const string HourToken = "{Hour}"; + const string HalfHourToken = "{HalfHour}"; + const string DateFormat = "yyyyMMdd"; + const string HourFormat = "yyyyMMddHH"; + const string HalfHourFormat = "yyyyMMddHHmm"; + static readonly TimeSpan DateInterval = TimeSpan.FromDays(1); + static readonly TimeSpan HourInterval = TimeSpan.FromHours(1); + static readonly TimeSpan HalfHourInterval = TimeSpan.FromMinutes(30); + + public static readonly Specifier Date = new Specifier("Date", DateToken, DateFormat, DateInterval); + public static readonly Specifier Hour = new Specifier("Hour", HourToken, HourFormat, HourInterval); + public static readonly Specifier HalfHour = new Specifier("HalfHour", HalfHourToken, HalfHourFormat, HalfHourInterval); - internal const string DateToken = "{Date}"; - internal const string HourToken = "{Hour}"; - internal const string HalfHourToken = "{HalfHour}"; - - internal const string DateFormat = "yyyyMMdd"; - internal const string HourFormat = "yyyyMMddHH"; - internal const string HalfHourFormat = "yyyyMMddHHmm"; - - internal static readonly TimeSpan DateInterval = TimeSpan.FromDays(1); - internal static readonly TimeSpan HourInterval = TimeSpan.FromHours(1); - internal static readonly TimeSpan HalfHourInterval = TimeSpan.FromMinutes(30); - - //------------------- - - public static readonly Specifier Date = new Specifier(SpecifierType.Date); - public static readonly Specifier Hour = new Specifier(SpecifierType.Hour); - public static readonly Specifier HalfHour = new Specifier(SpecifierType.HalfHour); - - //------------------- - - - public SpecifierType Type { get; } public string Name { get; } public string Token { get; } public string Format { get; } public TimeSpan Interval { get; } - Specifier(SpecifierType type) + Specifier(string name, string token, string format, TimeSpan interval) { - switch (type) - { - case SpecifierType.Date: - Token = Specifier.DateToken; - Format = Specifier.DateFormat; - Interval = Specifier.DateInterval; - break; - - case SpecifierType.Hour: - Token = Specifier.HourToken; - Format = Specifier.HourFormat; - Interval = Specifier.HourInterval; - break; - - case SpecifierType.HalfHour: - Token = Specifier.HalfHourToken; - Format = Specifier.HalfHourFormat; - Interval = Specifier.HalfHourInterval; - break; - } - - Type = type; - Name = (Token != null ? Token.Replace("{", string.Empty).Replace("}", string.Empty) : Token); + Name = name; + Token = token; + Format = format; + Interval = interval; } public DateTime GetCurrentCheckpoint(DateTime instant) { - if (Type == SpecifierType.Hour) + if (Token == Hour.Token) { return instant.Date.AddHours(instant.Hour); } - else if (Type == SpecifierType.HalfHour) + else if (Token == HalfHour.Token) { DateTime auxDT = instant.Date.AddHours(instant.Hour); if (instant.Minute >= 30) @@ -83,36 +56,28 @@ public DateTime GetNextCheckpoint(DateTime instant) return currentCheckpoint.Add(Interval); } - //------------- - - internal static Specifier GetFromTemplate(string template) + public static bool TryGetSpecifier(string template, out Specifier specifier) { + specifier = null; + if (!string.IsNullOrWhiteSpace(template)) { - if (template.Contains(Specifier.DateToken)) + if (template.Contains(Specifier.Date.Token)) { - return Specifier.Date; + specifier = Specifier.Date; } - else if (template.Contains(Specifier.HourToken)) + else if (template.Contains(Specifier.Hour.Token)) { - return Specifier.Hour; + specifier = Specifier.Hour; } - else if (template.Contains(Specifier.HalfHourToken)) + else if (template.Contains(Specifier.HalfHour.Token)) { - return Specifier.HalfHour; + specifier = Specifier.HalfHour; } } - return null; + return (specifier != null); } - //------------- - - internal enum SpecifierType - { - Date, - Hour, - HalfHour - } } } diff --git a/src/Serilog.Sinks.RollingFile/Sinks/RollingFile/TemplatedPathRoller.cs b/src/Serilog.Sinks.RollingFile/Sinks/RollingFile/TemplatedPathRoller.cs index f96cb01..71bcfa0 100644 --- a/src/Serilog.Sinks.RollingFile/Sinks/RollingFile/TemplatedPathRoller.cs +++ b/src/Serilog.Sinks.RollingFile/Sinks/RollingFile/TemplatedPathRoller.cs @@ -43,18 +43,18 @@ public TemplatedPathRoller(string pathTemplate) if (pathTemplate.Contains(Specifier.OldStyleDateToken)) throw new ArgumentException("The old-style date specifier " + Specifier.OldStyleDateToken + - " is no longer supported, instead please use " + Specifier.DateToken); + " is no longer supported, instead please use " + Specifier.Date.Token); int numSpecifiers = 0; - if (pathTemplate.Contains(Specifier.DateToken)) + if (pathTemplate.Contains(Specifier.Date.Token)) numSpecifiers++; - if (pathTemplate.Contains(Specifier.HourToken)) + if (pathTemplate.Contains(Specifier.Hour.Token)) numSpecifiers++; - if (pathTemplate.Contains(Specifier.HalfHourToken)) + if (pathTemplate.Contains(Specifier.HalfHour.Token)) numSpecifiers++; if (numSpecifiers > 1) throw new ArgumentException("The date, hour and half-hour specifiers (" + - Specifier.DateToken + "," + Specifier.HourToken + "," + Specifier.HalfHourToken + + Specifier.Date.Token + "," + Specifier.Hour.Token + "," + Specifier.HalfHour.Token + ") cannot be used at the same time"); var directory = Path.GetDirectoryName(pathTemplate); @@ -65,30 +65,22 @@ public TemplatedPathRoller(string pathTemplate) directory = Path.GetFullPath(directory); - if (directory.Contains(Specifier.DateToken)) - throw new ArgumentException("The date cannot form part of the directory name"); - if (directory.Contains(Specifier.HourToken)) - throw new ArgumentException("The hour specifiers cannot form part of the directory name"); - if (directory.Contains(Specifier.HalfHourToken)) - throw new ArgumentException("The half-hour specifiers cannot form part of the directory name"); + Specifier directorySpecifier; + if (Specifier.TryGetSpecifier(directory, out directorySpecifier)) + { + throw new ArgumentException($"The {directorySpecifier.Token} specifier cannot form part of the directory name."); + } var filenameTemplate = Path.GetFileName(pathTemplate); - if (!filenameTemplate.Contains(Specifier.DateToken) && - !filenameTemplate.Contains(Specifier.HourToken) && - !filenameTemplate.Contains(Specifier.HalfHourToken)) + if (!Specifier.TryGetSpecifier(filenameTemplate, out _specifier)) { - // If the file name doesn't use any of the admitted specifiers then it is added the date specifier + // If the file name doesn't use any of the admitted specifiers then it is set the date specifier // as de default one. + _specifier = Specifier.Date; filenameTemplate = Path.GetFileNameWithoutExtension(filenameTemplate) + DefaultSeparator + - Specifier.DateToken + Path.GetExtension(filenameTemplate); + _specifier.Token + Path.GetExtension(filenameTemplate); } - //--- - // From this point forward we don't reference the Date, Hour or HalfHour concret tokens and formats : - // we will reference only the one configured as _specifier. - - _specifier = Specifier.GetFromTemplate(filenameTemplate); - var indexOfSpecifier = filenameTemplate.IndexOf(_specifier.Token, StringComparison.Ordinal); var prefix = filenameTemplate.Substring(0, indexOfSpecifier); var suffix = filenameTemplate.Substring(indexOfSpecifier + _specifier.Token.Length); @@ -111,7 +103,7 @@ public TemplatedPathRoller(string pathTemplate) public void GetLogFilePath(DateTime date, int sequenceNumber, out string path) { - DateTime currentCheckpoint = GetCurrentCheckpoint(date); + var currentCheckpoint = GetCurrentCheckpoint(date); var tok = currentCheckpoint.ToString(_specifier.Format, CultureInfo.InvariantCulture); From 00c5395f883d5a00f147954c302e16985750c540 Mon Sep 17 00:00:00 2001 From: Nicholas Blumhardt Date: Mon, 10 Oct 2016 09:26:44 +1000 Subject: [PATCH 5/7] Dev version bump [Skip CI] --- src/Serilog.Sinks.RollingFile/project.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Serilog.Sinks.RollingFile/project.json b/src/Serilog.Sinks.RollingFile/project.json index a22a13b..8f94a93 100644 --- a/src/Serilog.Sinks.RollingFile/project.json +++ b/src/Serilog.Sinks.RollingFile/project.json @@ -1,5 +1,5 @@ -{ - "version": "3.1.0-*", +{ + "version": "3.1.1-*", "description": "The rolling file sink for Serilog - Simple .NET logging with fully-structured events", "authors": [ "Serilog Contributors" ], "packOptions": { From 01e04d6c9faf1572d3b2cdb26dd1aa21280295c7 Mon Sep 17 00:00:00 2001 From: Nicholas Blumhardt Date: Mon, 10 Oct 2016 10:41:07 +1000 Subject: [PATCH 6/7] Added more tests covering hour/half-hour rolling; removed 'old style' specifier check; general tidy --- .../Serilog.Sinks.RollingFile.xproj | 5 +- .../Sinks/RollingFile/IOErrors.cs | 31 +++++++ .../Sinks/RollingFile/RollingFileSink.cs | 7 +- .../Sinks/RollingFile/Specifier.cs | 90 +++++++++---------- .../Sinks/RollingFile/TemplatedPathRoller.cs | 44 ++------- src/Serilog.Sinks.RollingFile/project.json | 2 +- .../TemplatedPathRollerTests.cs | 60 ++++++------- 7 files changed, 111 insertions(+), 128 deletions(-) create mode 100644 src/Serilog.Sinks.RollingFile/Sinks/RollingFile/IOErrors.cs diff --git a/src/Serilog.Sinks.RollingFile/Serilog.Sinks.RollingFile.xproj b/src/Serilog.Sinks.RollingFile/Serilog.Sinks.RollingFile.xproj index cad3e0a..0d43938 100644 --- a/src/Serilog.Sinks.RollingFile/Serilog.Sinks.RollingFile.xproj +++ b/src/Serilog.Sinks.RollingFile/Serilog.Sinks.RollingFile.xproj @@ -4,11 +4,10 @@ 14.0 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - a3e6e5b4-995f-4c3d-9673-a4b6000f4e21 - Serilog.Sinks.RollingFile + Serilog .\obj .\bin\ @@ -16,4 +15,4 @@ 2.0 - + \ No newline at end of file diff --git a/src/Serilog.Sinks.RollingFile/Sinks/RollingFile/IOErrors.cs b/src/Serilog.Sinks.RollingFile/Sinks/RollingFile/IOErrors.cs new file mode 100644 index 0000000..b778dec --- /dev/null +++ b/src/Serilog.Sinks.RollingFile/Sinks/RollingFile/IOErrors.cs @@ -0,0 +1,31 @@ +// Copyright 2013-2016 Serilog Contributors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +using System.IO; + +namespace Serilog.Sinks.RollingFile +{ + static class IOErrors + { + public static bool IsLockedFile(IOException ex) + { +#if HRESULTS + var errorCode = System.Runtime.InteropServices.Marshal.GetHRForException(ex) & ((1 << 16) - 1); + return errorCode == 32 || errorCode == 33; +#else + return true; +#endif + } + } +} diff --git a/src/Serilog.Sinks.RollingFile/Sinks/RollingFile/RollingFileSink.cs b/src/Serilog.Sinks.RollingFile/Sinks/RollingFile/RollingFileSink.cs index a4748b1..7a735f1 100644 --- a/src/Serilog.Sinks.RollingFile/Sinks/RollingFile/RollingFileSink.cs +++ b/src/Serilog.Sinks.RollingFile/Sinks/RollingFile/RollingFileSink.cs @@ -12,11 +12,9 @@ // See the License for the specific language governing permissions and // limitations under the License. - using System; using System.IO; using System.Linq; -using System.Runtime.InteropServices; using System.Text; using Serilog.Core; using Serilog.Debugging; @@ -100,7 +98,7 @@ public void Emit(LogEvent logEvent) lock (_syncRoot) { - if (_isDisposed) throw new ObjectDisposedException("The rolling file has been disposed."); + if (_isDisposed) throw new ObjectDisposedException("The rolling log file has been disposed."); AlignCurrentFileTo(Clock.DateTimeNow); @@ -166,8 +164,7 @@ void OpenFile(DateTime now) } catch (IOException ex) { - var errorCode = Marshal.GetHRForException(ex) & ((1 << 16) - 1); - if (errorCode == 32 || errorCode == 33) + if (IOErrors.IsLockedFile(ex)) { SelfLog.WriteLine("Rolling file target {0} was locked, attempting to open next in sequence (attempt {1})", path, attempt + 1); sequence++; diff --git a/src/Serilog.Sinks.RollingFile/Sinks/RollingFile/Specifier.cs b/src/Serilog.Sinks.RollingFile/Sinks/RollingFile/Specifier.cs index d6faf7e..3bbca9f 100644 --- a/src/Serilog.Sinks.RollingFile/Sinks/RollingFile/Specifier.cs +++ b/src/Serilog.Sinks.RollingFile/Sinks/RollingFile/Specifier.cs @@ -1,83 +1,73 @@ -using System; +// Copyright 2013-2016 Serilog Contributors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. -namespace Serilog.Sinks.RollingFile.Sinks.RollingFile +using System; +using System.Linq; + +namespace Serilog.Sinks.RollingFile { class Specifier { - public const string OldStyleDateToken = "{0}"; - - const string DateToken = "{Date}"; - const string HourToken = "{Hour}"; - const string HalfHourToken = "{HalfHour}"; - const string DateFormat = "yyyyMMdd"; - const string HourFormat = "yyyyMMddHH"; - const string HalfHourFormat = "yyyyMMddHHmm"; - static readonly TimeSpan DateInterval = TimeSpan.FromDays(1); - static readonly TimeSpan HourInterval = TimeSpan.FromHours(1); - static readonly TimeSpan HalfHourInterval = TimeSpan.FromMinutes(30); - - public static readonly Specifier Date = new Specifier("Date", DateToken, DateFormat, DateInterval); - public static readonly Specifier Hour = new Specifier("Hour", HourToken, HourFormat, HourInterval); - public static readonly Specifier HalfHour = new Specifier("HalfHour", HalfHourToken, HalfHourFormat, HalfHourInterval); + public static readonly Specifier Date = new Specifier("Date", "yyyyMMdd", TimeSpan.FromDays(1)); + public static readonly Specifier Hour = new Specifier("Hour", "yyyyMMddHH", TimeSpan.FromHours(1)); + public static readonly Specifier HalfHour = new Specifier("HalfHour", "yyyyMMddHHmm", TimeSpan.FromMinutes(30)); - public string Name { get; } public string Token { get; } public string Format { get; } public TimeSpan Interval { get; } - Specifier(string name, string token, string format, TimeSpan interval) + Specifier(string name, string format, TimeSpan interval) { - Name = name; - Token = token; + if (name == null) throw new ArgumentNullException(nameof(name)); + if (format == null) throw new ArgumentNullException(nameof(format)); + + Token = "{" + name + "}"; Format = format; Interval = interval; } public DateTime GetCurrentCheckpoint(DateTime instant) { - if (Token == Hour.Token) + if (this == Hour) { return instant.Date.AddHours(instant.Hour); } - else if (Token == HalfHour.Token) + + if (this == HalfHour) { - DateTime auxDT = instant.Date.AddHours(instant.Hour); + var hour = instant.Date.AddHours(instant.Hour); if (instant.Minute >= 30) - auxDT = auxDT.AddMinutes(30); - return auxDT; + return hour.AddMinutes(30); + return hour; } return instant.Date; } - public DateTime GetNextCheckpoint(DateTime instant) - { - DateTime currentCheckpoint = GetCurrentCheckpoint(instant); - return currentCheckpoint.Add(Interval); - } + public DateTime GetNextCheckpoint(DateTime instant) => GetCurrentCheckpoint(instant).Add(Interval); - public static bool TryGetSpecifier(string template, out Specifier specifier) + public static bool TryGetSpecifier(string pathTemplate, out Specifier specifier) { - specifier = null; + if (pathTemplate == null) throw new ArgumentNullException(nameof(pathTemplate)); - if (!string.IsNullOrWhiteSpace(template)) - { - if (template.Contains(Specifier.Date.Token)) - { - specifier = Specifier.Date; - } - else if (template.Contains(Specifier.Hour.Token)) - { - specifier = Specifier.Hour; - } - else if (template.Contains(Specifier.HalfHour.Token)) - { - specifier = Specifier.HalfHour; - } - } + var specifiers = new[] { HalfHour, Hour, Date }.Where(s => pathTemplate.Contains(s.Token)).ToArray(); + + if (specifiers.Length > 1) + throw new ArgumentException("Only one interval specifier can be used in a rolling log file path.", nameof(pathTemplate)); - return (specifier != null); + specifier = specifiers.FirstOrDefault(); + return specifier != null; } - } } diff --git a/src/Serilog.Sinks.RollingFile/Sinks/RollingFile/TemplatedPathRoller.cs b/src/Serilog.Sinks.RollingFile/Sinks/RollingFile/TemplatedPathRoller.cs index 71bcfa0..0b450af 100644 --- a/src/Serilog.Sinks.RollingFile/Sinks/RollingFile/TemplatedPathRoller.cs +++ b/src/Serilog.Sinks.RollingFile/Sinks/RollingFile/TemplatedPathRoller.cs @@ -12,7 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -using Serilog.Sinks.RollingFile.Sinks.RollingFile; using System; using System.Collections.Generic; using System.Globalization; @@ -26,8 +25,7 @@ namespace Serilog.Sinks.RollingFile // Logs/log-{Date}.txt // class TemplatedPathRoller - { - + { const string DefaultSeparator = "-"; const string SpecifierMatchGroup = "specifier"; @@ -41,41 +39,19 @@ public TemplatedPathRoller(string pathTemplate) { if (pathTemplate == null) throw new ArgumentNullException(nameof(pathTemplate)); - if (pathTemplate.Contains(Specifier.OldStyleDateToken)) - throw new ArgumentException("The old-style date specifier " + Specifier.OldStyleDateToken + - " is no longer supported, instead please use " + Specifier.Date.Token); - - int numSpecifiers = 0; - if (pathTemplate.Contains(Specifier.Date.Token)) - numSpecifiers++; - if (pathTemplate.Contains(Specifier.Hour.Token)) - numSpecifiers++; - if (pathTemplate.Contains(Specifier.HalfHour.Token)) - numSpecifiers++; - if (numSpecifiers > 1) - throw new ArgumentException("The date, hour and half-hour specifiers (" + - Specifier.Date.Token + "," + Specifier.Hour.Token + "," + Specifier.HalfHour.Token + - ") cannot be used at the same time"); - var directory = Path.GetDirectoryName(pathTemplate); if (string.IsNullOrEmpty(directory)) - { directory = Directory.GetCurrentDirectory(); - } - - directory = Path.GetFullPath(directory); Specifier directorySpecifier; if (Specifier.TryGetSpecifier(directory, out directorySpecifier)) - { throw new ArgumentException($"The {directorySpecifier.Token} specifier cannot form part of the directory name."); - } + + directory = Path.GetFullPath(directory); var filenameTemplate = Path.GetFileName(pathTemplate); if (!Specifier.TryGetSpecifier(filenameTemplate, out _specifier)) { - // If the file name doesn't use any of the admitted specifiers then it is set the date specifier - // as de default one. _specifier = Specifier.Date; filenameTemplate = Path.GetFileNameWithoutExtension(filenameTemplate) + DefaultSeparator + _specifier.Token + Path.GetExtension(filenameTemplate); @@ -143,16 +119,8 @@ public IEnumerable SelectMatches(IEnumerable filenames) } } - public DateTime GetCurrentCheckpoint(DateTime instant) - { - return _specifier.GetCurrentCheckpoint(instant); - } + public DateTime GetCurrentCheckpoint(DateTime instant) => _specifier.GetCurrentCheckpoint(instant); - public DateTime GetNextCheckpoint(DateTime instant) - { - return _specifier.GetNextCheckpoint(instant); - } + public DateTime GetNextCheckpoint(DateTime instant) => _specifier.GetNextCheckpoint(instant); } - - -} \ No newline at end of file +} diff --git a/src/Serilog.Sinks.RollingFile/project.json b/src/Serilog.Sinks.RollingFile/project.json index 8f94a93..819f843 100644 --- a/src/Serilog.Sinks.RollingFile/project.json +++ b/src/Serilog.Sinks.RollingFile/project.json @@ -1,5 +1,5 @@ { - "version": "3.1.1-*", + "version": "3.2.0-*", "description": "The rolling file sink for Serilog - Simple .NET logging with fully-structured events", "authors": [ "Serilog Contributors" ], "packOptions": { diff --git a/test/Serilog.Sinks.RollingFile.Tests/TemplatedPathRollerTests.cs b/test/Serilog.Sinks.RollingFile.Tests/TemplatedPathRollerTests.cs index 0f40467..d003736 100644 --- a/test/Serilog.Sinks.RollingFile.Tests/TemplatedPathRollerTests.cs +++ b/test/Serilog.Sinks.RollingFile.Tests/TemplatedPathRollerTests.cs @@ -8,14 +8,7 @@ namespace Serilog.Sinks.RollingFile.Tests public class TemplatedPathRollerTests { [Fact] - public void WhenOldStyleSpecifierIsSuppliedTheExceptionIsInformative() - { - var ex = Assert.Throws(() => new TemplatedPathRoller("log-{0}.txt")); - Assert.True(ex.Message.Contains("{Date}")); - } - - [Fact] - public void NewStyleSpecifierCannotBeProvidedInDirectory() + public void SpecifierCannotBeProvidedInDirectory() { var ex = Assert.Throws(() => new TemplatedPathRoller("{Date}\\log.txt")); Assert.True(ex.Message.Contains("directory")); @@ -86,40 +79,45 @@ public void TheLogFileIsNotRequiredToIncludeADirectory() } [Fact] - public void TheDirectorSearchPatternUsesWildcardInPlaceOfDate() + public void MatchingExcludesSimilarButNonmatchingFiles() + { + var roller = new TemplatedPathRoller("log-{Date}.txt"); + const string similar1 = "log-0.txt"; + const string similar2 = "log-helloyou.txt"; + var matched = roller.SelectMatches(new[] { similar1, similar2 }); + Assert.Equal(0, matched.Count()); + } + + [Theory] + [InlineData("Logs\\log-{Date}.txt")] + [InlineData("Logs\\log-{Hour}.txt")] + [InlineData("Logs\\log-{HalfHour}.txt")] + public void TheDirectorSearchPatternUsesWildcardInPlaceOfDate(string template) { - var roller = new TemplatedPathRoller("Logs\\log-{Date}.txt"); + var roller = new TemplatedPathRoller(template); Assert.Equal("log-*.txt", roller.DirectorySearchPattern); } - [Fact] - public void MatchingSelectsFiles() + [Theory] + [InlineData("log-{Date}.txt", "log-20131210.txt", "log-20131210_031.txt")] + [InlineData("log-{Hour}.txt", "log-2013121013.txt", "log-2013121013_031.txt")] + [InlineData("log-{HalfHour}.txt", "log-201312100100.txt", "log-201312100230_031.txt")] + public void MatchingSelectsFiles(string template, string zeroth, string thirtyFirst) { - var roller = new TemplatedPathRoller("log-{Date}.txt"); - const string example1 = "log-20131210.txt"; - const string example2 = "log-20131210_031.txt"; - var matched = roller.SelectMatches(new[] { example1, example2 }).ToArray(); + var roller = new TemplatedPathRoller(template); + var matched = roller.SelectMatches(new[] { zeroth, thirtyFirst }).ToArray(); Assert.Equal(2, matched.Count()); Assert.Equal(0, matched[0].SequenceNumber); Assert.Equal(31, matched[1].SequenceNumber); } - [Fact] - public void MatchingExcludesSimilarButNonmatchingFiles() + [Theory] + [InlineData("log-{Date}.txt", "log-20150101.txt", "log-20141231.txt")] + [InlineData("log-{Hour}.txt", "log-2015010110.txt", "log-2015010109.txt")] + [InlineData("log-{HalfHour}.txt", "log-201501011400.txt", "log-201501011330.txt")] + public void MatchingParsesSubstitutions(string template, string newer, string older) { - var roller = new TemplatedPathRoller("log-{Date}.txt"); - const string similar1 = "log-0.txt"; - const string similar2 = "log-helloyou.txt"; - var matched = roller.SelectMatches(new[] { similar1, similar2 }); - Assert.Equal(0, matched.Count()); - } - - [Fact] - public void MatchingParsesDates() - { - var roller = new TemplatedPathRoller("log-{Date}.txt"); - const string newer = "log-20150101.txt"; - const string older = "log-20141231.txt"; + var roller = new TemplatedPathRoller(template); var matched = roller.SelectMatches(new[] { older, newer }).OrderByDescending(m => m.DateTime).Select(m => m.Filename).ToArray(); Assert.Equal(new[] { newer, older }, matched); } From 21d252ca3501bd93ca00e6883b08c308ba964f3a Mon Sep 17 00:00:00 2001 From: Nicholas Blumhardt Date: Mon, 10 Oct 2016 10:43:36 +1000 Subject: [PATCH 7/7] Define HRESULTS when targeting .NET 4.5 --- src/Serilog.Sinks.RollingFile/project.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Serilog.Sinks.RollingFile/project.json b/src/Serilog.Sinks.RollingFile/project.json index 819f843..8c28070 100644 --- a/src/Serilog.Sinks.RollingFile/project.json +++ b/src/Serilog.Sinks.RollingFile/project.json @@ -18,7 +18,7 @@ }, "frameworks": { "net4.5": { - "buildOptions": {"define": ["SHARING"]} + "buildOptions": {"define": ["SHARING", "HRESULTS"]} }, "netstandard1.3": { "dependencies": {