diff --git a/CHANGELOG.md b/CHANGELOG.md index 923c7a8d..d0597d81 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Added + +- Debug-level logs are now written to file in addition to the Info-level logs in console output. + ## [1.4.2] - 2021-05-15 ### Fixed diff --git a/src/Directory.Build.targets b/src/Directory.Build.targets index c064ddce..7fb4a4bc 100644 --- a/src/Directory.Build.targets +++ b/src/Directory.Build.targets @@ -6,6 +6,7 @@ + @@ -13,7 +14,6 @@ - @@ -26,6 +26,7 @@ + diff --git a/src/Trash.Tests/LogJanitorTest.cs b/src/Trash.Tests/LogJanitorTest.cs new file mode 100644 index 00000000..c72957a1 --- /dev/null +++ b/src/Trash.Tests/LogJanitorTest.cs @@ -0,0 +1,41 @@ +using System.IO.Abstractions; +using NSubstitute; +using NUnit.Framework; + +namespace Trash.Tests +{ + [TestFixture] + [Parallelizable(ParallelScope.All)] + public class LogJanitorTest + { + [Test] + public void Keep_correct_number_of_newest_log_files() + { + var fs = Substitute.For(); + var janitor = new LogJanitor(fs); + + var testFileInfoList = new[] + { + Substitute.For(), + Substitute.For(), + Substitute.For(), + Substitute.For() + }; + + testFileInfoList[0].Name.Returns("trash_2021-05-15_19-00-00"); + testFileInfoList[1].Name.Returns("trash_2021-05-15_20-00-00"); + testFileInfoList[2].Name.Returns("trash_2021-05-15_21-00-00"); + testFileInfoList[3].Name.Returns("trash_2021-05-15_22-00-00"); + + fs.DirectoryInfo.FromDirectoryName(Arg.Any()).GetFiles() + .Returns(testFileInfoList); + + janitor.DeleteOldestLogFiles(2); + + testFileInfoList[0].Received().Delete(); + testFileInfoList[1].Received().Delete(); + testFileInfoList[2].DidNotReceive().Delete(); + testFileInfoList[3].DidNotReceive().Delete(); + } + } +} diff --git a/src/Trash/AppPaths.cs b/src/Trash/AppPaths.cs index 569d8330..a8bb2476 100644 --- a/src/Trash/AppPaths.cs +++ b/src/Trash/AppPaths.cs @@ -9,5 +9,7 @@ namespace Trash Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "trash-updater"); public static string DefaultConfigPath { get; } = Path.Combine(AppContext.BaseDirectory, "trash.yml"); + + public static string LogDirectory { get; } = Path.Combine(AppDataPath, "logs"); } } diff --git a/src/Trash/Command/ServiceCommand.cs b/src/Trash/Command/ServiceCommand.cs index 08d7bbc2..d8b51aa6 100644 --- a/src/Trash/Command/ServiceCommand.cs +++ b/src/Trash/Command/ServiceCommand.cs @@ -19,10 +19,12 @@ namespace Trash.Command public abstract class ServiceCommand : ICommand, IServiceCommand { private readonly LoggingLevelSwitch _loggingLevelSwitch; + private readonly ILogJanitor _logJanitor; - protected ServiceCommand(ILogger logger, LoggingLevelSwitch loggingLevelSwitch) + protected ServiceCommand(ILogger logger, LoggingLevelSwitch loggingLevelSwitch, ILogJanitor logJanitor) { _loggingLevelSwitch = loggingLevelSwitch; + _logJanitor = logJanitor; Log = logger; } @@ -54,6 +56,10 @@ namespace Trash.Command Log.Error(e, "Unrecoverable Exception"); ExitDueToFailure(); } + finally + { + CleanupOldLogFiles(); + } } [CommandOption("preview", 'p', Description = @@ -72,6 +78,11 @@ namespace Trash.Command public abstract string CacheStoragePath { get; } + private void CleanupOldLogFiles() + { + _logJanitor.DeleteOldestLogFiles(20); + } + private void SetupLogging() { _loggingLevelSwitch.MinimumLevel = diff --git a/src/Trash/CompositionRoot.cs b/src/Trash/CompositionRoot.cs index 5b34f157..63888a28 100644 --- a/src/Trash/CompositionRoot.cs +++ b/src/Trash/CompositionRoot.cs @@ -1,4 +1,6 @@ -using System.IO.Abstractions; +using System; +using System.IO; +using System.IO.Abstractions; using System.Reflection; using Autofac; using Autofac.Extras.AggregateService; @@ -27,16 +29,23 @@ namespace Trash { private static void SetupLogging(ContainerBuilder builder) { + builder.RegisterType().As(); builder.RegisterType().SingleInstance(); builder.Register(c => { - const string template = "[{Level:u3}] {Message:lj}{NewLine}{Exception}"; + var logPath = Path.Combine(AppPaths.LogDirectory, + $"trash_{DateTime.Now:yyyy-MM-dd_HH-mm-ss}.log"); + + const string consoleTemplate = "[{Level:u3}] {Message:lj}{NewLine}{Exception}"; + return new LoggerConfiguration() - .MinimumLevel.ControlledBy(c.Resolve()) - .WriteTo.Console(outputTemplate: template) + .MinimumLevel.Debug() + .WriteTo.Console(outputTemplate: consoleTemplate, levelSwitch: c.Resolve()) + .WriteTo.File(logPath) .CreateLogger(); }) - .As(); + .As() + .SingleInstance(); } private static void SonarrRegistrations(ContainerBuilder builder) @@ -123,9 +132,7 @@ namespace Trash public static IContainer Setup(ContainerBuilder builder) { - builder.RegisterType() - .As(); - + builder.RegisterType().As(); builder.RegisterType().As(); builder.RegisterType().As(); diff --git a/src/Trash/ILogJanitor.cs b/src/Trash/ILogJanitor.cs new file mode 100644 index 00000000..766d65c9 --- /dev/null +++ b/src/Trash/ILogJanitor.cs @@ -0,0 +1,7 @@ +namespace Trash +{ + public interface ILogJanitor + { + void DeleteOldestLogFiles(int numberOfNewestToKeep); + } +} diff --git a/src/Trash/LogJanitor.cs b/src/Trash/LogJanitor.cs new file mode 100644 index 00000000..bd52351f --- /dev/null +++ b/src/Trash/LogJanitor.cs @@ -0,0 +1,25 @@ +using System.IO.Abstractions; +using System.Linq; + +namespace Trash +{ + public class LogJanitor : ILogJanitor + { + private readonly IFileSystem _fileSystem; + + public LogJanitor(IFileSystem fileSystem) + { + _fileSystem = fileSystem; + } + + public void DeleteOldestLogFiles(int numberOfNewestToKeep) + { + foreach (var file in _fileSystem.DirectoryInfo.FromDirectoryName(AppPaths.LogDirectory).GetFiles() + .OrderByDescending(f => f.Name) + .Skip(numberOfNewestToKeep)) + { + file.Delete(); + } + } + } +} diff --git a/src/Trash/Radarr/RadarrCommand.cs b/src/Trash/Radarr/RadarrCommand.cs index 979497cf..4a7cbbfe 100644 --- a/src/Trash/Radarr/RadarrCommand.cs +++ b/src/Trash/Radarr/RadarrCommand.cs @@ -24,10 +24,11 @@ namespace Trash.Radarr public RadarrCommand( ILogger logger, LoggingLevelSwitch loggingLevelSwitch, + ILogJanitor logJanitor, IConfigurationLoader configLoader, Func qualityUpdaterFactory, Lazy customFormatUpdater) - : base(logger, loggingLevelSwitch) + : base(logger, loggingLevelSwitch, logJanitor) { _configLoader = configLoader; _qualityUpdaterFactory = qualityUpdaterFactory; diff --git a/src/Trash/Sonarr/SonarrCommand.cs b/src/Trash/Sonarr/SonarrCommand.cs index adb2b835..83a8b982 100644 --- a/src/Trash/Sonarr/SonarrCommand.cs +++ b/src/Trash/Sonarr/SonarrCommand.cs @@ -24,10 +24,11 @@ namespace Trash.Sonarr public SonarrCommand( ILogger logger, LoggingLevelSwitch loggingLevelSwitch, + ILogJanitor logJanitor, IConfigurationLoader configLoader, Func profileUpdaterFactory, Func qualityUpdaterFactory) - : base(logger, loggingLevelSwitch) + : base(logger, loggingLevelSwitch, logJanitor) { _configLoader = configLoader; _profileUpdaterFactory = profileUpdaterFactory; diff --git a/src/Trash/Trash.csproj b/src/Trash/Trash.csproj index 21a9d26b..c0c4d331 100644 --- a/src/Trash/Trash.csproj +++ b/src/Trash/Trash.csproj @@ -12,6 +12,7 @@ +