From 010449c0735db653d8f450fc24f7ba9002b541b9 Mon Sep 17 00:00:00 2001 From: Nicholas Blumhardt Date: Fri, 2 Feb 2024 13:07:39 +1000 Subject: [PATCH] Prevent capturing of the sink-creation-time ExecutionContext by the batching loop/batched sink --- .../PeriodicBatching/PeriodicBatchingSink.cs | 6 ++++- .../PeriodicBatchingSinkTests.cs | 23 +++++++++++++++++++ .../Support/CallbackBatchedSink.cs | 16 +++++++++++++ 3 files changed, 44 insertions(+), 1 deletion(-) create mode 100644 test/Serilog.Sinks.PeriodicBatching.Tests/Support/CallbackBatchedSink.cs diff --git a/src/Serilog.Sinks.PeriodicBatching/Sinks/PeriodicBatching/PeriodicBatchingSink.cs b/src/Serilog.Sinks.PeriodicBatching/Sinks/PeriodicBatching/PeriodicBatchingSink.cs index 2415ea0..78eae64 100644 --- a/src/Serilog.Sinks.PeriodicBatching/Sinks/PeriodicBatching/PeriodicBatchingSink.cs +++ b/src/Serilog.Sinks.PeriodicBatching/Sinks/PeriodicBatching/PeriodicBatchingSink.cs @@ -75,7 +75,11 @@ public PeriodicBatchingSink(IBatchedLogEventSink batchedSink, PeriodicBatchingSi _waitForShutdownSignal = Task.Delay(Timeout.InfiniteTimeSpan, _shutdownSignal.Token) .ContinueWith(e => e.Exception, TaskContinuationOptions.OnlyOnFaulted); - _runLoop = Task.Run(LoopAsync); + // The conditional here is no longer required in .NET 8+ (dotnet/runtime#82912) + using (ExecutionContext.IsFlowSuppressed() ? (IDisposable?)null : ExecutionContext.SuppressFlow()) + { + _runLoop = Task.Run(LoopAsync); + } } /// diff --git a/test/Serilog.Sinks.PeriodicBatching.Tests/PeriodicBatchingSinkTests.cs b/test/Serilog.Sinks.PeriodicBatching.Tests/PeriodicBatchingSinkTests.cs index e2399bf..22a7fac 100644 --- a/test/Serilog.Sinks.PeriodicBatching.Tests/PeriodicBatchingSinkTests.cs +++ b/test/Serilog.Sinks.PeriodicBatching.Tests/PeriodicBatchingSinkTests.cs @@ -86,4 +86,27 @@ public void WhenAnEventIsEnqueuedItIsWrittenToABatchOnDisposeWhileRunning() Assert.True(bs.IsDisposed); Assert.False(bs.WasCalledAfterDisposal); } + + [Fact] + public void ExecutionContextDoesNotFlowToBatchedSink() + { + var local = new AsyncLocal + { + Value = 5 + }; + + var observed = 17; + var bs = new CallbackBatchedSink(_ => + { + observed = local.Value; + return Task.CompletedTask; + }); + + var pbs = new PeriodicBatchingSink(bs, new()); + var evt = Some.InformationEvent(); + pbs.Emit(evt); + pbs.Dispose(); + + Assert.Equal(default(int), observed); + } } \ No newline at end of file diff --git a/test/Serilog.Sinks.PeriodicBatching.Tests/Support/CallbackBatchedSink.cs b/test/Serilog.Sinks.PeriodicBatching.Tests/Support/CallbackBatchedSink.cs new file mode 100644 index 0000000..eaf3459 --- /dev/null +++ b/test/Serilog.Sinks.PeriodicBatching.Tests/Support/CallbackBatchedSink.cs @@ -0,0 +1,16 @@ +using Serilog.Events; + +namespace Serilog.Sinks.PeriodicBatching.Tests.Support; + +class CallbackBatchedSink(Func, Task> callback) : IBatchedLogEventSink +{ + public Task EmitBatchAsync(IEnumerable batch) + { + return callback(batch); + } + + public Task OnEmptyBatchAsync() + { + return Task.CompletedTask; + } +}