diff --git a/src/Serilog.Sinks.File/FileLoggerConfigurationExtensions.cs b/src/Serilog.Sinks.File/FileLoggerConfigurationExtensions.cs index 3518322..0e59f2a 100644 --- a/src/Serilog.Sinks.File/FileLoggerConfigurationExtensions.cs +++ b/src/Serilog.Sinks.File/FileLoggerConfigurationExtensions.cs @@ -23,6 +23,7 @@ using Serilog.Formatting; using Serilog.Formatting.Display; using Serilog.Formatting.Json; +using Serilog.Interval; using Serilog.Sinks.File; // ReSharper disable RedundantArgumentDefaultValue, MethodOverloadWithOptionalParameter @@ -151,7 +152,7 @@ public static LoggerConfiguration File( bool buffered, bool shared, TimeSpan? flushToDiskInterval, - RollingInterval rollingInterval, + Interval.RollingInterval rollingInterval, bool rollOnFileSizeLimit, int? retainedFileCountLimit, Encoding encoding) @@ -166,7 +167,7 @@ public static LoggerConfiguration File( /// Logger sink configuration. /// A formatter, such as , to convert the log events into /// text for the file. If control of regular text formatting is required, use the other - /// overload of + /// overload of /// and specify the outputTemplate parameter instead. /// /// Path to the file. @@ -199,7 +200,7 @@ public static LoggerConfiguration File( bool buffered, bool shared, TimeSpan? flushToDiskInterval, - RollingInterval rollingInterval, + Interval.RollingInterval rollingInterval, bool rollOnFileSizeLimit, int? retainedFileCountLimit, Encoding encoding) @@ -259,7 +260,7 @@ public static LoggerConfiguration File( bool buffered = false, bool shared = false, TimeSpan? flushToDiskInterval = null, - RollingInterval rollingInterval = RollingInterval.Infinite, + Interval.RollingInterval rollingInterval = null, bool rollOnFileSizeLimit = false, int? retainedFileCountLimit = DefaultRetainedFileCountLimit, Encoding? encoding = null, @@ -282,7 +283,7 @@ public static LoggerConfiguration File( /// Logger sink configuration. /// A formatter, such as , to convert the log events into /// text for the file. If control of regular text formatting is required, use the other - /// overload of + /// overload of /// and specify the outputTemplate parameter instead. /// /// Path to the file. @@ -328,7 +329,7 @@ public static LoggerConfiguration File( bool buffered = false, bool shared = false, TimeSpan? flushToDiskInterval = null, - RollingInterval rollingInterval = RollingInterval.Infinite, + Interval.RollingInterval rollingInterval = null, bool rollOnFileSizeLimit = false, int? retainedFileCountLimit = DefaultRetainedFileCountLimit, Encoding? encoding = null, @@ -340,7 +341,7 @@ public static LoggerConfiguration File( if (path == null) throw new ArgumentNullException(nameof(path)); return ConfigureFile(sinkConfiguration.Sink, formatter, path, restrictedToMinimumLevel, fileSizeLimitBytes, levelSwitch, - buffered, false, shared, flushToDiskInterval, encoding, rollingInterval, rollOnFileSizeLimit, + buffered, false, shared, flushToDiskInterval, encoding, rollingInterval ?? new InfiniteRollingInterval(), rollOnFileSizeLimit, retainedFileCountLimit, hooks, retainedFileTimeLimit); } @@ -510,8 +511,8 @@ static LoggerConfiguration ConfigureFile( bool propagateExceptions, bool shared, TimeSpan? flushToDiskInterval, - Encoding? encoding, - RollingInterval rollingInterval, + Encoding encoding, + Interval.RollingInterval rollingInterval, bool rollOnFileSizeLimit, int? retainedFileCountLimit, FileLifecycleHooks? hooks, @@ -530,7 +531,7 @@ static LoggerConfiguration ConfigureFile( try { - if (rollOnFileSizeLimit || rollingInterval != RollingInterval.Infinite) + if (rollOnFileSizeLimit || !(rollingInterval is InfiniteRollingInterval)) { sink = new RollingFileSink(path, formatter, fileSizeLimitBytes, retainedFileCountLimit, encoding, buffered, shared, rollingInterval, rollOnFileSizeLimit, hooks, retainedFileTimeLimit); } diff --git a/src/Serilog.Sinks.File/Interval/DayRollingInterval.cs b/src/Serilog.Sinks.File/Interval/DayRollingInterval.cs new file mode 100644 index 0000000..46c5747 --- /dev/null +++ b/src/Serilog.Sinks.File/Interval/DayRollingInterval.cs @@ -0,0 +1,27 @@ +using System; + +namespace Serilog.Interval +{ + /// + /// Day Rolling Interval + /// + public class DayRollingInterval : RollingInterval + { + /// + /// Format of rolling file name + /// + public override string Format => "yyyyMMdd"; + + /// + /// Normalize time to current checkpoint + /// + public override DateTime? CurrentCheckpoint(DateTime instant) => Normalize(instant); + + /// + /// Calculate next checkpoint from time + /// + public override DateTime? NextCheckpoint(DateTime instant) => Normalize(instant).AddDays(1); + + private static DateTime Normalize(DateTime instant) => new DateTime(instant.Year, instant.Month, instant.Day, 0, 0, 0, instant.Kind); + } +} diff --git a/src/Serilog.Sinks.File/Interval/HourRollingInterval.cs b/src/Serilog.Sinks.File/Interval/HourRollingInterval.cs new file mode 100644 index 0000000..de953ef --- /dev/null +++ b/src/Serilog.Sinks.File/Interval/HourRollingInterval.cs @@ -0,0 +1,27 @@ +using System; + +namespace Serilog.Interval +{ + /// + /// Hour Rolling Interval + /// + public class HourRollingInterval : RollingInterval + { + /// + /// Format of rolling file name + /// + public override string Format => "yyyyMMddHH"; + + /// + /// Normalize time to current checkpoint + /// + public override DateTime? CurrentCheckpoint(DateTime instant) => Normalize(instant); + + /// + /// Calculate next checkpoint from time + /// + public override DateTime? NextCheckpoint(DateTime instant) => Normalize(instant).AddHours(1); + + private static DateTime Normalize(DateTime instant) => new DateTime(instant.Year, instant.Month, instant.Day, instant.Hour, 0, 0, instant.Kind); + } +} diff --git a/src/Serilog.Sinks.File/Interval/InfiniteRollingInterval.cs b/src/Serilog.Sinks.File/Interval/InfiniteRollingInterval.cs new file mode 100644 index 0000000..1fa4af6 --- /dev/null +++ b/src/Serilog.Sinks.File/Interval/InfiniteRollingInterval.cs @@ -0,0 +1,25 @@ +using System; + +namespace Serilog.Interval +{ + /// + /// Infinite Rolling Interval + /// + public class InfiniteRollingInterval : RollingInterval + { + /// + /// Format of rolling file name + /// + public override string Format => string.Empty; + + /// + /// Normalize time to current checkpoint + /// + public override DateTime? CurrentCheckpoint(DateTime instant) => null; + + /// + /// Calculate next checkpoint from time + /// + public override DateTime? NextCheckpoint(DateTime instant) => null; + } +} diff --git a/src/Serilog.Sinks.File/Interval/MinuteRollingInterval.cs b/src/Serilog.Sinks.File/Interval/MinuteRollingInterval.cs new file mode 100644 index 0000000..1b49b2c --- /dev/null +++ b/src/Serilog.Sinks.File/Interval/MinuteRollingInterval.cs @@ -0,0 +1,27 @@ +using System; + +namespace Serilog.Interval +{ + /// + /// Minute Rolling Interval + /// + public class MinuteRollingInterval : RollingInterval + { + /// + /// Format of rolling file name + /// + public override string Format => "yyyyMMddHHmm"; + + /// + /// Normalize time to current checkpoint + /// + public override DateTime? CurrentCheckpoint(DateTime instant) => Normalize(instant); + + /// + /// Calculate next checkpoint from time + /// + public override DateTime? NextCheckpoint(DateTime instant) => Normalize(instant).AddMinutes(1); + + private static DateTime Normalize(DateTime instant) => new DateTime(instant.Year, instant.Month, instant.Day, instant.Hour, instant.Minute, 0, instant.Kind); + } +} diff --git a/src/Serilog.Sinks.File/Interval/MonthRollingInterval.cs b/src/Serilog.Sinks.File/Interval/MonthRollingInterval.cs new file mode 100644 index 0000000..19591ee --- /dev/null +++ b/src/Serilog.Sinks.File/Interval/MonthRollingInterval.cs @@ -0,0 +1,27 @@ +using System; + +namespace Serilog.Interval +{ + /// + /// Month Rolling Interval + /// + public class MonthRollingInterval : RollingInterval + { + /// + /// Format of rolling file name + /// + public override string Format => "yyyyMM"; + + /// + /// Normalize time to current checkpoint + /// + public override DateTime? CurrentCheckpoint(DateTime instant) => Normalize(instant); + + /// + /// Calculate next checkpoint from time + /// + public override DateTime? NextCheckpoint(DateTime instant) => Normalize(instant).AddMonths(1); + + private static DateTime Normalize(DateTime instant) => new DateTime(instant.Year, instant.Month, 1, 0, 0, 0, instant.Kind); + } +} diff --git a/src/Serilog.Sinks.File/Interval/RollingInterval.cs b/src/Serilog.Sinks.File/Interval/RollingInterval.cs new file mode 100644 index 0000000..3c9a298 --- /dev/null +++ b/src/Serilog.Sinks.File/Interval/RollingInterval.cs @@ -0,0 +1,55 @@ +using System; + +namespace Serilog.Interval +{ + /// + /// Specifies the frequency at which the log file should roll. + /// + public abstract class RollingInterval + { + /// + /// Format of rolling file name + /// + public abstract string Format { get; } + + /// + /// Normalize time to current checkpoint (year, month and etc) + /// + /// + /// + public abstract DateTime? CurrentCheckpoint(DateTime instant); + + /// + /// Calculate next checkpoint from time + /// + /// + /// + public abstract DateTime? NextCheckpoint(DateTime instant); + + /// + /// Create RollInterval + /// + /// + /// + public static implicit operator RollingInterval(Serilog.RollingInterval intervalType) + { + switch (intervalType) + { + case Serilog.RollingInterval.Infinite: + return new InfiniteRollingInterval(); + case Serilog.RollingInterval.Year: + return new YearRollingInterval(); + case Serilog.RollingInterval.Month: + return new MonthRollingInterval(); + case Serilog.RollingInterval.Day: + return new DayRollingInterval(); + case Serilog.RollingInterval.Hour: + return new HourRollingInterval(); + case Serilog.RollingInterval.Minute: + return new MinuteRollingInterval(); + default: + throw new ArgumentException("Invalid rolling interval"); + } + } + } +} diff --git a/src/Serilog.Sinks.File/Interval/YearRollingInterval.cs b/src/Serilog.Sinks.File/Interval/YearRollingInterval.cs new file mode 100644 index 0000000..7771c3b --- /dev/null +++ b/src/Serilog.Sinks.File/Interval/YearRollingInterval.cs @@ -0,0 +1,27 @@ +using System; + +namespace Serilog.Interval +{ + /// + /// Year Rolling Interval + /// + public class YearRollingInterval : RollingInterval + { + /// + /// Format of rolling file name + /// + public override string Format => "yyyy"; + + /// + /// Normalize time to current checkpoint + /// + public override DateTime? CurrentCheckpoint(DateTime instant) => Normalize(instant); + + /// + /// Calculate next checkpoint from time + /// + public override DateTime? NextCheckpoint(DateTime instant) => Normalize(instant).AddYears(1); + + private static DateTime Normalize(DateTime instant) => new DateTime(instant.Year, 1, 1, 0, 0, 0, instant.Kind); + } +} diff --git a/src/Serilog.Sinks.File/Sinks/File/PathRoller.cs b/src/Serilog.Sinks.File/Sinks/File/PathRoller.cs index 79a6915..e618298 100644 --- a/src/Serilog.Sinks.File/Sinks/File/PathRoller.cs +++ b/src/Serilog.Sinks.File/Sinks/File/PathRoller.cs @@ -30,14 +30,14 @@ class PathRoller readonly string _filenameSuffix; readonly Regex _filenameMatcher; - readonly RollingInterval _interval; + readonly Interval.RollingInterval _interval; readonly string _periodFormat; - public PathRoller(string path, RollingInterval interval) + public PathRoller(string path, Interval.RollingInterval interval) { if (path == null) throw new ArgumentNullException(nameof(path)); _interval = interval; - _periodFormat = interval.GetFormat(); + _periodFormat = interval.Format; var pathDirectory = Path.GetDirectoryName(path); if (string.IsNullOrEmpty(pathDirectory)) @@ -110,8 +110,8 @@ public IEnumerable SelectMatches(IEnumerable filenames) } } - public DateTime? GetCurrentCheckpoint(DateTime instant) => _interval.GetCurrentCheckpoint(instant); + public DateTime? GetCurrentCheckpoint(DateTime instant) => _interval.CurrentCheckpoint(instant); - public DateTime? GetNextCheckpoint(DateTime instant) => _interval.GetNextCheckpoint(instant); + public DateTime? GetNextCheckpoint(DateTime instant) => _interval.NextCheckpoint(instant); } } diff --git a/src/Serilog.Sinks.File/Sinks/File/RollingFileSink.cs b/src/Serilog.Sinks.File/Sinks/File/RollingFileSink.cs index dccb802..44e94f2 100644 --- a/src/Serilog.Sinks.File/Sinks/File/RollingFileSink.cs +++ b/src/Serilog.Sinks.File/Sinks/File/RollingFileSink.cs @@ -49,7 +49,7 @@ public RollingFileSink(string path, Encoding? encoding, bool buffered, bool shared, - RollingInterval rollingInterval, + Interval.RollingInterval rollingInterval, bool rollOnFileSizeLimit, FileLifecycleHooks? hooks, TimeSpan? retainedFileTimeLimit) diff --git a/src/Serilog.Sinks.File/Sinks/File/RollingIntervalExtensions.cs b/src/Serilog.Sinks.File/Sinks/File/RollingIntervalExtensions.cs deleted file mode 100644 index 2c9e2fd..0000000 --- a/src/Serilog.Sinks.File/Sinks/File/RollingIntervalExtensions.cs +++ /dev/null @@ -1,86 +0,0 @@ -// Copyright 2017 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; - -namespace Serilog.Sinks.File -{ - static class RollingIntervalExtensions - { - public static string GetFormat(this RollingInterval interval) - { - switch (interval) - { - case RollingInterval.Infinite: - return ""; - case RollingInterval.Year: - return "yyyy"; - case RollingInterval.Month: - return "yyyyMM"; - case RollingInterval.Day: - return "yyyyMMdd"; - case RollingInterval.Hour: - return "yyyyMMddHH"; - case RollingInterval.Minute: - return "yyyyMMddHHmm"; - default: - throw new ArgumentException("Invalid rolling interval"); - } - } - - public static DateTime? GetCurrentCheckpoint(this RollingInterval interval, DateTime instant) - { - switch (interval) - { - case RollingInterval.Infinite: - return null; - case RollingInterval.Year: - return new DateTime(instant.Year, 1, 1, 0, 0, 0, instant.Kind); - case RollingInterval.Month: - return new DateTime(instant.Year, instant.Month, 1, 0, 0, 0, instant.Kind); - case RollingInterval.Day: - return new DateTime(instant.Year, instant.Month, instant.Day, 0, 0, 0, instant.Kind); - case RollingInterval.Hour: - return new DateTime(instant.Year, instant.Month, instant.Day, instant.Hour, 0, 0, instant.Kind); - case RollingInterval.Minute: - return new DateTime(instant.Year, instant.Month, instant.Day, instant.Hour, instant.Minute, 0, instant.Kind); - default: - throw new ArgumentException("Invalid rolling interval"); - } - } - - public static DateTime? GetNextCheckpoint(this RollingInterval interval, DateTime instant) - { - var current = GetCurrentCheckpoint(interval, instant); - if (current == null) - return null; - - switch (interval) - { - case RollingInterval.Year: - return current.Value.AddYears(1); - case RollingInterval.Month: - return current.Value.AddMonths(1); - case RollingInterval.Day: - return current.Value.AddDays(1); - case RollingInterval.Hour: - return current.Value.AddHours(1); - case RollingInterval.Minute: - return current.Value.AddMinutes(1); - default: - throw new ArgumentException("Invalid rolling interval"); - } - } - } -} diff --git a/test/Serilog.Sinks.File.Tests/RollingIntervalExtensionsTests.cs b/test/Serilog.Sinks.File.Tests/RollingIntervalExtensionsTests.cs index 404d5b4..069fb9d 100644 --- a/test/Serilog.Sinks.File.Tests/RollingIntervalExtensionsTests.cs +++ b/test/Serilog.Sinks.File.Tests/RollingIntervalExtensionsTests.cs @@ -24,10 +24,11 @@ public class RollingIntervalExtensionsTests [MemberData(nameof(IntervalInstantCurrentNextCheckpoint))] public void NextIntervalTests(RollingInterval interval, DateTime instant, DateTime? currentCheckpoint, DateTime? nextCheckpoint) { - var current = interval.GetCurrentCheckpoint(instant); + Interval.RollingInterval rollingInterval = interval; + var current = rollingInterval.CurrentCheckpoint(instant); Assert.Equal(currentCheckpoint, current); - var next = interval.GetNextCheckpoint(instant); + var next = rollingInterval.NextCheckpoint(instant); Assert.Equal(nextCheckpoint, next); } }