From 17d808319489226a9f0991f8406c3e5dbfecd9b8 Mon Sep 17 00:00:00 2001 From: Thibaud Desodt Date: Sat, 14 Jul 2018 10:13:10 +0200 Subject: [PATCH 1/6] Add test to check support for custom destructuring extension Methods --- .../ConfigurationSettingsTests.cs | 24 +++++++++++++++++++ ...DummyHardCodedStringDestructuringPolicy.cs | 22 +++++++++++++++++ .../DummyLoggerConfigurationExtensions.cs | 10 +++++++- 3 files changed, 55 insertions(+), 1 deletion(-) create mode 100644 test/TestDummies/DummyHardCodedStringDestructuringPolicy.cs diff --git a/test/Serilog.Settings.Configuration.Tests/ConfigurationSettingsTests.cs b/test/Serilog.Settings.Configuration.Tests/ConfigurationSettingsTests.cs index f0d8809..efa78c9 100644 --- a/test/Serilog.Settings.Configuration.Tests/ConfigurationSettingsTests.cs +++ b/test/Serilog.Settings.Configuration.Tests/ConfigurationSettingsTests.cs @@ -679,5 +679,29 @@ private string GetDestructuredProperty(object x, string json) var result = evt.Properties["X"].ToString(); return result; } + + [Fact] + public void DestructuringWithCustomExtensionMethodIsApplied() + { + var json = @"{ + ""Serilog"": { + ""Using"": [""TestDummies""], + ""Destructure"": [ + { + ""Name"": ""WithDummyHardCodedString"", + ""Args"": { ""hardCodedString"": ""hardcoded"" } + }] + } + }"; + + LogEvent evt = null; + var log = ConfigFromJson(json) + .WriteTo.Sink(new DelegatingSink(e => evt = e)) + .CreateLogger(); + log.Information("Destructuring with hard-coded policy {@Input}", new { Foo = "Bar" }); + var formattedProperty = evt.Properties["Input"].ToString(); + + Assert.Equal("\"hardcoded\"", formattedProperty); + } } } diff --git a/test/TestDummies/DummyHardCodedStringDestructuringPolicy.cs b/test/TestDummies/DummyHardCodedStringDestructuringPolicy.cs new file mode 100644 index 0000000..25d2724 --- /dev/null +++ b/test/TestDummies/DummyHardCodedStringDestructuringPolicy.cs @@ -0,0 +1,22 @@ +using System; +using Serilog.Core; +using Serilog.Events; + +namespace TestDummies +{ + public class DummyHardCodedStringDestructuringPolicy : IDestructuringPolicy + { + readonly string _hardCodedString; + + public DummyHardCodedStringDestructuringPolicy(string hardCodedString) + { + _hardCodedString = hardCodedString ?? throw new ArgumentNullException(nameof(hardCodedString)); + } + + public bool TryDestructure(object value, ILogEventPropertyValueFactory propertyValueFactory, out LogEventPropertyValue result) + { + result = new ScalarValue(_hardCodedString); + return true; + } + } +} diff --git a/test/TestDummies/DummyLoggerConfigurationExtensions.cs b/test/TestDummies/DummyLoggerConfigurationExtensions.cs index 5f1e039..c5ff18c 100644 --- a/test/TestDummies/DummyLoggerConfigurationExtensions.cs +++ b/test/TestDummies/DummyLoggerConfigurationExtensions.cs @@ -109,6 +109,14 @@ public static LoggerConfiguration Dummy( s => new DummyWrappingSink(s), wrappedSinkAction); } - + + public static LoggerConfiguration WithDummyHardCodedString( + this LoggerDestructuringConfiguration loggerDestructuringConfiguration, + string hardCodedString + ) + { + return loggerDestructuringConfiguration.With(new DummyHardCodedStringDestructuringPolicy(hardCodedString)); + } + } } From c5731c960d52a923d768c3b6a023d66a27dd5164 Mon Sep 17 00:00:00 2001 From: Thibaud Desodt Date: Sat, 14 Jul 2018 10:13:26 +0200 Subject: [PATCH 2/6] fix ReSharper warning --- sample/Sample/Program.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sample/Sample/Program.cs b/sample/Sample/Program.cs index a213a4b..562e427 100644 --- a/sample/Sample/Program.cs +++ b/sample/Sample/Program.cs @@ -40,7 +40,7 @@ public static void Main(string[] args) new { TwentyChars = "0123456789abcdefghij" }); logger.Information("Destructure with max collection count:\n{@BigData}", - new { TenItems = new string[] { "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten" } }); + new { TenItems = new[] { "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten" } }); logger.Information("Destructure with policy to strip password:\n{@LoginData}", new LoginData { Username = "BGates", Password = "isityearoflinuxyet" }); From 24264878f70c4b84545888a8678e92bda1cfb45a Mon Sep 17 00:00:00 2001 From: Thibaud Desodt Date: Sat, 14 Jul 2018 10:31:19 +0200 Subject: [PATCH 3/6] Reformat / light refactor in ConfigurationReader renamed a variable and reindented properly --- .../Configuration/ConfigurationReader.cs | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/Serilog.Settings.Configuration/Settings/Configuration/ConfigurationReader.cs b/src/Serilog.Settings.Configuration/Settings/Configuration/ConfigurationReader.cs index a8b1823..0fb6a87 100644 --- a/src/Serilog.Settings.Configuration/Settings/Configuration/ConfigurationReader.cs +++ b/src/Serilog.Settings.Configuration/Settings/Configuration/ConfigurationReader.cs @@ -155,10 +155,10 @@ void ApplyFilters(LoggerConfiguration loggerConfiguration, IReadOnlyDictionary declaredLevelSwitches) { - var filterDirective = _section.GetSection("Destructure"); - if(filterDirective.GetChildren().Any()) + var destructureDirective = _section.GetSection("Destructure"); + if (destructureDirective.GetChildren().Any()) { - var methodCalls = GetMethodCalls(filterDirective); + var methodCalls = GetMethodCalls(destructureDirective); CallConfigurationMethods(methodCalls, FindDestructureConfigurationMethods(_configurationAssemblies), loggerConfiguration.Destructure, declaredLevelSwitches); } } @@ -221,9 +221,11 @@ internal ILookup> GetMet where child.Value == null let name = GetSectionName(child) let callArgs = (from argument in child.GetSection("Args").GetChildren() - select new { + select new + { Name = argument.Key, - Value = GetArgumentValue(argument) }).ToDictionary(p => p.Name, p => p.Value) + Value = GetArgumentValue(argument) + }).ToDictionary(p => p.Name, p => p.Value) select new { Name = name, Args = callArgs })) .ToLookup(p => p.Name, p => p.Args); @@ -330,7 +332,7 @@ static void CallConfigurationMethods(ILookup i.ParameterType == typeof(IConfiguration)); - if(parm != null) call[parm.Position - 1] = _configuration; + if (parm != null) call[parm.Position - 1] = _configuration; call.Insert(0, receiver); @@ -376,7 +378,7 @@ internal static IList FindFilterConfigurationMethods(IReadOnlyCollec internal static IList FindDestructureConfigurationMethods(IReadOnlyCollection configurationAssemblies) { var found = FindConfigurationExtensionMethods(configurationAssemblies, typeof(LoggerDestructuringConfiguration)); - if(configurationAssemblies.Contains(typeof(LoggerDestructuringConfiguration).GetTypeInfo().Assembly)) + if (configurationAssemblies.Contains(typeof(LoggerDestructuringConfiguration).GetTypeInfo().Assembly)) { found.Add(GetSurrogateConfigurationMethod((c, d, _) => With(c, d))); found.Add(GetSurrogateConfigurationMethod((c, m, _) => ToMaximumDepth(c, m))); From 761f01413ebc86a4ab667d8bbb81437dd7bf2ce7 Mon Sep 17 00:00:00 2001 From: Thibaud Desodt Date: Sat, 14 Jul 2018 10:32:08 +0200 Subject: [PATCH 4/6] Add support for handling arguments of type Type by accepting qualified type name --- .../Configuration/StringArgumentValue.cs | 3 ++- .../StringArgumentValueTests.cs | 24 ++++++++++++++++++- 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/src/Serilog.Settings.Configuration/Settings/Configuration/StringArgumentValue.cs b/src/Serilog.Settings.Configuration/Settings/Configuration/StringArgumentValue.cs index e5f79b0..5291f2a 100644 --- a/src/Serilog.Settings.Configuration/Settings/Configuration/StringArgumentValue.cs +++ b/src/Serilog.Settings.Configuration/Settings/Configuration/StringArgumentValue.cs @@ -27,7 +27,8 @@ public StringArgumentValue(Func valueProducer, Func change static readonly Dictionary> ExtendedTypeConversions = new Dictionary> { { typeof(Uri), s => new Uri(s) }, - { typeof(TimeSpan), s => TimeSpan.Parse(s) } + { typeof(TimeSpan), s => TimeSpan.Parse(s) }, + { typeof(Type), s => Type.GetType(s, throwOnError:true) }, }; public object ConvertTo(Type toType, IReadOnlyDictionary declaredLevelSwitches) diff --git a/test/Serilog.Settings.Configuration.Tests/StringArgumentValueTests.cs b/test/Serilog.Settings.Configuration.Tests/StringArgumentValueTests.cs index 4c1811a..e432eda 100644 --- a/test/Serilog.Settings.Configuration.Tests/StringArgumentValueTests.cs +++ b/test/Serilog.Settings.Configuration.Tests/StringArgumentValueTests.cs @@ -163,5 +163,27 @@ public void ReferencingUndeclaredLevelSwitchThrows() Assert.Contains("$mySwitch", ex.Message); Assert.Contains("\"LevelSwitches\":{\"$mySwitch\":", ex.Message); } + + [Fact] + public void StringValuesConvertToTypeFromShortTypeName() + { + var shortTypeName = "System.Version"; + var stringArgumentValue = new StringArgumentValue(() => shortTypeName); + + var actual = (Type)stringArgumentValue.ConvertTo(typeof(Type), new Dictionary()); + + Assert.Equal(typeof(Version), actual); + } + + [Fact] + public void StringValuesConvertToTypeFromAssemblyQualifiedName() + { + var assemblyQualifiedName = typeof(Version).AssemblyQualifiedName; + var stringArgumentValue = new StringArgumentValue(() => assemblyQualifiedName); + + var actual = (Type)stringArgumentValue.ConvertTo(typeof(Type), new Dictionary()); + + Assert.Equal(typeof(Version), actual); + } } -} \ No newline at end of file +} From fac151ffa2172968d73756524f994617b2d69bc3 Mon Sep 17 00:00:00 2001 From: Thibaud Desodt Date: Sat, 14 Jul 2018 10:32:55 +0200 Subject: [PATCH 5/6] Expose Destructure.AsScalar(Type scalarType) to the configuration --- .../Configuration/ConfigurationReader.cs | 4 ++ .../ConfigurationSettingsTests.cs | 48 +++++++++++++++++++ 2 files changed, 52 insertions(+) diff --git a/src/Serilog.Settings.Configuration/Settings/Configuration/ConfigurationReader.cs b/src/Serilog.Settings.Configuration/Settings/Configuration/ConfigurationReader.cs index 0fb6a87..eacb9f8 100644 --- a/src/Serilog.Settings.Configuration/Settings/Configuration/ConfigurationReader.cs +++ b/src/Serilog.Settings.Configuration/Settings/Configuration/ConfigurationReader.cs @@ -384,6 +384,7 @@ internal static IList FindDestructureConfigurationMethods(IReadOnlyC found.Add(GetSurrogateConfigurationMethod((c, m, _) => ToMaximumDepth(c, m))); found.Add(GetSurrogateConfigurationMethod((c, m, _) => ToMaximumStringLength(c, m))); found.Add(GetSurrogateConfigurationMethod((c, m, _) => ToMaximumCollectionCount(c, m))); + found.Add(GetSurrogateConfigurationMethod((c, t, _) => AsScalar(c, t))); } return found; @@ -435,6 +436,9 @@ internal static LoggerConfiguration ToMaximumStringLength(LoggerDestructuringCon internal static LoggerConfiguration ToMaximumCollectionCount(LoggerDestructuringConfiguration loggerDestructuringConfiguration, int maximumCollectionCount) => loggerDestructuringConfiguration.ToMaximumCollectionCount(maximumCollectionCount); + internal static LoggerConfiguration AsScalar(LoggerDestructuringConfiguration loggerDestructuringConfiguration, Type scalarType) + => loggerDestructuringConfiguration.AsScalar(scalarType); + internal static LoggerConfiguration FromLogContext(LoggerEnrichmentConfiguration loggerEnrichmentConfiguration) => loggerEnrichmentConfiguration.FromLogContext(); diff --git a/test/Serilog.Settings.Configuration.Tests/ConfigurationSettingsTests.cs b/test/Serilog.Settings.Configuration.Tests/ConfigurationSettingsTests.cs index efa78c9..85a0bac 100644 --- a/test/Serilog.Settings.Configuration.Tests/ConfigurationSettingsTests.cs +++ b/test/Serilog.Settings.Configuration.Tests/ConfigurationSettingsTests.cs @@ -703,5 +703,53 @@ public void DestructuringWithCustomExtensionMethodIsApplied() Assert.Equal("\"hardcoded\"", formattedProperty); } + + [Fact] + public void DestructuringAsScalarIsAppliedWithShortTypeName() + { + var json = @"{ + ""Serilog"": { + ""Destructure"": [ + { + ""Name"": ""AsScalar"", + ""Args"": { ""scalarType"": ""System.Version"" } + }] + } + }"; + + LogEvent evt = null; + var log = ConfigFromJson(json) + .WriteTo.Sink(new DelegatingSink(e => evt = e)) + .CreateLogger(); + + log.Information("Destructuring as scalar {@Scalarized}", new Version(2,3)); + var prop = evt.Properties["Scalarized"]; + + Assert.IsType(prop); + } + + [Fact] + public void DestructuringAsScalarIsAppliedWithAssemblyQualifiedName() + { + var json = $@"{{ + ""Serilog"": {{ + ""Destructure"": [ + {{ + ""Name"": ""AsScalar"", + ""Args"": {{ ""scalarType"": ""{typeof(Version).AssemblyQualifiedName}"" }} + }}] + }} + }}"; + + LogEvent evt = null; + var log = ConfigFromJson(json) + .WriteTo.Sink(new DelegatingSink(e => evt = e)) + .CreateLogger(); + + log.Information("Destructuring as scalar {@Scalarized}", new Version(2,3)); + var prop = evt.Properties["Scalarized"]; + + Assert.IsType(prop); + } } } From d9d6cec8841f595272f103b5d22382ae6240337e Mon Sep 17 00:00:00 2001 From: Thibaud Desodt Date: Sun, 15 Jul 2018 15:57:25 +0200 Subject: [PATCH 6/6] Refactor ConfigurationReader and move Surrogate methods to a separate class --- .../Configuration/ConfigurationReader.cs | 59 +---------- .../SurrogateConfigurationMethods.cs | 99 +++++++++++++++++++ 2 files changed, 104 insertions(+), 54 deletions(-) create mode 100644 src/Serilog.Settings.Configuration/Settings/Configuration/SurrogateConfigurationMethods.cs diff --git a/src/Serilog.Settings.Configuration/Settings/Configuration/ConfigurationReader.cs b/src/Serilog.Settings.Configuration/Settings/Configuration/ConfigurationReader.cs index eacb9f8..0a5ffbf 100644 --- a/src/Serilog.Settings.Configuration/Settings/Configuration/ConfigurationReader.cs +++ b/src/Serilog.Settings.Configuration/Settings/Configuration/ConfigurationReader.cs @@ -11,7 +11,6 @@ using Serilog.Core; using Serilog.Debugging; using Serilog.Events; -using System.Linq.Expressions; using System.Text.RegularExpressions; namespace Serilog.Settings.Configuration @@ -354,7 +353,7 @@ internal static IList FindSinkConfigurationMethods(IReadOnlyCollecti { var found = FindConfigurationExtensionMethods(configurationAssemblies, typeof(LoggerSinkConfiguration)); if (configurationAssemblies.Contains(typeof(LoggerSinkConfiguration).GetTypeInfo().Assembly)) - found.Add(GetSurrogateConfigurationMethod, LoggingLevelSwitch>((c, a, s) => Logger(c, a, LevelAlias.Minimum, s))); + found.AddRange(SurrogateConfigurationMethods.WriteTo); return found; } @@ -370,7 +369,7 @@ internal static IList FindFilterConfigurationMethods(IReadOnlyCollec { var found = FindConfigurationExtensionMethods(configurationAssemblies, typeof(LoggerFilterConfiguration)); if (configurationAssemblies.Contains(typeof(LoggerFilterConfiguration).GetTypeInfo().Assembly)) - found.Add(GetSurrogateConfigurationMethod((c, f, _) => With(c, f))); + found.AddRange(SurrogateConfigurationMethods.Filter); return found; } @@ -379,13 +378,7 @@ internal static IList FindDestructureConfigurationMethods(IReadOnlyC { var found = FindConfigurationExtensionMethods(configurationAssemblies, typeof(LoggerDestructuringConfiguration)); if (configurationAssemblies.Contains(typeof(LoggerDestructuringConfiguration).GetTypeInfo().Assembly)) - { - found.Add(GetSurrogateConfigurationMethod((c, d, _) => With(c, d))); - found.Add(GetSurrogateConfigurationMethod((c, m, _) => ToMaximumDepth(c, m))); - found.Add(GetSurrogateConfigurationMethod((c, m, _) => ToMaximumStringLength(c, m))); - found.Add(GetSurrogateConfigurationMethod((c, m, _) => ToMaximumCollectionCount(c, m))); - found.Add(GetSurrogateConfigurationMethod((c, t, _) => AsScalar(c, t))); - } + found.AddRange(SurrogateConfigurationMethods.Destructure); return found; } @@ -394,12 +387,12 @@ internal static IList FindEventEnricherConfigurationMethods(IReadOnl { var found = FindConfigurationExtensionMethods(configurationAssemblies, typeof(LoggerEnrichmentConfiguration)); if (configurationAssemblies.Contains(typeof(LoggerEnrichmentConfiguration).GetTypeInfo().Assembly)) - found.Add(GetSurrogateConfigurationMethod((c, _, __) => FromLogContext(c))); + found.AddRange(SurrogateConfigurationMethods.Enrich); return found; } - internal static IList FindConfigurationExtensionMethods(IReadOnlyCollection configurationAssemblies, Type configType) + internal static List FindConfigurationExtensionMethods(IReadOnlyCollection configurationAssemblies, Type configType) { return configurationAssemblies .SelectMany(a => a.ExportedTypes @@ -411,48 +404,6 @@ internal static IList FindConfigurationExtensionMethods(IReadOnlyCol .ToList(); } - /* - 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. - */ - - // TODO: add overload for array argument (ILogEventEnricher[]) - internal static LoggerConfiguration With(LoggerFilterConfiguration loggerFilterConfiguration, ILogEventFilter filter) - => loggerFilterConfiguration.With(filter); - - // TODO: add overload for array argument (IDestructuringPolicy[]) - internal static LoggerConfiguration With(LoggerDestructuringConfiguration loggerDestructuringConfiguration, IDestructuringPolicy policy) - => loggerDestructuringConfiguration.With(policy); - - internal static LoggerConfiguration ToMaximumDepth(LoggerDestructuringConfiguration loggerDestructuringConfiguration, int maximumDestructuringDepth) - => loggerDestructuringConfiguration.ToMaximumDepth(maximumDestructuringDepth); - - internal static LoggerConfiguration ToMaximumStringLength(LoggerDestructuringConfiguration loggerDestructuringConfiguration, int maximumStringLength) - => loggerDestructuringConfiguration.ToMaximumStringLength(maximumStringLength); - - internal static LoggerConfiguration ToMaximumCollectionCount(LoggerDestructuringConfiguration loggerDestructuringConfiguration, int maximumCollectionCount) - => loggerDestructuringConfiguration.ToMaximumCollectionCount(maximumCollectionCount); - - internal static LoggerConfiguration AsScalar(LoggerDestructuringConfiguration loggerDestructuringConfiguration, Type scalarType) - => loggerDestructuringConfiguration.AsScalar(scalarType); - - internal static LoggerConfiguration FromLogContext(LoggerEnrichmentConfiguration loggerEnrichmentConfiguration) - => loggerEnrichmentConfiguration.FromLogContext(); - - // Unlike the other configuration methods, Logger is an instance method rather than an extension. - internal static LoggerConfiguration Logger( - LoggerSinkConfiguration loggerSinkConfiguration, - Action configureLogger, - LogEventLevel restrictedToMinimumLevel = LevelAlias.Minimum, - LoggingLevelSwitch levelSwitch = null) - => loggerSinkConfiguration.Logger(configureLogger, restrictedToMinimumLevel, levelSwitch); - - internal static MethodInfo GetSurrogateConfigurationMethod(Expression> method) - => (method.Body as MethodCallExpression)?.Method; - internal static bool IsValidSwitchName(string input) { return Regex.IsMatch(input, LevelSwitchNameRegex); diff --git a/src/Serilog.Settings.Configuration/Settings/Configuration/SurrogateConfigurationMethods.cs b/src/Serilog.Settings.Configuration/Settings/Configuration/SurrogateConfigurationMethods.cs new file mode 100644 index 0000000..71faa7f --- /dev/null +++ b/src/Serilog.Settings.Configuration/Settings/Configuration/SurrogateConfigurationMethods.cs @@ -0,0 +1,99 @@ +using System; +using System.Collections.Generic; +using System.Linq.Expressions; +using System.Reflection; +using Serilog.Configuration; +using Serilog.Core; +using Serilog.Events; + +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 + /// are actually "regular" method calls and would not be found otherwise. + /// + /// This static class contains internal methods that can be used instead. + /// + /// + static class SurrogateConfigurationMethods + { + public static IEnumerable WriteTo + { + get + { + yield return GetSurrogateConfigurationMethod, LoggingLevelSwitch>((c, a, s) => Logger(c, a, LevelAlias.Minimum, s)); + } + } + + public static IEnumerable Filter + { + get + { + yield return GetSurrogateConfigurationMethod((c, f, _) => With(c, f)); + } + } + + 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)); + } + } + + static MethodInfo GetSurrogateConfigurationMethod(Expression> method) + => (method.Body as MethodCallExpression)?.Method; + + /* + 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. + */ + + // TODO: add overload for array argument (ILogEventEnricher[]) + static LoggerConfiguration With(LoggerFilterConfiguration loggerFilterConfiguration, ILogEventFilter filter) + => loggerFilterConfiguration.With(filter); + + // TODO: add overload for array argument (IDestructuringPolicy[]) + static LoggerConfiguration With(LoggerDestructuringConfiguration loggerDestructuringConfiguration, IDestructuringPolicy policy) + => loggerDestructuringConfiguration.With(policy); + + static LoggerConfiguration ToMaximumDepth(LoggerDestructuringConfiguration loggerDestructuringConfiguration, int maximumDestructuringDepth) + => loggerDestructuringConfiguration.ToMaximumDepth(maximumDestructuringDepth); + + static LoggerConfiguration ToMaximumStringLength(LoggerDestructuringConfiguration loggerDestructuringConfiguration, int maximumStringLength) + => loggerDestructuringConfiguration.ToMaximumStringLength(maximumStringLength); + + static LoggerConfiguration ToMaximumCollectionCount(LoggerDestructuringConfiguration loggerDestructuringConfiguration, int maximumCollectionCount) + => loggerDestructuringConfiguration.ToMaximumCollectionCount(maximumCollectionCount); + + static LoggerConfiguration AsScalar(LoggerDestructuringConfiguration loggerDestructuringConfiguration, Type scalarType) + => loggerDestructuringConfiguration.AsScalar(scalarType); + + 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); + } +}