From 6546958286d20ea37edefff75d55c77e3363e181 Mon Sep 17 00:00:00 2001 From: Ruben Bartelink Date: Tue, 24 Apr 2018 14:15:38 +0100 Subject: [PATCH] Add IAsyncLogEventSinkMonitor --- .../LoggerConfigurationAsyncExtensions.cs | 32 +++++++++++++++++-- .../Sinks/Async/BackgroundWorkerSink.cs | 6 +++- .../Sinks/Async/IAsyncLogEventSinkMonitor.cs | 15 +++++++++ .../BackgroundWorkerSinkSpec.cs | 2 +- 4 files changed, 51 insertions(+), 4 deletions(-) create mode 100644 src/Serilog.Sinks.Async/Sinks/Async/IAsyncLogEventSinkMonitor.cs diff --git a/src/Serilog.Sinks.Async/LoggerConfigurationAsyncExtensions.cs b/src/Serilog.Sinks.Async/LoggerConfigurationAsyncExtensions.cs index ea53e0b..2bf7091 100644 --- a/src/Serilog.Sinks.Async/LoggerConfigurationAsyncExtensions.cs +++ b/src/Serilog.Sinks.Async/LoggerConfigurationAsyncExtensions.cs @@ -44,10 +44,38 @@ public static LoggerConfiguration Async( Action configure, int bufferSize = 10000, bool blockWhenFull = false) + { + return loggerSinkConfiguration.Async(configure, null, bufferSize, blockWhenFull); + } + + /// + /// Configure a sink to be invoked asynchronously, on a background worker thread. + /// Accepts a reference to a that will be supplied the internal state interface for health monitoring purposes. + /// + /// The being configured. + /// An action that configures the wrapped sink. + /// The size of the concurrent queue used to feed the background worker thread. If + /// the thread is unable to process events quickly enough and the queue is filled, depending on + /// the queue will block or subsequent events will be dropped until + /// room is made in the queue. + /// Block when the queue is full, instead of dropping events. + /// Monitor to supply buffer information to. If the monitor implements , Dispose() will be called to advise of the Sink being Dispose()d. + /// A allowing configuration to continue. + public static LoggerConfiguration Async( + this LoggerSinkConfiguration loggerSinkConfiguration, + Action configure, + IAsyncLogEventSinkMonitor monitor, + int bufferSize, + bool blockWhenFull) { return LoggerSinkConfiguration.Wrap( loggerSinkConfiguration, - wrappedSink => new BackgroundWorkerSink(wrappedSink, bufferSize, blockWhenFull), + wrappedSink => + { + var sink = new BackgroundWorkerSink(wrappedSink, bufferSize, blockWhenFull, monitor); + monitor?.MonitorState(sink); + return sink; + }, configure); } @@ -77,7 +105,7 @@ public static LoggerConfiguration Async( loggerSinkConfiguration, wrappedSink => { - var sink = new BackgroundWorkerSink(wrappedSink, bufferSize, blockWhenFull); + var sink = new BackgroundWorkerSink(wrappedSink, bufferSize, blockWhenFull, null); stateLens = sink; return sink; }, diff --git a/src/Serilog.Sinks.Async/Sinks/Async/BackgroundWorkerSink.cs b/src/Serilog.Sinks.Async/Sinks/Async/BackgroundWorkerSink.cs index 75239f5..91b3221 100644 --- a/src/Serilog.Sinks.Async/Sinks/Async/BackgroundWorkerSink.cs +++ b/src/Serilog.Sinks.Async/Sinks/Async/BackgroundWorkerSink.cs @@ -14,16 +14,18 @@ sealed class BackgroundWorkerSink : ILogEventSink, IAsyncLogEventSinkState, IDis readonly bool _blockWhenFull; readonly BlockingCollection _queue; readonly Task _worker; + readonly IAsyncLogEventSinkMonitor _monitor; long _droppedMessages; - public BackgroundWorkerSink(ILogEventSink pipeline, int bufferCapacity, bool blockWhenFull) + public BackgroundWorkerSink(ILogEventSink pipeline, int bufferCapacity, bool blockWhenFull, IAsyncLogEventSinkMonitor monitor = null) { if (bufferCapacity <= 0) throw new ArgumentOutOfRangeException(nameof(bufferCapacity)); _pipeline = pipeline ?? throw new ArgumentNullException(nameof(pipeline)); _blockWhenFull = blockWhenFull; _queue = new BlockingCollection(bufferCapacity); _worker = Task.Factory.StartNew(Pump, CancellationToken.None, TaskCreationOptions.LongRunning | TaskCreationOptions.DenyChildAttach, TaskScheduler.Default); + _monitor = monitor; } public void Emit(LogEvent logEvent) @@ -62,6 +64,8 @@ public void Dispose() _worker.Wait(); (_pipeline as IDisposable)?.Dispose(); + + (_monitor as IDisposable)?.Dispose(); } void Pump() diff --git a/src/Serilog.Sinks.Async/Sinks/Async/IAsyncLogEventSinkMonitor.cs b/src/Serilog.Sinks.Async/Sinks/Async/IAsyncLogEventSinkMonitor.cs new file mode 100644 index 0000000..4b88ef3 --- /dev/null +++ b/src/Serilog.Sinks.Async/Sinks/Async/IAsyncLogEventSinkMonitor.cs @@ -0,0 +1,15 @@ +namespace Serilog.Sinks.Async +{ + /// + /// Defines a mechanism for the Async Sink to provide buffer metadata to facilitate integration into system health checking. + /// + /// If the instance implements , it will be Dispose()d at then time the Sink is. + public interface IAsyncLogEventSinkMonitor + { + /// + /// Invoked by Sink to supply the buffer state hook to the monitor. + /// + /// The Async Sink's state information interface. + void MonitorState(IAsyncLogEventSinkState state); + } +} \ No newline at end of file diff --git a/test/Serilog.Sinks.Async.Tests/BackgroundWorkerSinkSpec.cs b/test/Serilog.Sinks.Async.Tests/BackgroundWorkerSinkSpec.cs index 9a0e572..048ed62 100644 --- a/test/Serilog.Sinks.Async.Tests/BackgroundWorkerSinkSpec.cs +++ b/test/Serilog.Sinks.Async.Tests/BackgroundWorkerSinkSpec.cs @@ -25,7 +25,7 @@ public BackgroundWorkerSinkSpec() [Fact] public void WhenCtorWithNullSink_ThenThrows() { - Assert.Throws(() => new BackgroundWorkerSink(null, 10000, false)); + Assert.Throws(() => new BackgroundWorkerSink(null, 10000, false, null)); } [Fact]