Skip to content

Commit

Permalink
Added Suspend and Reset methods to LogContext to make possible cleari…
Browse files Browse the repository at this point in the history
…ng enrichers especially in async context.
  • Loading branch information
mariozski committed Jul 27, 2017
1 parent f989fd6 commit d8b6e94
Show file tree
Hide file tree
Showing 2 changed files with 84 additions and 0 deletions.
28 changes: 28 additions & 0 deletions src/Serilog/Context/LogContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,34 @@ public static ILogEventEnricher Clone()
return new SafeAggregateEnricher(stack);
}

/// <summary>
/// Remove all enrichers from <see cref="LogContext"/>, returning <see cref="IDisposable"/>
/// that must later be used to restore enrichers that were on the stack before <see cref="Suspend"/> was called.
/// </summary>
/// <returns>A token that must be disposed, in order, to restore properties back to the stack.</returns>
public static IDisposable Suspend()
{
var stack = GetOrCreateEnricherStack();
var bookmark = new ContextStackBookmark(stack);

Enrichers = ImmutableStack<ILogEventEnricher>.Empty;

return bookmark;
}

/// <summary>
/// Remove all enrichers from <see cref="LogContext"/> for current async scope.
/// </summary>
public static void Reset()
{
var enrichers = GetOrCreateEnricherStack();
if (!enrichers.IsEmpty)
{
enrichers = ImmutableStack<ILogEventEnricher>.Empty;
Enrichers = enrichers;
}
}

static ImmutableStack<ILogEventEnricher> GetOrCreateEnricherStack()
{
var enrichers = Enrichers;
Expand Down
56 changes: 56 additions & 0 deletions test/Serilog.Tests/Context/LogContextTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down

0 comments on commit d8b6e94

Please sign in to comment.