From d8b6e94734216a42fb5214fbf7befe19b592e9e4 Mon Sep 17 00:00:00 2001 From: Mariusz Zielinski Date: Fri, 28 Jul 2017 01:25:02 +0200 Subject: [PATCH] Added Suspend and Reset methods to LogContext to make possible clearing enrichers especially in async context. --- src/Serilog/Context/LogContext.cs | 28 ++++++++++ test/Serilog.Tests/Context/LogContextTests.cs | 56 +++++++++++++++++++ 2 files changed, 84 insertions(+) diff --git a/src/Serilog/Context/LogContext.cs b/src/Serilog/Context/LogContext.cs index feeef11eb..e969f169e 100644 --- a/src/Serilog/Context/LogContext.cs +++ b/src/Serilog/Context/LogContext.cs @@ -150,6 +150,34 @@ public static ILogEventEnricher Clone() return new SafeAggregateEnricher(stack); } + /// + /// Remove all enrichers from , returning + /// that must later be used to restore enrichers that were on the stack before was called. + /// + /// A token that must be disposed, in order, to restore properties back to the stack. + public static IDisposable Suspend() + { + var stack = GetOrCreateEnricherStack(); + var bookmark = new ContextStackBookmark(stack); + + Enrichers = ImmutableStack.Empty; + + return bookmark; + } + + /// + /// Remove all enrichers from for current async scope. + /// + public static void Reset() + { + var enrichers = GetOrCreateEnricherStack(); + if (!enrichers.IsEmpty) + { + enrichers = ImmutableStack.Empty; + Enrichers = enrichers; + } + } + static ImmutableStack GetOrCreateEnricherStack() { var enrichers = Enrichers; diff --git a/test/Serilog.Tests/Context/LogContextTests.cs b/test/Serilog.Tests/Context/LogContextTests.cs index 44d313473..7fc0b62df 100644 --- a/test/Serilog.Tests/Context/LogContextTests.cs +++ b/test/Serilog.Tests/Context/LogContextTests.cs @@ -199,6 +199,62 @@ public async Task ContextPropertiesCrossAsyncCalls() } } + [Fact] + public async Task ContextEnrichersInAsyncScopeCanBeCleared() + { + LogEvent lastEvent = null; + + var log = new LoggerConfiguration() + .Enrich.FromLogContext() + .WriteTo.Sink(new DelegatingSink(e => lastEvent = e)) + .CreateLogger(); + + using (LogContext.Push(new PropertyEnricher("A", 1))) + { + await Task.Run(() => + { + LogContext.Reset(); + log.Write(Some.InformationEvent()); + }); + + Assert.Empty(lastEvent.Properties); + + // Reset should only work for current async scope, outside of it previous Context + // instance should be available again. + log.Write(Some.InformationEvent()); + Assert.Equal(1, lastEvent.Properties["A"].LiteralValue()); + } + } + + [Fact] + public async Task ContextEnrichersCanBeTemporarilyCleared() + { + LogEvent lastEvent = null; + + var log = new LoggerConfiguration() + .Enrich.FromLogContext() + .WriteTo.Sink(new DelegatingSink(e => lastEvent = e)) + .CreateLogger(); + + using (LogContext.Push(new PropertyEnricher("A", 1))) + { + using (LogContext.Suspend()) + { + await Task.Run(() => + { + log.Write(Some.InformationEvent()); + }); + + Assert.Empty(lastEvent.Properties); + } + + // Suspend should only work for scope of using. After calling Dispose all enrichers + // should be restored. + log.Write(Some.InformationEvent()); + Assert.Equal(1, lastEvent.Properties["A"].LiteralValue()); + } + } + #if APPDOMAIN // Must not actually try to pass context across domains, // since user property types may not be serializable.