The logger, which also writes to a file in addition to console, requires `IAppPaths` in order to find the directory to place the log files. However, this cannot be obtained until the system calculates the app data directory OR the user specifies it with the `--app-data` option. A custom sink has been added that will allow the logger to write to console without file logs until that initialization is performed and the log directory is available.pull/76/head
parent
035836db49
commit
a1f07c4ad0
@ -0,0 +1,29 @@
|
||||
using System.IO.Abstractions;
|
||||
using AutoFixture.NUnit3;
|
||||
using NSubstitute;
|
||||
using NUnit.Framework;
|
||||
using Recyclarr.Logging;
|
||||
using Serilog.Events;
|
||||
using TestLibrary.AutoFixture;
|
||||
using TrashLib;
|
||||
|
||||
namespace Recyclarr.Tests.Logging;
|
||||
|
||||
[TestFixture]
|
||||
[Parallelizable(ParallelScope.All)]
|
||||
public class DelayedFileSinkTest
|
||||
{
|
||||
[Test, AutoMockData]
|
||||
public void Should_not_open_file_if_app_data_invalid(
|
||||
[Frozen] IAppPaths paths,
|
||||
[Frozen] IFileSystem fs,
|
||||
LogEvent logEvent,
|
||||
DelayedFileSink sut)
|
||||
{
|
||||
paths.IsAppDataPathValid.Returns(false);
|
||||
|
||||
sut.Emit(logEvent);
|
||||
|
||||
fs.File.DidNotReceiveWithAnyArgs().OpenWrite(default!);
|
||||
}
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
using System.IO.Abstractions;
|
||||
using Serilog.Events;
|
||||
using TrashLib;
|
||||
|
||||
namespace Recyclarr.Logging;
|
||||
|
||||
public class DelayedFileSink : IDelayedFileSink
|
||||
{
|
||||
private readonly IAppPaths _paths;
|
||||
private readonly Lazy<StreamWriter> _stream;
|
||||
|
||||
public DelayedFileSink(IAppPaths paths, IFileSystem fs)
|
||||
{
|
||||
_paths = paths;
|
||||
_stream = new Lazy<StreamWriter>(() =>
|
||||
{
|
||||
var logPath = fs.Path.Combine(_paths.LogDirectory, $"trash_{DateTime.Now:yyyy-MM-dd_HH-mm-ss}.log");
|
||||
return fs.File.CreateText(logPath);
|
||||
});
|
||||
}
|
||||
|
||||
public void Emit(LogEvent logEvent)
|
||||
{
|
||||
if (!_paths.IsAppDataPathValid)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_stream.Value.WriteLine(logEvent.RenderMessage());
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (_stream.IsValueCreated)
|
||||
{
|
||||
_stream.Value.Close();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
using Serilog.Core;
|
||||
|
||||
namespace Recyclarr.Logging;
|
||||
|
||||
public interface IDelayedFileSink : ILogEventSink, IDisposable
|
||||
{
|
||||
}
|
@ -1,33 +1,27 @@
|
||||
using System.IO.Abstractions;
|
||||
using Serilog;
|
||||
using Serilog.Core;
|
||||
using TrashLib;
|
||||
|
||||
namespace Recyclarr.Logging;
|
||||
|
||||
public class LoggerFactory
|
||||
{
|
||||
private readonly IFileSystem _fs;
|
||||
private readonly IAppPaths _paths;
|
||||
private readonly LoggingLevelSwitch _logLevel;
|
||||
private readonly IDelayedFileSink _fileSink;
|
||||
|
||||
public LoggerFactory(IFileSystem fs, IAppPaths paths, LoggingLevelSwitch logLevel)
|
||||
public LoggerFactory(LoggingLevelSwitch logLevel, IDelayedFileSink fileSink)
|
||||
{
|
||||
_fs = fs;
|
||||
_paths = paths;
|
||||
_logLevel = logLevel;
|
||||
_fileSink = fileSink;
|
||||
}
|
||||
|
||||
public ILogger Create()
|
||||
{
|
||||
var logPath = _fs.Path.Combine(_paths.LogDirectory, $"trash_{DateTime.Now:yyyy-MM-dd_HH-mm-ss}.log");
|
||||
|
||||
const string consoleTemplate = "[{Level:u3}] {Message:lj}{NewLine}{Exception}";
|
||||
|
||||
return new LoggerConfiguration()
|
||||
.MinimumLevel.Debug()
|
||||
.WriteTo.Console(outputTemplate: consoleTemplate, levelSwitch: _logLevel)
|
||||
.WriteTo.File(logPath)
|
||||
.WriteTo.Sink(_fileSink)
|
||||
.CreateLogger();
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in new issue