Skip to content

Added support for customising date in filename #343

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 44 additions & 10 deletions src/Serilog.Sinks.File/Sinks/File/PathRoller.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,16 +43,9 @@ public PathRoller(string path, RollingInterval interval)
_directory = Path.GetFullPath(pathDirectory);
_filenamePrefix = Path.GetFileNameWithoutExtension(path);
_filenameSuffix = Path.GetExtension(path);
_filenameMatcher = new Regex(
"^" +
Regex.Escape(_filenamePrefix) +
"(?<" + PeriodMatchGroup + ">\\d{" + _periodFormat.Length + "})" +
"(?<" + SequenceNumberMatchGroup + ">_[0-9]{3,}){0,1}" +
Regex.Escape(_filenameSuffix) +
"$",
RegexOptions.Compiled);
_filenameMatcher = GetFileNameMatcher();

DirectorySearchPattern = $"{_filenamePrefix}*{_filenameSuffix}";
DirectorySearchPattern = GetDirectorySearchPattern();
}

public string LogFileDirectory => _directory;
Expand All @@ -68,7 +61,12 @@ public void GetLogFilePath(DateTime date, int? sequenceNumber, out string path)
if (sequenceNumber != null)
tok += "_" + sequenceNumber.Value.ToString("000", CultureInfo.InvariantCulture);

path = Path.Combine(_directory, _filenamePrefix + tok + _filenameSuffix);
string fileNameReplaced = ReplaceDatePlaceholder(_filenamePrefix, tok);

if (string.Equals(_filenamePrefix, fileNameReplaced, StringComparison.InvariantCultureIgnoreCase))
fileNameReplaced += tok;

path = Path.Combine(_directory, fileNameReplaced + _filenameSuffix);
}

public IEnumerable<RollingLogFile> SelectMatches(IEnumerable<string> filenames)
Expand Down Expand Up @@ -110,4 +108,40 @@ public IEnumerable<RollingLogFile> SelectMatches(IEnumerable<string> filenames)
public DateTime? GetCurrentCheckpoint(DateTime instant) => _interval.GetCurrentCheckpoint(instant);

public DateTime? GetNextCheckpoint(DateTime instant) => _interval.GetNextCheckpoint(instant);

Regex GetFileNameMatcher()
{
if (_filenamePrefix.StartsWith("{Date}", StringComparison.InvariantCultureIgnoreCase))
{
return new Regex(
"^" +
"(?<" + PeriodMatchGroup + ">\\d{" + _periodFormat.Length + "})" +
"(?<" + SequenceNumberMatchGroup + ">_[0-9]{3,}){0,1}" +
Regex.Escape(ReplaceDatePlaceholder(_filenamePrefix, string.Empty)) +
Regex.Escape(_filenameSuffix) +
"$",
RegexOptions.Compiled);
}

return new Regex(
"^" +
Regex.Escape(_filenamePrefix) +
"(?<" + PeriodMatchGroup + ">\\d{" + _periodFormat.Length + "})" +
"(?<" + SequenceNumberMatchGroup + ">_[0-9]{3,}){0,1}" +
Regex.Escape(_filenameSuffix) +
"$",
RegexOptions.Compiled);
}

string GetDirectorySearchPattern()
{
return _filenamePrefix.StartsWith("{Date}", StringComparison.InvariantCultureIgnoreCase)
? $"*{ReplaceDatePlaceholder(_filenamePrefix, string.Empty)}{_filenameSuffix}"
: $"{_filenamePrefix}*{_filenameSuffix}";
}

static string ReplaceDatePlaceholder(string filenamePrefix, string dateString)
{
return Regex.Replace(filenamePrefix, @"\{Date}", dateString, RegexOptions.IgnoreCase);
}
}
23 changes: 20 additions & 3 deletions test/Serilog.Sinks.File.Tests/RollingFileSinkTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,23 @@ public void LogEventsAreEmittedToTheFileNamedAccordingToTheEventTimestamp()
TestRollingEventSequence(Some.InformationEvent());
}

[Fact]
public void ShouldCreateFileWithDatePlaceHolder()
{
var config = new LoggerConfiguration()
.WriteTo.File("{Date}-log.txt", rollingInterval: RollingInterval.Day);
var log = config.CreateLogger();

var now = new DateTime(2013, 7, 14, 3, 24, 9, 980);

Clock.SetTestDateTimeNow(now);
log.Write(Some.InformationEvent());

var path = Path.Combine(Directory.GetCurrentDirectory(), "20130714-log.txt");

Assert.True(System.IO.File.Exists(path));
}

[Fact]
public void EventsAreWrittenWhenSharingIsEnabled()
{
Expand Down Expand Up @@ -172,7 +189,7 @@ public void WhenFirstOpeningFailedWithLockRetryDelayedUntilNextCheckpoint()
e3 = Some.InformationEvent(e1.Timestamp.AddMinutes(5)),
e4 = Some.InformationEvent(e1.Timestamp.AddMinutes(31));
LogEvent[] logEvents = new[] { e1, e2, e3, e4 };

foreach (var logEvent in logEvents)
{
Clock.SetTestDateTimeNow(logEvent.Timestamp.DateTime);
Expand Down Expand Up @@ -210,7 +227,7 @@ public void WhenFirstOpeningFailedWithLockRetryDelayed30Minutes()
e3 = Some.InformationEvent(e1.Timestamp.AddMinutes(5)),
e4 = Some.InformationEvent(e1.Timestamp.AddMinutes(31));
LogEvent[] logEvents = new[] { e1, e2, e3, e4 };

SelfLog.Enable(_testOutputHelper.WriteLine);
foreach (var logEvent in logEvents)
{
Expand Down Expand Up @@ -247,7 +264,7 @@ public void WhenFirstOpeningFailedWithoutLockRetryDelayed30Minutes()
e3 = Some.InformationEvent(e1.Timestamp.AddMinutes(5)),
e4 = Some.InformationEvent(e1.Timestamp.AddMinutes(31));
LogEvent[] logEvents = new[] { e1, e2, e3, e4 };

SelfLog.Enable(_testOutputHelper.WriteLine);
foreach (var logEvent in logEvents)
{
Expand Down
82 changes: 80 additions & 2 deletions test/Serilog.Sinks.File.Tests/TemplatedPathRollerTests.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,42 @@
using Xunit;
using System.Globalization;
using Xunit;

namespace Serilog.Sinks.File.Tests;

public class PathRollerTests
{
[Theory]
[InlineData(null)]
[InlineData(2)]
public void GetLogFilePath_WhenPathContainsDateTokenAtStart_ShouldReplaceDateToken(int? sequenceNumber)
{
var now = new DateTime(2013, 7, 14, 3, 24, 9, 980);
string expectedName = sequenceNumber is null
? $"{now:yyyyMMdd}-logs.txt"
: $"{now:yyyyMMdd}_{sequenceNumber.Value.ToString("000", CultureInfo.InvariantCulture)}-logs.txt";

var roller = new PathRoller(Path.Combine("Logs", "{date}-logs.txt"), RollingInterval.Day);
roller.GetLogFilePath(now, sequenceNumber, out string actualName);

AssertEqualAbsolute(Path.Combine("Logs", expectedName), actualName);
}

[Theory]
[InlineData(null)]
[InlineData(2)]
public void GetLogFilePath_WhenPathContainsDateTokenAtEnd_ShouldReplaceDateToken(int? sequenceNumber)
{
var now = new DateTime(2013, 7, 14, 3, 24, 9, 980);
string expectedName = sequenceNumber is null
? $"logs-{now:yyyyMMdd}.txt"
: $"logs-{now:yyyyMMdd}_{sequenceNumber.Value.ToString("000", CultureInfo.InvariantCulture)}.txt";

var roller = new PathRoller(Path.Combine("Logs", "logs-{Date}.txt"), RollingInterval.Day);
roller.GetLogFilePath(now, sequenceNumber, out string actualName);

AssertEqualAbsolute(Path.Combine("Logs", expectedName), actualName);
}

[Fact]
public void TheLogFileIncludesDateToken()
{
Expand All @@ -22,6 +55,15 @@ public void ANonZeroIncrementIsIncludedAndPadded()
AssertEqualAbsolute(Path.Combine("Logs", "log-20130714_012.txt"), path);
}

[Fact]
public void ANonZeroIncrementIsIncludedAndPaddedWhenDatePlaceHolderExists()
{
var roller = new PathRoller(Path.Combine("Logs", "{Date}-log.txt"), RollingInterval.Day);
var now = new DateTime(2013, 7, 14, 3, 24, 9, 980);
roller.GetLogFilePath(now, 12, out var path);
AssertEqualAbsolute(Path.Combine("Logs", "20130714_012-log.txt"), path);
}

static void AssertEqualAbsolute(string path1, string path2)
{
var abs1 = Path.GetFullPath(path1);
Expand All @@ -36,6 +78,13 @@ public void TheRollerReturnsTheLogFileDirectory()
AssertEqualAbsolute("Logs", roller.LogFileDirectory);
}

[Fact]
public void TheRollerReturnsTheLogFileDirectoryWhenDatePlaceHolderExists()
{
var roller = new PathRoller(Path.Combine("Logs", "{Date}-log.txt"), RollingInterval.Day);
AssertEqualAbsolute("Logs", roller.LogFileDirectory);
}

[Fact]
public void TheLogFileIsNotRequiredToIncludeAnExtension()
{
Expand All @@ -45,6 +94,15 @@ public void TheLogFileIsNotRequiredToIncludeAnExtension()
AssertEqualAbsolute(Path.Combine("Logs", "log-20130714"), path);
}

[Fact]
public void TheLogFileIsNotRequiredToIncludeAnExtensionWhenDatePlaceHolderExists()
{
var roller = new PathRoller(Path.Combine("Logs", "{Date}-log"), RollingInterval.Day);
var now = new DateTime(2013, 7, 14, 3, 24, 9, 980);
roller.GetLogFilePath(now, null, out var path);
AssertEqualAbsolute(Path.Combine("Logs", "20130714-log"), path);
}

[Fact]
public void TheLogFileIsNotRequiredToIncludeADirectory()
{
Expand All @@ -54,13 +112,24 @@ public void TheLogFileIsNotRequiredToIncludeADirectory()
AssertEqualAbsolute("log-20130714", path);
}

[Fact]
public void TheLogFileIsNotRequiredToIncludeADirectoryWhenDatePlaceHolderExists()
{
var roller = new PathRoller("{Date}-log", RollingInterval.Day);
var now = new DateTime(2013, 7, 14, 3, 24, 9, 980);
roller.GetLogFilePath(now, null, out var path);
AssertEqualAbsolute("20130714-log", path);
}

[Fact]
public void MatchingExcludesSimilarButNonMatchingFiles()
{
var roller = new PathRoller("log-.txt", RollingInterval.Day);
const string similar1 = "log-0.txt";
const string similar2 = "log-hello.txt";
var matched = roller.SelectMatches(new[] { similar1, similar2 });
const string similar3 = "0-log.txt";
const string similar4 = "hello-log.txt";
var matched = roller.SelectMatches(new[] { similar1, similar2, similar3, similar4 });
Assert.Empty(matched);
}

Expand All @@ -71,9 +140,17 @@ public void TheDirectorSearchPatternUsesWildcardInPlaceOfDate()
Assert.Equal("log-*.txt", roller.DirectorySearchPattern);
}

[Fact]
public void TheDirectorSearchPatternUsesWildcardInPlaceOfDateWhenDatePlaceHolderExists()
{
var roller = new PathRoller(Path.Combine("Logs", "{Date}-log.txt"), RollingInterval.Day);
Assert.Equal("*-log.txt", roller.DirectorySearchPattern);
}

[Theory]
[InlineData("log-.txt", "log-20131210.txt", "log-20131210_031.txt", RollingInterval.Day)]
[InlineData("log-.txt", "log-2013121013.txt", "log-2013121013_031.txt", RollingInterval.Hour)]
[InlineData("{Date}-log.txt", "2013121013-log.txt", "2013121013_031-log.txt", RollingInterval.Hour)]
public void MatchingSelectsFiles(string template, string zeroth, string thirtyFirst, RollingInterval interval)
{
var roller = new PathRoller(template, interval);
Expand All @@ -86,6 +163,7 @@ public void MatchingSelectsFiles(string template, string zeroth, string thirtyFi
[Theory]
[InlineData("log-.txt", "log-20150101.txt", "log-20141231.txt", RollingInterval.Day)]
[InlineData("log-.txt", "log-2015010110.txt", "log-2015010109.txt", RollingInterval.Hour)]
[InlineData("{Date}-log.txt", "2015010110-log.txt", "2015010109-log.txt", RollingInterval.Hour)]
public void MatchingParsesSubstitutions(string template, string newer, string older, RollingInterval interval)
{
var roller = new PathRoller(template, interval);
Expand Down