From 2fe5f4fcb4b4f59a56f42ee1c68621b8f8b030b6 Mon Sep 17 00:00:00 2001 From: Thibaud Desodt Date: Sat, 6 Oct 2018 16:17:37 +0200 Subject: [PATCH 1/9] Minor refactoring to properly reset static properties --- .../ConfigurationSettingsTests.cs | 30 +++++++++---------- test/TestDummies/DummyRollingFileAuditSink.cs | 11 +++++-- test/TestDummies/DummyRollingFileSink.cs | 11 +++++-- test/TestDummies/DummyWrappingSink.cs | 13 +++++--- 4 files changed, 40 insertions(+), 25 deletions(-) diff --git a/test/Serilog.Settings.Configuration.Tests/ConfigurationSettingsTests.cs b/test/Serilog.Settings.Configuration.Tests/ConfigurationSettingsTests.cs index 1cd0d70..4c75a58 100644 --- a/test/Serilog.Settings.Configuration.Tests/ConfigurationSettingsTests.cs +++ b/test/Serilog.Settings.Configuration.Tests/ConfigurationSettingsTests.cs @@ -1,4 +1,4 @@ -using System; +using System; using Microsoft.Extensions.Configuration; using Serilog.Core; using Serilog.Events; @@ -118,8 +118,8 @@ public void SinksAreConfigured() var log = ConfigFromJson(json) .CreateLogger(); - DummyRollingFileSink.Emitted.Clear(); - DummyRollingFileAuditSink.Emitted.Clear(); + DummyRollingFileSink.Reset(); + DummyRollingFileAuditSink.Reset(); log.Write(Some.InformationEvent()); @@ -143,8 +143,8 @@ public void AuditSinksAreConfigured() var log = ConfigFromJson(json) .CreateLogger(); - DummyRollingFileSink.Emitted.Clear(); - DummyRollingFileAuditSink.Emitted.Clear(); + DummyRollingFileSink.Reset(); + DummyRollingFileAuditSink.Reset(); log.Write(Some.InformationEvent()); @@ -438,7 +438,7 @@ public void SinkWithIConfigurationArguments() var log = ConfigFromJson(json) .CreateLogger(); - DummyRollingFileSink.Emitted.Clear(); + DummyRollingFileSink.Reset(); log.Write(Some.InformationEvent()); @@ -462,7 +462,7 @@ public void SinkWithConfigurationBindingArgument() var log = ConfigFromJson(json) .CreateLogger(); - DummyRollingFileSink.Emitted.Clear(); + DummyRollingFileSink.Reset(); log.Write(Some.InformationEvent()); @@ -486,7 +486,7 @@ public void SinkWithStringArrayArgument() var log = ConfigFromJson(json) .CreateLogger(); - DummyRollingFileSink.Emitted.Clear(); + DummyRollingFileSink.Reset(); log.Write(Some.InformationEvent()); @@ -510,7 +510,7 @@ public void SinkWithIntArrayArgument() var log = ConfigFromJson(json) .CreateLogger(); - DummyRollingFileSink.Emitted.Clear(); + DummyRollingFileSink.Reset(); log.Write(Some.InformationEvent()); @@ -534,7 +534,7 @@ public void CaseInsensitiveArgumentNameMatching() var log = ConfigFromJson(json) .CreateLogger(); - DummyRollingFileSink.Emitted.Clear(); + DummyRollingFileSink.Reset(); log.Write(Some.InformationEvent()); @@ -565,7 +565,7 @@ public void WriteToLoggerWithRestrictedToMinimumLevelIsSupported() var log = ConfigFromJson(json) .CreateLogger(); - DummyRollingFileSink.Emitted.Clear(); + DummyRollingFileSink.Reset(); log.Write(Some.InformationEvent()); log.Write(Some.WarningEvent()); @@ -598,9 +598,9 @@ public void WriteToSubLoggerWithLevelSwitchIsSupported() }"; var log = ConfigFromJson(json) - .CreateLogger(); + .CreateLogger(); - DummyRollingFileSink.Emitted.Clear(); + DummyRollingFileSink.Reset(); log.Write(Some.InformationEvent()); log.Write(Some.WarningEvent()); @@ -771,7 +771,7 @@ public void DestructuringAsScalarIsAppliedWithShortTypeName() .WriteTo.Sink(new DelegatingSink(e => evt = e)) .CreateLogger(); - log.Information("Destructuring as scalar {@Scalarized}", new Version(2,3)); + log.Information("Destructuring as scalar {@Scalarized}", new Version(2, 3)); var prop = evt.Properties["Scalarized"]; Assert.IsType(prop); @@ -795,7 +795,7 @@ public void DestructuringAsScalarIsAppliedWithAssemblyQualifiedName() .WriteTo.Sink(new DelegatingSink(e => evt = e)) .CreateLogger(); - log.Information("Destructuring as scalar {@Scalarized}", new Version(2,3)); + log.Information("Destructuring as scalar {@Scalarized}", new Version(2, 3)); var prop = evt.Properties["Scalarized"]; Assert.IsType(prop); diff --git a/test/TestDummies/DummyRollingFileAuditSink.cs b/test/TestDummies/DummyRollingFileAuditSink.cs index e8618d0..2ba17e3 100644 --- a/test/TestDummies/DummyRollingFileAuditSink.cs +++ b/test/TestDummies/DummyRollingFileAuditSink.cs @@ -8,13 +8,18 @@ namespace TestDummies public class DummyRollingFileAuditSink : ILogEventSink { [ThreadStatic] - // ReSharper disable ThreadStaticFieldHasInitializer - public static List Emitted = new List(); - // ReSharper restore ThreadStaticFieldHasInitializer + static List _emitted; + + public static List Emitted => _emitted ?? (_emitted = new List()); public void Emit(LogEvent logEvent) { Emitted.Add(logEvent); } + + public static void Reset() + { + _emitted = null; + } } } diff --git a/test/TestDummies/DummyRollingFileSink.cs b/test/TestDummies/DummyRollingFileSink.cs index bc98ed2..2f6f229 100644 --- a/test/TestDummies/DummyRollingFileSink.cs +++ b/test/TestDummies/DummyRollingFileSink.cs @@ -8,13 +8,18 @@ namespace TestDummies public class DummyRollingFileSink : ILogEventSink { [ThreadStatic] - // ReSharper disable ThreadStaticFieldHasInitializer - public static List Emitted = new List(); - // ReSharper restore ThreadStaticFieldHasInitializer + static List _emitted; + + public static List Emitted => _emitted ?? (_emitted = new List()); public void Emit(LogEvent logEvent) { Emitted.Add(logEvent); } + + public static void Reset() + { + _emitted = null; + } } } diff --git a/test/TestDummies/DummyWrappingSink.cs b/test/TestDummies/DummyWrappingSink.cs index cd15d8c..cb2f048 100644 --- a/test/TestDummies/DummyWrappingSink.cs +++ b/test/TestDummies/DummyWrappingSink.cs @@ -8,11 +8,11 @@ namespace TestDummies public class DummyWrappingSink : ILogEventSink { [ThreadStatic] - // ReSharper disable ThreadStaticFieldHasInitializer - public static List Emitted = new List(); - // ReSharper restore ThreadStaticFieldHasInitializer + static List _emitted; - private readonly ILogEventSink _sink; + public static List Emitted => _emitted ?? (_emitted = new List()); + + readonly ILogEventSink _sink; public DummyWrappingSink(ILogEventSink sink) { @@ -24,5 +24,10 @@ public void Emit(LogEvent logEvent) Emitted.Add(logEvent); _sink.Emit(logEvent); } + + public static void Reset() + { + _emitted = null; + } } } From b98aba2088b5eaa73de72c4baef02f9cd88a426a Mon Sep 17 00:00:00 2001 From: Thibaud Desodt Date: Sat, 6 Oct 2018 21:42:02 +0200 Subject: [PATCH 2/9] Add support for WriteTo.Sink() Support for `WriteTo.Sink(ILogEventSink logEventSink, LogEventLevel restrictedToMinimumLevel = LevelAlias.Minimum, LoggingLevelSwitch levelSwitch = null)` --- .../SurrogateConfigurationMethods.cs | 10 +++ .../ConfigurationSettingsTests.cs | 83 ++++++++++++++++++- 2 files changed, 92 insertions(+), 1 deletion(-) diff --git a/src/Serilog.Settings.Configuration/Settings/Configuration/SurrogateConfigurationMethods.cs b/src/Serilog.Settings.Configuration/Settings/Configuration/SurrogateConfigurationMethods.cs index 71faa7f..869b3c0 100644 --- a/src/Serilog.Settings.Configuration/Settings/Configuration/SurrogateConfigurationMethods.cs +++ b/src/Serilog.Settings.Configuration/Settings/Configuration/SurrogateConfigurationMethods.cs @@ -23,6 +23,7 @@ public static IEnumerable WriteTo get { yield return GetSurrogateConfigurationMethod, LoggingLevelSwitch>((c, a, s) => Logger(c, a, LevelAlias.Minimum, s)); + yield return GetSurrogateConfigurationMethod((c, sink, s) => Sink(c, sink, LevelAlias.Minimum, s)); } } @@ -65,6 +66,15 @@ invocation expressions as surrogates so that SelectConfigurationMethod has a way to match and invoke these instance methods. */ + internal static LoggerConfiguration Sink( + LoggerSinkConfiguration loggerSinkConfiguration, + ILogEventSink sink, + LogEventLevel restrictedToMinimumLevel = LevelAlias.Minimum, + LoggingLevelSwitch levelSwitch = null) + { + return loggerSinkConfiguration.Sink(sink, restrictedToMinimumLevel, levelSwitch); + } + // TODO: add overload for array argument (ILogEventEnricher[]) static LoggerConfiguration With(LoggerFilterConfiguration loggerFilterConfiguration, ILogEventFilter filter) => loggerFilterConfiguration.With(filter); diff --git a/test/Serilog.Settings.Configuration.Tests/ConfigurationSettingsTests.cs b/test/Serilog.Settings.Configuration.Tests/ConfigurationSettingsTests.cs index 4c75a58..71a03d1 100644 --- a/test/Serilog.Settings.Configuration.Tests/ConfigurationSettingsTests.cs +++ b/test/Serilog.Settings.Configuration.Tests/ConfigurationSettingsTests.cs @@ -1,4 +1,4 @@ -using System; +using System; using Microsoft.Extensions.Configuration; using Serilog.Core; using Serilog.Events; @@ -800,5 +800,86 @@ public void DestructuringAsScalarIsAppliedWithAssemblyQualifiedName() Assert.IsType(prop); } + + + [Fact] + public void WriteToSinkIsAppliedWithCustomSink() + { + var json = $@"{{ + ""Serilog"": {{ + ""Using"": [""TestDummies""], + ""WriteTo"": [ + {{ + ""Name"": ""Sink"", + ""Args"": {{ + ""sink"": ""{typeof(DummyRollingFileSink).AssemblyQualifiedName}"" + }} + }}] + }} + }}"; + + var log = ConfigFromJson(json) + .CreateLogger(); + + DummyRollingFileSink.Reset(); + log.Write(Some.InformationEvent()); + + Assert.Single(DummyRollingFileSink.Emitted); + } + + [Fact] + public void WriteToSinkIsAppliedWithCustomSinkAndMinimumLevel() + { + var json = $@"{{ + ""Serilog"": {{ + ""Using"": [""TestDummies""], + ""WriteTo"": [ + {{ + ""Name"": ""Sink"", + ""Args"": {{ + ""sink"": ""{typeof(DummyRollingFileSink).AssemblyQualifiedName}"", + ""restrictedToMinimumLevel"": ""Warning"" + }} + }}] + }} + }}"; + + var log = ConfigFromJson(json) + .CreateLogger(); + + DummyRollingFileSink.Reset(); + log.Write(Some.InformationEvent()); + log.Write(Some.WarningEvent()); + + Assert.Single(DummyRollingFileSink.Emitted); + } + + [Fact] + public void WriteToSinkIsAppliedWithCustomSinkAndLevelSwitch() + { + var json = $@"{{ + ""Serilog"": {{ + ""Using"": [""TestDummies""], + ""LevelSwitches"": {{""$switch1"": ""Warning"" }}, + ""WriteTo"": [ + {{ + ""Name"": ""Sink"", + ""Args"": {{ + ""sink"": ""{typeof(DummyRollingFileSink).AssemblyQualifiedName}"", + ""levelSwitch"": ""$switch1"" + }} + }}] + }} + }}"; + + var log = ConfigFromJson(json) + .CreateLogger(); + + DummyRollingFileSink.Reset(); + log.Write(Some.InformationEvent()); + log.Write(Some.WarningEvent()); + + Assert.Single(DummyRollingFileSink.Emitted); + } } } From ed9c04914a79c44d02101a2364985f38ecee596c Mon Sep 17 00:00:00 2001 From: Thibaud Desodt Date: Sat, 6 Oct 2018 21:55:34 +0200 Subject: [PATCH 3/9] Add support for AuditTo.Sink() Support for `AuditTo.Sink(ILogEventSink logEventSink, LogEventLevel restrictedToMinimumLevel = LevelAlias.Minimum, LoggingLevelSwitch levelSwitch = null)` --- .../Configuration/ConfigurationReader.cs | 3 +- .../SurrogateConfigurationMethods.cs | 43 ++++++++-- .../ConfigurationSettingsTests.cs | 81 +++++++++++++++++++ 3 files changed, 118 insertions(+), 9 deletions(-) diff --git a/src/Serilog.Settings.Configuration/Settings/Configuration/ConfigurationReader.cs b/src/Serilog.Settings.Configuration/Settings/Configuration/ConfigurationReader.cs index 3ef88b8..f72bb13 100644 --- a/src/Serilog.Settings.Configuration/Settings/Configuration/ConfigurationReader.cs +++ b/src/Serilog.Settings.Configuration/Settings/Configuration/ConfigurationReader.cs @@ -374,7 +374,8 @@ internal static IList FindSinkConfigurationMethods(IReadOnlyCollecti internal static IList FindAuditSinkConfigurationMethods(IReadOnlyCollection configurationAssemblies) { var found = FindConfigurationExtensionMethods(configurationAssemblies, typeof(LoggerAuditSinkConfiguration)); - + if (configurationAssemblies.Contains(typeof(LoggerAuditSinkConfiguration).GetTypeInfo().Assembly)) + found.AddRange(SurrogateConfigurationMethods.AuditTo); return found; } diff --git a/src/Serilog.Settings.Configuration/Settings/Configuration/SurrogateConfigurationMethods.cs b/src/Serilog.Settings.Configuration/Settings/Configuration/SurrogateConfigurationMethods.cs index 869b3c0..580a3de 100644 --- a/src/Serilog.Settings.Configuration/Settings/Configuration/SurrogateConfigurationMethods.cs +++ b/src/Serilog.Settings.Configuration/Settings/Configuration/SurrogateConfigurationMethods.cs @@ -27,6 +27,14 @@ public static IEnumerable WriteTo } } + public static IEnumerable AuditTo + { + get + { + yield return GetSurrogateConfigurationMethod((c, sink, s) => Sink(c, sink, LevelAlias.Minimum, s)); + } + } + public static IEnumerable Filter { get @@ -66,7 +74,9 @@ invocation expressions as surrogates so that SelectConfigurationMethod has a way to match and invoke these instance methods. */ - internal static LoggerConfiguration Sink( + // .WriteTo... + // ======== + static LoggerConfiguration Sink( LoggerSinkConfiguration loggerSinkConfiguration, ILogEventSink sink, LogEventLevel restrictedToMinimumLevel = LevelAlias.Minimum, @@ -75,10 +85,32 @@ internal static LoggerConfiguration Sink( return loggerSinkConfiguration.Sink(sink, restrictedToMinimumLevel, levelSwitch); } + static LoggerConfiguration Logger( + LoggerSinkConfiguration loggerSinkConfiguration, + Action configureLogger, + LogEventLevel restrictedToMinimumLevel = LevelAlias.Minimum, + LoggingLevelSwitch levelSwitch = null) + => loggerSinkConfiguration.Logger(configureLogger, restrictedToMinimumLevel, levelSwitch); + + // .AuditTo... + // ======== + static LoggerConfiguration Sink( + LoggerAuditSinkConfiguration auditSinkConfiguration, + ILogEventSink sink, + LogEventLevel restrictedToMinimumLevel = LevelAlias.Minimum, + LoggingLevelSwitch levelSwitch = null) + { + return auditSinkConfiguration.Sink(sink, restrictedToMinimumLevel, levelSwitch); + } + + // .Filter... + // ======= // TODO: add overload for array argument (ILogEventEnricher[]) static LoggerConfiguration With(LoggerFilterConfiguration loggerFilterConfiguration, ILogEventFilter filter) => loggerFilterConfiguration.With(filter); + // .Destructure... + // ============ // TODO: add overload for array argument (IDestructuringPolicy[]) static LoggerConfiguration With(LoggerDestructuringConfiguration loggerDestructuringConfiguration, IDestructuringPolicy policy) => loggerDestructuringConfiguration.With(policy); @@ -95,15 +127,10 @@ static LoggerConfiguration ToMaximumCollectionCount(LoggerDestructuringConfigura static LoggerConfiguration AsScalar(LoggerDestructuringConfiguration loggerDestructuringConfiguration, Type scalarType) => loggerDestructuringConfiguration.AsScalar(scalarType); + // .Enrich... + // ======= static LoggerConfiguration FromLogContext(LoggerEnrichmentConfiguration loggerEnrichmentConfiguration) => loggerEnrichmentConfiguration.FromLogContext(); - // Unlike the other configuration methods, Logger is an instance method rather than an extension. - static LoggerConfiguration Logger( - LoggerSinkConfiguration loggerSinkConfiguration, - Action configureLogger, - LogEventLevel restrictedToMinimumLevel = LevelAlias.Minimum, - LoggingLevelSwitch levelSwitch = null) - => loggerSinkConfiguration.Logger(configureLogger, restrictedToMinimumLevel, levelSwitch); } } diff --git a/test/Serilog.Settings.Configuration.Tests/ConfigurationSettingsTests.cs b/test/Serilog.Settings.Configuration.Tests/ConfigurationSettingsTests.cs index 71a03d1..d0273fc 100644 --- a/test/Serilog.Settings.Configuration.Tests/ConfigurationSettingsTests.cs +++ b/test/Serilog.Settings.Configuration.Tests/ConfigurationSettingsTests.cs @@ -881,5 +881,86 @@ public void WriteToSinkIsAppliedWithCustomSinkAndLevelSwitch() Assert.Single(DummyRollingFileSink.Emitted); } + + + [Fact] + public void AuditToSinkIsAppliedWithCustomSink() + { + var json = $@"{{ + ""Serilog"": {{ + ""Using"": [""TestDummies""], + ""AuditTo"": [ + {{ + ""Name"": ""Sink"", + ""Args"": {{ + ""sink"": ""{typeof(DummyRollingFileSink).AssemblyQualifiedName}"" + }} + }}] + }} + }}"; + + var log = ConfigFromJson(json) + .CreateLogger(); + + DummyRollingFileSink.Reset(); + log.Write(Some.InformationEvent()); + + Assert.Single(DummyRollingFileSink.Emitted); + } + + [Fact] + public void AuditToSinkIsAppliedWithCustomSinkAndMinimumLevel() + { + var json = $@"{{ + ""Serilog"": {{ + ""Using"": [""TestDummies""], + ""AuditTo"": [ + {{ + ""Name"": ""Sink"", + ""Args"": {{ + ""sink"": ""{typeof(DummyRollingFileSink).AssemblyQualifiedName}"", + ""restrictedToMinimumLevel"": ""Warning"" + }} + }}] + }} + }}"; + + var log = ConfigFromJson(json) + .CreateLogger(); + + DummyRollingFileSink.Reset(); + log.Write(Some.InformationEvent()); + log.Write(Some.WarningEvent()); + + Assert.Single(DummyRollingFileSink.Emitted); + } + + [Fact] + public void AuditToSinkIsAppliedWithCustomSinkAndLevelSwitch() + { + var json = $@"{{ + ""Serilog"": {{ + ""Using"": [""TestDummies""], + ""LevelSwitches"": {{""$switch1"": ""Warning"" }}, + ""AuditTo"": [ + {{ + ""Name"": ""Sink"", + ""Args"": {{ + ""sink"": ""{typeof(DummyRollingFileSink).AssemblyQualifiedName}"", + ""levelSwitch"": ""$switch1"" + }} + }}] + }} + }}"; + + var log = ConfigFromJson(json) + .CreateLogger(); + + DummyRollingFileSink.Reset(); + log.Write(Some.InformationEvent()); + log.Write(Some.WarningEvent()); + + Assert.Single(DummyRollingFileSink.Emitted); + } } } From 0b3b7399797b562c6c4085d0e0a56c256e826cf3 Mon Sep 17 00:00:00 2001 From: Thibaud Desodt Date: Sat, 6 Oct 2018 22:03:47 +0200 Subject: [PATCH 4/9] Add support for Enrich.With() Support for `Enrich.With(ILogEventEnricher enricher)` --- .../SurrogateConfigurationMethods.cs | 6 ++++ .../ConfigurationSettingsTests.cs | 29 +++++++++++++++++++ test/TestDummies/DummyThreadIdEnricher.cs | 4 ++- 3 files changed, 38 insertions(+), 1 deletion(-) diff --git a/src/Serilog.Settings.Configuration/Settings/Configuration/SurrogateConfigurationMethods.cs b/src/Serilog.Settings.Configuration/Settings/Configuration/SurrogateConfigurationMethods.cs index 580a3de..36452c8 100644 --- a/src/Serilog.Settings.Configuration/Settings/Configuration/SurrogateConfigurationMethods.cs +++ b/src/Serilog.Settings.Configuration/Settings/Configuration/SurrogateConfigurationMethods.cs @@ -60,6 +60,7 @@ public static IEnumerable Enrich get { yield return GetSurrogateConfigurationMethod((c, _, __) => FromLogContext(c)); + yield return GetSurrogateConfigurationMethod((c, e, __) => With(c, e)); } } @@ -132,5 +133,10 @@ static LoggerConfiguration AsScalar(LoggerDestructuringConfiguration loggerDestr static LoggerConfiguration FromLogContext(LoggerEnrichmentConfiguration loggerEnrichmentConfiguration) => loggerEnrichmentConfiguration.FromLogContext(); + static LoggerConfiguration With(LoggerEnrichmentConfiguration loggerEnrichmentConfiguration, ILogEventEnricher enricher) + { + return loggerEnrichmentConfiguration.With(enricher); + } + } } diff --git a/test/Serilog.Settings.Configuration.Tests/ConfigurationSettingsTests.cs b/test/Serilog.Settings.Configuration.Tests/ConfigurationSettingsTests.cs index d0273fc..38a1662 100644 --- a/test/Serilog.Settings.Configuration.Tests/ConfigurationSettingsTests.cs +++ b/test/Serilog.Settings.Configuration.Tests/ConfigurationSettingsTests.cs @@ -962,5 +962,34 @@ public void AuditToSinkIsAppliedWithCustomSinkAndLevelSwitch() Assert.Single(DummyRollingFileSink.Emitted); } + + + [Fact] + public void EnrichWithIsAppliedWithCustomEnricher() + { + LogEvent evt = null; + + var json = $@"{{ + ""Serilog"": {{ + ""Using"": [""TestDummies""], + ""Enrich"": [ + {{ + ""Name"": ""With"", + ""Args"": {{ + ""enricher"": ""{typeof(DummyThreadIdEnricher).AssemblyQualifiedName}"" + }} + }}] + }} + }}"; + + var log = ConfigFromJson(json) + .WriteTo.Sink(new DelegatingSink(e => evt = e)) + .CreateLogger(); + + log.Write(Some.InformationEvent()); + + Assert.NotNull(evt); + Assert.True(evt.Properties.ContainsKey("ThreadId"), "Event should have enriched property ThreadId"); + } } } diff --git a/test/TestDummies/DummyThreadIdEnricher.cs b/test/TestDummies/DummyThreadIdEnricher.cs index 4ba740e..a640d55 100644 --- a/test/TestDummies/DummyThreadIdEnricher.cs +++ b/test/TestDummies/DummyThreadIdEnricher.cs @@ -6,7 +6,9 @@ namespace TestDummies public class DummyThreadIdEnricher : ILogEventEnricher { public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory) - { + { + logEvent.AddPropertyIfAbsent(propertyFactory + .CreateProperty("ThreadId", "SomeId")); } } } From 70e4f0b1c1f88128de3f7f2875f590fddfef0f5e Mon Sep 17 00:00:00 2001 From: Thibaud Desodt Date: Sat, 6 Oct 2018 22:12:12 +0200 Subject: [PATCH 5/9] Add test for support Filter.With() Turns out support for `Filter.With(ILogEventFilter filter)` was already there since commit 4424523d1e0a9c1f41ad409ddd9d236d3daf9eca --- .../ConfigurationSettingsTests.cs | 28 +++++++++++++++++++ test/TestDummies/DummyAnonymousUserFilter.cs | 25 +++++++++++++++++ 2 files changed, 53 insertions(+) create mode 100644 test/TestDummies/DummyAnonymousUserFilter.cs diff --git a/test/Serilog.Settings.Configuration.Tests/ConfigurationSettingsTests.cs b/test/Serilog.Settings.Configuration.Tests/ConfigurationSettingsTests.cs index 38a1662..ac59e8e 100644 --- a/test/Serilog.Settings.Configuration.Tests/ConfigurationSettingsTests.cs +++ b/test/Serilog.Settings.Configuration.Tests/ConfigurationSettingsTests.cs @@ -991,5 +991,33 @@ public void EnrichWithIsAppliedWithCustomEnricher() Assert.NotNull(evt); Assert.True(evt.Properties.ContainsKey("ThreadId"), "Event should have enriched property ThreadId"); } + + [Fact] + public void FilterWithIsAppliedWithCustomFilter() + { + LogEvent evt = null; + + var json = $@"{{ + ""Serilog"": {{ + ""Using"": [""TestDummies""], + ""Filter"": [ + {{ + ""Name"": ""With"", + ""Args"": {{ + ""filter"": ""{typeof(DummyAnonymousUserFilter).AssemblyQualifiedName}"" + }} + }}] + }} + }}"; + + var log = ConfigFromJson(json) + .WriteTo.Sink(new DelegatingSink(e => evt = e)) + .CreateLogger(); + + log.ForContext("User", "anonymous").Write(Some.InformationEvent()); + Assert.Null(evt); + log.ForContext("User", "the user").Write(Some.InformationEvent()); + Assert.NotNull(evt); + } } } diff --git a/test/TestDummies/DummyAnonymousUserFilter.cs b/test/TestDummies/DummyAnonymousUserFilter.cs new file mode 100644 index 0000000..a47dd11 --- /dev/null +++ b/test/TestDummies/DummyAnonymousUserFilter.cs @@ -0,0 +1,25 @@ + +using Serilog.Core; +using Serilog.Events; + +namespace TestDummies +{ + public class DummyAnonymousUserFilter : ILogEventFilter + { + public bool IsEnabled(LogEvent logEvent) + { + if (logEvent.Properties.ContainsKey("User")) + { + if (logEvent.Properties["User"] is ScalarValue sv) + { + if (sv.Value is string s && s == "anonymous") + { + return false; + } + } + } + + return true; + } + } +} From a55fc9f59e20677641baf3dd78508bf754c3eeed Mon Sep 17 00:00:00 2001 From: Thibaud Desodt Date: Sat, 6 Oct 2018 22:21:14 +0200 Subject: [PATCH 6/9] Refactor `SurrogateConfigurationMethods` so that all methods in the class are dynamically discovered and exposed to Serilog settings as if they were regular extension methods --- .../SurrogateConfigurationMethods.cs | 64 +++++-------------- 1 file changed, 16 insertions(+), 48 deletions(-) diff --git a/src/Serilog.Settings.Configuration/Settings/Configuration/SurrogateConfigurationMethods.cs b/src/Serilog.Settings.Configuration/Settings/Configuration/SurrogateConfigurationMethods.cs index 36452c8..d6b3d6f 100644 --- a/src/Serilog.Settings.Configuration/Settings/Configuration/SurrogateConfigurationMethods.cs +++ b/src/Serilog.Settings.Configuration/Settings/Configuration/SurrogateConfigurationMethods.cs @@ -1,6 +1,6 @@ using System; using System.Collections.Generic; -using System.Linq.Expressions; +using System.Linq; using System.Reflection; using Serilog.Configuration; using Serilog.Core; @@ -10,7 +10,7 @@ namespace Serilog.Settings.Configuration { /// /// Contains "fake extension" methods for the Serilog configuration API. - /// By default the settings knows how to find extension methods, but some configuration + /// By default the settings know how to find extension methods, but some configuration /// are actually "regular" method calls and would not be found otherwise. /// /// This static class contains internal methods that can be used instead. @@ -18,54 +18,17 @@ namespace Serilog.Settings.Configuration /// static class SurrogateConfigurationMethods { - public static IEnumerable WriteTo - { - get - { - yield return GetSurrogateConfigurationMethod, LoggingLevelSwitch>((c, a, s) => Logger(c, a, LevelAlias.Minimum, s)); - yield return GetSurrogateConfigurationMethod((c, sink, s) => Sink(c, sink, LevelAlias.Minimum, s)); - } - } - - public static IEnumerable AuditTo - { - get - { - yield return GetSurrogateConfigurationMethod((c, sink, s) => Sink(c, sink, LevelAlias.Minimum, s)); - } - } - - public static IEnumerable Filter - { - get - { - yield return GetSurrogateConfigurationMethod((c, f, _) => With(c, f)); - } - } + static readonly Dictionary SurrogateMethodCandidates = typeof(SurrogateConfigurationMethods) + .GetTypeInfo().DeclaredMethods + .GroupBy(m => m.GetParameters().First().ParameterType) + .ToDictionary(g => g.Key, g => g.ToArray()); - public static IEnumerable Destructure - { - get - { - yield return GetSurrogateConfigurationMethod((c, d, _) => With(c, d)); - yield return GetSurrogateConfigurationMethod((c, m, _) => ToMaximumDepth(c, m)); - yield return GetSurrogateConfigurationMethod((c, m, _) => ToMaximumStringLength(c, m)); - yield return GetSurrogateConfigurationMethod((c, m, _) => ToMaximumCollectionCount(c, m)); - yield return GetSurrogateConfigurationMethod((c, t, _) => AsScalar(c, t)); - } - } - public static IEnumerable Enrich - { - get - { - yield return GetSurrogateConfigurationMethod((c, _, __) => FromLogContext(c)); - yield return GetSurrogateConfigurationMethod((c, e, __) => With(c, e)); - } - } - - static MethodInfo GetSurrogateConfigurationMethod(Expression> method) - => (method.Body as MethodCallExpression)?.Method; + internal static readonly MethodInfo[] WriteTo = SurrogateMethodCandidates[typeof(LoggerSinkConfiguration)]; + internal static readonly MethodInfo[] AuditTo = SurrogateMethodCandidates[typeof(LoggerAuditSinkConfiguration)]; + internal static readonly MethodInfo[] Enrich = SurrogateMethodCandidates[typeof(LoggerEnrichmentConfiguration)]; + internal static readonly MethodInfo[] Destructure = SurrogateMethodCandidates[typeof(LoggerDestructuringConfiguration)]; + internal static readonly MethodInfo[] Filter = SurrogateMethodCandidates[typeof(LoggerFilterConfiguration)]; /* Pass-through calls to various Serilog config methods which are @@ -75,6 +38,10 @@ invocation expressions as surrogates so that SelectConfigurationMethod has a way to match and invoke these instance methods. */ + // ReSharper disable UnusedMember.Local + // those methods are discovered through reflection by `SurrogateMethodCandidates` + // ReSharper has no way to see that they are actually used ... + // .WriteTo... // ======== static LoggerConfiguration Sink( @@ -138,5 +105,6 @@ static LoggerConfiguration With(LoggerEnrichmentConfiguration loggerEnrichmentCo return loggerEnrichmentConfiguration.With(enricher); } + // ReSharper restore UnusedMember.Local } } From 01b1cfd3fe0a8ec5b21cf963f5b5ebb5e06d20d9 Mon Sep 17 00:00:00 2001 From: Thibaud Desodt Date: Sat, 6 Oct 2018 22:35:56 +0200 Subject: [PATCH 7/9] Minor reformatting and documentation --- .../SurrogateConfigurationMethods.cs | 28 +++++++++---------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/src/Serilog.Settings.Configuration/Settings/Configuration/SurrogateConfigurationMethods.cs b/src/Serilog.Settings.Configuration/Settings/Configuration/SurrogateConfigurationMethods.cs index d6b3d6f..6350eca 100644 --- a/src/Serilog.Settings.Configuration/Settings/Configuration/SurrogateConfigurationMethods.cs +++ b/src/Serilog.Settings.Configuration/Settings/Configuration/SurrogateConfigurationMethods.cs @@ -32,10 +32,9 @@ static class SurrogateConfigurationMethods /* Pass-through calls to various Serilog config methods which are - implemented as instance methods rather than extension methods. The - FindXXXConfigurationMethods calls (above) use these to add method - invocation expressions as surrogates so that SelectConfigurationMethod - has a way to match and invoke these instance methods. + implemented as instance methods rather than extension methods. + ConfigurationReader adds those to the already discovered extension methods + so they can be invoked as well. */ // ReSharper disable UnusedMember.Local @@ -49,9 +48,7 @@ static LoggerConfiguration Sink( ILogEventSink sink, LogEventLevel restrictedToMinimumLevel = LevelAlias.Minimum, LoggingLevelSwitch levelSwitch = null) - { - return loggerSinkConfiguration.Sink(sink, restrictedToMinimumLevel, levelSwitch); - } + => loggerSinkConfiguration.Sink(sink, restrictedToMinimumLevel, levelSwitch); static LoggerConfiguration Logger( LoggerSinkConfiguration loggerSinkConfiguration, @@ -67,19 +64,19 @@ static LoggerConfiguration Sink( ILogEventSink sink, LogEventLevel restrictedToMinimumLevel = LevelAlias.Minimum, LoggingLevelSwitch levelSwitch = null) - { - return auditSinkConfiguration.Sink(sink, restrictedToMinimumLevel, levelSwitch); - } + => auditSinkConfiguration.Sink(sink, restrictedToMinimumLevel, levelSwitch); // .Filter... // ======= // TODO: add overload for array argument (ILogEventEnricher[]) + // expose `With(params ILogEventFilter[] filters)` as if it was `With(ILogEventFilter filter)` static LoggerConfiguration With(LoggerFilterConfiguration loggerFilterConfiguration, ILogEventFilter filter) => loggerFilterConfiguration.With(filter); // .Destructure... // ============ // TODO: add overload for array argument (IDestructuringPolicy[]) + // expose `With(params IDestructuringPolicy[] destructuringPolicies)` as if it was `With(IDestructuringPolicy policy)` static LoggerConfiguration With(LoggerDestructuringConfiguration loggerDestructuringConfiguration, IDestructuringPolicy policy) => loggerDestructuringConfiguration.With(policy); @@ -97,14 +94,15 @@ static LoggerConfiguration AsScalar(LoggerDestructuringConfiguration loggerDestr // .Enrich... // ======= + // expose `With(params ILogEventEnricher[] enrichers)` as if it was `With(ILogEventEnricher enricher)` + static LoggerConfiguration With( + LoggerEnrichmentConfiguration loggerEnrichmentConfiguration, + ILogEventEnricher enricher) + => loggerEnrichmentConfiguration.With(enricher); + static LoggerConfiguration FromLogContext(LoggerEnrichmentConfiguration loggerEnrichmentConfiguration) => loggerEnrichmentConfiguration.FromLogContext(); - static LoggerConfiguration With(LoggerEnrichmentConfiguration loggerEnrichmentConfiguration, ILogEventEnricher enricher) - { - return loggerEnrichmentConfiguration.With(enricher); - } - // ReSharper restore UnusedMember.Local } } From cf81e5aa9660c79049d68032a51f7717a3ee76b9 Mon Sep 17 00:00:00 2001 From: Thibaud Desodt Date: Sat, 6 Oct 2018 22:36:34 +0200 Subject: [PATCH 8/9] Mark as private the members that are not used elsewhere --- .../Settings/Configuration/ConfigurationReader.cs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/Serilog.Settings.Configuration/Settings/Configuration/ConfigurationReader.cs b/src/Serilog.Settings.Configuration/Settings/Configuration/ConfigurationReader.cs index f72bb13..87359bb 100644 --- a/src/Serilog.Settings.Configuration/Settings/Configuration/ConfigurationReader.cs +++ b/src/Serilog.Settings.Configuration/Settings/Configuration/ConfigurationReader.cs @@ -362,7 +362,7 @@ internal static MethodInfo SelectConfigurationMethod(IEnumerable can .FirstOrDefault(); } - internal static IList FindSinkConfigurationMethods(IReadOnlyCollection configurationAssemblies) + static IList FindSinkConfigurationMethods(IReadOnlyCollection configurationAssemblies) { var found = FindConfigurationExtensionMethods(configurationAssemblies, typeof(LoggerSinkConfiguration)); if (configurationAssemblies.Contains(typeof(LoggerSinkConfiguration).GetTypeInfo().Assembly)) @@ -371,7 +371,7 @@ internal static IList FindSinkConfigurationMethods(IReadOnlyCollecti return found; } - internal static IList FindAuditSinkConfigurationMethods(IReadOnlyCollection configurationAssemblies) + static IList FindAuditSinkConfigurationMethods(IReadOnlyCollection configurationAssemblies) { var found = FindConfigurationExtensionMethods(configurationAssemblies, typeof(LoggerAuditSinkConfiguration)); if (configurationAssemblies.Contains(typeof(LoggerAuditSinkConfiguration).GetTypeInfo().Assembly)) @@ -379,7 +379,7 @@ internal static IList FindAuditSinkConfigurationMethods(IReadOnlyCol return found; } - internal static IList FindFilterConfigurationMethods(IReadOnlyCollection configurationAssemblies) + static IList FindFilterConfigurationMethods(IReadOnlyCollection configurationAssemblies) { var found = FindConfigurationExtensionMethods(configurationAssemblies, typeof(LoggerFilterConfiguration)); if (configurationAssemblies.Contains(typeof(LoggerFilterConfiguration).GetTypeInfo().Assembly)) @@ -388,7 +388,7 @@ internal static IList FindFilterConfigurationMethods(IReadOnlyCollec return found; } - internal static IList FindDestructureConfigurationMethods(IReadOnlyCollection configurationAssemblies) + static IList FindDestructureConfigurationMethods(IReadOnlyCollection configurationAssemblies) { var found = FindConfigurationExtensionMethods(configurationAssemblies, typeof(LoggerDestructuringConfiguration)); if (configurationAssemblies.Contains(typeof(LoggerDestructuringConfiguration).GetTypeInfo().Assembly)) @@ -397,7 +397,7 @@ internal static IList FindDestructureConfigurationMethods(IReadOnlyC return found; } - internal static IList FindEventEnricherConfigurationMethods(IReadOnlyCollection configurationAssemblies) + static IList FindEventEnricherConfigurationMethods(IReadOnlyCollection configurationAssemblies) { var found = FindConfigurationExtensionMethods(configurationAssemblies, typeof(LoggerEnrichmentConfiguration)); if (configurationAssemblies.Contains(typeof(LoggerEnrichmentConfiguration).GetTypeInfo().Assembly)) @@ -406,7 +406,7 @@ internal static IList FindEventEnricherConfigurationMethods(IReadOnl return found; } - internal static List FindConfigurationExtensionMethods(IReadOnlyCollection configurationAssemblies, Type configType) + static List FindConfigurationExtensionMethods(IReadOnlyCollection configurationAssemblies, Type configType) { return configurationAssemblies .SelectMany(a => a.ExportedTypes @@ -423,7 +423,7 @@ internal static bool IsValidSwitchName(string input) return Regex.IsMatch(input, LevelSwitchNameRegex); } - internal static LogEventLevel ParseLogEventLevel(string value) + static LogEventLevel ParseLogEventLevel(string value) { if (!Enum.TryParse(value, out LogEventLevel parsedLevel)) throw new InvalidOperationException($"The value {value} is not a valid Serilog level."); From 4c932e4368a11547385b550ce1016fb2883f019a Mon Sep 17 00:00:00 2001 From: Thibaud Desodt Date: Sat, 6 Oct 2018 22:44:29 +0200 Subject: [PATCH 9/9] Minor whitespace reformatting --- .../ConfigurationSettingsTests.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/test/Serilog.Settings.Configuration.Tests/ConfigurationSettingsTests.cs b/test/Serilog.Settings.Configuration.Tests/ConfigurationSettingsTests.cs index ac59e8e..f8f7a95 100644 --- a/test/Serilog.Settings.Configuration.Tests/ConfigurationSettingsTests.cs +++ b/test/Serilog.Settings.Configuration.Tests/ConfigurationSettingsTests.cs @@ -801,7 +801,6 @@ public void DestructuringAsScalarIsAppliedWithAssemblyQualifiedName() Assert.IsType(prop); } - [Fact] public void WriteToSinkIsAppliedWithCustomSink() { @@ -882,7 +881,6 @@ public void WriteToSinkIsAppliedWithCustomSinkAndLevelSwitch() Assert.Single(DummyRollingFileSink.Emitted); } - [Fact] public void AuditToSinkIsAppliedWithCustomSink() { @@ -963,7 +961,6 @@ public void AuditToSinkIsAppliedWithCustomSinkAndLevelSwitch() Assert.Single(DummyRollingFileSink.Emitted); } - [Fact] public void EnrichWithIsAppliedWithCustomEnricher() {