Skip to content

Commit 5c6e5df

Browse files
authored
Merge pull request #99 from serilog/dev
2.1.0 Release
2 parents 8dc424e + 9675270 commit 5c6e5df

File tree

9 files changed

+102
-13
lines changed

9 files changed

+102
-13
lines changed

.DS_Store

6 KB
Binary file not shown.

Build.ps1

+2-2
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ foreach ($src in ls src/*) {
2929
} else {
3030
& dotnet pack -c Release -o ..\..\artifacts --no-build
3131
}
32-
if($LASTEXITCODE -ne 0) { exit 1 }
32+
if($LASTEXITCODE -ne 0) { throw "build failed" }
3333

3434
Pop-Location
3535
}
@@ -40,7 +40,7 @@ foreach ($test in ls test/*.Tests) {
4040
echo "build: Testing project in $test"
4141

4242
& dotnet test -c Release
43-
if($LASTEXITCODE -ne 0) { exit 3 }
43+
if($LASTEXITCODE -ne 0) { throw "tests failed" }
4444

4545
Pop-Location
4646
}

README.md

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Serilog.Sinks.Async [![Build status](https://ci.appveyor.com/api/projects/status/gvk0wl7aows14spn?svg=true)](https://ci.appveyor.com/project/serilog/serilog-sinks-async) [![NuGet](https://img.shields.io/nuget/v/Serilog.Sinks.Async.svg)](https://www.nuget.org/packages/Serilog.Sinks.Async) [![Join the chat at https://gitter.im/serilog/serilog](https://img.shields.io/gitter/room/serilog/serilog.svg)](https://gitter.im/serilog/serilog)
1+
# Serilog.Sinks.Async [![Build status](https://ci.appveyor.com/api/projects/status/gvk0wl7aows14spn?svg=true)](https://ci.appveyor.com/project/serilog/serilog-sinks-async) [![NuGet](https://img.shields.io/nuget/v/Serilog.Sinks.Async.svg)](https://www.nuget.org/packages/Serilog.Sinks.Async)
22

33
An asynchronous wrapper for other [Serilog](https://serilog.net) sinks. Use this sink to reduce the overhead of logging calls by delegating work to a background thread. This is especially suited to non-batching sinks like the [File](https://github.com/serilog/serilog-sinks-file) and [RollingFile](https://github.com/serilog/serilog-sinks-rollingfile) sinks that may be affected by I/O bottlenecks.
44

@@ -8,8 +8,8 @@ An asynchronous wrapper for other [Serilog](https://serilog.net) sinks. Use this
88

99
Install from [NuGet](https://nuget.org/packages/serilog.sinks.async):
1010

11-
```powershell
12-
Install-Package Serilog.Sinks.Async
11+
```sh
12+
dotnet add package Serilog.Sinks.Async
1313
```
1414

1515
Assuming you have already installed the target sink, such as the file sink, move the wrapped sink's configuration within a `WriteTo.Async()` statement:

src/Serilog.Sinks.Async/Serilog.Sinks.Async.csproj

+2-2
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
<PropertyGroup>
44
<Description>Asynchronous sink wrapper for Serilog.</Description>
5-
<VersionPrefix>2.0.0</VersionPrefix>
5+
<VersionPrefix>2.1.0</VersionPrefix>
66
<Authors>Jezz Santos;Serilog Contributors</Authors>
77
<!-- .NET Framework version targeting is frozen at these two TFMs. -->
88
<TargetFrameworks Condition=" '$(OS)' == 'Windows_NT'">net471;net462</TargetFrameworks>
@@ -29,7 +29,7 @@
2929
</PropertyGroup>
3030

3131
<ItemGroup>
32-
<PackageReference Include="Serilog" Version="4.0.0" />
32+
<PackageReference Include="Serilog" Version="4.1.0" />
3333
<PackageReference Include="Nullable" Version="1.3.1" PrivateAssets="all" />
3434
</ItemGroup>
3535

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

+17-5
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,16 @@
2222

2323
namespace Serilog.Sinks.Async;
2424

25-
sealed class BackgroundWorkerSink : ILogEventSink, IAsyncLogEventSinkInspector, IDisposable
25+
sealed class BackgroundWorkerSink : ILogEventSink, IAsyncLogEventSinkInspector, IDisposable, ISetLoggingFailureListener
2626
{
2727
readonly ILogEventSink _wrappedSink;
2828
readonly bool _blockWhenFull;
2929
readonly BlockingCollection<LogEvent> _queue;
3030
readonly Task _worker;
3131
readonly IAsyncLogEventSinkMonitor? _monitor;
32+
33+
// By contract, set only during initialization, so updates are not synchronized.
34+
ILoggingFailureListener _failureListener = SelfLog.FailureListener;
3235

3336
long _droppedMessages;
3437

@@ -46,7 +49,10 @@ public BackgroundWorkerSink(ILogEventSink wrappedSink, int bufferCapacity, bool
4649
public void Emit(LogEvent logEvent)
4750
{
4851
if (_queue.IsAddingCompleted)
52+
{
53+
_failureListener.OnLoggingFailed(this, LoggingFailureKind.Final, "the sink has been disposed", [logEvent], null);
4954
return;
55+
}
5056

5157
try
5258
{
@@ -59,14 +65,15 @@ public void Emit(LogEvent logEvent)
5965
if (!_queue.TryAdd(logEvent))
6066
{
6167
Interlocked.Increment(ref _droppedMessages);
62-
SelfLog.WriteLine("{0} unable to enqueue, capacity {1}", typeof(BackgroundWorkerSink), _queue.BoundedCapacity);
68+
_failureListener.OnLoggingFailed(this, LoggingFailureKind.Permanent, $"unable to enqueue, capacity {_queue.BoundedCapacity}", [logEvent], null);
6369
}
6470
}
6571
}
66-
catch (InvalidOperationException)
72+
catch (InvalidOperationException ex)
6773
{
6874
// Thrown in the event of a race condition when we try to add another event after
6975
// CompleteAdding has been called
76+
_failureListener.OnLoggingFailed(this, LoggingFailureKind.Final, "the sink has been disposed", [logEvent], ex);
7077
}
7178
}
7279

@@ -95,13 +102,13 @@ void Pump()
95102
}
96103
catch (Exception ex)
97104
{
98-
SelfLog.WriteLine("{0} failed to emit event to wrapped sink: {1}", typeof(BackgroundWorkerSink), ex);
105+
_failureListener.OnLoggingFailed(this, LoggingFailureKind.Permanent, "failed to emit event to wrapped sink", [next], ex);
99106
}
100107
}
101108
}
102109
catch (Exception fatal)
103110
{
104-
SelfLog.WriteLine("{0} fatal error in worker thread: {1}", typeof(BackgroundWorkerSink), fatal);
111+
_failureListener.OnLoggingFailed(this, LoggingFailureKind.Final, "fatal error in worker thread", null, fatal);
105112
}
106113
}
107114

@@ -110,4 +117,9 @@ void Pump()
110117
int IAsyncLogEventSinkInspector.Count => _queue.Count;
111118

112119
long IAsyncLogEventSinkInspector.DroppedMessagesCount => _droppedMessages;
120+
121+
public void SetFailureListener(ILoggingFailureListener failureListener)
122+
{
123+
_failureListener = failureListener ?? throw new ArgumentNullException(nameof(failureListener));
124+
}
113125
}

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

+18-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
using Serilog.Sinks.Async.Tests.Support;
1+
using System;
2+
using Serilog.Events;
3+
using Serilog.Sinks.Async.Tests.Support;
24
using Xunit;
35

46
namespace Serilog.Sinks.Async.Tests;
@@ -50,4 +52,19 @@ public void CtorAndDisposeInformMonitor()
5052

5153
Assert.Null(monitor.Inspector);
5254
}
55+
56+
[Fact]
57+
public void SupportsLoggingFailureListener()
58+
{
59+
var failureListener = new CollectingFailureListener();
60+
var sink = new BackgroundWorkerSink(new NotImplementedSink(), 1, false, null);
61+
sink.SetFailureListener(failureListener);
62+
var evt = new LogEvent(DateTimeOffset.Now, LogEventLevel.Information, null, MessageTemplate.Empty, []);
63+
sink.Emit(evt);
64+
sink.Dispose();
65+
var collected = Assert.Single(failureListener.Events);
66+
Assert.Same(evt, collected);
67+
var exception = Assert.Single(failureListener.Exceptions);
68+
Assert.IsType<NotImplementedException>(exception);
69+
}
5370
}

test/Serilog.Sinks.Async.Tests/Serilog.Sinks.Async.Tests.csproj

+1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
<AssemblyOriginatorKeyFile>../../assets/Serilog.snk</AssemblyOriginatorKeyFile>
77
<SignAssembly>true</SignAssembly>
88
<PublicSign Condition=" '$(OS)' != 'Windows_NT' ">true</PublicSign>
9+
<LangVersion>12</LangVersion>
910
</PropertyGroup>
1011

1112
<ItemGroup>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using Serilog.Core;
5+
using Serilog.Events;
6+
7+
namespace Serilog.Sinks.Async.Tests.Support;
8+
9+
class CollectingFailureListener: ILoggingFailureListener
10+
{
11+
readonly object _sync = new();
12+
readonly List<LogEvent> _events = [];
13+
readonly List<Exception> _exceptions = [];
14+
15+
public IReadOnlyList<LogEvent> Events
16+
{
17+
get
18+
{
19+
lock (_sync)
20+
return _events.ToList();
21+
}
22+
}
23+
public IReadOnlyList<Exception> Exceptions
24+
{
25+
get
26+
{
27+
lock (_sync)
28+
return _exceptions.ToList();
29+
}
30+
}
31+
32+
public void OnLoggingFailed(object sender, LoggingFailureKind kind, string message, IReadOnlyCollection<LogEvent> events,
33+
Exception exception)
34+
{
35+
lock (_sync)
36+
{
37+
if (exception != null)
38+
_exceptions.Add(exception);
39+
40+
foreach (var logEvent in events ?? [])
41+
{
42+
_events.Add(logEvent);
43+
}
44+
}
45+
}
46+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
using System;
2+
using Serilog.Core;
3+
using Serilog.Events;
4+
5+
namespace Serilog.Sinks.Async.Tests.Support;
6+
7+
class NotImplementedSink: ILogEventSink
8+
{
9+
public void Emit(LogEvent logEvent)
10+
{
11+
throw new NotImplementedException();
12+
}
13+
}

0 commit comments

Comments
 (0)