Skip to content

Commit

Permalink
Merge pull request #99 from serilog/dev
Browse files Browse the repository at this point in the history
2.1.0 Release
  • Loading branch information
nblumhardt authored Oct 24, 2024
2 parents 8dc424e + 9675270 commit 5c6e5df
Show file tree
Hide file tree
Showing 9 changed files with 102 additions and 13 deletions.
Binary file added .DS_Store
Binary file not shown.
4 changes: 2 additions & 2 deletions Build.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ foreach ($src in ls src/*) {
} else {
& dotnet pack -c Release -o ..\..\artifacts --no-build
}
if($LASTEXITCODE -ne 0) { exit 1 }
if($LASTEXITCODE -ne 0) { throw "build failed" }

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

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

Pop-Location
}
Expand Down
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# 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)
# 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)

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.

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

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

```powershell
Install-Package Serilog.Sinks.Async
```sh
dotnet add package Serilog.Sinks.Async
```

Assuming you have already installed the target sink, such as the file sink, move the wrapped sink's configuration within a `WriteTo.Async()` statement:
Expand Down
4 changes: 2 additions & 2 deletions src/Serilog.Sinks.Async/Serilog.Sinks.Async.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

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

<ItemGroup>
<PackageReference Include="Serilog" Version="4.0.0" />
<PackageReference Include="Serilog" Version="4.1.0" />
<PackageReference Include="Nullable" Version="1.3.1" PrivateAssets="all" />
</ItemGroup>

Expand Down
22 changes: 17 additions & 5 deletions src/Serilog.Sinks.Async/Sinks/Async/BackgroundWorkerSink.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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<LogEvent> _queue;
readonly Task _worker;
readonly IAsyncLogEventSinkMonitor? _monitor;

// By contract, set only during initialization, so updates are not synchronized.
ILoggingFailureListener _failureListener = SelfLog.FailureListener;

long _droppedMessages;

Expand All @@ -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
{
Expand All @@ -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);
}
}

Expand Down Expand Up @@ -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);
}
}

Expand All @@ -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));
}
}
19 changes: 18 additions & 1 deletion test/Serilog.Sinks.Async.Tests/BackgroundWorkerSinkTests.cs
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -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<NotImplementedException>(exception);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
<AssemblyOriginatorKeyFile>../../assets/Serilog.snk</AssemblyOriginatorKeyFile>
<SignAssembly>true</SignAssembly>
<PublicSign Condition=" '$(OS)' != 'Windows_NT' ">true</PublicSign>
<LangVersion>12</LangVersion>
</PropertyGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
@@ -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<LogEvent> _events = [];
readonly List<Exception> _exceptions = [];

public IReadOnlyList<LogEvent> Events
{
get
{
lock (_sync)
return _events.ToList();
}
}
public IReadOnlyList<Exception> Exceptions
{
get
{
lock (_sync)
return _exceptions.ToList();
}
}

public void OnLoggingFailed(object sender, LoggingFailureKind kind, string message, IReadOnlyCollection<LogEvent> events,
Exception exception)
{
lock (_sync)
{
if (exception != null)
_exceptions.Add(exception);

foreach (var logEvent in events ?? [])
{
_events.Add(logEvent);
}
}
}
}
13 changes: 13 additions & 0 deletions test/Serilog.Sinks.Async.Tests/Support/NotImplementedSink.cs
Original file line number Diff line number Diff line change
@@ -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();
}
}

0 comments on commit 5c6e5df

Please sign in to comment.