Skip to content

Commit 6546958

Browse files
committed
Add IAsyncLogEventSinkMonitor
1 parent 510db8d commit 6546958

File tree

4 files changed

+51
-4
lines changed

4 files changed

+51
-4
lines changed

src/Serilog.Sinks.Async/LoggerConfigurationAsyncExtensions.cs

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,10 +44,38 @@ public static LoggerConfiguration Async(
4444
Action<LoggerSinkConfiguration> configure,
4545
int bufferSize = 10000,
4646
bool blockWhenFull = false)
47+
{
48+
return loggerSinkConfiguration.Async(configure, null, bufferSize, blockWhenFull);
49+
}
50+
51+
/// <summary>
52+
/// Configure a sink to be invoked asynchronously, on a background worker thread.
53+
/// Accepts a reference to a <paramref name="monitor"/> that will be supplied the internal state interface for health monitoring purposes.
54+
/// </summary>
55+
/// <param name="loggerSinkConfiguration">The <see cref="LoggerSinkConfiguration"/> being configured.</param>
56+
/// <param name="configure">An action that configures the wrapped sink.</param>
57+
/// <param name="bufferSize">The size of the concurrent queue used to feed the background worker thread. If
58+
/// the thread is unable to process events quickly enough and the queue is filled, depending on
59+
/// <paramref name="blockWhenFull"/> the queue will block or subsequent events will be dropped until
60+
/// room is made in the queue.</param>
61+
/// <param name="blockWhenFull">Block when the queue is full, instead of dropping events.</param>
62+
/// <param name="monitor">Monitor to supply buffer information to. If the monitor implements <see cref="IDisposable"/>, <c>Dispose()</c> will be called to advise of the Sink being <c>Dispose()</c>d.</param>
63+
/// <returns>A <see cref="LoggerConfiguration"/> allowing configuration to continue.</returns>
64+
public static LoggerConfiguration Async(
65+
this LoggerSinkConfiguration loggerSinkConfiguration,
66+
Action<LoggerSinkConfiguration> configure,
67+
IAsyncLogEventSinkMonitor monitor,
68+
int bufferSize,
69+
bool blockWhenFull)
4770
{
4871
return LoggerSinkConfiguration.Wrap(
4972
loggerSinkConfiguration,
50-
wrappedSink => new BackgroundWorkerSink(wrappedSink, bufferSize, blockWhenFull),
73+
wrappedSink =>
74+
{
75+
var sink = new BackgroundWorkerSink(wrappedSink, bufferSize, blockWhenFull, monitor);
76+
monitor?.MonitorState(sink);
77+
return sink;
78+
},
5179
configure);
5280
}
5381

@@ -77,7 +105,7 @@ public static LoggerConfiguration Async(
77105
loggerSinkConfiguration,
78106
wrappedSink =>
79107
{
80-
var sink = new BackgroundWorkerSink(wrappedSink, bufferSize, blockWhenFull);
108+
var sink = new BackgroundWorkerSink(wrappedSink, bufferSize, blockWhenFull, null);
81109
stateLens = sink;
82110
return sink;
83111
},

src/Serilog.Sinks.Async/Sinks/Async/BackgroundWorkerSink.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,16 +14,18 @@ sealed class BackgroundWorkerSink : ILogEventSink, IAsyncLogEventSinkState, IDis
1414
readonly bool _blockWhenFull;
1515
readonly BlockingCollection<LogEvent> _queue;
1616
readonly Task _worker;
17+
readonly IAsyncLogEventSinkMonitor _monitor;
1718

1819
long _droppedMessages;
1920

20-
public BackgroundWorkerSink(ILogEventSink pipeline, int bufferCapacity, bool blockWhenFull)
21+
public BackgroundWorkerSink(ILogEventSink pipeline, int bufferCapacity, bool blockWhenFull, IAsyncLogEventSinkMonitor monitor = null)
2122
{
2223
if (bufferCapacity <= 0) throw new ArgumentOutOfRangeException(nameof(bufferCapacity));
2324
_pipeline = pipeline ?? throw new ArgumentNullException(nameof(pipeline));
2425
_blockWhenFull = blockWhenFull;
2526
_queue = new BlockingCollection<LogEvent>(bufferCapacity);
2627
_worker = Task.Factory.StartNew(Pump, CancellationToken.None, TaskCreationOptions.LongRunning | TaskCreationOptions.DenyChildAttach, TaskScheduler.Default);
28+
_monitor = monitor;
2729
}
2830

2931
public void Emit(LogEvent logEvent)
@@ -62,6 +64,8 @@ public void Dispose()
6264
_worker.Wait();
6365

6466
(_pipeline as IDisposable)?.Dispose();
67+
68+
(_monitor as IDisposable)?.Dispose();
6569
}
6670

6771
void Pump()
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
namespace Serilog.Sinks.Async
2+
{
3+
/// <summary>
4+
/// Defines a mechanism for the Async Sink to provide buffer metadata to facilitate integration into system health checking.
5+
/// </summary>
6+
/// <remarks>If the instance implements <see cref="System.IDisposable"/>, it will be <c>Dispose()</c>d at then time the Sink is.</remarks>
7+
public interface IAsyncLogEventSinkMonitor
8+
{
9+
/// <summary>
10+
/// Invoked by Sink to supply the buffer state hook to the monitor.
11+
/// </summary>
12+
/// <param name="state">The Async Sink's state information interface.</param>
13+
void MonitorState(IAsyncLogEventSinkState state);
14+
}
15+
}

test/Serilog.Sinks.Async.Tests/BackgroundWorkerSinkSpec.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ public BackgroundWorkerSinkSpec()
2525
[Fact]
2626
public void WhenCtorWithNullSink_ThenThrows()
2727
{
28-
Assert.Throws<ArgumentNullException>(() => new BackgroundWorkerSink(null, 10000, false));
28+
Assert.Throws<ArgumentNullException>(() => new BackgroundWorkerSink(null, 10000, false, null));
2929
}
3030

3131
[Fact]

0 commit comments

Comments
 (0)