Skip to content

Commit

Permalink
LoggerEnrichmentConfiguration.Wrap()
Browse files Browse the repository at this point in the history
  • Loading branch information
nblumhardt committed May 29, 2019
1 parent a1e9850 commit ac5400b
Show file tree
Hide file tree
Showing 9 changed files with 133 additions and 9 deletions.
1 change: 1 addition & 0 deletions Serilog.sln.DotSettings
Original file line number Diff line number Diff line change
Expand Up @@ -558,6 +558,7 @@ II.2.12 <HandlesEvent />

<s:String x:Key="/Default/FilterSettingsManager/AttributeFilterXml/@EntryValue">&lt;data /&gt;</s:String>
<s:String x:Key="/Default/FilterSettingsManager/CoverageFilterXml/@EntryValue">&lt;data&gt;&lt;IncludeFilters /&gt;&lt;ExcludeFilters /&gt;&lt;/data&gt;</s:String>
<s:Boolean x:Key="/Default/UserDictionary/Words/=auditable/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=cacheable/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=destructure/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Enricher/@EntryIndexedValue">True</s:Boolean>
Expand Down
54 changes: 54 additions & 0 deletions src/Serilog/Configuration/LoggerEnrichmentConfiguration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,12 @@
// limitations under the License.

using System;
using System.Collections.Generic;
using System.Linq;
using Serilog.Core;
using Serilog.Core.Enrichers;
using Serilog.Core.Sinks;
using Serilog.Debugging;
using Serilog.Enrichers;

namespace Serilog.Configuration
Expand Down Expand Up @@ -85,5 +89,55 @@ public LoggerConfiguration WithProperty(string name, object value, bool destruct
/// <returns>Configuration object allowing method chaining.</returns>
/// <exception cref="ArgumentNullException"></exception>
public LoggerConfiguration FromLogContext() => With<LogContextEnricher>();

/// <summary>
/// Helper method for wrapping sinks.
/// </summary>
/// <param name="loggerEnrichmentConfiguration">The parent enrichment configuration.</param>
/// <param name="wrapEnricher">A function that allows for wrapping <see cref="ILogEventEnricher"/>s
/// added in <paramref name="configureWrappedEnricher"/>.</param>
/// <param name="configureWrappedEnricher">An action that configures enrichers to be wrapped in <paramref name="wrapEnricher"/>.</param>
/// <returns>Configuration object allowing method chaining.</returns>
public static LoggerConfiguration Wrap(
LoggerEnrichmentConfiguration loggerEnrichmentConfiguration,
Func<ILogEventEnricher, ILogEventEnricher> wrapEnricher,
Action<LoggerEnrichmentConfiguration> configureWrappedEnricher)
{
if (loggerEnrichmentConfiguration == null) throw new ArgumentNullException(nameof(loggerEnrichmentConfiguration));
if (wrapEnricher == null) throw new ArgumentNullException(nameof(wrapEnricher));
if (configureWrappedEnricher == null) throw new ArgumentNullException(nameof(configureWrappedEnricher));

var enrichersToWrap = new List<ILogEventEnricher>();

var capturingConfiguration = new LoggerConfiguration();
var capturingLoggerEnrichmentConfiguration = new LoggerEnrichmentConfiguration(
capturingConfiguration,
enrichersToWrap.Add);

// `Enrich.With()` will return the capturing configuration; this ensures chained `Enrich` gets back
// to the capturing enrichment configuration, enabling `Enrich.WithX().Enrich.WithY()`.
capturingConfiguration.Enrich = capturingLoggerEnrichmentConfiguration;

configureWrappedEnricher(capturingLoggerEnrichmentConfiguration);

if (enrichersToWrap.Count == 0)
return loggerEnrichmentConfiguration._loggerConfiguration;

var enclosed = enrichersToWrap.Count == 1 ?
enrichersToWrap.Single() :
new SafeAggregateEnricher(enrichersToWrap);

var wrappedEnricher = wrapEnricher(enclosed);

// ReSharper disable once SuspiciousTypeConversion.Global
if (!(wrappedEnricher is IDisposable))
{
SelfLog.WriteLine("Wrapping enricher {0} does not implement IDisposable; to ensure " +
"wrapped sinks are properly flushed, wrappers should dispose " +
"their wrapped contents", wrappedEnricher);
}

return loggerEnrichmentConfiguration.With(wrappedEnricher);
}
}
}
2 changes: 1 addition & 1 deletion src/Serilog/Core/Pipeline/SilentLogger.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ class SilentLogger : ILogger
{
public static readonly ILogger Instance = new SilentLogger();

private SilentLogger()
SilentLogger()
{
}

Expand Down
3 changes: 2 additions & 1 deletion src/Serilog/LoggerConfiguration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ public class LoggerConfiguration
public LoggerConfiguration()
{
WriteTo = new LoggerSinkConfiguration(this, s => _logEventSinks.Add(s), ApplyInheritedConfiguration);
Enrich = new LoggerEnrichmentConfiguration(this, e => _enrichers.Add(e));
}

void ApplyInheritedConfiguration(LoggerConfiguration child)
Expand Down Expand Up @@ -102,7 +103,7 @@ public LoggerMinimumLevelConfiguration MinimumLevel
/// Configures enrichment of <see cref="LogEvent"/>s. Enrichers can add, remove and
/// modify the properties associated with events.
/// </summary>
public LoggerEnrichmentConfiguration Enrich => new LoggerEnrichmentConfiguration(this, e => _enrichers.Add(e));
public LoggerEnrichmentConfiguration Enrich { get; internal set; }

/// <summary>
/// Configures global filtering of <see cref="LogEvent"/>s.
Expand Down
4 changes: 2 additions & 2 deletions src/Serilog/Serilog.csproj
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<Description>Simple .NET logging with fully-structured events</Description>
<VersionPrefix>2.8.1</VersionPrefix>
<VersionPrefix>2.9.0</VersionPrefix>
<Authors>Serilog Contributors</Authors>
<TargetFrameworks>net45;net46;netstandard1.0;netstandard1.3;netstandard2.0</TargetFrameworks>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
Expand Down
27 changes: 24 additions & 3 deletions test/Serilog.Tests/LoggerConfigurationTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Serilog.Configuration;
using TestDummies;
using Xunit;

Expand Down Expand Up @@ -355,7 +356,7 @@ public void MaximumStringLengthNOTEffectiveForObject()

class ToStringOfLength
{
private readonly int _toStringOfLength;
readonly int _toStringOfLength;

public ToStringOfLength(int toStringOfLength)
{
Expand Down Expand Up @@ -427,7 +428,7 @@ public void MaximumCollectionCountNotEffectiveForDictionaryWithAsManyKeysAsLimit
Assert.Contains("2", limitedCollection);
}

private static string LogAndGetAsString(object x, Func<LoggerConfiguration, LoggerConfiguration> conf, string destructuringSymbol = "")
static string LogAndGetAsString(object x, Func<LoggerConfiguration, LoggerConfiguration> conf, string destructuringSymbol = "")
{
LogEvent evt = null;
var logConf = new LoggerConfiguration()
Expand Down Expand Up @@ -705,7 +706,7 @@ public void WrappingSinkRespectsLevelSwitchSetting()
}

[Fact]
public void WrappingSinkRespectsSetting()
public void WrappingSinkReceivesEventsWhenLevelIsAppropriate()
{
DummyWrappingSink.Reset();
var sink = new CollectingSink();
Expand All @@ -720,5 +721,25 @@ public void WrappingSinkRespectsSetting()
Assert.NotEmpty(DummyWrappingSink.Emitted);
Assert.NotEmpty(sink.Events);
}

[Fact]
public void EnrichersCanBeWrapped()
{
var enricher = new CollectingEnricher();

var configuration = new LoggerConfiguration();
LoggerEnrichmentConfiguration.Wrap(
configuration.Enrich,
e => new ConditionalEnricher(e, le => le.Level == LogEventLevel.Warning),
enrich => enrich.With(enricher));

var logger = configuration.CreateLogger();
logger.Information("Information");
logger.Warning("Warning");
logger.Error("Error");

var evt = Assert.Single(enricher.Events);
Assert.Equal(LogEventLevel.Warning, evt.Level);
}
}
}
19 changes: 19 additions & 0 deletions test/Serilog.Tests/Support/CollectingEnricher.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
using System.Collections.Generic;
using System.Linq;
using Serilog.Core;
using Serilog.Events;

namespace Serilog.Tests.Support
{
class CollectingEnricher : ILogEventEnricher
{
public List<LogEvent> Events { get; } = new List<LogEvent>();

public LogEvent SingleEvent => Events.Single();

public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory)
{
Events.Add(logEvent);
}
}
}
29 changes: 29 additions & 0 deletions test/Serilog.Tests/Support/ConditionalEnricher.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
using System;
using Serilog.Core;
using Serilog.Events;

namespace Serilog.Tests.Support
{
class ConditionalEnricher : ILogEventEnricher, IDisposable
{
readonly ILogEventEnricher _wrapped;
readonly Func<LogEvent, bool> _condition;

public ConditionalEnricher(ILogEventEnricher wrapped, Func<LogEvent, bool> condition)
{
_wrapped = wrapped;
_condition = condition;
}

public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory)
{
if (_condition(logEvent))
_wrapped.Enrich(logEvent, propertyFactory);
}

public void Dispose()
{
(_wrapped as IDisposable)?.Dispose();
}
}
}
3 changes: 1 addition & 2 deletions test/TestDummies/DummyLoggerConfigurationExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -89,8 +89,7 @@ public static LoggerConfiguration DummyWrap(

public static LoggerConfiguration WithDummyHardCodedString(
this LoggerDestructuringConfiguration loggerDestructuringConfiguration,
string hardCodedString
)
string hardCodedString)
{
return loggerDestructuringConfiguration.With(new DummyHardCodedStringDestructuringPolicy(hardCodedString));
}
Expand Down

0 comments on commit ac5400b

Please sign in to comment.