Skip to content

Commit 510db8d

Browse files
committed
Address nblumhardt review comments
1 parent d3b5309 commit 510db8d

File tree

5 files changed

+43
-41
lines changed

5 files changed

+43
-41
lines changed

README.md

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -32,18 +32,18 @@ Because the memory buffer may contain events that have not yet been written to t
3232

3333
### Buffering & Dropping
3434

35-
The default memory buffer feeding the worker thread is capped to 10,000 items, after which arriving events will be dropped. To increase or decrease this limit, specify it when configuring the async sink. One can determine whether events have been dropped via `IQueueState.DroppedMessagesCount` (see Buffer Inspection interface below).
35+
The default memory buffer feeding the worker thread is capped to 10,000 items, after which arriving events will be dropped. To increase or decrease this limit, specify it when configuring the async sink. One can determine whether events have been dropped via `Serilog.Async.IAsyncLogEventSinkState.DroppedMessagesCount` (see Sink State Inspection interface below).
3636

3737
```csharp
3838
// Reduce the buffer to 500 events
3939
.WriteTo.Async(a => a.File("logs/myapp.log"), bufferSize: 500)
4040
```
4141

42-
### Health Monitoring via the Buffer Inspection interface
42+
### Health Monitoring via the Sink State Inspection interface
4343

44-
The Async wrapper is primarily intended to allow one to achieve minimal logging latency at all times, even when writing to sinks that may momentarily block during the course of their processing (e.g., a File sink might block for a low number of ms while flushing). The dropping behavior is an important failsafe in that it avoids having an unbounded buffering behaviour should logging frequency overwhelm the sink, or the sink ingestion throughput degrades to a major degree.
44+
The `Async` wrapper is primarily intended to allow one to achieve minimal logging latency at all times, even when writing to sinks that may momentarily block during the course of their processing (e.g., a `File` Sink might block for a low number of ms while flushing). The dropping behavior is an important failsafe; it avoids having an unbounded buffering behaviour should logging frequency overwhelm the sink, or the sink ingestion throughput degrade to a major degree.
4545

46-
In practice, this configuration (assuming one provisions an adequate `bufferSize`) achieves an efficient and resilient logging configuration that can handle load gracefully. The key risk is of course that events may be dropped when the buffer threshold gets breached. The `inspector` allows one to arrange for your Application's health monitoring mechanism to actively validate that the buffer allocation is not being exceeded in practice.
46+
In practice, this configuration (assuming one provisions an adequate `bufferSize`) achieves an efficient and resilient logging configuration that can handle load safely. The key risk is of course that events get be dropped when the buffer threshold gets breached. The `inspector` allows one to arrange for your Application's health monitoring mechanism to actively validate that the buffer allocation is not being exceeded in practice.
4747

4848
```csharp
4949
// Example check: log message to an out of band alarm channel if logging is showing signs of getting overwhelmed
@@ -54,10 +54,10 @@ In practice, this configuration (assuming one provisions an adequate `bufferSize
5454
}
5555

5656
// Allow a backlog of up to 10,000 items to be maintained (dropping extras if full)
57-
.WriteTo.Async(a => a.File("logs/myapp.log"), inspector: out IQueueState inspector) ...
57+
.WriteTo.Async(a => a.File("logs/myapp.log"), inspector: out Async.IAsyncLogEventSinkState inspector) ...
5858

59-
// Wire the inspector through to health monitoring and/or metrics in order to periodically emit a metric, raise an alarm, etc.
60-
... healthMonitoring.RegisterCheck(() => new PeriodicMonitorCheck(inspector));
59+
// Wire the inspector through to application health monitoring and/or metrics in order to periodically emit a metric, raise an alarm, etc.
60+
... HealthMonitor.RegisterAsyncLogSink(inspector);
6161
```
6262

6363
### Blocking

src/Serilog.Sinks.Async/LoggerConfigurationAsyncExtensions.cs

Lines changed: 3 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -67,12 +67,12 @@ public static LoggerConfiguration Async(
6767
public static LoggerConfiguration Async(
6868
this LoggerSinkConfiguration loggerSinkConfiguration,
6969
Action<LoggerSinkConfiguration> configure,
70-
out IQueueState inspector,
70+
out IAsyncLogEventSinkState inspector,
7171
int bufferSize = 10000,
7272
bool blockWhenFull = false)
7373
{
7474
// Cannot assign directly to the out param from within the lambda, so we need a temp
75-
IQueueState stateLens = null;
75+
IAsyncLogEventSinkState stateLens = null;
7676
var result = LoggerSinkConfiguration.Wrap(
7777
loggerSinkConfiguration,
7878
wrappedSink =>
@@ -86,27 +86,4 @@ public static LoggerConfiguration Async(
8686
return result;
8787
}
8888
}
89-
90-
/// <summary>
91-
/// Provides a way to inspect the current state of Async wrapper's ingestion queue.
92-
/// </summary>
93-
public interface IQueueState
94-
{
95-
/// <summary>
96-
/// Count of items currently awaiting ingestion.
97-
/// </summary>
98-
/// <exception cref="T:System.ObjectDisposedException">The Sink has been disposed.</exception>
99-
int Count { get; }
100-
101-
/// <summary>
102-
/// Accumulated number of messages dropped due to attempted submission having breached <see cref="BufferSize"/> limit.
103-
/// </summary>
104-
long DroppedMessagesCount { get; }
105-
106-
/// <summary>
107-
/// Maximum number of items permitted to be held in the buffer awaiting ingestion.
108-
/// </summary>
109-
/// <exception cref="T:System.ObjectDisposedException">The Sink has been disposed.</exception>
110-
int BufferSize { get; }
111-
}
112-
}
89+
}

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
namespace Serilog.Sinks.Async
1010
{
11-
sealed class BackgroundWorkerSink : ILogEventSink, IQueueState, IDisposable
11+
sealed class BackgroundWorkerSink : ILogEventSink, IAsyncLogEventSinkState, IDisposable
1212
{
1313
readonly ILogEventSink _pipeline;
1414
readonly bool _blockWhenFull;
@@ -79,10 +79,10 @@ void Pump()
7979
}
8080
}
8181

82-
int IQueueState.Count => _queue.Count;
82+
int IAsyncLogEventSinkState.BufferSize => _queue.BoundedCapacity;
8383

84-
int IQueueState.BufferSize => _queue.BoundedCapacity;
84+
int IAsyncLogEventSinkState.Count => _queue.Count;
8585

86-
long IQueueState.DroppedMessagesCount => _droppedMessages;
86+
long IAsyncLogEventSinkState.DroppedMessagesCount => _droppedMessages;
8787
}
8888
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
namespace Serilog.Sinks.Async
2+
{
3+
/// <summary>
4+
/// Provides a way to monitor the state of Async wrapper's ingestion queue.
5+
/// </summary>
6+
public interface IAsyncLogEventSinkState
7+
{
8+
/// <summary>
9+
/// Configured maximum number of items permitted to be held in the buffer awaiting ingestion.
10+
/// </summary>
11+
/// <exception cref="T:System.ObjectDisposedException">The Sink has been disposed.</exception>
12+
int BufferSize { get; }
13+
14+
/// <summary>
15+
/// Current moment-in-time Count of items currently awaiting ingestion.
16+
/// </summary>
17+
/// <exception cref="T:System.ObjectDisposedException">The Sink has been disposed.</exception>
18+
int Count { get; }
19+
20+
/// <summary>
21+
/// Accumulated number of messages dropped due to breach of <see cref="BufferSize"/> limit.
22+
/// </summary>
23+
long DroppedMessagesCount { get; }
24+
}
25+
}

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ public async Task GivenDefaultConfig_WhenRequestsExceedCapacity_DoesNotBlock()
106106

107107
// Allow at least one to propagate
108108
await Task.Delay(TimeSpan.FromSeconds(1)).ConfigureAwait(false);
109-
Assert.NotEqual(0, ((IQueueState)sink).DroppedMessagesCount);
109+
Assert.NotEqual(0, ((IAsyncLogEventSinkState)sink).DroppedMessagesCount);
110110
}
111111
// Sanity check the overall timing
112112
batchTiming.Stop();
@@ -145,7 +145,7 @@ from e in _innerSink.Events
145145
Assert.InRange(2, 2 * 3 / 2 - 1, propagatedExcludingFinal.Count());
146146
// Final event should have made it through
147147
Assert.Contains(_innerSink.Events, x => Object.ReferenceEquals(finalEvent, x));
148-
Assert.NotEqual(0, ((IQueueState)sink).DroppedMessagesCount);
148+
Assert.NotEqual(0, ((IAsyncLogEventSinkState)sink).DroppedMessagesCount);
149149
}
150150
}
151151

@@ -184,7 +184,7 @@ public async Task GivenConfiguredToBlock_WhenQueueFilled_ThenBlocks()
184184

185185
// No events should be dropped
186186
Assert.Equal(3, _innerSink.Events.Count);
187-
Assert.Equal(0, ((IQueueState)sink).DroppedMessagesCount);
187+
Assert.Equal(0, ((IAsyncLogEventSinkState)sink).DroppedMessagesCount);
188188
}
189189
}
190190

@@ -195,7 +195,7 @@ public void InspectorOutParameterAffordsHealthMonitoringHook()
195195
// 2 spaces in queue; 1 would make the second log entry eligible for dropping if consumer does not activate instantaneously
196196
var bufferSize = 2;
197197
using (var logger = new LoggerConfiguration()
198-
.WriteTo.Async(w => w.Sink(collector), bufferSize: 2, inspector: out IQueueState inspector)
198+
.WriteTo.Async(w => w.Sink(collector), bufferSize: 2, inspector: out IAsyncLogEventSinkState inspector)
199199
.CreateLogger())
200200
{
201201
Assert.Equal(bufferSize, inspector.BufferSize);

0 commit comments

Comments
 (0)