diff --git a/.DS_Store b/.DS_Store
new file mode 100644
index 0000000..ae3a3c9
Binary files /dev/null and b/.DS_Store differ
diff --git a/src/Serilog.Sinks.Async/Serilog.Sinks.Async.csproj b/src/Serilog.Sinks.Async/Serilog.Sinks.Async.csproj
index 2301325..a073870 100644
--- a/src/Serilog.Sinks.Async/Serilog.Sinks.Async.csproj
+++ b/src/Serilog.Sinks.Async/Serilog.Sinks.Async.csproj
@@ -2,7 +2,7 @@
Asynchronous sink wrapper for Serilog.
- 2.0.1
+ 2.1.0
Jezz Santos;Serilog Contributors
net471;net462
@@ -29,7 +29,7 @@
-
+
diff --git a/src/Serilog.Sinks.Async/Sinks/Async/BackgroundWorkerSink.cs b/src/Serilog.Sinks.Async/Sinks/Async/BackgroundWorkerSink.cs
index e755cf3..f7c16af 100644
--- a/src/Serilog.Sinks.Async/Sinks/Async/BackgroundWorkerSink.cs
+++ b/src/Serilog.Sinks.Async/Sinks/Async/BackgroundWorkerSink.cs
@@ -22,13 +22,16 @@
namespace Serilog.Sinks.Async;
-sealed class BackgroundWorkerSink : ILogEventSink, IAsyncLogEventSinkInspector, IDisposable
+sealed class BackgroundWorkerSink : ILogEventSink, IAsyncLogEventSinkInspector, IDisposable, ISetLoggingFailureListener
{
readonly ILogEventSink _wrappedSink;
readonly bool _blockWhenFull;
readonly BlockingCollection _queue;
readonly Task _worker;
readonly IAsyncLogEventSinkMonitor? _monitor;
+
+ // By contract, set only during initialization, so updates are not synchronized.
+ ILoggingFailureListener _failureListener = SelfLog.FailureListener;
long _droppedMessages;
@@ -46,7 +49,10 @@ public BackgroundWorkerSink(ILogEventSink wrappedSink, int bufferCapacity, bool
public void Emit(LogEvent logEvent)
{
if (_queue.IsAddingCompleted)
+ {
+ _failureListener.OnLoggingFailed(this, LoggingFailureKind.Final, "the sink has been disposed", [logEvent], null);
return;
+ }
try
{
@@ -59,14 +65,15 @@ public void Emit(LogEvent logEvent)
if (!_queue.TryAdd(logEvent))
{
Interlocked.Increment(ref _droppedMessages);
- SelfLog.WriteLine("{0} unable to enqueue, capacity {1}", typeof(BackgroundWorkerSink), _queue.BoundedCapacity);
+ _failureListener.OnLoggingFailed(this, LoggingFailureKind.Permanent, $"unable to enqueue, capacity {_queue.BoundedCapacity}", [logEvent], null);
}
}
}
- catch (InvalidOperationException)
+ catch (InvalidOperationException ex)
{
// Thrown in the event of a race condition when we try to add another event after
// CompleteAdding has been called
+ _failureListener.OnLoggingFailed(this, LoggingFailureKind.Final, "the sink has been disposed", [logEvent], ex);
}
}
@@ -95,13 +102,13 @@ void Pump()
}
catch (Exception ex)
{
- SelfLog.WriteLine("{0} failed to emit event to wrapped sink: {1}", typeof(BackgroundWorkerSink), ex);
+ _failureListener.OnLoggingFailed(this, LoggingFailureKind.Permanent, "failed to emit event to wrapped sink", [next], ex);
}
}
}
catch (Exception fatal)
{
- SelfLog.WriteLine("{0} fatal error in worker thread: {1}", typeof(BackgroundWorkerSink), fatal);
+ _failureListener.OnLoggingFailed(this, LoggingFailureKind.Final, "fatal error in worker thread", null, fatal);
}
}
@@ -110,4 +117,9 @@ void Pump()
int IAsyncLogEventSinkInspector.Count => _queue.Count;
long IAsyncLogEventSinkInspector.DroppedMessagesCount => _droppedMessages;
+
+ public void SetFailureListener(ILoggingFailureListener failureListener)
+ {
+ _failureListener = failureListener ?? throw new ArgumentNullException(nameof(failureListener));
+ }
}
\ No newline at end of file
diff --git a/test/Serilog.Sinks.Async.Tests/BackgroundWorkerSinkTests.cs b/test/Serilog.Sinks.Async.Tests/BackgroundWorkerSinkTests.cs
index 50b6ce4..bd006c2 100644
--- a/test/Serilog.Sinks.Async.Tests/BackgroundWorkerSinkTests.cs
+++ b/test/Serilog.Sinks.Async.Tests/BackgroundWorkerSinkTests.cs
@@ -1,4 +1,6 @@
-using Serilog.Sinks.Async.Tests.Support;
+using System;
+using Serilog.Events;
+using Serilog.Sinks.Async.Tests.Support;
using Xunit;
namespace Serilog.Sinks.Async.Tests;
@@ -50,4 +52,19 @@ public void CtorAndDisposeInformMonitor()
Assert.Null(monitor.Inspector);
}
+
+ [Fact]
+ public void SupportsLoggingFailureListener()
+ {
+ var failureListener = new CollectingFailureListener();
+ var sink = new BackgroundWorkerSink(new NotImplementedSink(), 1, false, null);
+ sink.SetFailureListener(failureListener);
+ var evt = new LogEvent(DateTimeOffset.Now, LogEventLevel.Information, null, MessageTemplate.Empty, []);
+ sink.Emit(evt);
+ sink.Dispose();
+ var collected = Assert.Single(failureListener.Events);
+ Assert.Same(evt, collected);
+ var exception = Assert.Single(failureListener.Exceptions);
+ Assert.IsType(exception);
+ }
}
\ No newline at end of file
diff --git a/test/Serilog.Sinks.Async.Tests/Serilog.Sinks.Async.Tests.csproj b/test/Serilog.Sinks.Async.Tests/Serilog.Sinks.Async.Tests.csproj
index 644e6db..4dfe00a 100644
--- a/test/Serilog.Sinks.Async.Tests/Serilog.Sinks.Async.Tests.csproj
+++ b/test/Serilog.Sinks.Async.Tests/Serilog.Sinks.Async.Tests.csproj
@@ -6,6 +6,7 @@
../../assets/Serilog.snk
true
true
+ 12
diff --git a/test/Serilog.Sinks.Async.Tests/Support/CollectingFailureListener.cs b/test/Serilog.Sinks.Async.Tests/Support/CollectingFailureListener.cs
new file mode 100644
index 0000000..e35cc51
--- /dev/null
+++ b/test/Serilog.Sinks.Async.Tests/Support/CollectingFailureListener.cs
@@ -0,0 +1,46 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Serilog.Core;
+using Serilog.Events;
+
+namespace Serilog.Sinks.Async.Tests.Support;
+
+class CollectingFailureListener: ILoggingFailureListener
+{
+ readonly object _sync = new();
+ readonly List _events = [];
+ readonly List _exceptions = [];
+
+ public IReadOnlyList Events
+ {
+ get
+ {
+ lock (_sync)
+ return _events.ToList();
+ }
+ }
+ public IReadOnlyList Exceptions
+ {
+ get
+ {
+ lock (_sync)
+ return _exceptions.ToList();
+ }
+ }
+
+ public void OnLoggingFailed(object sender, LoggingFailureKind kind, string message, IReadOnlyCollection events,
+ Exception exception)
+ {
+ lock (_sync)
+ {
+ if (exception != null)
+ _exceptions.Add(exception);
+
+ foreach (var logEvent in events ?? [])
+ {
+ _events.Add(logEvent);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/test/Serilog.Sinks.Async.Tests/Support/NotImplementedSink.cs b/test/Serilog.Sinks.Async.Tests/Support/NotImplementedSink.cs
new file mode 100644
index 0000000..e0898c8
--- /dev/null
+++ b/test/Serilog.Sinks.Async.Tests/Support/NotImplementedSink.cs
@@ -0,0 +1,13 @@
+using System;
+using Serilog.Core;
+using Serilog.Events;
+
+namespace Serilog.Sinks.Async.Tests.Support;
+
+class NotImplementedSink: ILogEventSink
+{
+ public void Emit(LogEvent logEvent)
+ {
+ throw new NotImplementedException();
+ }
+}
\ No newline at end of file