From 34d64750f6b079978959d67b2b539d639c982233 Mon Sep 17 00:00:00 2001 From: Ivan Maximov Date: Mon, 19 Dec 2022 19:25:58 +0300 Subject: [PATCH] Implicit usings and file-scoped namespaces --- .editorconfig | 2 + Directory.Build.props | 1 + sample/Sample/Program.cs | 136 +- ...log-settings-configuration.sln.DotSettings | 16 +- ...figurationLoggerConfigurationExtensions.cs | 360 +++-- .../Assemblies/AssemblyFinder.cs | 67 +- .../Assemblies/ConfigurationAssemblySource.cs | 25 +- .../DependencyContextAssemblyFinder.cs | 50 +- .../Assemblies/DllScanningAssemblyFinder.cs | 87 +- .../Configuration/ConfigurationReader.cs | 870 ++++++------ .../IConfigurationArgumentValue.cs | 9 +- .../Configuration/IConfigurationReader.cs | 11 +- .../Configuration/LoggingFilterSwitchProxy.cs | 69 +- .../Configuration/ObjectArgumentValue.cs | 346 +++-- .../Configuration/ResolutionContext.cs | 119 +- .../Configuration/StringArgumentValue.cs | 292 ++--- .../SurrogateConfigurationMethods.cs | 230 ++-- .../ConfigurationReaderTests.cs | 374 +++--- .../ConfigurationSettingsTests.cs | 1165 ++++++++--------- .../DllScanningAssemblyFinderTests.cs | 93 +- .../DummyLoggerConfigurationExtensions.cs | 40 +- ...figurationWithMultipleMethodsExtensions.cs | 64 +- .../DynamicLevelChangeTests.cs | 133 +- .../LoggerConfigurationExtensionsTests.cs | 141 +- .../ObjectArgumentValueTests.cs | 103 +- ...erilog.Settings.Configuration.Tests.csproj | 4 + .../StringArgumentValueTests.cs | 370 +++--- .../Support/AbstractClass.cs | 9 +- .../Support/ConfigurationBuilderExtensions.cs | 13 +- .../Support/ConfigurationReaderTestHelpers.cs | 73 +- .../Support/CustomConsoleTheme.cs | 7 +- .../Support/DelegatingSink.cs | 46 +- .../Support/Extensions.cs | 25 +- .../Support/JsonStringConfigSource.cs | 84 +- .../Support/ReloadableConfigurationSource.cs | 46 +- .../Support/Some.cs | 184 ++- .../Support/StaticAccessorClasses.cs | 89 +- test/TestDummies/Console/DummyConsoleSink.cs | 34 +- .../Console/Themes/ConcreteConsoleTheme.cs | 7 +- .../Console/Themes/ConsoleTheme.cs | 9 +- .../Console/Themes/ConsoleThemes.cs | 9 +- .../Console/Themes/EmptyConsoleTheme.cs | 7 +- test/TestDummies/DummyAnonymousUserFilter.cs | 21 +- test/TestDummies/DummyConfigurationSink.cs | 59 +- ...DummyHardCodedStringDestructuringPolicy.cs | 28 +- .../DummyLoggerConfigurationExtensions.cs | 279 ++-- test/TestDummies/DummyPolicy.cs | 53 +- test/TestDummies/DummyRollingFileAuditSink.cs | 31 +- test/TestDummies/DummyRollingFileSink.cs | 31 +- test/TestDummies/DummyThreadIdEnricher.cs | 13 +- test/TestDummies/DummyWithLevelSwitchSink.cs | 35 +- test/TestDummies/DummyWrappingSink.cs | 43 +- test/TestDummies/TestDummies.csproj | 4 + 53 files changed, 3145 insertions(+), 3271 deletions(-) diff --git a/.editorconfig b/.editorconfig index 3687ef4..55dcd64 100644 --- a/.editorconfig +++ b/.editorconfig @@ -15,3 +15,5 @@ end_of_line = lf [*.{cmd, bat}] end_of_line = crlf + +csharp_style_namespace_declarations = file_scoped:suggestion diff --git a/Directory.Build.props b/Directory.Build.props index c402103..f6e3c1b 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -3,6 +3,7 @@ latest True + enable diff --git a/sample/Sample/Program.cs b/sample/Sample/Program.cs index 4f4d7f9..d2888aa 100644 --- a/sample/Sample/Program.cs +++ b/sample/Sample/Program.cs @@ -1,11 +1,4 @@ -using System; - -using System.IO; -using System.Linq; -using System.Collections.Generic; -using System.Threading; - -using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Configuration; using Serilog; using Serilog.Core; @@ -14,93 +7,92 @@ // ReSharper disable UnusedType.Global -namespace Sample +namespace Sample; + +public class Program { - public class Program + public static void Main(string[] args) { - public static void Main(string[] args) - { - SelfLog.Enable(Console.Error); + SelfLog.Enable(Console.Error); - Thread.CurrentThread.Name = "Main thread"; + Thread.CurrentThread.Name = "Main thread"; - var configuration = new ConfigurationBuilder() - .SetBasePath(Directory.GetCurrentDirectory()) - .AddJsonFile(path: "appsettings.json", optional: false, reloadOnChange: true) - .Build(); + var configuration = new ConfigurationBuilder() + .SetBasePath(Directory.GetCurrentDirectory()) + .AddJsonFile(path: "appsettings.json", optional: false, reloadOnChange: true) + .Build(); - var logger = new LoggerConfiguration() - .ReadFrom.Configuration(configuration) - .CreateLogger(); + var logger = new LoggerConfiguration() + .ReadFrom.Configuration(configuration) + .CreateLogger(); - logger.Information("Args: {Args}", args); + logger.Information("Args: {Args}", args); - do - { - logger.ForContext().Information("Hello, world!"); - logger.ForContext().Error("Hello, world!"); - logger.ForContext(Constants.SourceContextPropertyName, "Microsoft").Warning("Hello, world!"); - logger.ForContext(Constants.SourceContextPropertyName, "Microsoft").Error("Hello, world!"); - logger.ForContext(Constants.SourceContextPropertyName, "MyApp.Something.Tricky").Verbose("Hello, world!"); + do + { + logger.ForContext().Information("Hello, world!"); + logger.ForContext().Error("Hello, world!"); + logger.ForContext(Constants.SourceContextPropertyName, "Microsoft").Warning("Hello, world!"); + logger.ForContext(Constants.SourceContextPropertyName, "Microsoft").Error("Hello, world!"); + logger.ForContext(Constants.SourceContextPropertyName, "MyApp.Something.Tricky").Verbose("Hello, world!"); - logger.Information("Destructure with max object nesting depth:\n{@NestedObject}", - new { FiveDeep = new { Two = new { Three = new { Four = new { Five = "the end" } } } } }); + logger.Information("Destructure with max object nesting depth:\n{@NestedObject}", + new { FiveDeep = new { Two = new { Three = new { Four = new { Five = "the end" } } } } }); - logger.Information("Destructure with max string length:\n{@LongString}", - new { TwentyChars = "0123456789abcdefghij" }); + logger.Information("Destructure with max string length:\n{@LongString}", + new { TwentyChars = "0123456789abcdefghij" }); - logger.Information("Destructure with max collection count:\n{@BigData}", - new { TenItems = new[] { "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten" } }); + logger.Information("Destructure with max collection count:\n{@BigData}", + 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" }); + logger.Information("Destructure with policy to strip password:\n{@LoginData}", + new LoginData { Username = "BGates", Password = "isityearoflinuxyet" }); - Console.WriteLine("\nPress \"q\" to quit, or any other key to run again.\n"); - } - while (!args.Contains("--run-once") && (Console.ReadKey().KeyChar != 'q')); + Console.WriteLine("\nPress \"q\" to quit, or any other key to run again.\n"); } + while (!args.Contains("--run-once") && (Console.ReadKey().KeyChar != 'q')); } +} - // The filter syntax in the sample configuration file is - // processed by the Serilog.Filters.Expressions package. - public class CustomFilter : ILogEventFilter - { - readonly LogEventLevel _levelFilter; - - public CustomFilter(LogEventLevel levelFilter = LogEventLevel.Information) - { - _levelFilter = levelFilter; - } +// The filter syntax in the sample configuration file is +// processed by the Serilog.Filters.Expressions package. +public class CustomFilter : ILogEventFilter +{ + readonly LogEventLevel _levelFilter; - public bool IsEnabled(LogEvent logEvent) - { - return logEvent.Level >= _levelFilter; - } + public CustomFilter(LogEventLevel levelFilter = LogEventLevel.Information) + { + _levelFilter = levelFilter; } - public class LoginData + public bool IsEnabled(LogEvent logEvent) { - public string Username; - // ReSharper disable once NotAccessedField.Global - public string Password; + return logEvent.Level >= _levelFilter; } +} + +public class LoginData +{ + public string Username; + // ReSharper disable once NotAccessedField.Global + public string Password; +} - public class CustomPolicy : IDestructuringPolicy +public class CustomPolicy : IDestructuringPolicy +{ + public bool TryDestructure(object value, ILogEventPropertyValueFactory propertyValueFactory, out LogEventPropertyValue result) { - public bool TryDestructure(object value, ILogEventPropertyValueFactory propertyValueFactory, out LogEventPropertyValue result) + result = null; + + if (value is LoginData loginData) { - result = null; - - if (value is LoginData loginData) - { - result = new StructureValue( - new List - { - new("Username", new ScalarValue(loginData.Username)) - }); - } - - return (result != null); + result = new StructureValue( + new List + { + new("Username", new ScalarValue(loginData.Username)) + }); } + + return (result != null); } } diff --git a/serilog-settings-configuration.sln.DotSettings b/serilog-settings-configuration.sln.DotSettings index 2fdb7b2..6386ab0 100644 --- a/serilog-settings-configuration.sln.DotSettings +++ b/serilog-settings-configuration.sln.DotSettings @@ -1,6 +1,6 @@  - - + + True True True @@ -477,7 +477,7 @@ II.2.12 <HandlesEvent /> </Patterns> CustomLayout - + True False True @@ -551,11 +551,11 @@ II.2.12 <HandlesEvent /> True True True - - - - + + + + <data /> <data><IncludeFilters /><ExcludeFilters /></data> True - True \ No newline at end of file + True diff --git a/src/Serilog.Settings.Configuration/ConfigurationLoggerConfigurationExtensions.cs b/src/Serilog.Settings.Configuration/ConfigurationLoggerConfigurationExtensions.cs index aa70945..4e24eef 100644 --- a/src/Serilog.Settings.Configuration/ConfigurationLoggerConfigurationExtensions.cs +++ b/src/Serilog.Settings.Configuration/ConfigurationLoggerConfigurationExtensions.cs @@ -12,7 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -using System; using System.Reflection; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyModel; @@ -20,189 +19,188 @@ using Serilog.Settings.Configuration; using Serilog.Settings.Configuration.Assemblies; -namespace Serilog +namespace Serilog; + +/// +/// Extends with support for System.Configuration appSettings elements. +/// +public static class ConfigurationLoggerConfigurationExtensions { /// - /// Extends with support for System.Configuration appSettings elements. + /// Configuration section name required by this package. + /// + public const string DefaultSectionName = "Serilog"; + + /// + /// Reads logger settings from the provided configuration object using the provided section name. Generally this + /// is preferable over the other method that takes a configuration section. Only this version will populate + /// IConfiguration parameters on target methods. + /// + /// Logger setting configuration. + /// A configuration object which contains a Serilog section. + /// A section name for section which contains a Serilog section. + /// The dependency context from which sink/enricher packages can be located. If not supplied, the platform + /// default will be used. + /// An object allowing configuration to continue. + public static LoggerConfiguration Configuration( + this LoggerSettingsConfiguration settingConfiguration, + IConfiguration configuration, + string sectionName, + DependencyContext dependencyContext = null) + { + if (settingConfiguration == null) throw new ArgumentNullException(nameof(settingConfiguration)); + if (configuration == null) throw new ArgumentNullException(nameof(configuration)); + if (sectionName == null) throw new ArgumentNullException(nameof(sectionName)); + + var assemblyFinder = dependencyContext == null + ? AssemblyFinder.Auto() + : AssemblyFinder.ForDependencyContext(dependencyContext); + + return settingConfiguration.Settings( + new ConfigurationReader( + configuration.GetSection(sectionName), + assemblyFinder, + configuration)); + } + + /// + /// Reads logger settings from the provided configuration object using the default section name. Generally this + /// is preferable over the other method that takes a configuration section. Only this version will populate + /// IConfiguration parameters on target methods. + /// + /// Logger setting configuration. + /// A configuration object which contains a Serilog section. + /// The dependency context from which sink/enricher packages can be located. If not supplied, the platform + /// default will be used. + /// An object allowing configuration to continue. + public static LoggerConfiguration Configuration( + this LoggerSettingsConfiguration settingConfiguration, + IConfiguration configuration, + DependencyContext dependencyContext = null) + => Configuration(settingConfiguration, configuration, DefaultSectionName, dependencyContext); + + /// + /// Reads logger settings from the provided configuration section. Generally it is preferable to use the other + /// extension method that takes the full configuration object. + /// + /// Logger setting configuration. + /// The Serilog configuration section + /// The dependency context from which sink/enricher packages can be located. If not supplied, the platform + /// default will be used. + /// An object allowing configuration to continue. + [Obsolete("Use ReadFrom.Configuration(IConfiguration configuration, string sectionName, DependencyContext dependencyContext) instead.")] + public static LoggerConfiguration ConfigurationSection( + this LoggerSettingsConfiguration settingConfiguration, + IConfigurationSection configSection, + DependencyContext dependencyContext = null) + { + if (settingConfiguration == null) throw new ArgumentNullException(nameof(settingConfiguration)); + if (configSection == null) throw new ArgumentNullException(nameof(configSection)); + + var assemblyFinder = dependencyContext == null + ? AssemblyFinder.Auto() + : AssemblyFinder.ForDependencyContext(dependencyContext); + + return settingConfiguration.Settings( + new ConfigurationReader( + configSection, + assemblyFinder, + configuration: null)); + } + + /// + /// Reads logger settings from the provided configuration object using the provided section name. Generally this + /// is preferable over the other method that takes a configuration section. Only this version will populate + /// IConfiguration parameters on target methods. + /// + /// Logger setting configuration. + /// A configuration object which contains a Serilog section. + /// A section name for section which contains a Serilog section. + /// Defines how the package identifies assemblies to scan for sinks and other types. + /// An object allowing configuration to continue. + public static LoggerConfiguration Configuration( + this LoggerSettingsConfiguration settingConfiguration, + IConfiguration configuration, + string sectionName, + ConfigurationAssemblySource configurationAssemblySource) + { + if (settingConfiguration == null) throw new ArgumentNullException(nameof(settingConfiguration)); + if (configuration == null) throw new ArgumentNullException(nameof(configuration)); + if (sectionName == null) throw new ArgumentNullException(nameof(sectionName)); + + var assemblyFinder = AssemblyFinder.ForSource(configurationAssemblySource); + + return settingConfiguration.Settings(new ConfigurationReader(configuration.GetSection(sectionName), assemblyFinder, configuration)); + } + + /// + /// Reads logger settings from the provided configuration object using the default section name. Generally this + /// is preferable over the other method that takes a configuration section. Only this version will populate + /// IConfiguration parameters on target methods. /// - public static class ConfigurationLoggerConfigurationExtensions + /// Logger setting configuration. + /// A configuration object which contains a Serilog section. + /// Defines how the package identifies assemblies to scan for sinks and other types. + /// An object allowing configuration to continue. + public static LoggerConfiguration Configuration( + this LoggerSettingsConfiguration settingConfiguration, + IConfiguration configuration, + ConfigurationAssemblySource configurationAssemblySource) + => Configuration(settingConfiguration, configuration, DefaultSectionName, configurationAssemblySource); + + /// + /// Reads logger settings from the provided configuration section. Generally it is preferable to use the other + /// extension method that takes the full configuration object. + /// + /// Logger setting configuration. + /// The Serilog configuration section + /// Defines how the package identifies assemblies to scan for sinks and other types. + /// An object allowing configuration to continue. + [Obsolete("Use ReadFrom.Configuration(IConfiguration configuration, string sectionName, ConfigurationAssemblySource configurationAssemblySource) instead.")] + public static LoggerConfiguration ConfigurationSection( + this LoggerSettingsConfiguration settingConfiguration, + IConfigurationSection configSection, + ConfigurationAssemblySource configurationAssemblySource) { - /// - /// Configuration section name required by this package. - /// - public const string DefaultSectionName = "Serilog"; - - /// - /// Reads logger settings from the provided configuration object using the provided section name. Generally this - /// is preferable over the other method that takes a configuration section. Only this version will populate - /// IConfiguration parameters on target methods. - /// - /// Logger setting configuration. - /// A configuration object which contains a Serilog section. - /// A section name for section which contains a Serilog section. - /// The dependency context from which sink/enricher packages can be located. If not supplied, the platform - /// default will be used. - /// An object allowing configuration to continue. - public static LoggerConfiguration Configuration( - this LoggerSettingsConfiguration settingConfiguration, - IConfiguration configuration, - string sectionName, - DependencyContext dependencyContext = null) - { - if (settingConfiguration == null) throw new ArgumentNullException(nameof(settingConfiguration)); - if (configuration == null) throw new ArgumentNullException(nameof(configuration)); - if (sectionName == null) throw new ArgumentNullException(nameof(sectionName)); - - var assemblyFinder = dependencyContext == null - ? AssemblyFinder.Auto() - : AssemblyFinder.ForDependencyContext(dependencyContext); - - return settingConfiguration.Settings( - new ConfigurationReader( - configuration.GetSection(sectionName), - assemblyFinder, - configuration)); - } - - /// - /// Reads logger settings from the provided configuration object using the default section name. Generally this - /// is preferable over the other method that takes a configuration section. Only this version will populate - /// IConfiguration parameters on target methods. - /// - /// Logger setting configuration. - /// A configuration object which contains a Serilog section. - /// The dependency context from which sink/enricher packages can be located. If not supplied, the platform - /// default will be used. - /// An object allowing configuration to continue. - public static LoggerConfiguration Configuration( - this LoggerSettingsConfiguration settingConfiguration, - IConfiguration configuration, - DependencyContext dependencyContext = null) - => Configuration(settingConfiguration, configuration, DefaultSectionName, dependencyContext); - - /// - /// Reads logger settings from the provided configuration section. Generally it is preferable to use the other - /// extension method that takes the full configuration object. - /// - /// Logger setting configuration. - /// The Serilog configuration section - /// The dependency context from which sink/enricher packages can be located. If not supplied, the platform - /// default will be used. - /// An object allowing configuration to continue. - [Obsolete("Use ReadFrom.Configuration(IConfiguration configuration, string sectionName, DependencyContext dependencyContext) instead.")] - public static LoggerConfiguration ConfigurationSection( - this LoggerSettingsConfiguration settingConfiguration, - IConfigurationSection configSection, - DependencyContext dependencyContext = null) - { - if (settingConfiguration == null) throw new ArgumentNullException(nameof(settingConfiguration)); - if (configSection == null) throw new ArgumentNullException(nameof(configSection)); - - var assemblyFinder = dependencyContext == null - ? AssemblyFinder.Auto() - : AssemblyFinder.ForDependencyContext(dependencyContext); - - return settingConfiguration.Settings( - new ConfigurationReader( - configSection, - assemblyFinder, - configuration: null)); - } - - /// - /// Reads logger settings from the provided configuration object using the provided section name. Generally this - /// is preferable over the other method that takes a configuration section. Only this version will populate - /// IConfiguration parameters on target methods. - /// - /// Logger setting configuration. - /// A configuration object which contains a Serilog section. - /// A section name for section which contains a Serilog section. - /// Defines how the package identifies assemblies to scan for sinks and other types. - /// An object allowing configuration to continue. - public static LoggerConfiguration Configuration( - this LoggerSettingsConfiguration settingConfiguration, - IConfiguration configuration, - string sectionName, - ConfigurationAssemblySource configurationAssemblySource) - { - if (settingConfiguration == null) throw new ArgumentNullException(nameof(settingConfiguration)); - if (configuration == null) throw new ArgumentNullException(nameof(configuration)); - if (sectionName == null) throw new ArgumentNullException(nameof(sectionName)); - - var assemblyFinder = AssemblyFinder.ForSource(configurationAssemblySource); - - return settingConfiguration.Settings(new ConfigurationReader(configuration.GetSection(sectionName), assemblyFinder, configuration)); - } - - /// - /// Reads logger settings from the provided configuration object using the default section name. Generally this - /// is preferable over the other method that takes a configuration section. Only this version will populate - /// IConfiguration parameters on target methods. - /// - /// Logger setting configuration. - /// A configuration object which contains a Serilog section. - /// Defines how the package identifies assemblies to scan for sinks and other types. - /// An object allowing configuration to continue. - public static LoggerConfiguration Configuration( - this LoggerSettingsConfiguration settingConfiguration, - IConfiguration configuration, - ConfigurationAssemblySource configurationAssemblySource) - => Configuration(settingConfiguration, configuration, DefaultSectionName, configurationAssemblySource); - - /// - /// Reads logger settings from the provided configuration section. Generally it is preferable to use the other - /// extension method that takes the full configuration object. - /// - /// Logger setting configuration. - /// The Serilog configuration section - /// Defines how the package identifies assemblies to scan for sinks and other types. - /// An object allowing configuration to continue. - [Obsolete("Use ReadFrom.Configuration(IConfiguration configuration, string sectionName, ConfigurationAssemblySource configurationAssemblySource) instead.")] - public static LoggerConfiguration ConfigurationSection( - this LoggerSettingsConfiguration settingConfiguration, - IConfigurationSection configSection, - ConfigurationAssemblySource configurationAssemblySource) - { - if (settingConfiguration == null) throw new ArgumentNullException(nameof(settingConfiguration)); - if (configSection == null) throw new ArgumentNullException(nameof(configSection)); - - var assemblyFinder = AssemblyFinder.ForSource(configurationAssemblySource); - - return settingConfiguration.Settings(new ConfigurationReader(configSection, assemblyFinder, configuration: null)); - } - - /// - /// Reads logger settings from the provided configuration object using the provided section name. - /// - /// Logger setting configuration. - /// A configuration object which contains a Serilog section. - /// A section name for section which contains a Serilog section. - /// A collection of assemblies that contains sinks and other types. - /// An object allowing configuration to continue. - public static LoggerConfiguration Configuration( - this LoggerSettingsConfiguration settingConfiguration, - IConfiguration configuration, - string sectionName, - params Assembly[] assemblies) - { - if (settingConfiguration == null) throw new ArgumentNullException(nameof(settingConfiguration)); - if (configuration == null) throw new ArgumentNullException(nameof(configuration)); - if (sectionName == null) throw new ArgumentNullException(nameof(sectionName)); - - return settingConfiguration.Settings(new ConfigurationReader(configuration.GetSection(sectionName), assemblies, new ResolutionContext(configuration))); - } - - /// - /// Reads logger settings from the provided configuration object using the default section name. - /// - /// Logger setting configuration. - /// A configuration object which contains a Serilog section. - /// A collection of assemblies that contains sinks and other types. - /// An object allowing configuration to continue. - public static LoggerConfiguration Configuration( - this LoggerSettingsConfiguration settingConfiguration, - IConfiguration configuration, - params Assembly[] assemblies) - => Configuration(settingConfiguration, configuration, DefaultSectionName, assemblies); + if (settingConfiguration == null) throw new ArgumentNullException(nameof(settingConfiguration)); + if (configSection == null) throw new ArgumentNullException(nameof(configSection)); + + var assemblyFinder = AssemblyFinder.ForSource(configurationAssemblySource); + + return settingConfiguration.Settings(new ConfigurationReader(configSection, assemblyFinder, configuration: null)); } + + /// + /// Reads logger settings from the provided configuration object using the provided section name. + /// + /// Logger setting configuration. + /// A configuration object which contains a Serilog section. + /// A section name for section which contains a Serilog section. + /// A collection of assemblies that contains sinks and other types. + /// An object allowing configuration to continue. + public static LoggerConfiguration Configuration( + this LoggerSettingsConfiguration settingConfiguration, + IConfiguration configuration, + string sectionName, + params Assembly[] assemblies) + { + if (settingConfiguration == null) throw new ArgumentNullException(nameof(settingConfiguration)); + if (configuration == null) throw new ArgumentNullException(nameof(configuration)); + if (sectionName == null) throw new ArgumentNullException(nameof(sectionName)); + + return settingConfiguration.Settings(new ConfigurationReader(configuration.GetSection(sectionName), assemblies, new ResolutionContext(configuration))); + } + + /// + /// Reads logger settings from the provided configuration object using the default section name. + /// + /// Logger setting configuration. + /// A configuration object which contains a Serilog section. + /// A collection of assemblies that contains sinks and other types. + /// An object allowing configuration to continue. + public static LoggerConfiguration Configuration( + this LoggerSettingsConfiguration settingConfiguration, + IConfiguration configuration, + params Assembly[] assemblies) + => Configuration(settingConfiguration, configuration, DefaultSectionName, assemblies); } diff --git a/src/Serilog.Settings.Configuration/Settings/Configuration/Assemblies/AssemblyFinder.cs b/src/Serilog.Settings.Configuration/Settings/Configuration/Assemblies/AssemblyFinder.cs index cc16a55..c2c3481 100644 --- a/src/Serilog.Settings.Configuration/Settings/Configuration/Assemblies/AssemblyFinder.cs +++ b/src/Serilog.Settings.Configuration/Settings/Configuration/Assemblies/AssemblyFinder.cs @@ -1,50 +1,47 @@ -using System; -using System.Collections.Generic; -using System.Reflection; +using System.Reflection; using Microsoft.Extensions.DependencyModel; -namespace Serilog.Settings.Configuration.Assemblies +namespace Serilog.Settings.Configuration.Assemblies; + +abstract class AssemblyFinder { - abstract class AssemblyFinder - { - public abstract IReadOnlyList FindAssembliesContainingName(string nameToFind); + public abstract IReadOnlyList FindAssembliesContainingName(string nameToFind); - protected static bool IsCaseInsensitiveMatch(string text, string textToFind) - { - return text != null && text.ToLowerInvariant().Contains(textToFind.ToLowerInvariant()); - } + protected static bool IsCaseInsensitiveMatch(string text, string textToFind) + { + return text != null && text.ToLowerInvariant().Contains(textToFind.ToLowerInvariant()); + } - public static AssemblyFinder Auto() + public static AssemblyFinder Auto() + { + try { - try - { - // Need to check `Assembly.GetEntryAssembly()` first because - // `DependencyContext.Default` throws an exception when `Assembly.GetEntryAssembly()` returns null - if (Assembly.GetEntryAssembly() != null && DependencyContext.Default != null) - { - return new DependencyContextAssemblyFinder(DependencyContext.Default); - } - } - catch (NotSupportedException) when (typeof(object).Assembly.Location is "") // bundled mode detection + // Need to check `Assembly.GetEntryAssembly()` first because + // `DependencyContext.Default` throws an exception when `Assembly.GetEntryAssembly()` returns null + if (Assembly.GetEntryAssembly() != null && DependencyContext.Default != null) { + return new DependencyContextAssemblyFinder(DependencyContext.Default); } - - return new DllScanningAssemblyFinder(); } - - public static AssemblyFinder ForSource(ConfigurationAssemblySource configurationAssemblySource) + catch (NotSupportedException) when (typeof(object).Assembly.Location is "") // bundled mode detection { - return configurationAssemblySource switch - { - ConfigurationAssemblySource.UseLoadedAssemblies => Auto(), - ConfigurationAssemblySource.AlwaysScanDllFiles => new DllScanningAssemblyFinder(), - _ => throw new ArgumentOutOfRangeException(nameof(configurationAssemblySource), configurationAssemblySource, null), - }; } - public static AssemblyFinder ForDependencyContext(DependencyContext dependencyContext) + return new DllScanningAssemblyFinder(); + } + + public static AssemblyFinder ForSource(ConfigurationAssemblySource configurationAssemblySource) + { + return configurationAssemblySource switch { - return new DependencyContextAssemblyFinder(dependencyContext); - } + ConfigurationAssemblySource.UseLoadedAssemblies => Auto(), + ConfigurationAssemblySource.AlwaysScanDllFiles => new DllScanningAssemblyFinder(), + _ => throw new ArgumentOutOfRangeException(nameof(configurationAssemblySource), configurationAssemblySource, null), + }; + } + + public static AssemblyFinder ForDependencyContext(DependencyContext dependencyContext) + { + return new DependencyContextAssemblyFinder(dependencyContext); } } diff --git a/src/Serilog.Settings.Configuration/Settings/Configuration/Assemblies/ConfigurationAssemblySource.cs b/src/Serilog.Settings.Configuration/Settings/Configuration/Assemblies/ConfigurationAssemblySource.cs index de5800c..b6a6065 100644 --- a/src/Serilog.Settings.Configuration/Settings/Configuration/Assemblies/ConfigurationAssemblySource.cs +++ b/src/Serilog.Settings.Configuration/Settings/Configuration/Assemblies/ConfigurationAssemblySource.cs @@ -12,21 +12,20 @@ // See the License for the specific language governing permissions and // limitations under the License. -namespace Serilog.Settings.Configuration +namespace Serilog.Settings.Configuration; + +/// +/// Defines how the package will identify the assemblies which are scanned for sinks and other Type information. +/// +public enum ConfigurationAssemblySource { /// - /// Defines how the package will identify the assemblies which are scanned for sinks and other Type information. + /// Try to scan the assemblies already in memory. This is the default. If GetEntryAssembly is null, fallback to DLL scanning. /// - public enum ConfigurationAssemblySource - { - /// - /// Try to scan the assemblies already in memory. This is the default. If GetEntryAssembly is null, fallback to DLL scanning. - /// - UseLoadedAssemblies, + UseLoadedAssemblies, - /// - /// Scan for assemblies in DLLs from the working directory. This is the fallback when GetEntryAssembly is null. - /// - AlwaysScanDllFiles - } + /// + /// Scan for assemblies in DLLs from the working directory. This is the fallback when GetEntryAssembly is null. + /// + AlwaysScanDllFiles } diff --git a/src/Serilog.Settings.Configuration/Settings/Configuration/Assemblies/DependencyContextAssemblyFinder.cs b/src/Serilog.Settings.Configuration/Settings/Configuration/Assemblies/DependencyContextAssemblyFinder.cs index 7a6feaa..13e24f2 100644 --- a/src/Serilog.Settings.Configuration/Settings/Configuration/Assemblies/DependencyContextAssemblyFinder.cs +++ b/src/Serilog.Settings.Configuration/Settings/Configuration/Assemblies/DependencyContextAssemblyFinder.cs @@ -1,37 +1,33 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; +using System.Reflection; using Microsoft.Extensions.DependencyModel; -namespace Serilog.Settings.Configuration.Assemblies +namespace Serilog.Settings.Configuration.Assemblies; + +sealed class DependencyContextAssemblyFinder : AssemblyFinder { - sealed class DependencyContextAssemblyFinder : AssemblyFinder + readonly DependencyContext _dependencyContext; + + public DependencyContextAssemblyFinder(DependencyContext dependencyContext) { - readonly DependencyContext _dependencyContext; + _dependencyContext = dependencyContext ?? throw new ArgumentNullException(nameof(dependencyContext)); + } - public DependencyContextAssemblyFinder(DependencyContext dependencyContext) - { - _dependencyContext = dependencyContext ?? throw new ArgumentNullException(nameof(dependencyContext)); - } + public override IReadOnlyList FindAssembliesContainingName(string nameToFind) + { + var query = from library in _dependencyContext.RuntimeLibraries + where IsReferencingSerilog(library) + from assemblyName in library.GetDefaultAssemblyNames(_dependencyContext) + where IsCaseInsensitiveMatch(assemblyName.Name, nameToFind) + select assemblyName; - public override IReadOnlyList FindAssembliesContainingName(string nameToFind) - { - var query = from library in _dependencyContext.RuntimeLibraries - where IsReferencingSerilog(library) - from assemblyName in library.GetDefaultAssemblyNames(_dependencyContext) - where IsCaseInsensitiveMatch(assemblyName.Name, nameToFind) - select assemblyName; + return query.ToList().AsReadOnly(); - return query.ToList().AsReadOnly(); - - static bool IsReferencingSerilog(Library library) - { - const string Serilog = "serilog"; - return library.Dependencies.Any(dependency => - dependency.Name.StartsWith(Serilog, StringComparison.OrdinalIgnoreCase) && - (dependency.Name.Length == Serilog.Length || dependency.Name[Serilog.Length] == '.')); - } + static bool IsReferencingSerilog(Library library) + { + const string Serilog = "serilog"; + return library.Dependencies.Any(dependency => + dependency.Name.StartsWith(Serilog, StringComparison.OrdinalIgnoreCase) && + (dependency.Name.Length == Serilog.Length || dependency.Name[Serilog.Length] == '.')); } } } diff --git a/src/Serilog.Settings.Configuration/Settings/Configuration/Assemblies/DllScanningAssemblyFinder.cs b/src/Serilog.Settings.Configuration/Settings/Configuration/Assemblies/DllScanningAssemblyFinder.cs index 9cc9139..4d7570c 100644 --- a/src/Serilog.Settings.Configuration/Settings/Configuration/Assemblies/DllScanningAssemblyFinder.cs +++ b/src/Serilog.Settings.Configuration/Settings/Configuration/Assemblies/DllScanningAssemblyFinder.cs @@ -1,65 +1,60 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; using System.Reflection; -namespace Serilog.Settings.Configuration.Assemblies +namespace Serilog.Settings.Configuration.Assemblies; + +sealed class DllScanningAssemblyFinder : AssemblyFinder { - sealed class DllScanningAssemblyFinder : AssemblyFinder + public override IReadOnlyList FindAssembliesContainingName(string nameToFind) { - public override IReadOnlyList FindAssembliesContainingName(string nameToFind) + var probeDirs = new List(); + + if (!string.IsNullOrEmpty(AppDomain.CurrentDomain.BaseDirectory)) { - var probeDirs = new List(); - - if (!string.IsNullOrEmpty(AppDomain.CurrentDomain.BaseDirectory)) - { - probeDirs.Add(AppDomain.CurrentDomain.BaseDirectory); + probeDirs.Add(AppDomain.CurrentDomain.BaseDirectory); #if NETFRAMEWORK - var privateBinPath = AppDomain.CurrentDomain.SetupInformation.PrivateBinPath; - if (!string.IsNullOrEmpty(privateBinPath)) + var privateBinPath = AppDomain.CurrentDomain.SetupInformation.PrivateBinPath; + if (!string.IsNullOrEmpty(privateBinPath)) + { + foreach (var path in privateBinPath.Split(';')) { - foreach (var path in privateBinPath.Split(';')) + if (Path.IsPathRooted(path)) + { + probeDirs.Add(path); + } + else { - if (Path.IsPathRooted(path)) - { - probeDirs.Add(path); - } - else - { - probeDirs.Add(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, path)); - } + probeDirs.Add(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, path)); } } -#endif - } - else - { - probeDirs.Add(Path.GetDirectoryName(typeof(AssemblyFinder).Assembly.Location)); } +#endif + } + else + { + probeDirs.Add(Path.GetDirectoryName(typeof(AssemblyFinder).Assembly.Location)); + } - var query = from probeDir in probeDirs - where Directory.Exists(probeDir) - from outputAssemblyPath in Directory.GetFiles(probeDir, "*.dll") - let assemblyFileName = Path.GetFileNameWithoutExtension(outputAssemblyPath) - where IsCaseInsensitiveMatch(assemblyFileName, nameToFind) - let assemblyName = TryGetAssemblyNameFrom(outputAssemblyPath) - where assemblyName != null - select assemblyName; + var query = from probeDir in probeDirs + where Directory.Exists(probeDir) + from outputAssemblyPath in Directory.GetFiles(probeDir, "*.dll") + let assemblyFileName = Path.GetFileNameWithoutExtension(outputAssemblyPath) + where IsCaseInsensitiveMatch(assemblyFileName, nameToFind) + let assemblyName = TryGetAssemblyNameFrom(outputAssemblyPath) + where assemblyName != null + select assemblyName; - return query.ToList().AsReadOnly(); + return query.ToList().AsReadOnly(); - static AssemblyName TryGetAssemblyNameFrom(string path) + static AssemblyName TryGetAssemblyNameFrom(string path) + { + try { - try - { - return AssemblyName.GetAssemblyName(path); - } - catch (BadImageFormatException) - { - return null; - } + return AssemblyName.GetAssemblyName(path); + } + catch (BadImageFormatException) + { + return null; } } } diff --git a/src/Serilog.Settings.Configuration/Settings/Configuration/ConfigurationReader.cs b/src/Serilog.Settings.Configuration/Settings/Configuration/ConfigurationReader.cs index e9c75b2..8b20544 100644 --- a/src/Serilog.Settings.Configuration/Settings/Configuration/ConfigurationReader.cs +++ b/src/Serilog.Settings.Configuration/Settings/Configuration/ConfigurationReader.cs @@ -1,6 +1,3 @@ -using System; -using System.Collections.Generic; -using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Text.RegularExpressions; @@ -14,573 +11,572 @@ using Serilog.Events; using Serilog.Settings.Configuration.Assemblies; -namespace Serilog.Settings.Configuration +namespace Serilog.Settings.Configuration; + +class ConfigurationReader : IConfigurationReader { - class ConfigurationReader : IConfigurationReader - { - const string LevelSwitchNameRegex = @"^\${0,1}[A-Za-z]+[A-Za-z0-9]*$"; + const string LevelSwitchNameRegex = @"^\${0,1}[A-Za-z]+[A-Za-z0-9]*$"; - readonly IConfigurationSection _section; - readonly IReadOnlyCollection _configurationAssemblies; - readonly ResolutionContext _resolutionContext; + readonly IConfigurationSection _section; + readonly IReadOnlyCollection _configurationAssemblies; + readonly ResolutionContext _resolutionContext; #if NETSTANDARD || NET461 - readonly IConfigurationRoot _configurationRoot; + readonly IConfigurationRoot _configurationRoot; #endif - public ConfigurationReader(IConfigurationSection configSection, AssemblyFinder assemblyFinder, IConfiguration configuration = null) - { - _section = configSection ?? throw new ArgumentNullException(nameof(configSection)); - _configurationAssemblies = LoadConfigurationAssemblies(_section, assemblyFinder); - _resolutionContext = new ResolutionContext(configuration); + public ConfigurationReader(IConfigurationSection configSection, AssemblyFinder assemblyFinder, IConfiguration configuration = null) + { + _section = configSection ?? throw new ArgumentNullException(nameof(configSection)); + _configurationAssemblies = LoadConfigurationAssemblies(_section, assemblyFinder); + _resolutionContext = new ResolutionContext(configuration); #if NETSTANDARD || NET461 - _configurationRoot = configuration as IConfigurationRoot; + _configurationRoot = configuration as IConfigurationRoot; #endif - } + } - // Used internally for processing nested configuration sections -- see GetMethodCalls below. - internal ConfigurationReader(IConfigurationSection configSection, IReadOnlyCollection configurationAssemblies, ResolutionContext resolutionContext) - { - _section = configSection ?? throw new ArgumentNullException(nameof(configSection)); - _configurationAssemblies = configurationAssemblies ?? throw new ArgumentNullException(nameof(configurationAssemblies)); - _resolutionContext = resolutionContext ?? throw new ArgumentNullException(nameof(resolutionContext)); - #if NETSTANDARD || NET461 - _configurationRoot = resolutionContext.HasAppConfiguration ? resolutionContext.AppConfiguration as IConfigurationRoot : null; - #endif - } + // Used internally for processing nested configuration sections -- see GetMethodCalls below. + internal ConfigurationReader(IConfigurationSection configSection, IReadOnlyCollection configurationAssemblies, ResolutionContext resolutionContext) + { + _section = configSection ?? throw new ArgumentNullException(nameof(configSection)); + _configurationAssemblies = configurationAssemblies ?? throw new ArgumentNullException(nameof(configurationAssemblies)); + _resolutionContext = resolutionContext ?? throw new ArgumentNullException(nameof(resolutionContext)); + #if NETSTANDARD || NET461 + _configurationRoot = resolutionContext.HasAppConfiguration ? resolutionContext.AppConfiguration as IConfigurationRoot : null; + #endif + } - public void Configure(LoggerConfiguration loggerConfiguration) - { - ProcessLevelSwitchDeclarations(); - ProcessFilterSwitchDeclarations(); - - ApplyMinimumLevel(loggerConfiguration); - ApplyEnrichment(loggerConfiguration); - ApplyFilters(loggerConfiguration); - ApplyDestructuring(loggerConfiguration); - ApplySinks(loggerConfiguration); - ApplyAuditSinks(loggerConfiguration); - } + public void Configure(LoggerConfiguration loggerConfiguration) + { + ProcessLevelSwitchDeclarations(); + ProcessFilterSwitchDeclarations(); + + ApplyMinimumLevel(loggerConfiguration); + ApplyEnrichment(loggerConfiguration); + ApplyFilters(loggerConfiguration); + ApplyDestructuring(loggerConfiguration); + ApplySinks(loggerConfiguration); + ApplyAuditSinks(loggerConfiguration); + } + + void ProcessFilterSwitchDeclarations() + { + var filterSwitchesDirective = _section.GetSection("FilterSwitches"); - void ProcessFilterSwitchDeclarations() + foreach (var filterSwitchDeclaration in filterSwitchesDirective.GetChildren()) { - var filterSwitchesDirective = _section.GetSection("FilterSwitches"); + var filterSwitch = LoggingFilterSwitchProxy.Create(); + if (filterSwitch == null) + { + SelfLog.WriteLine($"FilterSwitches section found, but neither Serilog.Expressions nor Serilog.Filters.Expressions is referenced."); + break; + } - foreach (var filterSwitchDeclaration in filterSwitchesDirective.GetChildren()) + var switchName = filterSwitchDeclaration.Key; + // switchName must be something like $switch to avoid ambiguities + if (!IsValidSwitchName(switchName)) { - var filterSwitch = LoggingFilterSwitchProxy.Create(); - if (filterSwitch == null) - { - SelfLog.WriteLine($"FilterSwitches section found, but neither Serilog.Expressions nor Serilog.Filters.Expressions is referenced."); - break; - } + throw new FormatException($"\"{switchName}\" is not a valid name for a Filter Switch declaration. The first character of the name must be a letter or '$' sign, like \"FilterSwitches\" : {{\"$switchName\" : \"{{FilterExpression}}\"}}"); + } - var switchName = filterSwitchDeclaration.Key; - // switchName must be something like $switch to avoid ambiguities - if (!IsValidSwitchName(switchName)) - { - throw new FormatException($"\"{switchName}\" is not a valid name for a Filter Switch declaration. The first character of the name must be a letter or '$' sign, like \"FilterSwitches\" : {{\"$switchName\" : \"{{FilterExpression}}\"}}"); - } + SetFilterSwitch(throwOnError: true); + SubscribeToFilterExpressionChanges(); - SetFilterSwitch(throwOnError: true); - SubscribeToFilterExpressionChanges(); + _resolutionContext.AddFilterSwitch(switchName, filterSwitch); - _resolutionContext.AddFilterSwitch(switchName, filterSwitch); + void SubscribeToFilterExpressionChanges() + { + ChangeToken.OnChange(filterSwitchDeclaration.GetReloadToken, () => SetFilterSwitch(throwOnError: false)); + } - void SubscribeToFilterExpressionChanges() + void SetFilterSwitch(bool throwOnError) + { + var filterExpr = filterSwitchDeclaration.Value; + if (string.IsNullOrWhiteSpace(filterExpr)) { - ChangeToken.OnChange(filterSwitchDeclaration.GetReloadToken, () => SetFilterSwitch(throwOnError: false)); + filterSwitch.Expression = null; + return; } - void SetFilterSwitch(bool throwOnError) + try { - var filterExpr = filterSwitchDeclaration.Value; - if (string.IsNullOrWhiteSpace(filterExpr)) - { - filterSwitch.Expression = null; - return; - } - - try + filterSwitch.Expression = filterExpr; + } + catch (Exception e) + { + var errMsg = $"The expression '{filterExpr}' is invalid filter expression: {e.Message}."; + if (throwOnError) { - filterSwitch.Expression = filterExpr; + throw new InvalidOperationException(errMsg, e); } - catch (Exception e) - { - var errMsg = $"The expression '{filterExpr}' is invalid filter expression: {e.Message}."; - if (throwOnError) - { - throw new InvalidOperationException(errMsg, e); - } - SelfLog.WriteLine(errMsg); - } + SelfLog.WriteLine(errMsg); } } } + } - void ProcessLevelSwitchDeclarations() + void ProcessLevelSwitchDeclarations() + { + var levelSwitchesDirective = _section.GetSection("LevelSwitches"); + foreach (var levelSwitchDeclaration in levelSwitchesDirective.GetChildren()) { - var levelSwitchesDirective = _section.GetSection("LevelSwitches"); - foreach (var levelSwitchDeclaration in levelSwitchesDirective.GetChildren()) + var switchName = levelSwitchDeclaration.Key; + var switchInitialLevel = levelSwitchDeclaration.Value; + // switchName must be something like $switch to avoid ambiguities + if (!IsValidSwitchName(switchName)) { - var switchName = levelSwitchDeclaration.Key; - var switchInitialLevel = levelSwitchDeclaration.Value; - // switchName must be something like $switch to avoid ambiguities - if (!IsValidSwitchName(switchName)) - { - throw new FormatException($"\"{switchName}\" is not a valid name for a Level Switch declaration. The first character of the name must be a letter or '$' sign, like \"LevelSwitches\" : {{\"$switchName\" : \"InitialLevel\"}}"); - } + throw new FormatException($"\"{switchName}\" is not a valid name for a Level Switch declaration. The first character of the name must be a letter or '$' sign, like \"LevelSwitches\" : {{\"$switchName\" : \"InitialLevel\"}}"); + } - LoggingLevelSwitch newSwitch; - if (string.IsNullOrEmpty(switchInitialLevel)) - { - newSwitch = new LoggingLevelSwitch(); - } - else - { - var initialLevel = ParseLogEventLevel(switchInitialLevel); - newSwitch = new LoggingLevelSwitch(initialLevel); - } + LoggingLevelSwitch newSwitch; + if (string.IsNullOrEmpty(switchInitialLevel)) + { + newSwitch = new LoggingLevelSwitch(); + } + else + { + var initialLevel = ParseLogEventLevel(switchInitialLevel); + newSwitch = new LoggingLevelSwitch(initialLevel); + } - SubscribeToLoggingLevelChanges(levelSwitchDeclaration, newSwitch); + SubscribeToLoggingLevelChanges(levelSwitchDeclaration, newSwitch); - // make them available later on when resolving argument values - _resolutionContext.AddLevelSwitch(switchName, newSwitch); - } + // make them available later on when resolving argument values + _resolutionContext.AddLevelSwitch(switchName, newSwitch); + } + } + + void ApplyMinimumLevel(LoggerConfiguration loggerConfiguration) + { + var minimumLevelDirective = _section.GetSection("MinimumLevel"); + + IConfigurationSection defaultMinLevelDirective = GetDefaultMinLevelDirective(); + if (defaultMinLevelDirective.Value != null) + { + ApplyMinimumLevelConfiguration(defaultMinLevelDirective, (configuration, levelSwitch) => configuration.ControlledBy(levelSwitch)); } - void ApplyMinimumLevel(LoggerConfiguration loggerConfiguration) + var minLevelControlledByDirective = minimumLevelDirective.GetSection("ControlledBy"); + if (minLevelControlledByDirective.Value != null) { - var minimumLevelDirective = _section.GetSection("MinimumLevel"); + var globalMinimumLevelSwitch = _resolutionContext.LookUpLevelSwitchByName(minLevelControlledByDirective.Value); + // not calling ApplyMinimumLevel local function because here we have a reference to a LogLevelSwitch already + loggerConfiguration.MinimumLevel.ControlledBy(globalMinimumLevelSwitch); + } - IConfigurationSection defaultMinLevelDirective = GetDefaultMinLevelDirective(); - if (defaultMinLevelDirective.Value != null) + foreach (var overrideDirective in minimumLevelDirective.GetSection("Override").GetChildren()) + { + var overridePrefix = overrideDirective.Key; + var overridenLevelOrSwitch = overrideDirective.Value; + if (Enum.TryParse(overridenLevelOrSwitch, out LogEventLevel _)) { - ApplyMinimumLevelConfiguration(defaultMinLevelDirective, (configuration, levelSwitch) => configuration.ControlledBy(levelSwitch)); + ApplyMinimumLevelConfiguration(overrideDirective, (configuration, levelSwitch) => configuration.Override(overridePrefix, levelSwitch)); } - - var minLevelControlledByDirective = minimumLevelDirective.GetSection("ControlledBy"); - if (minLevelControlledByDirective.Value != null) + else { - var globalMinimumLevelSwitch = _resolutionContext.LookUpLevelSwitchByName(minLevelControlledByDirective.Value); + var overrideSwitch = _resolutionContext.LookUpLevelSwitchByName(overridenLevelOrSwitch); // not calling ApplyMinimumLevel local function because here we have a reference to a LogLevelSwitch already - loggerConfiguration.MinimumLevel.ControlledBy(globalMinimumLevelSwitch); + loggerConfiguration.MinimumLevel.Override(overridePrefix, overrideSwitch); } + } - foreach (var overrideDirective in minimumLevelDirective.GetSection("Override").GetChildren()) - { - var overridePrefix = overrideDirective.Key; - var overridenLevelOrSwitch = overrideDirective.Value; - if (Enum.TryParse(overridenLevelOrSwitch, out LogEventLevel _)) - { - ApplyMinimumLevelConfiguration(overrideDirective, (configuration, levelSwitch) => configuration.Override(overridePrefix, levelSwitch)); - } - else - { - var overrideSwitch = _resolutionContext.LookUpLevelSwitchByName(overridenLevelOrSwitch); - // not calling ApplyMinimumLevel local function because here we have a reference to a LogLevelSwitch already - loggerConfiguration.MinimumLevel.Override(overridePrefix, overrideSwitch); - } - } + void ApplyMinimumLevelConfiguration(IConfigurationSection directive, Action applyConfigAction) + { + var minimumLevel = ParseLogEventLevel(directive.Value); - void ApplyMinimumLevelConfiguration(IConfigurationSection directive, Action applyConfigAction) - { - var minimumLevel = ParseLogEventLevel(directive.Value); + var levelSwitch = new LoggingLevelSwitch(minimumLevel); + applyConfigAction(loggerConfiguration.MinimumLevel, levelSwitch); - var levelSwitch = new LoggingLevelSwitch(minimumLevel); - applyConfigAction(loggerConfiguration.MinimumLevel, levelSwitch); + SubscribeToLoggingLevelChanges(directive, levelSwitch); + } - SubscribeToLoggingLevelChanges(directive, levelSwitch); - } + IConfigurationSection GetDefaultMinLevelDirective() + { + #if NETSTANDARD || NET461 - IConfigurationSection GetDefaultMinLevelDirective() + var defaultLevelDirective = minimumLevelDirective.GetSection("Default"); + if (_configurationRoot != null && minimumLevelDirective.Value != null && defaultLevelDirective.Value != null) { - #if NETSTANDARD || NET461 - - var defaultLevelDirective = minimumLevelDirective.GetSection("Default"); - if (_configurationRoot != null && minimumLevelDirective.Value != null && defaultLevelDirective.Value != null) + foreach (var provider in _configurationRoot.Providers.Reverse()) { - foreach (var provider in _configurationRoot.Providers.Reverse()) + if (provider.TryGet(minimumLevelDirective.Path, out _)) { - if (provider.TryGet(minimumLevelDirective.Path, out _)) - { - return _configurationRoot.GetSection(minimumLevelDirective.Path); - } - - if (provider.TryGet(defaultLevelDirective.Path, out _)) - { - return _configurationRoot.GetSection(defaultLevelDirective.Path); - } + return _configurationRoot.GetSection(minimumLevelDirective.Path); } - return null; + if (provider.TryGet(defaultLevelDirective.Path, out _)) + { + return _configurationRoot.GetSection(defaultLevelDirective.Path); + } } - #endif //NET451 or fallback - - return minimumLevelDirective.Value != null ? minimumLevelDirective : minimumLevelDirective.GetSection("Default"); + return null; } - } - void SubscribeToLoggingLevelChanges(IConfigurationSection levelSection, LoggingLevelSwitch levelSwitch) - { - ChangeToken.OnChange( - levelSection.GetReloadToken, - () => - { - if (Enum.TryParse(levelSection.Value, out LogEventLevel minimumLevel)) - levelSwitch.MinimumLevel = minimumLevel; - else - SelfLog.WriteLine($"The value {levelSection.Value} is not a valid Serilog level."); - }); + #endif //NET451 or fallback + + return minimumLevelDirective.Value != null ? minimumLevelDirective : minimumLevelDirective.GetSection("Default"); } + } - void ApplyFilters(LoggerConfiguration loggerConfiguration) - { - var filterDirective = _section.GetSection("Filter"); - if (filterDirective.GetChildren().Any()) + void SubscribeToLoggingLevelChanges(IConfigurationSection levelSection, LoggingLevelSwitch levelSwitch) + { + ChangeToken.OnChange( + levelSection.GetReloadToken, + () => { - var methodCalls = GetMethodCalls(filterDirective); - CallConfigurationMethods(methodCalls, FindFilterConfigurationMethods(_configurationAssemblies), loggerConfiguration.Filter); - } - } + if (Enum.TryParse(levelSection.Value, out LogEventLevel minimumLevel)) + levelSwitch.MinimumLevel = minimumLevel; + else + SelfLog.WriteLine($"The value {levelSection.Value} is not a valid Serilog level."); + }); + } - void ApplyDestructuring(LoggerConfiguration loggerConfiguration) + void ApplyFilters(LoggerConfiguration loggerConfiguration) + { + var filterDirective = _section.GetSection("Filter"); + if (filterDirective.GetChildren().Any()) { - var destructureDirective = _section.GetSection("Destructure"); - if (destructureDirective.GetChildren().Any()) - { - var methodCalls = GetMethodCalls(destructureDirective); - CallConfigurationMethods(methodCalls, FindDestructureConfigurationMethods(_configurationAssemblies), loggerConfiguration.Destructure); - } + var methodCalls = GetMethodCalls(filterDirective); + CallConfigurationMethods(methodCalls, FindFilterConfigurationMethods(_configurationAssemblies), loggerConfiguration.Filter); } + } - void ApplySinks(LoggerConfiguration loggerConfiguration) + void ApplyDestructuring(LoggerConfiguration loggerConfiguration) + { + var destructureDirective = _section.GetSection("Destructure"); + if (destructureDirective.GetChildren().Any()) { - var writeToDirective = _section.GetSection("WriteTo"); - if (writeToDirective.GetChildren().Any()) - { - var methodCalls = GetMethodCalls(writeToDirective); - CallConfigurationMethods(methodCalls, FindSinkConfigurationMethods(_configurationAssemblies), loggerConfiguration.WriteTo); - } + var methodCalls = GetMethodCalls(destructureDirective); + CallConfigurationMethods(methodCalls, FindDestructureConfigurationMethods(_configurationAssemblies), loggerConfiguration.Destructure); } + } - void ApplyAuditSinks(LoggerConfiguration loggerConfiguration) + void ApplySinks(LoggerConfiguration loggerConfiguration) + { + var writeToDirective = _section.GetSection("WriteTo"); + if (writeToDirective.GetChildren().Any()) { - var auditToDirective = _section.GetSection("AuditTo"); - if (auditToDirective.GetChildren().Any()) - { - var methodCalls = GetMethodCalls(auditToDirective); - CallConfigurationMethods(methodCalls, FindAuditSinkConfigurationMethods(_configurationAssemblies), loggerConfiguration.AuditTo); - } + var methodCalls = GetMethodCalls(writeToDirective); + CallConfigurationMethods(methodCalls, FindSinkConfigurationMethods(_configurationAssemblies), loggerConfiguration.WriteTo); } + } - void IConfigurationReader.ApplySinks(LoggerSinkConfiguration loggerSinkConfiguration) + void ApplyAuditSinks(LoggerConfiguration loggerConfiguration) + { + var auditToDirective = _section.GetSection("AuditTo"); + if (auditToDirective.GetChildren().Any()) { - var methodCalls = GetMethodCalls(_section); - CallConfigurationMethods(methodCalls, FindSinkConfigurationMethods(_configurationAssemblies), loggerSinkConfiguration); + var methodCalls = GetMethodCalls(auditToDirective); + CallConfigurationMethods(methodCalls, FindAuditSinkConfigurationMethods(_configurationAssemblies), loggerConfiguration.AuditTo); } + } + + void IConfigurationReader.ApplySinks(LoggerSinkConfiguration loggerSinkConfiguration) + { + var methodCalls = GetMethodCalls(_section); + CallConfigurationMethods(methodCalls, FindSinkConfigurationMethods(_configurationAssemblies), loggerSinkConfiguration); + } + + void IConfigurationReader.ApplyEnrichment(LoggerEnrichmentConfiguration loggerEnrichmentConfiguration) + { + var methodCalls = GetMethodCalls(_section); + CallConfigurationMethods(methodCalls, FindEventEnricherConfigurationMethods(_configurationAssemblies), loggerEnrichmentConfiguration); + } - void IConfigurationReader.ApplyEnrichment(LoggerEnrichmentConfiguration loggerEnrichmentConfiguration) + void ApplyEnrichment(LoggerConfiguration loggerConfiguration) + { + var enrichDirective = _section.GetSection("Enrich"); + if (enrichDirective.GetChildren().Any()) { - var methodCalls = GetMethodCalls(_section); - CallConfigurationMethods(methodCalls, FindEventEnricherConfigurationMethods(_configurationAssemblies), loggerEnrichmentConfiguration); + var methodCalls = GetMethodCalls(enrichDirective); + CallConfigurationMethods(methodCalls, FindEventEnricherConfigurationMethods(_configurationAssemblies), loggerConfiguration.Enrich); } - void ApplyEnrichment(LoggerConfiguration loggerConfiguration) + var propertiesDirective = _section.GetSection("Properties"); + if (propertiesDirective.GetChildren().Any()) { - var enrichDirective = _section.GetSection("Enrich"); - if (enrichDirective.GetChildren().Any()) + foreach (var enrichPropertyDirective in propertiesDirective.GetChildren()) { - var methodCalls = GetMethodCalls(enrichDirective); - CallConfigurationMethods(methodCalls, FindEventEnricherConfigurationMethods(_configurationAssemblies), loggerConfiguration.Enrich); - } - - var propertiesDirective = _section.GetSection("Properties"); - if (propertiesDirective.GetChildren().Any()) - { - foreach (var enrichPropertyDirective in propertiesDirective.GetChildren()) - { - loggerConfiguration.Enrich.WithProperty(enrichPropertyDirective.Key, enrichPropertyDirective.Value); - } + loggerConfiguration.Enrich.WithProperty(enrichPropertyDirective.Key, enrichPropertyDirective.Value); } } + } - internal ILookup> GetMethodCalls(IConfigurationSection directive) + internal ILookup> GetMethodCalls(IConfigurationSection directive) + { + var children = directive.GetChildren().ToList(); + + var result = + (from child in children + where child.Value != null // Plain string + select new { Name = child.Value, Args = new Dictionary() }) + .Concat( + (from child in children + where child.Value == null + let name = GetSectionName(child) + let callArgs = (from argument in child.GetSection("Args").GetChildren() + select new + { + Name = argument.Key, + Value = GetArgumentValue(argument, _configurationAssemblies) + }).ToDictionary(p => p.Name, p => p.Value) + select new { Name = name, Args = callArgs })) + .ToLookup(p => p.Name, p => p.Args); + + return result; + + static string GetSectionName(IConfigurationSection s) { - var children = directive.GetChildren().ToList(); - - var result = - (from child in children - where child.Value != null // Plain string - select new { Name = child.Value, Args = new Dictionary() }) - .Concat( - (from child in children - where child.Value == null - let name = GetSectionName(child) - let callArgs = (from argument in child.GetSection("Args").GetChildren() - select new - { - Name = argument.Key, - Value = GetArgumentValue(argument, _configurationAssemblies) - }).ToDictionary(p => p.Name, p => p.Value) - select new { Name = name, Args = callArgs })) - .ToLookup(p => p.Name, p => p.Args); - - return result; - - static string GetSectionName(IConfigurationSection s) - { - var name = s.GetSection("Name"); - if (name.Value == null) - throw new InvalidOperationException($"The configuration value in {name.Path} has no 'Name' element."); + var name = s.GetSection("Name"); + if (name.Value == null) + throw new InvalidOperationException($"The configuration value in {name.Path} has no 'Name' element."); - return name.Value; - } + return name.Value; } + } - internal static IConfigurationArgumentValue GetArgumentValue(IConfigurationSection argumentSection, IReadOnlyCollection configurationAssemblies) + internal static IConfigurationArgumentValue GetArgumentValue(IConfigurationSection argumentSection, IReadOnlyCollection configurationAssemblies) + { + IConfigurationArgumentValue argumentValue; + + // Reject configurations where an element has both scalar and complex + // values as a result of reading multiple configuration sources. + if (argumentSection.Value != null && argumentSection.GetChildren().Any()) + throw new InvalidOperationException( + $"The value for the argument '{argumentSection.Path}' is assigned different value " + + "types in more than one configuration source. Ensure all configurations consistently " + + "use either a scalar (int, string, boolean) or a complex (array, section, list, " + + "POCO, etc.) type for this argument value."); + + if (argumentSection.Value != null) { - IConfigurationArgumentValue argumentValue; - - // Reject configurations where an element has both scalar and complex - // values as a result of reading multiple configuration sources. - if (argumentSection.Value != null && argumentSection.GetChildren().Any()) - throw new InvalidOperationException( - $"The value for the argument '{argumentSection.Path}' is assigned different value " + - "types in more than one configuration source. Ensure all configurations consistently " + - "use either a scalar (int, string, boolean) or a complex (array, section, list, " + - "POCO, etc.) type for this argument value."); - - if (argumentSection.Value != null) - { - argumentValue = new StringArgumentValue(argumentSection.Value); - } - else - { - argumentValue = new ObjectArgumentValue(argumentSection, configurationAssemblies); - } - - return argumentValue; + argumentValue = new StringArgumentValue(argumentSection.Value); } - - static IReadOnlyCollection LoadConfigurationAssemblies(IConfigurationSection section, AssemblyFinder assemblyFinder) + else { - var serilogAssembly = typeof(ILogger).Assembly; - var assemblies = new Dictionary { [serilogAssembly.FullName] = serilogAssembly }; + argumentValue = new ObjectArgumentValue(argumentSection, configurationAssemblies); + } - var usingSection = section.GetSection("Using"); - if (usingSection.GetChildren().Any()) - { - foreach (var simpleName in usingSection.GetChildren().Select(c => c.Value)) - { - if (string.IsNullOrWhiteSpace(simpleName)) - throw new InvalidOperationException( - "A zero-length or whitespace assembly name was supplied to a Serilog.Using configuration statement."); + return argumentValue; + } - var assembly = Assembly.Load(new AssemblyName(simpleName)); - if (!assemblies.ContainsKey(assembly.FullName)) - assemblies.Add(assembly.FullName, assembly); - } - } + static IReadOnlyCollection LoadConfigurationAssemblies(IConfigurationSection section, AssemblyFinder assemblyFinder) + { + var serilogAssembly = typeof(ILogger).Assembly; + var assemblies = new Dictionary { [serilogAssembly.FullName] = serilogAssembly }; - foreach (var assemblyName in assemblyFinder.FindAssembliesContainingName("serilog")) + var usingSection = section.GetSection("Using"); + if (usingSection.GetChildren().Any()) + { + foreach (var simpleName in usingSection.GetChildren().Select(c => c.Value)) { - var assumed = Assembly.Load(assemblyName); - if (assumed != null && !assemblies.ContainsKey(assumed.FullName)) - assemblies.Add(assumed.FullName, assumed); + if (string.IsNullOrWhiteSpace(simpleName)) + throw new InvalidOperationException( + "A zero-length or whitespace assembly name was supplied to a Serilog.Using configuration statement."); + + var assembly = Assembly.Load(new AssemblyName(simpleName)); + if (!assemblies.ContainsKey(assembly.FullName)) + assemblies.Add(assembly.FullName, assembly); } + } - return assemblies.Values.ToList().AsReadOnly(); + foreach (var assemblyName in assemblyFinder.FindAssembliesContainingName("serilog")) + { + var assumed = Assembly.Load(assemblyName); + if (assumed != null && !assemblies.ContainsKey(assumed.FullName)) + assemblies.Add(assumed.FullName, assumed); } - void CallConfigurationMethods(ILookup> methods, IReadOnlyCollection configurationMethods, object receiver) + return assemblies.Values.ToList().AsReadOnly(); + } + + void CallConfigurationMethods(ILookup> methods, IReadOnlyCollection configurationMethods, object receiver) + { + foreach (var method in methods.SelectMany(g => g.Select(x => new { g.Key, Value = x }))) { - foreach (var method in methods.SelectMany(g => g.Select(x => new { g.Key, Value = x }))) - { - var methodInfo = SelectConfigurationMethod(configurationMethods, method.Key, method.Value.Keys.ToList()); + var methodInfo = SelectConfigurationMethod(configurationMethods, method.Key, method.Value.Keys.ToList()); - if (methodInfo != null) - { - var call = (from p in methodInfo.GetParameters().Skip(1) - let directive = method.Value.FirstOrDefault(s => ParameterNameMatches(p.Name, s.Key)) - select directive.Key == null - ? GetImplicitValueForNotSpecifiedKey(p, methodInfo) - : directive.Value.ConvertTo(p.ParameterType, _resolutionContext)).ToList(); - - call.Insert(0, receiver); - methodInfo.Invoke(null, call.ToArray()); - } + if (methodInfo != null) + { + var call = (from p in methodInfo.GetParameters().Skip(1) + let directive = method.Value.FirstOrDefault(s => ParameterNameMatches(p.Name, s.Key)) + select directive.Key == null + ? GetImplicitValueForNotSpecifiedKey(p, methodInfo) + : directive.Value.ConvertTo(p.ParameterType, _resolutionContext)).ToList(); + + call.Insert(0, receiver); + methodInfo.Invoke(null, call.ToArray()); } } + } - static bool HasImplicitValueWhenNotSpecified(ParameterInfo paramInfo) + static bool HasImplicitValueWhenNotSpecified(ParameterInfo paramInfo) + { + return paramInfo.HasDefaultValue + // parameters of type IConfiguration are implicitly populated with provided Configuration + || paramInfo.ParameterType == typeof(IConfiguration); + } + + object GetImplicitValueForNotSpecifiedKey(ParameterInfo parameter, MethodInfo methodToInvoke) + { + if (!HasImplicitValueWhenNotSpecified(parameter)) { - return paramInfo.HasDefaultValue - // parameters of type IConfiguration are implicitly populated with provided Configuration - || paramInfo.ParameterType == typeof(IConfiguration); + throw new InvalidOperationException("GetImplicitValueForNotSpecifiedKey() should only be called for parameters for which HasImplicitValueWhenNotSpecified() is true. " + + "This means something is wrong in the Serilog.Settings.Configuration code."); } - object GetImplicitValueForNotSpecifiedKey(ParameterInfo parameter, MethodInfo methodToInvoke) + if (parameter.ParameterType == typeof(IConfiguration)) { - if (!HasImplicitValueWhenNotSpecified(parameter)) + if (_resolutionContext.HasAppConfiguration) { - throw new InvalidOperationException("GetImplicitValueForNotSpecifiedKey() should only be called for parameters for which HasImplicitValueWhenNotSpecified() is true. " + - "This means something is wrong in the Serilog.Settings.Configuration code."); + return _resolutionContext.AppConfiguration; } - - if (parameter.ParameterType == typeof(IConfiguration)) + if (parameter.HasDefaultValue) { - if (_resolutionContext.HasAppConfiguration) - { - return _resolutionContext.AppConfiguration; - } - if (parameter.HasDefaultValue) - { - return parameter.DefaultValue; - } - - throw new InvalidOperationException("Trying to invoke a configuration method accepting a `IConfiguration` argument. " + - $"This is not supported when only a `IConfigSection` has been provided. (method '{methodToInvoke}')"); + return parameter.DefaultValue; } - return parameter.DefaultValue; + throw new InvalidOperationException("Trying to invoke a configuration method accepting a `IConfiguration` argument. " + + $"This is not supported when only a `IConfigSection` has been provided. (method '{methodToInvoke}')"); } - internal static MethodInfo SelectConfigurationMethod(IReadOnlyCollection candidateMethods, string name, IReadOnlyCollection suppliedArgumentNames) - { - // Per issue #111, it is safe to use case-insensitive matching on argument names. The CLR doesn't permit this type - // of overloading, and the Microsoft.Extensions.Configuration keys are case-insensitive (case is preserved with some - // config sources, but key-matching is case-insensitive and case-preservation does not appear to be guaranteed). - var selectedMethod = candidateMethods - .Where(m => m.Name == name) - .Where(m => m.GetParameters() - .Skip(1) - .All(p => HasImplicitValueWhenNotSpecified(p) || - ParameterNameMatches(p.Name, suppliedArgumentNames))) - .OrderByDescending(m => - { - var matchingArgs = m.GetParameters().Where(p => ParameterNameMatches(p.Name, suppliedArgumentNames)).ToList(); - - // Prefer the configuration method with most number of matching arguments and of those the ones with - // the most string type parameters to predict best match with least type casting - return new Tuple( - matchingArgs.Count, - matchingArgs.Count(p => p.ParameterType == typeof(string))); - }) - .FirstOrDefault(); + return parameter.DefaultValue; + } - if (selectedMethod == null) + internal static MethodInfo SelectConfigurationMethod(IReadOnlyCollection candidateMethods, string name, IReadOnlyCollection suppliedArgumentNames) + { + // Per issue #111, it is safe to use case-insensitive matching on argument names. The CLR doesn't permit this type + // of overloading, and the Microsoft.Extensions.Configuration keys are case-insensitive (case is preserved with some + // config sources, but key-matching is case-insensitive and case-preservation does not appear to be guaranteed). + var selectedMethod = candidateMethods + .Where(m => m.Name == name) + .Where(m => m.GetParameters() + .Skip(1) + .All(p => HasImplicitValueWhenNotSpecified(p) || + ParameterNameMatches(p.Name, suppliedArgumentNames))) + .OrderByDescending(m => { - var methodsByName = candidateMethods - .Where(m => m.Name == name) - .Select(m => $"{m.Name}({string.Join(", ", m.GetParameters().Skip(1).Select(p => p.Name))})") - .ToList(); - - if (!methodsByName.Any()) - SelfLog.WriteLine($"Unable to find a method called {name}. Candidate methods are:{Environment.NewLine}{string.Join(Environment.NewLine, candidateMethods)}"); - else - SelfLog.WriteLine($"Unable to find a method called {name} " - + (suppliedArgumentNames.Any() - ? "for supplied arguments: " + string.Join(", ", suppliedArgumentNames) - : "with no supplied arguments") - + ". Candidate methods are:" - + Environment.NewLine - + string.Join(Environment.NewLine, methodsByName)); - } + var matchingArgs = m.GetParameters().Where(p => ParameterNameMatches(p.Name, suppliedArgumentNames)).ToList(); - return selectedMethod; - } + // Prefer the configuration method with most number of matching arguments and of those the ones with + // the most string type parameters to predict best match with least type casting + return new Tuple( + matchingArgs.Count, + matchingArgs.Count(p => p.ParameterType == typeof(string))); + }) + .FirstOrDefault(); - static bool ParameterNameMatches(string actualParameterName, string suppliedName) + if (selectedMethod == null) { - return suppliedName.Equals(actualParameterName, StringComparison.OrdinalIgnoreCase); - } + var methodsByName = candidateMethods + .Where(m => m.Name == name) + .Select(m => $"{m.Name}({string.Join(", ", m.GetParameters().Skip(1).Select(p => p.Name))})") + .ToList(); - static bool ParameterNameMatches(string actualParameterName, IEnumerable suppliedNames) - { - return suppliedNames.Any(s => ParameterNameMatches(actualParameterName, s)); + if (!methodsByName.Any()) + SelfLog.WriteLine($"Unable to find a method called {name}. Candidate methods are:{Environment.NewLine}{string.Join(Environment.NewLine, candidateMethods)}"); + else + SelfLog.WriteLine($"Unable to find a method called {name} " + + (suppliedArgumentNames.Any() + ? "for supplied arguments: " + string.Join(", ", suppliedArgumentNames) + : "with no supplied arguments") + + ". Candidate methods are:" + + Environment.NewLine + + string.Join(Environment.NewLine, methodsByName)); } - static IReadOnlyCollection FindSinkConfigurationMethods(IReadOnlyCollection configurationAssemblies) - { - var found = FindConfigurationExtensionMethods(configurationAssemblies, typeof(LoggerSinkConfiguration)); - if (configurationAssemblies.Contains(typeof(LoggerSinkConfiguration).GetTypeInfo().Assembly)) - found.AddRange(SurrogateConfigurationMethods.WriteTo); + return selectedMethod; + } - return found; - } + static bool ParameterNameMatches(string actualParameterName, string suppliedName) + { + return suppliedName.Equals(actualParameterName, StringComparison.OrdinalIgnoreCase); + } - static IReadOnlyCollection FindAuditSinkConfigurationMethods(IReadOnlyCollection configurationAssemblies) - { - var found = FindConfigurationExtensionMethods(configurationAssemblies, typeof(LoggerAuditSinkConfiguration)); - if (configurationAssemblies.Contains(typeof(LoggerAuditSinkConfiguration).GetTypeInfo().Assembly)) - found.AddRange(SurrogateConfigurationMethods.AuditTo); - return found; - } + static bool ParameterNameMatches(string actualParameterName, IEnumerable suppliedNames) + { + return suppliedNames.Any(s => ParameterNameMatches(actualParameterName, s)); + } - static IReadOnlyCollection FindFilterConfigurationMethods(IReadOnlyCollection configurationAssemblies) - { - var found = FindConfigurationExtensionMethods(configurationAssemblies, typeof(LoggerFilterConfiguration)); - if (configurationAssemblies.Contains(typeof(LoggerFilterConfiguration).GetTypeInfo().Assembly)) - found.AddRange(SurrogateConfigurationMethods.Filter); + static IReadOnlyCollection FindSinkConfigurationMethods(IReadOnlyCollection configurationAssemblies) + { + var found = FindConfigurationExtensionMethods(configurationAssemblies, typeof(LoggerSinkConfiguration)); + if (configurationAssemblies.Contains(typeof(LoggerSinkConfiguration).GetTypeInfo().Assembly)) + found.AddRange(SurrogateConfigurationMethods.WriteTo); - return found; - } + return found; + } - static IReadOnlyCollection FindDestructureConfigurationMethods(IReadOnlyCollection configurationAssemblies) - { - var found = FindConfigurationExtensionMethods(configurationAssemblies, typeof(LoggerDestructuringConfiguration)); - if (configurationAssemblies.Contains(typeof(LoggerDestructuringConfiguration).GetTypeInfo().Assembly)) - found.AddRange(SurrogateConfigurationMethods.Destructure); + static IReadOnlyCollection FindAuditSinkConfigurationMethods(IReadOnlyCollection configurationAssemblies) + { + var found = FindConfigurationExtensionMethods(configurationAssemblies, typeof(LoggerAuditSinkConfiguration)); + if (configurationAssemblies.Contains(typeof(LoggerAuditSinkConfiguration).GetTypeInfo().Assembly)) + found.AddRange(SurrogateConfigurationMethods.AuditTo); + return found; + } - return found; - } + static IReadOnlyCollection FindFilterConfigurationMethods(IReadOnlyCollection configurationAssemblies) + { + var found = FindConfigurationExtensionMethods(configurationAssemblies, typeof(LoggerFilterConfiguration)); + if (configurationAssemblies.Contains(typeof(LoggerFilterConfiguration).GetTypeInfo().Assembly)) + found.AddRange(SurrogateConfigurationMethods.Filter); - static IReadOnlyCollection FindEventEnricherConfigurationMethods(IReadOnlyCollection configurationAssemblies) - { - var found = FindConfigurationExtensionMethods(configurationAssemblies, typeof(LoggerEnrichmentConfiguration)); - if (configurationAssemblies.Contains(typeof(LoggerEnrichmentConfiguration).GetTypeInfo().Assembly)) - found.AddRange(SurrogateConfigurationMethods.Enrich); + return found; + } - return found; - } + static IReadOnlyCollection FindDestructureConfigurationMethods(IReadOnlyCollection configurationAssemblies) + { + var found = FindConfigurationExtensionMethods(configurationAssemblies, typeof(LoggerDestructuringConfiguration)); + if (configurationAssemblies.Contains(typeof(LoggerDestructuringConfiguration).GetTypeInfo().Assembly)) + found.AddRange(SurrogateConfigurationMethods.Destructure); + + return found; + } + + static IReadOnlyCollection FindEventEnricherConfigurationMethods(IReadOnlyCollection configurationAssemblies) + { + var found = FindConfigurationExtensionMethods(configurationAssemblies, typeof(LoggerEnrichmentConfiguration)); + if (configurationAssemblies.Contains(typeof(LoggerEnrichmentConfiguration).GetTypeInfo().Assembly)) + found.AddRange(SurrogateConfigurationMethods.Enrich); + + return found; + } - static List FindConfigurationExtensionMethods(IReadOnlyCollection configurationAssemblies, Type configType) + static List FindConfigurationExtensionMethods(IReadOnlyCollection configurationAssemblies, Type configType) + { + // ExtensionAttribute can be polyfilled to support extension methods + static bool HasCustomExtensionAttribute(MethodInfo m) { - // ExtensionAttribute can be polyfilled to support extension methods - static bool HasCustomExtensionAttribute(MethodInfo m) + try { - try - { - return m.CustomAttributes.Any(a => a.AttributeType.FullName == "System.Runtime.CompilerServices.ExtensionAttribute"); - } - catch (CustomAttributeFormatException) - { - return false; - } + return m.CustomAttributes.Any(a => a.AttributeType.FullName == "System.Runtime.CompilerServices.ExtensionAttribute"); + } + catch (CustomAttributeFormatException) + { + return false; } - - return configurationAssemblies - .SelectMany(a => a.ExportedTypes - .Select(t => t.GetTypeInfo()) - .Where(t => t.IsSealed && t.IsAbstract && !t.IsNested)) - .SelectMany(t => t.DeclaredMethods) - .Where(m => m.IsStatic && m.IsPublic && (m.IsDefined(typeof(ExtensionAttribute), false) || HasCustomExtensionAttribute(m))) - .Where(m => m.GetParameters()[0].ParameterType == configType) - .ToList(); } - internal static bool IsValidSwitchName(string input) - { - return Regex.IsMatch(input, LevelSwitchNameRegex); - } + return configurationAssemblies + .SelectMany(a => a.ExportedTypes + .Select(t => t.GetTypeInfo()) + .Where(t => t.IsSealed && t.IsAbstract && !t.IsNested)) + .SelectMany(t => t.DeclaredMethods) + .Where(m => m.IsStatic && m.IsPublic && (m.IsDefined(typeof(ExtensionAttribute), false) || HasCustomExtensionAttribute(m))) + .Where(m => m.GetParameters()[0].ParameterType == configType) + .ToList(); + } - static LogEventLevel ParseLogEventLevel(string value) - { - if (!Enum.TryParse(value, ignoreCase: true, out LogEventLevel parsedLevel)) - throw new InvalidOperationException($"The value {value} is not a valid Serilog level."); - return parsedLevel; - } + internal static bool IsValidSwitchName(string input) + { + return Regex.IsMatch(input, LevelSwitchNameRegex); + } + + static LogEventLevel ParseLogEventLevel(string value) + { + if (!Enum.TryParse(value, ignoreCase: true, out LogEventLevel parsedLevel)) + throw new InvalidOperationException($"The value {value} is not a valid Serilog level."); + return parsedLevel; } } diff --git a/src/Serilog.Settings.Configuration/Settings/Configuration/IConfigurationArgumentValue.cs b/src/Serilog.Settings.Configuration/Settings/Configuration/IConfigurationArgumentValue.cs index e24e8e0..d39015c 100644 --- a/src/Serilog.Settings.Configuration/Settings/Configuration/IConfigurationArgumentValue.cs +++ b/src/Serilog.Settings.Configuration/Settings/Configuration/IConfigurationArgumentValue.cs @@ -1,9 +1,6 @@ -using System; +namespace Serilog.Settings.Configuration; -namespace Serilog.Settings.Configuration +interface IConfigurationArgumentValue { - interface IConfigurationArgumentValue - { - object ConvertTo(Type toType, ResolutionContext resolutionContext); - } + object ConvertTo(Type toType, ResolutionContext resolutionContext); } diff --git a/src/Serilog.Settings.Configuration/Settings/Configuration/IConfigurationReader.cs b/src/Serilog.Settings.Configuration/Settings/Configuration/IConfigurationReader.cs index af815af..f3dd36f 100644 --- a/src/Serilog.Settings.Configuration/Settings/Configuration/IConfigurationReader.cs +++ b/src/Serilog.Settings.Configuration/Settings/Configuration/IConfigurationReader.cs @@ -1,10 +1,9 @@ using Serilog.Configuration; -namespace Serilog.Settings.Configuration +namespace Serilog.Settings.Configuration; + +interface IConfigurationReader : ILoggerSettings { - interface IConfigurationReader : ILoggerSettings - { - void ApplySinks(LoggerSinkConfiguration loggerSinkConfiguration); - void ApplyEnrichment(LoggerEnrichmentConfiguration loggerEnrichmentConfiguration); - } + void ApplySinks(LoggerSinkConfiguration loggerSinkConfiguration); + void ApplyEnrichment(LoggerEnrichmentConfiguration loggerEnrichmentConfiguration); } diff --git a/src/Serilog.Settings.Configuration/Settings/Configuration/LoggingFilterSwitchProxy.cs b/src/Serilog.Settings.Configuration/Settings/Configuration/LoggingFilterSwitchProxy.cs index 676a2dd..a35d6b1 100644 --- a/src/Serilog.Settings.Configuration/Settings/Configuration/LoggingFilterSwitchProxy.cs +++ b/src/Serilog.Settings.Configuration/Settings/Configuration/LoggingFilterSwitchProxy.cs @@ -1,50 +1,47 @@ -using System; +namespace Serilog.Settings.Configuration; -namespace Serilog.Settings.Configuration +class LoggingFilterSwitchProxy { - class LoggingFilterSwitchProxy + readonly Action _setProxy; + readonly Func _getProxy; + + LoggingFilterSwitchProxy(object realSwitch) { - readonly Action _setProxy; - readonly Func _getProxy; + RealSwitch = realSwitch ?? throw new ArgumentNullException(nameof(realSwitch)); - LoggingFilterSwitchProxy(object realSwitch) - { - RealSwitch = realSwitch ?? throw new ArgumentNullException(nameof(realSwitch)); + var type = realSwitch.GetType(); + var expressionProperty = type.GetProperty("Expression") ?? throw new MissingMemberException(type.FullName, "Expression"); + + _setProxy = (Action)Delegate.CreateDelegate( + typeof(Action), + realSwitch, + expressionProperty.GetSetMethod()); - var type = realSwitch.GetType(); - var expressionProperty = type.GetProperty("Expression") ?? throw new MissingMemberException(type.FullName, "Expression"); + _getProxy = (Func)Delegate.CreateDelegate( + typeof(Func), + realSwitch, + expressionProperty.GetGetMethod()); + } - _setProxy = (Action)Delegate.CreateDelegate( - typeof(Action), - realSwitch, - expressionProperty.GetSetMethod()); + public object RealSwitch { get; } - _getProxy = (Func)Delegate.CreateDelegate( - typeof(Func), - realSwitch, - expressionProperty.GetGetMethod()); - } + public string Expression + { + get => _getProxy(); + set => _setProxy(value); + } - public object RealSwitch { get; } + public static LoggingFilterSwitchProxy Create(string expression = null) + { + var filterSwitchType = + Type.GetType("Serilog.Expressions.LoggingFilterSwitch, Serilog.Expressions") ?? + Type.GetType("Serilog.Filters.Expressions.LoggingFilterSwitch, Serilog.Filters.Expressions"); - public string Expression + if (filterSwitchType is null) { - get => _getProxy(); - set => _setProxy(value); + return null; } - public static LoggingFilterSwitchProxy Create(string expression = null) - { - var filterSwitchType = - Type.GetType("Serilog.Expressions.LoggingFilterSwitch, Serilog.Expressions") ?? - Type.GetType("Serilog.Filters.Expressions.LoggingFilterSwitch, Serilog.Filters.Expressions"); - - if (filterSwitchType is null) - { - return null; - } - - return new LoggingFilterSwitchProxy(Activator.CreateInstance(filterSwitchType, expression)); - } + return new LoggingFilterSwitchProxy(Activator.CreateInstance(filterSwitchType, expression)); } } diff --git a/src/Serilog.Settings.Configuration/Settings/Configuration/ObjectArgumentValue.cs b/src/Serilog.Settings.Configuration/Settings/Configuration/ObjectArgumentValue.cs index d22f78b..87d8ace 100644 --- a/src/Serilog.Settings.Configuration/Settings/Configuration/ObjectArgumentValue.cs +++ b/src/Serilog.Settings.Configuration/Settings/Configuration/ObjectArgumentValue.cs @@ -1,6 +1,3 @@ -using System; -using System.Collections.Generic; -using System.Linq; using System.Linq.Expressions; using System.Reflection; @@ -8,234 +5,233 @@ using Serilog.Configuration; -namespace Serilog.Settings.Configuration +namespace Serilog.Settings.Configuration; + +class ObjectArgumentValue : IConfigurationArgumentValue { - class ObjectArgumentValue : IConfigurationArgumentValue + readonly IConfigurationSection _section; + readonly IReadOnlyCollection _configurationAssemblies; + + public ObjectArgumentValue(IConfigurationSection section, IReadOnlyCollection configurationAssemblies) { - readonly IConfigurationSection _section; - readonly IReadOnlyCollection _configurationAssemblies; + _section = section ?? throw new ArgumentNullException(nameof(section)); - public ObjectArgumentValue(IConfigurationSection section, IReadOnlyCollection configurationAssemblies) - { - _section = section ?? throw new ArgumentNullException(nameof(section)); + // used by nested logger configurations to feed a new pass by ConfigurationReader + _configurationAssemblies = configurationAssemblies ?? throw new ArgumentNullException(nameof(configurationAssemblies)); + } - // used by nested logger configurations to feed a new pass by ConfigurationReader - _configurationAssemblies = configurationAssemblies ?? throw new ArgumentNullException(nameof(configurationAssemblies)); - } + public object ConvertTo(Type toType, ResolutionContext resolutionContext) + { + // return the entire section for internal processing + if (toType == typeof(IConfigurationSection)) return _section; - public object ConvertTo(Type toType, ResolutionContext resolutionContext) + // process a nested configuration to populate an Action<> logger/sink config parameter? + var typeInfo = toType.GetTypeInfo(); + if (typeInfo.IsGenericType && + typeInfo.GetGenericTypeDefinition() is Type genericType && genericType == typeof(Action<>)) { - // return the entire section for internal processing - if (toType == typeof(IConfigurationSection)) return _section; + var configType = typeInfo.GenericTypeArguments[0]; + IConfigurationReader configReader = new ConfigurationReader(_section, _configurationAssemblies, resolutionContext); - // process a nested configuration to populate an Action<> logger/sink config parameter? - var typeInfo = toType.GetTypeInfo(); - if (typeInfo.IsGenericType && - typeInfo.GetGenericTypeDefinition() is Type genericType && genericType == typeof(Action<>)) + return configType switch { - var configType = typeInfo.GenericTypeArguments[0]; - IConfigurationReader configReader = new ConfigurationReader(_section, _configurationAssemblies, resolutionContext); - - return configType switch - { - _ when configType == typeof(LoggerConfiguration) => new Action(configReader.Configure), - _ when configType == typeof(LoggerSinkConfiguration) => new Action(configReader.ApplySinks), - _ when configType == typeof(LoggerEnrichmentConfiguration) => new Action(configReader.ApplyEnrichment), - _ => throw new ArgumentException($"Configuration resolution for Action<{configType.Name}> parameter type at the path {_section.Path} is not implemented.") - }; - } + _ when configType == typeof(LoggerConfiguration) => new Action(configReader.Configure), + _ when configType == typeof(LoggerSinkConfiguration) => new Action(configReader.ApplySinks), + _ when configType == typeof(LoggerEnrichmentConfiguration) => new Action(configReader.ApplyEnrichment), + _ => throw new ArgumentException($"Configuration resolution for Action<{configType.Name}> parameter type at the path {_section.Path} is not implemented.") + }; + } - if (toType.IsArray) - return CreateArray(); + if (toType.IsArray) + return CreateArray(); - if (IsContainer(toType, out var elementType) && TryCreateContainer(out var container)) - return container; + if (IsContainer(toType, out var elementType) && TryCreateContainer(out var container)) + return container; - if (TryBuildCtorExpression(_section, toType, resolutionContext, out var ctorExpression)) - { - return Expression.Lambda>(ctorExpression).Compile().Invoke(); - } + if (TryBuildCtorExpression(_section, toType, resolutionContext, out var ctorExpression)) + { + return Expression.Lambda>(ctorExpression).Compile().Invoke(); + } - // MS Config binding can work with a limited set of primitive types and collections - return _section.Get(toType); + // MS Config binding can work with a limited set of primitive types and collections + return _section.Get(toType); - object CreateArray() + object CreateArray() + { + var arrayElementType = toType.GetElementType()!; + var configurationElements = _section.GetChildren().ToArray(); + var array = Array.CreateInstance(arrayElementType, configurationElements.Length); + for (int i = 0; i < configurationElements.Length; ++i) { - var arrayElementType = toType.GetElementType()!; - var configurationElements = _section.GetChildren().ToArray(); - var array = Array.CreateInstance(arrayElementType, configurationElements.Length); - for (int i = 0; i < configurationElements.Length; ++i) - { - var argumentValue = ConfigurationReader.GetArgumentValue(configurationElements[i], _configurationAssemblies); - var value = argumentValue.ConvertTo(arrayElementType, resolutionContext); - array.SetValue(value, i); - } - - return array; + var argumentValue = ConfigurationReader.GetArgumentValue(configurationElements[i], _configurationAssemblies); + var value = argumentValue.ConvertTo(arrayElementType, resolutionContext); + array.SetValue(value, i); } - bool TryCreateContainer(out object result) - { - result = null; + return array; + } - if (toType.GetConstructor(Type.EmptyTypes) == null) - return false; + bool TryCreateContainer(out object result) + { + result = null; - // https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/object-and-collection-initializers#collection-initializers - var addMethod = toType.GetMethods().FirstOrDefault(m => !m.IsStatic && m.Name == "Add" && m.GetParameters().Length == 1 && m.GetParameters()[0].ParameterType == elementType); - if (addMethod == null) - return false; + if (toType.GetConstructor(Type.EmptyTypes) == null) + return false; - var configurationElements = _section.GetChildren().ToArray(); - result = Activator.CreateInstance(toType); + // https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/object-and-collection-initializers#collection-initializers + var addMethod = toType.GetMethods().FirstOrDefault(m => !m.IsStatic && m.Name == "Add" && m.GetParameters().Length == 1 && m.GetParameters()[0].ParameterType == elementType); + if (addMethod == null) + return false; - for (int i = 0; i < configurationElements.Length; ++i) - { - var argumentValue = ConfigurationReader.GetArgumentValue(configurationElements[i], _configurationAssemblies); - var value = argumentValue.ConvertTo(elementType, resolutionContext); - addMethod.Invoke(result, new[] { value }); - } + var configurationElements = _section.GetChildren().ToArray(); + result = Activator.CreateInstance(toType); - return true; + for (int i = 0; i < configurationElements.Length; ++i) + { + var argumentValue = ConfigurationReader.GetArgumentValue(configurationElements[i], _configurationAssemblies); + var value = argumentValue.ConvertTo(elementType, resolutionContext); + addMethod.Invoke(result, new[] { value }); } + + return true; } + } - internal static bool TryBuildCtorExpression( - IConfigurationSection section, Type parameterType, ResolutionContext resolutionContext, out NewExpression ctorExpression) - { - ctorExpression = null; + internal static bool TryBuildCtorExpression( + IConfigurationSection section, Type parameterType, ResolutionContext resolutionContext, out NewExpression ctorExpression) + { + ctorExpression = null; - var typeDirective = section.GetValue("$type") switch + var typeDirective = section.GetValue("$type") switch + { + not null => "$type", + null => section.GetValue("type") switch { - not null => "$type", - null => section.GetValue("type") switch - { - not null => "type", - null => null, - }, - }; + not null => "type", + null => null, + }, + }; - var type = typeDirective switch - { - not null => Type.GetType(section.GetValue(typeDirective), throwOnError: false), - null => parameterType, - }; + var type = typeDirective switch + { + not null => Type.GetType(section.GetValue(typeDirective), throwOnError: false), + null => parameterType, + }; - if (type is null or { IsAbstract: true }) - { - return false; - } + if (type is null or { IsAbstract: true }) + { + return false; + } - var suppliedArguments = section.GetChildren().Where(s => s.Key != typeDirective) - .ToDictionary(s => s.Key, StringComparer.OrdinalIgnoreCase); + var suppliedArguments = section.GetChildren().Where(s => s.Key != typeDirective) + .ToDictionary(s => s.Key, StringComparer.OrdinalIgnoreCase); - if (suppliedArguments.Count == 0 && - type.GetConstructor(Type.EmptyTypes) is ConstructorInfo parameterlessCtor) - { - ctorExpression = Expression.New(parameterlessCtor); - return true; - } + if (suppliedArguments.Count == 0 && + type.GetConstructor(Type.EmptyTypes) is ConstructorInfo parameterlessCtor) + { + ctorExpression = Expression.New(parameterlessCtor); + return true; + } - var ctor = - (from c in type.GetConstructors() - from p in c.GetParameters() - let argumentBindResult = suppliedArguments.TryGetValue(p.Name, out var argValue) switch - { - true => new { success = true, hasMatch = true, value = (object)argValue }, - false => p.HasDefaultValue switch - { - true => new { success = true, hasMatch = false, value = p.DefaultValue }, - false => new { success = false, hasMatch = false, value = (object)null }, - }, - } - group new { argumentBindResult, p.ParameterType } by c into gr - where gr.All(z => z.argumentBindResult.success) - let matchedArgs = gr.Where(z => z.argumentBindResult.hasMatch).ToList() - orderby matchedArgs.Count descending, - matchedArgs.Count(p => p.ParameterType == typeof(string)) descending - select new + var ctor = + (from c in type.GetConstructors() + from p in c.GetParameters() + let argumentBindResult = suppliedArguments.TryGetValue(p.Name, out var argValue) switch + { + true => new { success = true, hasMatch = true, value = (object)argValue }, + false => p.HasDefaultValue switch { - ConstructorInfo = gr.Key, - ArgumentValues = gr.Select(z => new { Value = z.argumentBindResult.value, Type = z.ParameterType }) - .ToList() - }).FirstOrDefault(); + true => new { success = true, hasMatch = false, value = p.DefaultValue }, + false => new { success = false, hasMatch = false, value = (object)null }, + }, + } + group new { argumentBindResult, p.ParameterType } by c into gr + where gr.All(z => z.argumentBindResult.success) + let matchedArgs = gr.Where(z => z.argumentBindResult.hasMatch).ToList() + orderby matchedArgs.Count descending, + matchedArgs.Count(p => p.ParameterType == typeof(string)) descending + select new + { + ConstructorInfo = gr.Key, + ArgumentValues = gr.Select(z => new { Value = z.argumentBindResult.value, Type = z.ParameterType }) + .ToList() + }).FirstOrDefault(); + + if (ctor is null) + { + return false; + } - if (ctor is null) + var ctorArguments = new List(); + foreach (var argumentValue in ctor.ArgumentValues) + { + if (TryBindToCtorArgument(argumentValue.Value, argumentValue.Type, resolutionContext, out var argumentExpression)) { - return false; + ctorArguments.Add(argumentExpression); } - - var ctorArguments = new List(); - foreach (var argumentValue in ctor.ArgumentValues) + else { - if (TryBindToCtorArgument(argumentValue.Value, argumentValue.Type, resolutionContext, out var argumentExpression)) - { - ctorArguments.Add(argumentExpression); - } - else - { - return false; - } + return false; } + } - ctorExpression = Expression.New(ctor.ConstructorInfo, ctorArguments); - return true; + ctorExpression = Expression.New(ctor.ConstructorInfo, ctorArguments); + return true; - static bool TryBindToCtorArgument(object value, Type type, ResolutionContext resolutionContext, out Expression argumentExpression) - { - argumentExpression = null; + static bool TryBindToCtorArgument(object value, Type type, ResolutionContext resolutionContext, out Expression argumentExpression) + { + argumentExpression = null; - if (value is IConfigurationSection s) + if (value is IConfigurationSection s) + { + if (s.Value is string argValue) { - if (s.Value is string argValue) + var stringArgumentValue = new StringArgumentValue(argValue); + try { - var stringArgumentValue = new StringArgumentValue(argValue); - try - { - argumentExpression = Expression.Constant( - stringArgumentValue.ConvertTo(type, resolutionContext), - type); - - return true; - } - catch (Exception) - { - return false; - } + argumentExpression = Expression.Constant( + stringArgumentValue.ConvertTo(type, resolutionContext), + type); + + return true; } - else if (s.GetChildren().Any()) + catch (Exception) { - if (TryBuildCtorExpression(s, type, resolutionContext, out var ctorExpression)) - { - argumentExpression = ctorExpression; - return true; - } - return false; } } + else if (s.GetChildren().Any()) + { + if (TryBuildCtorExpression(s, type, resolutionContext, out var ctorExpression)) + { + argumentExpression = ctorExpression; + return true; + } - argumentExpression = Expression.Constant(value, type); - return true; + return false; + } } + + argumentExpression = Expression.Constant(value, type); + return true; } + } - static bool IsContainer(Type type, out Type elementType) + static bool IsContainer(Type type, out Type elementType) + { + elementType = null; + foreach (var iface in type.GetInterfaces()) { - elementType = null; - foreach (var iface in type.GetInterfaces()) + if (iface.IsGenericType) { - if (iface.IsGenericType) + if (iface.GetGenericTypeDefinition() == typeof(IEnumerable<>)) { - if (iface.GetGenericTypeDefinition() == typeof(IEnumerable<>)) - { - elementType = iface.GetGenericArguments()[0]; - return true; - } + elementType = iface.GetGenericArguments()[0]; + return true; } } - - return false; } + + return false; } } diff --git a/src/Serilog.Settings.Configuration/Settings/Configuration/ResolutionContext.cs b/src/Serilog.Settings.Configuration/Settings/Configuration/ResolutionContext.cs index 2963a64..1db02a5 100644 --- a/src/Serilog.Settings.Configuration/Settings/Configuration/ResolutionContext.cs +++ b/src/Serilog.Settings.Configuration/Settings/Configuration/ResolutionContext.cs @@ -1,85 +1,82 @@ -using System; -using System.Collections.Generic; -using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Configuration; using Serilog.Core; -namespace Serilog.Settings.Configuration +namespace Serilog.Settings.Configuration; + +/// +/// Keeps track of available elements that are useful when resolving values in the settings system. +/// +sealed class ResolutionContext { + readonly IDictionary _declaredLevelSwitches; + readonly IDictionary _declaredFilterSwitches; + readonly IConfiguration _appConfiguration; + + public ResolutionContext(IConfiguration appConfiguration = null) + { + _declaredLevelSwitches = new Dictionary(); + _declaredFilterSwitches = new Dictionary(); + _appConfiguration = appConfiguration; + } + /// - /// Keeps track of available elements that are useful when resolving values in the settings system. + /// Looks up a switch in the declared LoggingLevelSwitches /// - sealed class ResolutionContext + /// the name of a switch to look up + /// the LoggingLevelSwitch registered with the name + /// if no switch has been registered with + public LoggingLevelSwitch LookUpLevelSwitchByName(string switchName) { - readonly IDictionary _declaredLevelSwitches; - readonly IDictionary _declaredFilterSwitches; - readonly IConfiguration _appConfiguration; - - public ResolutionContext(IConfiguration appConfiguration = null) + if (_declaredLevelSwitches.TryGetValue(switchName, out var levelSwitch)) { - _declaredLevelSwitches = new Dictionary(); - _declaredFilterSwitches = new Dictionary(); - _appConfiguration = appConfiguration; + return levelSwitch; } - /// - /// Looks up a switch in the declared LoggingLevelSwitches - /// - /// the name of a switch to look up - /// the LoggingLevelSwitch registered with the name - /// if no switch has been registered with - public LoggingLevelSwitch LookUpLevelSwitchByName(string switchName) - { - if (_declaredLevelSwitches.TryGetValue(switchName, out var levelSwitch)) - { - return levelSwitch; - } - - throw new InvalidOperationException($"No LoggingLevelSwitch has been declared with name \"{switchName}\". You might be missing a section \"LevelSwitches\":{{\"{switchName}\":\"InitialLevel\"}}"); - } + throw new InvalidOperationException($"No LoggingLevelSwitch has been declared with name \"{switchName}\". You might be missing a section \"LevelSwitches\":{{\"{switchName}\":\"InitialLevel\"}}"); + } - public LoggingFilterSwitchProxy LookUpFilterSwitchByName(string switchName) + public LoggingFilterSwitchProxy LookUpFilterSwitchByName(string switchName) + { + if (_declaredFilterSwitches.TryGetValue(switchName, out var filterSwitch)) { - if (_declaredFilterSwitches.TryGetValue(switchName, out var filterSwitch)) - { - return filterSwitch; - } - - throw new InvalidOperationException($"No LoggingFilterSwitch has been declared with name \"{switchName}\". You might be missing a section \"FilterSwitches\":{{\"{switchName}\":\"{{FilterExpression}}\"}}"); + return filterSwitch; } - public bool HasAppConfiguration => _appConfiguration != null; + throw new InvalidOperationException($"No LoggingFilterSwitch has been declared with name \"{switchName}\". You might be missing a section \"FilterSwitches\":{{\"{switchName}\":\"{{FilterExpression}}\"}}"); + } - public IConfiguration AppConfiguration + public bool HasAppConfiguration => _appConfiguration != null; + + public IConfiguration AppConfiguration + { + get { - get + if (!HasAppConfiguration) { - if (!HasAppConfiguration) - { - throw new InvalidOperationException("AppConfiguration is not available"); - } - - return _appConfiguration; + throw new InvalidOperationException("AppConfiguration is not available"); } - } - public void AddLevelSwitch(string levelSwitchName, LoggingLevelSwitch levelSwitch) - { - if (levelSwitchName == null) throw new ArgumentNullException(nameof(levelSwitchName)); - if (levelSwitch == null) throw new ArgumentNullException(nameof(levelSwitch)); - _declaredLevelSwitches[ToSwitchReference(levelSwitchName)] = levelSwitch; + return _appConfiguration; } + } - public void AddFilterSwitch(string filterSwitchName, LoggingFilterSwitchProxy filterSwitch) - { - if (filterSwitchName == null) throw new ArgumentNullException(nameof(filterSwitchName)); - if (filterSwitch == null) throw new ArgumentNullException(nameof(filterSwitch)); - _declaredFilterSwitches[ToSwitchReference(filterSwitchName)] = filterSwitch; - } + public void AddLevelSwitch(string levelSwitchName, LoggingLevelSwitch levelSwitch) + { + if (levelSwitchName == null) throw new ArgumentNullException(nameof(levelSwitchName)); + if (levelSwitch == null) throw new ArgumentNullException(nameof(levelSwitch)); + _declaredLevelSwitches[ToSwitchReference(levelSwitchName)] = levelSwitch; + } - string ToSwitchReference(string switchName) - { - return switchName.StartsWith("$") ? switchName : $"${switchName}"; - } + public void AddFilterSwitch(string filterSwitchName, LoggingFilterSwitchProxy filterSwitch) + { + if (filterSwitchName == null) throw new ArgumentNullException(nameof(filterSwitchName)); + if (filterSwitch == null) throw new ArgumentNullException(nameof(filterSwitch)); + _declaredFilterSwitches[ToSwitchReference(filterSwitchName)] = filterSwitch; + } + + string ToSwitchReference(string switchName) + { + return switchName.StartsWith("$") ? switchName : $"${switchName}"; } } diff --git a/src/Serilog.Settings.Configuration/Settings/Configuration/StringArgumentValue.cs b/src/Serilog.Settings.Configuration/Settings/Configuration/StringArgumentValue.cs index 6d94639..c15c4b1 100644 --- a/src/Serilog.Settings.Configuration/Settings/Configuration/StringArgumentValue.cs +++ b/src/Serilog.Settings.Configuration/Settings/Configuration/StringArgumentValue.cs @@ -1,202 +1,198 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; +using System.Reflection; using System.Text.RegularExpressions; using Serilog.Core; -namespace Serilog.Settings.Configuration +namespace Serilog.Settings.Configuration; + +class StringArgumentValue : IConfigurationArgumentValue { - class StringArgumentValue : IConfigurationArgumentValue - { - readonly string _providedValue; + readonly string _providedValue; + + static readonly Regex StaticMemberAccessorRegex = new Regex("^(?[^:]+)::(?[A-Za-z][A-Za-z0-9]*)(?[^:]*)$"); - static readonly Regex StaticMemberAccessorRegex = new Regex("^(?[^:]+)::(?[A-Za-z][A-Za-z0-9]*)(?[^:]*)$"); + public StringArgumentValue(string providedValue) + { + _providedValue = providedValue ?? throw new ArgumentNullException(nameof(providedValue)); + } - public StringArgumentValue(string providedValue) + static readonly Dictionary> ExtendedTypeConversions = new Dictionary> { - _providedValue = providedValue ?? throw new ArgumentNullException(nameof(providedValue)); - } + { typeof(Uri), s => new Uri(s) }, + { typeof(TimeSpan), s => TimeSpan.Parse(s) }, + { typeof(Type), s => Type.GetType(s, throwOnError:true) }, + }; - static readonly Dictionary> ExtendedTypeConversions = new Dictionary> - { - { typeof(Uri), s => new Uri(s) }, - { typeof(TimeSpan), s => TimeSpan.Parse(s) }, - { typeof(Type), s => Type.GetType(s, throwOnError:true) }, - }; + public object ConvertTo(Type toType, ResolutionContext resolutionContext) + { + var argumentValue = Environment.ExpandEnvironmentVariables(_providedValue); - public object ConvertTo(Type toType, ResolutionContext resolutionContext) + if (toType == typeof(LoggingLevelSwitch)) { - var argumentValue = Environment.ExpandEnvironmentVariables(_providedValue); - - if (toType == typeof(LoggingLevelSwitch)) - { - return resolutionContext.LookUpLevelSwitchByName(argumentValue); - } + return resolutionContext.LookUpLevelSwitchByName(argumentValue); + } - if (toType.FullName == "Serilog.Expressions.LoggingFilterSwitch" || - toType.FullName == "Serilog.Filters.Expressions.LoggingFilterSwitch") - { - return resolutionContext.LookUpFilterSwitchByName(argumentValue).RealSwitch; - } + if (toType.FullName == "Serilog.Expressions.LoggingFilterSwitch" || + toType.FullName == "Serilog.Filters.Expressions.LoggingFilterSwitch") + { + return resolutionContext.LookUpFilterSwitchByName(argumentValue).RealSwitch; + } - var toTypeInfo = toType.GetTypeInfo(); - if (toTypeInfo.IsGenericType && toType.GetGenericTypeDefinition() == typeof(Nullable<>)) - { - if (string.IsNullOrEmpty(argumentValue)) - return null; + var toTypeInfo = toType.GetTypeInfo(); + if (toTypeInfo.IsGenericType && toType.GetGenericTypeDefinition() == typeof(Nullable<>)) + { + if (string.IsNullOrEmpty(argumentValue)) + return null; - // unwrap Nullable<> type since we're not handling null situations - toType = toTypeInfo.GenericTypeArguments[0]; - toTypeInfo = toType.GetTypeInfo(); - } + // unwrap Nullable<> type since we're not handling null situations + toType = toTypeInfo.GenericTypeArguments[0]; + toTypeInfo = toType.GetTypeInfo(); + } - if (toTypeInfo.IsEnum) - return Enum.Parse(toType, argumentValue); + if (toTypeInfo.IsEnum) + return Enum.Parse(toType, argumentValue); - var convertor = ExtendedTypeConversions - .Where(t => t.Key.GetTypeInfo().IsAssignableFrom(toTypeInfo)) - .Select(t => t.Value) - .FirstOrDefault(); + var convertor = ExtendedTypeConversions + .Where(t => t.Key.GetTypeInfo().IsAssignableFrom(toTypeInfo)) + .Select(t => t.Value) + .FirstOrDefault(); - if (convertor != null) - return convertor(argumentValue); + if (convertor != null) + return convertor(argumentValue); - if (!string.IsNullOrWhiteSpace(argumentValue)) + if (!string.IsNullOrWhiteSpace(argumentValue)) + { + // check if value looks like a static property or field directive + // like "Namespace.TypeName::StaticProperty, AssemblyName" + if (toType != typeof(string) && + TryParseStaticMemberAccessor(argumentValue, out var accessorTypeName, out var memberName)) { - // check if value looks like a static property or field directive - // like "Namespace.TypeName::StaticProperty, AssemblyName" - if (toType != typeof(string) && - TryParseStaticMemberAccessor(argumentValue, out var accessorTypeName, out var memberName)) + var accessorType = Type.GetType(accessorTypeName, throwOnError: true); + + // if delegate, look for a method and then construct a delegate + if (typeof(Delegate).IsAssignableFrom(toType) || typeof(MethodInfo) == toType) { - var accessorType = Type.GetType(accessorTypeName, throwOnError: true); + var methodCandidates = accessorType.GetTypeInfo().DeclaredMethods + .Where(x => x.Name == memberName) + .Where(x => x.IsPublic) + .Where(x => !x.IsGenericMethod) + .Where(x => x.IsStatic) + .ToList(); - // if delegate, look for a method and then construct a delegate - if (typeof(Delegate).IsAssignableFrom(toType) || typeof(MethodInfo) == toType) + if (methodCandidates.Count > 1) { - var methodCandidates = accessorType.GetTypeInfo().DeclaredMethods - .Where(x => x.Name == memberName) - .Where(x => x.IsPublic) - .Where(x => !x.IsGenericMethod) - .Where(x => x.IsStatic) + // filter possible method overloads + + var delegateSig = toType.GetMethod("Invoke"); + var delegateParameters = delegateSig!.GetParameters().Select(x => x.ParameterType); + methodCandidates = methodCandidates + .Where(x => x.ReturnType == delegateSig.ReturnType && x.GetParameters().Select(y => y.ParameterType).SequenceEqual(delegateParameters)) .ToList(); + } - if (methodCandidates.Count > 1) - { - // filter possible method overloads + var methodCandidate = methodCandidates.SingleOrDefault(); - var delegateSig = toType.GetMethod("Invoke"); - var delegateParameters = delegateSig!.GetParameters().Select(x => x.ParameterType); - methodCandidates = methodCandidates - .Where(x => x.ReturnType == delegateSig.ReturnType && x.GetParameters().Select(y => y.ParameterType).SequenceEqual(delegateParameters)) - .ToList(); + if (methodCandidate != null) + { + if (typeof(MethodInfo) == toType) + { + return methodCandidate; } - - var methodCandidate = methodCandidates.SingleOrDefault(); - - if (methodCandidate != null) + else { - if (typeof(MethodInfo) == toType) - { - return methodCandidate; - } - else - { - return methodCandidate.CreateDelegate(toType); - } + return methodCandidate.CreateDelegate(toType); } } + } - // is there a public static property with that name ? - var publicStaticPropertyInfo = accessorType.GetTypeInfo().DeclaredProperties - .Where(x => x.Name == memberName) - .Where(x => x.GetMethod != null) - .Where(x => x.GetMethod.IsPublic) - .FirstOrDefault(x => x.GetMethod.IsStatic); - - if (publicStaticPropertyInfo != null) - { - return publicStaticPropertyInfo.GetValue(null); // static property, no instance to pass - } + // is there a public static property with that name ? + var publicStaticPropertyInfo = accessorType.GetTypeInfo().DeclaredProperties + .Where(x => x.Name == memberName) + .Where(x => x.GetMethod != null) + .Where(x => x.GetMethod.IsPublic) + .FirstOrDefault(x => x.GetMethod.IsStatic); - // no property ? look for a public static field - var publicStaticFieldInfo = accessorType.GetTypeInfo().DeclaredFields - .Where(x => x.Name == memberName) - .Where(x => x.IsPublic) - .FirstOrDefault(x => x.IsStatic); + if (publicStaticPropertyInfo != null) + { + return publicStaticPropertyInfo.GetValue(null); // static property, no instance to pass + } - if (publicStaticFieldInfo != null) - { - return publicStaticFieldInfo.GetValue(null); // static field, no instance to pass - } + // no property ? look for a public static field + var publicStaticFieldInfo = accessorType.GetTypeInfo().DeclaredFields + .Where(x => x.Name == memberName) + .Where(x => x.IsPublic) + .FirstOrDefault(x => x.IsStatic); - throw new InvalidOperationException($"Could not find a public static property or field with name `{memberName}` on type `{accessorTypeName}`"); + if (publicStaticFieldInfo != null) + { + return publicStaticFieldInfo.GetValue(null); // static field, no instance to pass } - if (toTypeInfo.IsInterface || toTypeInfo.IsAbstract) + throw new InvalidOperationException($"Could not find a public static property or field with name `{memberName}` on type `{accessorTypeName}`"); + } + + if (toTypeInfo.IsInterface || toTypeInfo.IsAbstract) + { + // maybe it's the assembly-qualified type name of a concrete implementation + // with a default constructor + var type = FindType(argumentValue.Trim()); + if (type == null) { - // maybe it's the assembly-qualified type name of a concrete implementation - // with a default constructor - var type = FindType(argumentValue.Trim()); - if (type == null) - { - throw new InvalidOperationException($"Type {argumentValue} was not found."); - } + throw new InvalidOperationException($"Type {argumentValue} was not found."); + } - var ctor = type.GetTypeInfo().DeclaredConstructors.Where(ci => !ci.IsStatic).FirstOrDefault(ci => - { - var parameters = ci.GetParameters(); - return parameters.Length == 0 || parameters.All(pi => pi.HasDefaultValue); - }); + var ctor = type.GetTypeInfo().DeclaredConstructors.Where(ci => !ci.IsStatic).FirstOrDefault(ci => + { + var parameters = ci.GetParameters(); + return parameters.Length == 0 || parameters.All(pi => pi.HasDefaultValue); + }); - if (ctor == null) - throw new InvalidOperationException($"A default constructor was not found on {type.FullName}."); + if (ctor == null) + throw new InvalidOperationException($"A default constructor was not found on {type.FullName}."); - var call = ctor.GetParameters().Select(pi => pi.DefaultValue).ToArray(); - return ctor.Invoke(call); - } + var call = ctor.GetParameters().Select(pi => pi.DefaultValue).ToArray(); + return ctor.Invoke(call); } - - return Convert.ChangeType(argumentValue, toType); } - internal static Type FindType(string typeName) + return Convert.ChangeType(argumentValue, toType); + } + + internal static Type FindType(string typeName) + { + var type = Type.GetType(typeName); + if (type == null) { - var type = Type.GetType(typeName); - if (type == null) + if (!typeName.Contains(',')) { - if (!typeName.Contains(',')) - { - type = Type.GetType($"{typeName}, Serilog"); - } + type = Type.GetType($"{typeName}, Serilog"); } - - return type; } - internal static bool TryParseStaticMemberAccessor(string input, out string accessorTypeName, out string memberName) + return type; + } + + internal static bool TryParseStaticMemberAccessor(string input, out string accessorTypeName, out string memberName) + { + if (input == null) { - if (input == null) - { - accessorTypeName = null; - memberName = null; - return false; - } - if (StaticMemberAccessorRegex.IsMatch(input)) - { - var match = StaticMemberAccessorRegex.Match(input); - var shortAccessorTypeName = match.Groups["shortTypeName"].Value; - var rawMemberName = match.Groups["memberName"].Value; - var extraQualifiers = match.Groups["typeNameExtraQualifiers"].Value; - - memberName = rawMemberName.Trim(); - accessorTypeName = shortAccessorTypeName.Trim() + extraQualifiers.TrimEnd(); - return true; - } accessorTypeName = null; memberName = null; return false; } + if (StaticMemberAccessorRegex.IsMatch(input)) + { + var match = StaticMemberAccessorRegex.Match(input); + var shortAccessorTypeName = match.Groups["shortTypeName"].Value; + var rawMemberName = match.Groups["memberName"].Value; + var extraQualifiers = match.Groups["typeNameExtraQualifiers"].Value; + + memberName = rawMemberName.Trim(); + accessorTypeName = shortAccessorTypeName.Trim() + extraQualifiers.TrimEnd(); + return true; + } + accessorTypeName = null; + memberName = null; + return false; } } diff --git a/src/Serilog.Settings.Configuration/Settings/Configuration/SurrogateConfigurationMethods.cs b/src/Serilog.Settings.Configuration/Settings/Configuration/SurrogateConfigurationMethods.cs index 4b460b3..cbc2869 100644 --- a/src/Serilog.Settings.Configuration/Settings/Configuration/SurrogateConfigurationMethods.cs +++ b/src/Serilog.Settings.Configuration/Settings/Configuration/SurrogateConfigurationMethods.cs @@ -1,124 +1,120 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; +using System.Reflection; using Serilog.Configuration; using Serilog.Core; using Serilog.Events; -namespace Serilog.Settings.Configuration +namespace Serilog.Settings.Configuration; + +/// +/// Contains "fake extension" methods for the Serilog configuration API. +/// 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. +/// +/// +static class SurrogateConfigurationMethods { - /// - /// Contains "fake extension" methods for the Serilog configuration API. - /// 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. - /// - /// - static class SurrogateConfigurationMethods - { - static readonly Dictionary SurrogateMethodCandidates = typeof(SurrogateConfigurationMethods) - .GetTypeInfo().DeclaredMethods - .GroupBy(m => m.GetParameters().First().ParameterType) - .ToDictionary(g => g.Key, g => g.ToArray()); - - - 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 - 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 - // those methods are discovered through reflection by `SurrogateMethodCandidates` - // ReSharper has no way to see that they are actually used ... - - // .WriteTo... - // ======== - static LoggerConfiguration Sink( - LoggerSinkConfiguration loggerSinkConfiguration, - ILogEventSink sink, - LogEventLevel restrictedToMinimumLevel = LevelAlias.Minimum, - LoggingLevelSwitch levelSwitch = null) - => 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) - => auditSinkConfiguration.Sink(sink, restrictedToMinimumLevel, levelSwitch); - - static LoggerConfiguration Logger( - LoggerAuditSinkConfiguration auditSinkConfiguration, - Action configureLogger, - LogEventLevel restrictedToMinimumLevel = LevelAlias.Minimum, - LoggingLevelSwitch levelSwitch = null) - => auditSinkConfiguration.Logger(configureLogger, 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); - - 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); - - // .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 AtLevel( - LoggerEnrichmentConfiguration loggerEnrichmentConfiguration, - Action configureEnricher, - LogEventLevel enrichFromLevel = LevelAlias.Minimum, - LoggingLevelSwitch levelSwitch = null) - => levelSwitch != null ? loggerEnrichmentConfiguration.AtLevel(levelSwitch, configureEnricher) - : loggerEnrichmentConfiguration.AtLevel(enrichFromLevel, configureEnricher); - - static LoggerConfiguration FromLogContext(LoggerEnrichmentConfiguration loggerEnrichmentConfiguration) - => loggerEnrichmentConfiguration.FromLogContext(); - - // ReSharper restore UnusedMember.Local - } + static readonly Dictionary SurrogateMethodCandidates = typeof(SurrogateConfigurationMethods) + .GetTypeInfo().DeclaredMethods + .GroupBy(m => m.GetParameters().First().ParameterType) + .ToDictionary(g => g.Key, g => g.ToArray()); + + + 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 + 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 + // those methods are discovered through reflection by `SurrogateMethodCandidates` + // ReSharper has no way to see that they are actually used ... + + // .WriteTo... + // ======== + static LoggerConfiguration Sink( + LoggerSinkConfiguration loggerSinkConfiguration, + ILogEventSink sink, + LogEventLevel restrictedToMinimumLevel = LevelAlias.Minimum, + LoggingLevelSwitch levelSwitch = null) + => 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) + => auditSinkConfiguration.Sink(sink, restrictedToMinimumLevel, levelSwitch); + + static LoggerConfiguration Logger( + LoggerAuditSinkConfiguration auditSinkConfiguration, + Action configureLogger, + LogEventLevel restrictedToMinimumLevel = LevelAlias.Minimum, + LoggingLevelSwitch levelSwitch = null) + => auditSinkConfiguration.Logger(configureLogger, 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); + + 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); + + // .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 AtLevel( + LoggerEnrichmentConfiguration loggerEnrichmentConfiguration, + Action configureEnricher, + LogEventLevel enrichFromLevel = LevelAlias.Minimum, + LoggingLevelSwitch levelSwitch = null) + => levelSwitch != null ? loggerEnrichmentConfiguration.AtLevel(levelSwitch, configureEnricher) + : loggerEnrichmentConfiguration.AtLevel(enrichFromLevel, configureEnricher); + + static LoggerConfiguration FromLogContext(LoggerEnrichmentConfiguration loggerEnrichmentConfiguration) + => loggerEnrichmentConfiguration.FromLogContext(); + + // ReSharper restore UnusedMember.Local } diff --git a/test/Serilog.Settings.Configuration.Tests/ConfigurationReaderTests.cs b/test/Serilog.Settings.Configuration.Tests/ConfigurationReaderTests.cs index 8639fc0..bbee31b 100644 --- a/test/Serilog.Settings.Configuration.Tests/ConfigurationReaderTests.cs +++ b/test/Serilog.Settings.Configuration.Tests/ConfigurationReaderTests.cs @@ -1,7 +1,4 @@ -using Xunit; -using System.Collections.Generic; -using System.Reflection; -using System.Linq; +using System.Reflection; using Microsoft.Extensions.Configuration; using Serilog.Events; using Serilog.Formatting; @@ -9,57 +6,57 @@ using Serilog.Settings.Configuration.Tests.Support; using static Serilog.Settings.Configuration.Tests.Support.ConfigurationReaderTestHelpers; -namespace Serilog.Settings.Configuration.Tests +namespace Serilog.Settings.Configuration.Tests; + +public class ConfigurationReaderTests { - public class ConfigurationReaderTests - { - readonly ConfigurationReader _configurationReader; + readonly ConfigurationReader _configurationReader; - public ConfigurationReaderTests() - { - _configurationReader = new ConfigurationReader( - JsonStringConfigSource.LoadSection(@"{ 'Serilog': { } }", "Serilog"), - AssemblyFinder.ForSource(ConfigurationAssemblySource.UseLoadedAssemblies)); - } + public ConfigurationReaderTests() + { + _configurationReader = new ConfigurationReader( + JsonStringConfigSource.LoadSection(@"{ 'Serilog': { } }", "Serilog"), + AssemblyFinder.ForSource(ConfigurationAssemblySource.UseLoadedAssemblies)); + } - [Fact] - public void WriteToSupportSimplifiedSyntax() - { - var json = @" + [Fact] + public void WriteToSupportSimplifiedSyntax() + { + var json = @" { 'WriteTo': [ 'LiterateConsole', 'DiagnosticTrace' ] }"; - var result = _configurationReader.GetMethodCalls(JsonStringConfigSource.LoadSection(json, "WriteTo")); - Assert.Equal(2, result.Count); - Assert.True(result.Contains("LiterateConsole")); - Assert.True(result.Contains("DiagnosticTrace")); + var result = _configurationReader.GetMethodCalls(JsonStringConfigSource.LoadSection(json, "WriteTo")); + Assert.Equal(2, result.Count); + Assert.True(result.Contains("LiterateConsole")); + Assert.True(result.Contains("DiagnosticTrace")); - Assert.Single(result["LiterateConsole"]); - Assert.Single(result["DiagnosticTrace"]); - } + Assert.Single(result["LiterateConsole"]); + Assert.Single(result["DiagnosticTrace"]); + } - [Fact] - public void WriteToSupportExpandedSyntaxWithoutArgs() - { - var json = @" + [Fact] + public void WriteToSupportExpandedSyntaxWithoutArgs() + { + var json = @" { 'WriteTo': [ { 'Name': 'LiterateConsole' }] }"; - var result = _configurationReader.GetMethodCalls(JsonStringConfigSource.LoadSection(json, "WriteTo")); - Assert.Equal(1, result.Count); - Assert.True(result.Contains("LiterateConsole")); + var result = _configurationReader.GetMethodCalls(JsonStringConfigSource.LoadSection(json, "WriteTo")); + Assert.Equal(1, result.Count); + Assert.True(result.Contains("LiterateConsole")); - Assert.Single(result["LiterateConsole"]); - } + Assert.Single(result["LiterateConsole"]); + } - [Fact] - public void WriteToSupportExpandedSyntaxWithArgs() - { - var json = @" + [Fact] + public void WriteToSupportExpandedSyntaxWithArgs() + { + var json = @" { 'WriteTo': [ { 'Name': 'LiterateConsole', @@ -69,24 +66,24 @@ public void WriteToSupportExpandedSyntaxWithArgs() }] }"; - var result = _configurationReader.GetMethodCalls(JsonStringConfigSource.LoadSection(json, "WriteTo")); + var result = _configurationReader.GetMethodCalls(JsonStringConfigSource.LoadSection(json, "WriteTo")); - Assert.Single(result); - Assert.True(result.Contains("LiterateConsole")); + Assert.Single(result); + Assert.True(result.Contains("LiterateConsole")); - Assert.Single(result["LiterateConsole"]); + Assert.Single(result["LiterateConsole"]); - var args = result["LiterateConsole"].Single().ToArray(); + var args = result["LiterateConsole"].Single().ToArray(); - Assert.Single(args); - Assert.Equal("outputTemplate", args[0].Key); - Assert.Equal("{Message}", args[0].Value.ConvertTo(typeof(string), new ResolutionContext())); - } + Assert.Single(args); + Assert.Equal("outputTemplate", args[0].Key); + Assert.Equal("{Message}", args[0].Value.ConvertTo(typeof(string), new ResolutionContext())); + } - [Fact] - public void WriteToSupportMultipleSinksOfTheSameKind() - { - var json = @" + [Fact] + public void WriteToSupportMultipleSinksOfTheSameKind() + { + var json = @" { 'WriteTo': [ { @@ -111,176 +108,175 @@ public void WriteToSupportMultipleSinksOfTheSameKind() } }"; - var result = _configurationReader.GetMethodCalls(JsonStringConfigSource.LoadSection(json, "WriteTo")); + var result = _configurationReader.GetMethodCalls(JsonStringConfigSource.LoadSection(json, "WriteTo")); - Assert.Equal(3, result.Count); - Assert.True(result.Contains("LiterateConsole")); - Assert.True(result.Contains("DiagnosticTrace")); - Assert.True(result.Contains("File")); + Assert.Equal(3, result.Count); + Assert.True(result.Contains("LiterateConsole")); + Assert.True(result.Contains("DiagnosticTrace")); + Assert.True(result.Contains("File")); - Assert.Single(result["LiterateConsole"]); - Assert.Single(result["DiagnosticTrace"]); - Assert.Equal(2, result["File"].Count()); - } + Assert.Single(result["LiterateConsole"]); + Assert.Single(result["DiagnosticTrace"]); + Assert.Equal(2, result["File"].Count()); + } - [Fact] - public void Enrich_SupportSimplifiedSyntax() - { - var json = @" + [Fact] + public void Enrich_SupportSimplifiedSyntax() + { + var json = @" { 'Enrich': [ 'FromLogContext', 'WithMachineName', 'WithThreadId' ] }"; - var result = _configurationReader.GetMethodCalls(JsonStringConfigSource.LoadSection(json, "Enrich")); - Assert.Equal(3, result.Count); - Assert.True(result.Contains("FromLogContext")); - Assert.True(result.Contains("WithMachineName")); - Assert.True(result.Contains("WithThreadId")); + var result = _configurationReader.GetMethodCalls(JsonStringConfigSource.LoadSection(json, "Enrich")); + Assert.Equal(3, result.Count); + Assert.True(result.Contains("FromLogContext")); + Assert.True(result.Contains("WithMachineName")); + Assert.True(result.Contains("WithThreadId")); - Assert.Single(result["FromLogContext"]); - Assert.Single(result["WithMachineName"]); - Assert.Single(result["WithThreadId"]); - } + Assert.Single(result["FromLogContext"]); + Assert.Single(result["WithMachineName"]); + Assert.Single(result["WithThreadId"]); + } - [Fact] - public void CallableMethodsAreSelected() - { - var options = typeof(DummyLoggerConfigurationExtensions).GetTypeInfo().DeclaredMethods.ToList(); - Assert.Equal(2, options.Count(mi => mi.Name == "DummyRollingFile")); - var suppliedArgumentNames = new[] { "pathFormat" }; + [Fact] + public void CallableMethodsAreSelected() + { + var options = typeof(DummyLoggerConfigurationExtensions).GetTypeInfo().DeclaredMethods.ToList(); + Assert.Equal(2, options.Count(mi => mi.Name == "DummyRollingFile")); + var suppliedArgumentNames = new[] { "pathFormat" }; - var selected = ConfigurationReader.SelectConfigurationMethod(options, "DummyRollingFile", suppliedArgumentNames); - Assert.Equal(typeof(string), selected.GetParameters()[1].ParameterType); - } + var selected = ConfigurationReader.SelectConfigurationMethod(options, "DummyRollingFile", suppliedArgumentNames); + Assert.Equal(typeof(string), selected.GetParameters()[1].ParameterType); + } - [Fact] - public void MethodsAreSelectedBasedOnCountOfMatchedArguments() - { - var options = typeof(DummyLoggerConfigurationExtensions).GetTypeInfo().DeclaredMethods.ToList(); - Assert.Equal(2, options.Count(mi => mi.Name == "DummyRollingFile")); + [Fact] + public void MethodsAreSelectedBasedOnCountOfMatchedArguments() + { + var options = typeof(DummyLoggerConfigurationExtensions).GetTypeInfo().DeclaredMethods.ToList(); + Assert.Equal(2, options.Count(mi => mi.Name == "DummyRollingFile")); - var suppliedArgumentNames = new[] { "pathFormat", "formatter" }; + var suppliedArgumentNames = new[] { "pathFormat", "formatter" }; - var selected = ConfigurationReader.SelectConfigurationMethod(options, "DummyRollingFile", suppliedArgumentNames); - Assert.Equal(typeof(ITextFormatter), selected.GetParameters()[1].ParameterType); - } + var selected = ConfigurationReader.SelectConfigurationMethod(options, "DummyRollingFile", suppliedArgumentNames); + Assert.Equal(typeof(ITextFormatter), selected.GetParameters()[1].ParameterType); + } - [Fact] - public void MethodsAreSelectedBasedOnCountOfMatchedArgumentsAndThenStringType() - { - var options = typeof(DummyLoggerConfigurationWithMultipleMethodsExtensions).GetTypeInfo().DeclaredMethods.ToList(); - Assert.Equal(3, options.Count(mi => mi.Name == "DummyRollingFile")); + [Fact] + public void MethodsAreSelectedBasedOnCountOfMatchedArgumentsAndThenStringType() + { + var options = typeof(DummyLoggerConfigurationWithMultipleMethodsExtensions).GetTypeInfo().DeclaredMethods.ToList(); + Assert.Equal(3, options.Count(mi => mi.Name == "DummyRollingFile")); - var suppliedArgumentNames = new[] { "pathFormat", "formatter" }; + var suppliedArgumentNames = new[] { "pathFormat", "formatter" }; - var selected = ConfigurationReader.SelectConfigurationMethod(options, "DummyRollingFile", suppliedArgumentNames); - Assert.Equal(typeof(string), selected.GetParameters()[2].ParameterType); + var selected = ConfigurationReader.SelectConfigurationMethod(options, "DummyRollingFile", suppliedArgumentNames); + Assert.Equal(typeof(string), selected.GetParameters()[2].ParameterType); + } + + public static IEnumerable FlatMinimumLevel => new List + { + new object[] { GetConfigRoot(appsettingsJsonLevel: minimumLevelFlatTemplate.Format(LogEventLevel.Error)), LogEventLevel.Error }, + new object[] { GetConfigRoot(appsettingsDevelopmentJsonLevel: minimumLevelFlatTemplate.Format(LogEventLevel.Error)), LogEventLevel.Error }, + new object[] { GetConfigRoot(envVariables: new Dictionary() {{minimumLevelFlatKey, LogEventLevel.Error.ToString()}}), LogEventLevel.Error}, + new object[] { GetConfigRoot( + appsettingsJsonLevel: minimumLevelFlatTemplate.Format(LogEventLevel.Debug), + envVariables: new Dictionary() {{minimumLevelFlatKey, LogEventLevel.Error.ToString()}}), + LogEventLevel.Error } + }; - public static IEnumerable FlatMinimumLevel => new List - { - new object[] { GetConfigRoot(appsettingsJsonLevel: minimumLevelFlatTemplate.Format(LogEventLevel.Error)), LogEventLevel.Error }, - new object[] { GetConfigRoot(appsettingsDevelopmentJsonLevel: minimumLevelFlatTemplate.Format(LogEventLevel.Error)), LogEventLevel.Error }, - new object[] { GetConfigRoot(envVariables: new Dictionary() {{minimumLevelFlatKey, LogEventLevel.Error.ToString()}}), LogEventLevel.Error}, - new object[] { GetConfigRoot( - appsettingsJsonLevel: minimumLevelFlatTemplate.Format(LogEventLevel.Debug), - envVariables: new Dictionary() {{minimumLevelFlatKey, LogEventLevel.Error.ToString()}}), - LogEventLevel.Error - } - }; - - [Theory] - [MemberData(nameof(FlatMinimumLevel))] - public void FlatMinimumLevelCorrectOneIsEnabledOnLogger(IConfigurationRoot root, LogEventLevel expectedMinimumLevel) - { - var reader = new ConfigurationReader(root.GetSection("Serilog"), AssemblyFinder.ForSource(ConfigurationAssemblySource.UseLoadedAssemblies), root); - var loggerConfig = new LoggerConfiguration(); + [Theory] + [MemberData(nameof(FlatMinimumLevel))] + public void FlatMinimumLevelCorrectOneIsEnabledOnLogger(IConfigurationRoot root, LogEventLevel expectedMinimumLevel) + { + var reader = new ConfigurationReader(root.GetSection("Serilog"), AssemblyFinder.ForSource(ConfigurationAssemblySource.UseLoadedAssemblies), root); + var loggerConfig = new LoggerConfiguration(); - reader.Configure(loggerConfig); + reader.Configure(loggerConfig); - AssertLogEventLevels(loggerConfig, expectedMinimumLevel); - } - - public static IEnumerable ObjectMinimumLevel => new List - { - new object[] { GetConfigRoot(appsettingsJsonLevel: minimumLevelObjectTemplate.Format(LogEventLevel.Error)), LogEventLevel.Error }, - new object[] { GetConfigRoot(appsettingsJsonLevel: minimumLevelObjectTemplate.Format(LogEventLevel.Error.ToString().ToUpper())), LogEventLevel.Error }, - new object[] { GetConfigRoot(appsettingsDevelopmentJsonLevel: minimumLevelObjectTemplate.Format(LogEventLevel.Error)), LogEventLevel.Error }, - new object[] { GetConfigRoot(envVariables: new Dictionary(){{minimumLevelObjectKey, LogEventLevel.Error.ToString() } }), LogEventLevel.Error }, - new object[] { GetConfigRoot( - appsettingsJsonLevel: minimumLevelObjectTemplate.Format(LogEventLevel.Error), - appsettingsDevelopmentJsonLevel: minimumLevelObjectTemplate.Format(LogEventLevel.Debug)), - LogEventLevel.Debug } - }; + AssertLogEventLevels(loggerConfig, expectedMinimumLevel); + } - [Theory] - [MemberData(nameof(ObjectMinimumLevel))] - public void ObjectMinimumLevelCorrectOneIsEnabledOnLogger(IConfigurationRoot root, LogEventLevel expectedMinimumLevel) - { - var reader = new ConfigurationReader(root.GetSection("Serilog"), AssemblyFinder.ForSource(ConfigurationAssemblySource.UseLoadedAssemblies), root); - var loggerConfig = new LoggerConfiguration(); + public static IEnumerable ObjectMinimumLevel => new List + { + new object[] { GetConfigRoot(appsettingsJsonLevel: minimumLevelObjectTemplate.Format(LogEventLevel.Error)), LogEventLevel.Error }, + new object[] { GetConfigRoot(appsettingsJsonLevel: minimumLevelObjectTemplate.Format(LogEventLevel.Error.ToString().ToUpper())), LogEventLevel.Error }, + new object[] { GetConfigRoot(appsettingsDevelopmentJsonLevel: minimumLevelObjectTemplate.Format(LogEventLevel.Error)), LogEventLevel.Error }, + new object[] { GetConfigRoot(envVariables: new Dictionary(){{minimumLevelObjectKey, LogEventLevel.Error.ToString() } }), LogEventLevel.Error }, + new object[] { GetConfigRoot( + appsettingsJsonLevel: minimumLevelObjectTemplate.Format(LogEventLevel.Error), + appsettingsDevelopmentJsonLevel: minimumLevelObjectTemplate.Format(LogEventLevel.Debug)), + LogEventLevel.Debug } + }; + + [Theory] + [MemberData(nameof(ObjectMinimumLevel))] + public void ObjectMinimumLevelCorrectOneIsEnabledOnLogger(IConfigurationRoot root, LogEventLevel expectedMinimumLevel) + { + var reader = new ConfigurationReader(root.GetSection("Serilog"), AssemblyFinder.ForSource(ConfigurationAssemblySource.UseLoadedAssemblies), root); + var loggerConfig = new LoggerConfiguration(); - reader.Configure(loggerConfig); + reader.Configure(loggerConfig); - AssertLogEventLevels(loggerConfig, expectedMinimumLevel); - } + AssertLogEventLevels(loggerConfig, expectedMinimumLevel); + } - #if !(NET452) + #if !(NET452) - // currently only works in the .NET 4.6.1 and .NET Standard builds of Serilog.Settings.Configuration - public static IEnumerable MixedMinimumLevel => new List + // currently only works in the .NET 4.6.1 and .NET Standard builds of Serilog.Settings.Configuration + public static IEnumerable MixedMinimumLevel => new List + { + new object[] + { + GetConfigRoot( + appsettingsJsonLevel: minimumLevelObjectTemplate.Format(LogEventLevel.Error), + appsettingsDevelopmentJsonLevel: minimumLevelFlatTemplate.Format(LogEventLevel.Debug)), + LogEventLevel.Debug + }, + new object[] { - new object[] - { - GetConfigRoot( - appsettingsJsonLevel: minimumLevelObjectTemplate.Format(LogEventLevel.Error), - appsettingsDevelopmentJsonLevel: minimumLevelFlatTemplate.Format(LogEventLevel.Debug)), - LogEventLevel.Debug - }, - new object[] - { - GetConfigRoot( - appsettingsJsonLevel: minimumLevelFlatTemplate.Format(LogEventLevel.Error), - appsettingsDevelopmentJsonLevel: minimumLevelObjectTemplate.Format(LogEventLevel.Debug)), - LogEventLevel.Debug - }, - // precedence should be flat > object if from the same source - new object[] - { - GetConfigRoot( - envVariables: new Dictionary() - { - {minimumLevelObjectKey, LogEventLevel.Error.ToString()}, - {minimumLevelFlatKey, LogEventLevel.Debug.ToString()} - }), - LogEventLevel.Debug - } - }; - - [Theory] - [MemberData(nameof(MixedMinimumLevel))] - public void MixedMinimumLevelCorrectOneIsEnabledOnLogger(IConfigurationRoot root, LogEventLevel expectedMinimumLevel) + GetConfigRoot( + appsettingsJsonLevel: minimumLevelFlatTemplate.Format(LogEventLevel.Error), + appsettingsDevelopmentJsonLevel: minimumLevelObjectTemplate.Format(LogEventLevel.Debug)), + LogEventLevel.Debug + }, + // precedence should be flat > object if from the same source + new object[] { - var reader = new ConfigurationReader(root.GetSection("Serilog"), AssemblyFinder.ForSource(ConfigurationAssemblySource.UseLoadedAssemblies), root); - var loggerConfig = new LoggerConfiguration(); + GetConfigRoot( + envVariables: new Dictionary() + { + {minimumLevelObjectKey, LogEventLevel.Error.ToString()}, + {minimumLevelFlatKey, LogEventLevel.Debug.ToString()} + }), + LogEventLevel.Debug + } + }; + + [Theory] + [MemberData(nameof(MixedMinimumLevel))] + public void MixedMinimumLevelCorrectOneIsEnabledOnLogger(IConfigurationRoot root, LogEventLevel expectedMinimumLevel) + { + var reader = new ConfigurationReader(root.GetSection("Serilog"), AssemblyFinder.ForSource(ConfigurationAssemblySource.UseLoadedAssemblies), root); + var loggerConfig = new LoggerConfiguration(); - reader.Configure(loggerConfig); + reader.Configure(loggerConfig); - AssertLogEventLevels(loggerConfig, expectedMinimumLevel); - } + AssertLogEventLevels(loggerConfig, expectedMinimumLevel); + } - #endif + #endif - [Fact] - public void NoConfigurationRootUsedStillValid() - { - var section = JsonStringConfigSource.LoadSection(@"{ 'Nest': { 'Serilog': { 'MinimumLevel': 'Error' } } }", "Nest"); - var reader = new ConfigurationReader(section.GetSection("Serilog"), AssemblyFinder.ForSource(ConfigurationAssemblySource.UseLoadedAssemblies), section); - var loggerConfig = new LoggerConfiguration(); + [Fact] + public void NoConfigurationRootUsedStillValid() + { + var section = JsonStringConfigSource.LoadSection(@"{ 'Nest': { 'Serilog': { 'MinimumLevel': 'Error' } } }", "Nest"); + var reader = new ConfigurationReader(section.GetSection("Serilog"), AssemblyFinder.ForSource(ConfigurationAssemblySource.UseLoadedAssemblies), section); + var loggerConfig = new LoggerConfiguration(); - reader.Configure(loggerConfig); + reader.Configure(loggerConfig); - AssertLogEventLevels(loggerConfig, LogEventLevel.Error); - } + AssertLogEventLevels(loggerConfig, LogEventLevel.Error); } } diff --git a/test/Serilog.Settings.Configuration.Tests/ConfigurationSettingsTests.cs b/test/Serilog.Settings.Configuration.Tests/ConfigurationSettingsTests.cs index b9f163a..94e8ff9 100644 --- a/test/Serilog.Settings.Configuration.Tests/ConfigurationSettingsTests.cs +++ b/test/Serilog.Settings.Configuration.Tests/ConfigurationSettingsTests.cs @@ -1,43 +1,41 @@ -using System; -using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Configuration; using Serilog.Core; using Serilog.Events; using Serilog.Settings.Configuration.Tests.Support; using TestDummies; using TestDummies.Console; using TestDummies.Console.Themes; -using Xunit; -namespace Serilog.Settings.Configuration.Tests +namespace Serilog.Settings.Configuration.Tests; + +public class ConfigurationSettingsTests { - public class ConfigurationSettingsTests + static LoggerConfiguration ConfigFromJson(string jsonString, string secondJsonSource = null) { - static LoggerConfiguration ConfigFromJson(string jsonString, string secondJsonSource = null) - { - return ConfigFromJson(jsonString, secondJsonSource, out _); - } + return ConfigFromJson(jsonString, secondJsonSource, out _); + } - static LoggerConfiguration ConfigFromJson(string jsonString, out IConfiguration configuration) - { - return ConfigFromJson(jsonString, null, out configuration); - } + static LoggerConfiguration ConfigFromJson(string jsonString, out IConfiguration configuration) + { + return ConfigFromJson(jsonString, null, out configuration); + } - static LoggerConfiguration ConfigFromJson(string jsonString, string secondJsonSource, out IConfiguration configuration) - { - var builder = new ConfigurationBuilder().AddJsonString(jsonString); - if (secondJsonSource != null) - builder.AddJsonString(secondJsonSource); - configuration = builder.Build(); - return new LoggerConfiguration() - .ReadFrom.Configuration(configuration); - } - - [Fact] - public void PropertyEnrichmentIsApplied() - { - LogEvent evt = null; + static LoggerConfiguration ConfigFromJson(string jsonString, string secondJsonSource, out IConfiguration configuration) + { + var builder = new ConfigurationBuilder().AddJsonString(jsonString); + if (secondJsonSource != null) + builder.AddJsonString(secondJsonSource); + configuration = builder.Build(); + return new LoggerConfiguration() + .ReadFrom.Configuration(configuration); + } + + [Fact] + public void PropertyEnrichmentIsApplied() + { + LogEvent evt = null; - var json = @"{ + var json = @"{ ""Serilog"": { ""Properties"": { ""App"": ""Test"" @@ -45,19 +43,19 @@ public void PropertyEnrichmentIsApplied() } }"; - var log = ConfigFromJson(json) - .WriteTo.Sink(new DelegatingSink(e => evt = e)) - .CreateLogger(); + var log = ConfigFromJson(json) + .WriteTo.Sink(new DelegatingSink(e => evt = e)) + .CreateLogger(); - log.Information("Has a test property"); + log.Information("Has a test property"); - Assert.NotNull(evt); - Assert.Equal("Test", evt.Properties["App"].LiteralValue()); - } + Assert.NotNull(evt); + Assert.Equal("Test", evt.Properties["App"].LiteralValue()); + } - [Theory] - [InlineData("extended syntax", - @"{ + [Theory] + [InlineData("extended syntax", + @"{ ""Serilog"": { ""Using"": [""TestDummies""], ""WriteTo"": [ @@ -66,58 +64,58 @@ public void PropertyEnrichmentIsApplied() ] } }")] - [InlineData("simplified syntax", - @"{ + [InlineData("simplified syntax", + @"{ ""Serilog"": { ""Using"": [""TestDummies""], ""WriteTo"": [""DummyConsole"", ""DummyWithLevelSwitch"" ] } }")] - public void ParameterlessSinksAreConfigured(string syntax, string json) - { - _ = syntax; + public void ParameterlessSinksAreConfigured(string syntax, string json) + { + _ = syntax; - var log = ConfigFromJson(json) - .CreateLogger(); + var log = ConfigFromJson(json) + .CreateLogger(); - DummyConsoleSink.Emitted.Clear(); - DummyWithLevelSwitchSink.Emitted.Clear(); + DummyConsoleSink.Emitted.Clear(); + DummyWithLevelSwitchSink.Emitted.Clear(); - log.Write(Some.InformationEvent()); + log.Write(Some.InformationEvent()); - Assert.Single(DummyConsoleSink.Emitted); - Assert.Single(DummyWithLevelSwitchSink.Emitted); - } + Assert.Single(DummyConsoleSink.Emitted); + Assert.Single(DummyWithLevelSwitchSink.Emitted); + } - [Fact] - public void ConfigurationAssembliesFromDllScanning() - { - var json = @"{ + [Fact] + public void ConfigurationAssembliesFromDllScanning() + { + var json = @"{ ""Serilog"": { ""Using"": [""TestDummies""], ""WriteTo"": [""DummyConsole""] } }"; - var builder = new ConfigurationBuilder().AddJsonString(json); - var config = builder.Build(); - var log = new LoggerConfiguration() - .ReadFrom.Configuration( - configuration: config, - configurationAssemblySource: ConfigurationAssemblySource.AlwaysScanDllFiles) - .CreateLogger(); + var builder = new ConfigurationBuilder().AddJsonString(json); + var config = builder.Build(); + var log = new LoggerConfiguration() + .ReadFrom.Configuration( + configuration: config, + configurationAssemblySource: ConfigurationAssemblySource.AlwaysScanDllFiles) + .CreateLogger(); - DummyConsoleSink.Emitted.Clear(); + DummyConsoleSink.Emitted.Clear(); - log.Write(Some.InformationEvent()); + log.Write(Some.InformationEvent()); - Assert.Single(DummyConsoleSink.Emitted); - } + Assert.Single(DummyConsoleSink.Emitted); + } - [Fact] - public void SinksAreConfigured() - { - var json = @"{ + [Fact] + public void SinksAreConfigured() + { + var json = @"{ ""Serilog"": { ""Using"": [""TestDummies""], ""WriteTo"": [{ @@ -127,22 +125,22 @@ public void SinksAreConfigured() } }"; - var log = ConfigFromJson(json) - .CreateLogger(); + var log = ConfigFromJson(json) + .CreateLogger(); - DummyRollingFileSink.Reset(); - DummyRollingFileAuditSink.Reset(); + DummyRollingFileSink.Reset(); + DummyRollingFileAuditSink.Reset(); - log.Write(Some.InformationEvent()); + log.Write(Some.InformationEvent()); - Assert.Single(DummyRollingFileSink.Emitted); - Assert.Empty(DummyRollingFileAuditSink.Emitted); - } + Assert.Single(DummyRollingFileSink.Emitted); + Assert.Empty(DummyRollingFileAuditSink.Emitted); + } - [Fact] - public void AuditSinksAreConfigured() - { - var json = @"{ + [Fact] + public void AuditSinksAreConfigured() + { + var json = @"{ ""Serilog"": { ""Using"": [""TestDummies""], ""AuditTo"": [{ @@ -152,22 +150,22 @@ public void AuditSinksAreConfigured() } }"; - var log = ConfigFromJson(json) - .CreateLogger(); + var log = ConfigFromJson(json) + .CreateLogger(); - DummyRollingFileSink.Reset(); - DummyRollingFileAuditSink.Reset(); + DummyRollingFileSink.Reset(); + DummyRollingFileAuditSink.Reset(); - log.Write(Some.InformationEvent()); + log.Write(Some.InformationEvent()); - Assert.Empty(DummyRollingFileSink.Emitted); - Assert.Single(DummyRollingFileAuditSink.Emitted); - } + Assert.Empty(DummyRollingFileSink.Emitted); + Assert.Single(DummyRollingFileAuditSink.Emitted); + } - [Fact] - public void AuditToSubLoggersAreConfigured() - { - var json = @"{ + [Fact] + public void AuditToSubLoggersAreConfigured() + { + var json = @"{ ""Serilog"": { ""Using"": [""TestDummies""], ""AuditTo"": [{ @@ -183,22 +181,22 @@ public void AuditToSubLoggersAreConfigured() } }"; - var log = ConfigFromJson(json) - .CreateLogger(); + var log = ConfigFromJson(json) + .CreateLogger(); - DummyRollingFileSink.Reset(); - DummyRollingFileAuditSink.Reset(); + DummyRollingFileSink.Reset(); + DummyRollingFileAuditSink.Reset(); - log.Write(Some.InformationEvent()); + log.Write(Some.InformationEvent()); - Assert.Empty(DummyRollingFileSink.Emitted); - Assert.Single(DummyRollingFileAuditSink.Emitted); - } + Assert.Empty(DummyRollingFileSink.Emitted); + Assert.Single(DummyRollingFileAuditSink.Emitted); + } - [Fact] - public void TestMinimumLevelOverrides() - { - var json = @"{ + [Fact] + public void TestMinimumLevelOverrides() + { + var json = @"{ ""Serilog"": { ""MinimumLevel"" : { ""Override"" : { @@ -208,29 +206,29 @@ public void TestMinimumLevelOverrides() } }"; - LogEvent evt = null; + LogEvent evt = null; - var log = ConfigFromJson(json) - .WriteTo.Sink(new DelegatingSink(e => evt = e)) - .CreateLogger(); + var log = ConfigFromJson(json) + .WriteTo.Sink(new DelegatingSink(e => evt = e)) + .CreateLogger(); - var systemLogger = log.ForContext(); - systemLogger.Write(Some.InformationEvent()); + var systemLogger = log.ForContext(); + systemLogger.Write(Some.InformationEvent()); - Assert.Null(evt); + Assert.Null(evt); - systemLogger.Warning("Bad things"); - Assert.NotNull(evt); + systemLogger.Warning("Bad things"); + Assert.NotNull(evt); - evt = null; - log.Write(Some.InformationEvent()); - Assert.NotNull(evt); - } + evt = null; + log.Write(Some.InformationEvent()); + Assert.NotNull(evt); + } - [Fact] - public void TestMinimumLevelOverridesForChildContext() - { - var json = @"{ + [Fact] + public void TestMinimumLevelOverridesForChildContext() + { + var json = @"{ ""Serilog"": { ""MinimumLevel"" : { ""Default"" : ""Warning"", @@ -242,29 +240,29 @@ public void TestMinimumLevelOverridesForChildContext() } }"; - LogEvent evt = null; + LogEvent evt = null; - var log = ConfigFromJson(json) - .WriteTo.Sink(new DelegatingSink(e => evt = e)) - .CreateLogger(); + var log = ConfigFromJson(json) + .WriteTo.Sink(new DelegatingSink(e => evt = e)) + .CreateLogger(); - log.Write(Some.DebugEvent()); - Assert.Null(evt); + log.Write(Some.DebugEvent()); + Assert.Null(evt); - var custom = log.ForContext(Constants.SourceContextPropertyName, typeof(System.Threading.Tasks.Task).FullName + "<42>"); - custom.Write(Some.DebugEvent()); - Assert.NotNull(evt); + var custom = log.ForContext(Constants.SourceContextPropertyName, typeof(System.Threading.Tasks.Task).FullName + "<42>"); + custom.Write(Some.DebugEvent()); + Assert.NotNull(evt); - evt = null; - var systemThreadingLogger = log.ForContext(); - systemThreadingLogger.Write(Some.DebugEvent()); - Assert.NotNull(evt); - } + evt = null; + var systemThreadingLogger = log.ForContext(); + systemThreadingLogger.Write(Some.DebugEvent()); + Assert.NotNull(evt); + } - [Fact] - public void SinksWithAbstractParamsAreConfiguredWithTypeName() - { - var json = @"{ + [Fact] + public void SinksWithAbstractParamsAreConfiguredWithTypeName() + { + var json = @"{ ""Serilog"": { ""Using"": [""TestDummies""], ""WriteTo"": [{ @@ -274,19 +272,19 @@ public void SinksWithAbstractParamsAreConfiguredWithTypeName() } }"; - DummyConsoleSink.Theme = null; + DummyConsoleSink.Theme = null; - ConfigFromJson(json) - .CreateLogger(); + ConfigFromJson(json) + .CreateLogger(); - Assert.NotNull(DummyConsoleSink.Theme); - Assert.IsType(DummyConsoleSink.Theme); - } + Assert.NotNull(DummyConsoleSink.Theme); + Assert.IsType(DummyConsoleSink.Theme); + } - [Fact] - public void SinksAreConfiguredWithStaticMember() - { - var json = @"{ + [Fact] + public void SinksAreConfiguredWithStaticMember() + { + var json = @"{ ""Serilog"": { ""Using"": [""TestDummies""], ""WriteTo"": [{ @@ -296,58 +294,58 @@ public void SinksAreConfiguredWithStaticMember() } }"; - DummyConsoleSink.Theme = null; + DummyConsoleSink.Theme = null; - ConfigFromJson(json) - .CreateLogger(); - - Assert.Equal(ConsoleThemes.Theme1, DummyConsoleSink.Theme); - } - - [Theory] - [InlineData("$switchName", true)] - [InlineData("$SwitchName", true)] - [InlineData("SwitchName", true)] - [InlineData("$switch1", true)] - [InlineData("$sw1tch0", true)] - [InlineData("sw1tch0", true)] - [InlineData("$SWITCHNAME", true)] - [InlineData("$$switchname", false)] - [InlineData("$switchname$", false)] - [InlineData("switch$name", false)] - [InlineData("$", false)] - [InlineData("", false)] - [InlineData(" ", false)] - [InlineData("$1switch", false)] - [InlineData("$switch_name", false)] - public void LoggingLevelSwitchNameValidityScenarios(string switchName, bool expectedValid) - { - Assert.True(ConfigurationReader.IsValidSwitchName(switchName) == expectedValid, - $"expected IsValidSwitchName({switchName}) to return {expectedValid} "); - } + ConfigFromJson(json) + .CreateLogger(); - [Fact] - public void LoggingLevelSwitchWithInvalidNameThrowsFormatException() - { - var json = @"{ + Assert.Equal(ConsoleThemes.Theme1, DummyConsoleSink.Theme); + } + + [Theory] + [InlineData("$switchName", true)] + [InlineData("$SwitchName", true)] + [InlineData("SwitchName", true)] + [InlineData("$switch1", true)] + [InlineData("$sw1tch0", true)] + [InlineData("sw1tch0", true)] + [InlineData("$SWITCHNAME", true)] + [InlineData("$$switchname", false)] + [InlineData("$switchname$", false)] + [InlineData("switch$name", false)] + [InlineData("$", false)] + [InlineData("", false)] + [InlineData(" ", false)] + [InlineData("$1switch", false)] + [InlineData("$switch_name", false)] + public void LoggingLevelSwitchNameValidityScenarios(string switchName, bool expectedValid) + { + Assert.True(ConfigurationReader.IsValidSwitchName(switchName) == expectedValid, + $"expected IsValidSwitchName({switchName}) to return {expectedValid} "); + } + + [Fact] + public void LoggingLevelSwitchWithInvalidNameThrowsFormatException() + { + var json = @"{ ""Serilog"": { ""LevelSwitches"": {""1InvalidSwitchName"" : ""Warning"" } } }"; - var ex = Assert.Throws(() => ConfigFromJson(json)); + var ex = Assert.Throws(() => ConfigFromJson(json)); - Assert.Contains("\"1InvalidSwitchName\"", ex.Message); - Assert.Contains("'$' sign", ex.Message); - Assert.Contains("\"LevelSwitches\" : {\"$switchName\" :", ex.Message); - } + Assert.Contains("\"1InvalidSwitchName\"", ex.Message); + Assert.Contains("'$' sign", ex.Message); + Assert.Contains("\"LevelSwitches\" : {\"$switchName\" :", ex.Message); + } - [Theory] - [InlineData("$mySwitch")] - [InlineData("mySwitch")] - public void LoggingFilterSwitchIsConfigured(string switchName) - { - var json = $@"{{ + [Theory] + [InlineData("$mySwitch")] + [InlineData("mySwitch")] + public void LoggingFilterSwitchIsConfigured(string switchName) + { + var json = $@"{{ 'Serilog': {{ 'FilterSwitches': {{ '{switchName}': 'Prop = 42' }}, 'Filter:BySwitch': {{ @@ -358,25 +356,25 @@ public void LoggingFilterSwitchIsConfigured(string switchName) }} }} }}"; - LogEvent evt = null; + LogEvent evt = null; - var log = ConfigFromJson(json) - .WriteTo.Sink(new DelegatingSink(e => evt = e)) - .CreateLogger(); + var log = ConfigFromJson(json) + .WriteTo.Sink(new DelegatingSink(e => evt = e)) + .CreateLogger(); - log.Write(Some.InformationEvent()); - Assert.Null(evt); + log.Write(Some.InformationEvent()); + Assert.Null(evt); - log.ForContext("Prop", 42).Write(Some.InformationEvent()); - Assert.NotNull(evt); - } + log.ForContext("Prop", 42).Write(Some.InformationEvent()); + Assert.NotNull(evt); + } - [Theory] - [InlineData("$switch1")] - [InlineData("switch1")] - public void LoggingLevelSwitchIsConfigured(string switchName) - { - var json = $@"{{ + [Theory] + [InlineData("$switch1")] + [InlineData("switch1")] + public void LoggingLevelSwitchIsConfigured(string switchName) + { + var json = $@"{{ 'Serilog': {{ 'LevelSwitches': {{ '{switchName}' : 'Warning' }}, 'MinimumLevel' : {{ @@ -384,24 +382,24 @@ public void LoggingLevelSwitchIsConfigured(string switchName) }} }} }}"; - LogEvent evt = null; - - var log = ConfigFromJson(json) - .WriteTo.Sink(new DelegatingSink(e => evt = e)) - .CreateLogger(); - - log.Write(Some.DebugEvent()); - Assert.True(evt is null, "LoggingLevelSwitch initial level was Warning. It should not log Debug messages"); - log.Write(Some.InformationEvent()); - Assert.True(evt is null, "LoggingLevelSwitch initial level was Warning. It should not log Information messages"); - log.Write(Some.WarningEvent()); - Assert.True(evt != null, "LoggingLevelSwitch initial level was Warning. It should log Warning messages"); - } - - [Fact] - public void SettingMinimumLevelControlledByToAnUndeclaredSwitchThrows() - { - var json = @"{ + LogEvent evt = null; + + var log = ConfigFromJson(json) + .WriteTo.Sink(new DelegatingSink(e => evt = e)) + .CreateLogger(); + + log.Write(Some.DebugEvent()); + Assert.True(evt is null, "LoggingLevelSwitch initial level was Warning. It should not log Debug messages"); + log.Write(Some.InformationEvent()); + Assert.True(evt is null, "LoggingLevelSwitch initial level was Warning. It should not log Information messages"); + log.Write(Some.WarningEvent()); + Assert.True(evt != null, "LoggingLevelSwitch initial level was Warning. It should log Warning messages"); + } + + [Fact] + public void SettingMinimumLevelControlledByToAnUndeclaredSwitchThrows() + { + var json = @"{ ""Serilog"": { ""LevelSwitches"": {""$switch1"" : ""Warning"" }, ""MinimumLevel"" : { @@ -410,18 +408,18 @@ public void SettingMinimumLevelControlledByToAnUndeclaredSwitchThrows() } }"; - var ex = Assert.Throws(() => - ConfigFromJson(json) - .CreateLogger()); + var ex = Assert.Throws(() => + ConfigFromJson(json) + .CreateLogger()); - Assert.Contains("$switch2", ex.Message); - Assert.Contains("\"LevelSwitches\":{\"$switch2\":", ex.Message); - } + Assert.Contains("$switch2", ex.Message); + Assert.Contains("\"LevelSwitches\":{\"$switch2\":", ex.Message); + } - [Fact] - public void LoggingLevelSwitchIsPassedToSinks() - { - var json = @"{ + [Fact] + public void LoggingLevelSwitchIsPassedToSinks() + { + var json = @"{ ""Serilog"": { ""Using"": [""TestDummies""], ""LevelSwitches"": {""$switch1"" : ""Information"" }, @@ -435,29 +433,29 @@ public void LoggingLevelSwitchIsPassedToSinks() } }"; - LogEvent evt = null; + LogEvent evt = null; - var log = ConfigFromJson(json) - .WriteTo.Sink(new DelegatingSink(e => evt = e)) - .CreateLogger(); + var log = ConfigFromJson(json) + .WriteTo.Sink(new DelegatingSink(e => evt = e)) + .CreateLogger(); - Assert.False(DummyWithLevelSwitchSink.ControlLevelSwitch == null, "Sink ControlLevelSwitch should have been initialized"); + Assert.False(DummyWithLevelSwitchSink.ControlLevelSwitch == null, "Sink ControlLevelSwitch should have been initialized"); - var controlSwitch = DummyWithLevelSwitchSink.ControlLevelSwitch; - Assert.NotNull(controlSwitch); + var controlSwitch = DummyWithLevelSwitchSink.ControlLevelSwitch; + Assert.NotNull(controlSwitch); - log.Write(Some.DebugEvent()); - Assert.True(evt is null, "LoggingLevelSwitch initial level was information. It should not log Debug messages"); + log.Write(Some.DebugEvent()); + Assert.True(evt is null, "LoggingLevelSwitch initial level was information. It should not log Debug messages"); - controlSwitch.MinimumLevel = LogEventLevel.Debug; - log.Write(Some.DebugEvent()); - Assert.True(evt != null, "LoggingLevelSwitch level was changed to Debug. It should log Debug messages"); - } + controlSwitch.MinimumLevel = LogEventLevel.Debug; + log.Write(Some.DebugEvent()); + Assert.True(evt != null, "LoggingLevelSwitch level was changed to Debug. It should log Debug messages"); + } - [Fact] - public void ReferencingAnUndeclaredSwitchInSinkThrows() - { - var json = @"{ + [Fact] + public void ReferencingAnUndeclaredSwitchInSinkThrows() + { + var json = @"{ ""Serilog"": { ""Using"": [""TestDummies""], ""LevelSwitches"": {""$switch1"" : ""Information"" }, @@ -471,18 +469,18 @@ public void ReferencingAnUndeclaredSwitchInSinkThrows() } }"; - var ex = Assert.Throws(() => - ConfigFromJson(json) - .CreateLogger()); + var ex = Assert.Throws(() => + ConfigFromJson(json) + .CreateLogger()); - Assert.Contains("$switch2", ex.Message); - Assert.Contains("\"LevelSwitches\":{\"$switch2\":", ex.Message); - } + Assert.Contains("$switch2", ex.Message); + Assert.Contains("\"LevelSwitches\":{\"$switch2\":", ex.Message); + } - [Fact] - public void LoggingLevelSwitchCanBeUsedForMinimumLevelOverrides() - { - var json = @"{ + [Fact] + public void LoggingLevelSwitchCanBeUsedForMinimumLevelOverrides() + { + var json = @"{ ""Serilog"": { ""Using"": [""TestDummies""], ""LevelSwitches"": {""$specificSwitch"" : ""Warning"" }, @@ -499,41 +497,41 @@ public void LoggingLevelSwitchCanBeUsedForMinimumLevelOverrides() } }"; - LogEvent evt = null; + LogEvent evt = null; - var log = ConfigFromJson(json) - .WriteTo.Sink(new DelegatingSink(e => evt = e)) - .CreateLogger(); + var log = ConfigFromJson(json) + .WriteTo.Sink(new DelegatingSink(e => evt = e)) + .CreateLogger(); - var systemLogger = log.ForContext(Constants.SourceContextPropertyName, "System.Bar"); + var systemLogger = log.ForContext(Constants.SourceContextPropertyName, "System.Bar"); - log.Write(Some.InformationEvent()); - Assert.False(evt is null, "Minimum level is Debug. It should log Information messages"); + log.Write(Some.InformationEvent()); + Assert.False(evt is null, "Minimum level is Debug. It should log Information messages"); - evt = null; - // ReSharper disable HeuristicUnreachableCode - systemLogger.Write(Some.InformationEvent()); - Assert.True(evt is null, "LoggingLevelSwitch initial level was Warning for logger System.*. It should not log Information messages for SourceContext System.Bar"); + evt = null; + // ReSharper disable HeuristicUnreachableCode + systemLogger.Write(Some.InformationEvent()); + Assert.True(evt is null, "LoggingLevelSwitch initial level was Warning for logger System.*. It should not log Information messages for SourceContext System.Bar"); - systemLogger.Write(Some.WarningEvent()); - Assert.False(evt is null, "LoggingLevelSwitch initial level was Warning for logger System.*. It should log Warning messages for SourceContext System.Bar"); + systemLogger.Write(Some.WarningEvent()); + Assert.False(evt is null, "LoggingLevelSwitch initial level was Warning for logger System.*. It should log Warning messages for SourceContext System.Bar"); - evt = null; - var controlSwitch = DummyWithLevelSwitchSink.ControlLevelSwitch; + evt = null; + var controlSwitch = DummyWithLevelSwitchSink.ControlLevelSwitch; - controlSwitch.MinimumLevel = LogEventLevel.Information; - systemLogger.Write(Some.InformationEvent()); - Assert.False(evt is null, "LoggingLevelSwitch level was changed to Information for logger System.*. It should now log Information events for SourceContext System.Bar."); - // ReSharper restore HeuristicUnreachableCode - } + controlSwitch.MinimumLevel = LogEventLevel.Information; + systemLogger.Write(Some.InformationEvent()); + Assert.False(evt is null, "LoggingLevelSwitch level was changed to Information for logger System.*. It should now log Information events for SourceContext System.Bar."); + // ReSharper restore HeuristicUnreachableCode + } - [Fact] + [Fact] - [Trait("BugFix", "https://github.com/serilog/serilog-settings-configuration/issues/142")] - public void SinkWithIConfigurationArguments() - { - var json = @"{ + [Trait("BugFix", "https://github.com/serilog/serilog-settings-configuration/issues/142")] + public void SinkWithIConfigurationArguments() + { + var json = @"{ ""Serilog"": { ""Using"": [""TestDummies""], ""WriteTo"": [{ @@ -543,21 +541,21 @@ public void SinkWithIConfigurationArguments() } }"; - DummyConfigurationSink.Reset(); - var log = ConfigFromJson(json, out var expectedConfig) - .CreateLogger(); + DummyConfigurationSink.Reset(); + var log = ConfigFromJson(json, out var expectedConfig) + .CreateLogger(); - log.Write(Some.InformationEvent()); + log.Write(Some.InformationEvent()); - Assert.NotNull(DummyConfigurationSink.Configuration); - Assert.Same(expectedConfig, DummyConfigurationSink.Configuration); - } + Assert.NotNull(DummyConfigurationSink.Configuration); + Assert.Same(expectedConfig, DummyConfigurationSink.Configuration); + } - [Fact] - [Trait("BugFix", "https://github.com/serilog/serilog-settings-configuration/issues/142")] - public void SinkWithOptionalIConfigurationArguments() - { - var json = @"{ + [Fact] + [Trait("BugFix", "https://github.com/serilog/serilog-settings-configuration/issues/142")] + public void SinkWithOptionalIConfigurationArguments() + { + var json = @"{ ""Serilog"": { ""Using"": [""TestDummies""], ""WriteTo"": [{ @@ -567,21 +565,21 @@ public void SinkWithOptionalIConfigurationArguments() } }"; - DummyConfigurationSink.Reset(); - var log = ConfigFromJson(json, out var expectedConfig) - .CreateLogger(); + DummyConfigurationSink.Reset(); + var log = ConfigFromJson(json, out var expectedConfig) + .CreateLogger(); - log.Write(Some.InformationEvent()); + log.Write(Some.InformationEvent()); - // null is the default value, but we have a configuration to provide - Assert.NotNull(DummyConfigurationSink.Configuration); - Assert.Same(expectedConfig, DummyConfigurationSink.Configuration); - } + // null is the default value, but we have a configuration to provide + Assert.NotNull(DummyConfigurationSink.Configuration); + Assert.Same(expectedConfig, DummyConfigurationSink.Configuration); + } - [Fact] - public void SinkWithIConfigSectionArguments() - { - var json = @"{ + [Fact] + public void SinkWithIConfigSectionArguments() + { + var json = @"{ ""Serilog"": { ""Using"": [""TestDummies""], ""WriteTo"": [{ @@ -591,21 +589,21 @@ public void SinkWithIConfigSectionArguments() } }"; - DummyConfigurationSink.Reset(); - var log = ConfigFromJson(json) - .CreateLogger(); + DummyConfigurationSink.Reset(); + var log = ConfigFromJson(json) + .CreateLogger(); - log.Write(Some.InformationEvent()); + log.Write(Some.InformationEvent()); - Assert.NotNull(DummyConfigurationSink.ConfigSection); - Assert.Equal("bar", DummyConfigurationSink.ConfigSection["foo"]); - } + Assert.NotNull(DummyConfigurationSink.ConfigSection); + Assert.Equal("bar", DummyConfigurationSink.ConfigSection["foo"]); + } - [Fact] - public void SinkWithConfigurationBindingArgument() - { - var json = @"{ + [Fact] + public void SinkWithConfigurationBindingArgument() + { + var json = @"{ ""Serilog"": { ""Using"": [""TestDummies""], ""WriteTo"": [{ @@ -616,20 +614,20 @@ public void SinkWithConfigurationBindingArgument() } }"; - var log = ConfigFromJson(json) - .CreateLogger(); + var log = ConfigFromJson(json) + .CreateLogger(); - DummyRollingFileSink.Reset(); + DummyRollingFileSink.Reset(); - log.Write(Some.InformationEvent()); + log.Write(Some.InformationEvent()); - Assert.Single(DummyRollingFileSink.Emitted); - } + Assert.Single(DummyRollingFileSink.Emitted); + } - [Fact] - public void SinkWithStringArrayArgument() - { - var json = @"{ + [Fact] + public void SinkWithStringArrayArgument() + { + var json = @"{ ""Serilog"": { ""Using"": [""TestDummies""], ""WriteTo"": [{ @@ -640,20 +638,20 @@ public void SinkWithStringArrayArgument() } }"; - var log = ConfigFromJson(json) - .CreateLogger(); + var log = ConfigFromJson(json) + .CreateLogger(); - DummyRollingFileSink.Reset(); + DummyRollingFileSink.Reset(); - log.Write(Some.InformationEvent()); + log.Write(Some.InformationEvent()); - Assert.Single(DummyRollingFileSink.Emitted); - } + Assert.Single(DummyRollingFileSink.Emitted); + } - [Fact] - public void DestructureWithCollectionsOfTypeArgument() - { - var json = @"{ + [Fact] + public void DestructureWithCollectionsOfTypeArgument() + { + var json = @"{ ""Serilog"": { ""Using"": [ ""TestDummies"" ], ""Destructure"": [{ @@ -679,22 +677,22 @@ public void DestructureWithCollectionsOfTypeArgument() } }"; - DummyPolicy.Current = null; + DummyPolicy.Current = null; - ConfigFromJson(json); + ConfigFromJson(json); - Assert.NotNull(DummyPolicy.Current); - Assert.Equal(typeof(TimeSpan), DummyPolicy.Current.Type); - Assert.Equal(new[] { typeof(int), typeof(string) }, DummyPolicy.Current.Array); - Assert.Equal(new[] { typeof(byte), typeof(short) }, DummyPolicy.Current.List); - Assert.Equal(typeof(long), DummyPolicy.Current.Custom.First); - Assert.Equal("System.UInt32", DummyPolicy.Current.CustomStrings.First); - } + Assert.NotNull(DummyPolicy.Current); + Assert.Equal(typeof(TimeSpan), DummyPolicy.Current.Type); + Assert.Equal(new[] { typeof(int), typeof(string) }, DummyPolicy.Current.Array); + Assert.Equal(new[] { typeof(byte), typeof(short) }, DummyPolicy.Current.List); + Assert.Equal(typeof(long), DummyPolicy.Current.Custom.First); + Assert.Equal("System.UInt32", DummyPolicy.Current.CustomStrings.First); + } - [Fact] - public void SinkWithIntArrayArgument() - { - var json = @"{ + [Fact] + public void SinkWithIntArrayArgument() + { + var json = @"{ ""Serilog"": { ""Using"": [""TestDummies""], ""WriteTo"": [{ @@ -705,21 +703,21 @@ public void SinkWithIntArrayArgument() } }"; - var log = ConfigFromJson(json) - .CreateLogger(); + var log = ConfigFromJson(json) + .CreateLogger(); - DummyRollingFileSink.Reset(); + DummyRollingFileSink.Reset(); - log.Write(Some.InformationEvent()); + log.Write(Some.InformationEvent()); - Assert.Single(DummyRollingFileSink.Emitted); - } + Assert.Single(DummyRollingFileSink.Emitted); + } - [Trait("Bugfix", "#111")] - [Fact] - public void CaseInsensitiveArgumentNameMatching() - { - var json = @"{ + [Trait("Bugfix", "#111")] + [Fact] + public void CaseInsensitiveArgumentNameMatching() + { + var json = @"{ ""Serilog"": { ""Using"": [""TestDummies""], ""WriteTo"": [{ @@ -729,21 +727,21 @@ public void CaseInsensitiveArgumentNameMatching() } }"; - var log = ConfigFromJson(json) - .CreateLogger(); + var log = ConfigFromJson(json) + .CreateLogger(); - DummyRollingFileSink.Reset(); + DummyRollingFileSink.Reset(); - log.Write(Some.InformationEvent()); + log.Write(Some.InformationEvent()); - Assert.Single(DummyRollingFileSink.Emitted); - } + Assert.Single(DummyRollingFileSink.Emitted); + } - [Trait("Bugfix", "#91")] - [Fact] - public void WriteToLoggerWithRestrictedToMinimumLevelIsSupported() - { - var json = @"{ + [Trait("Bugfix", "#91")] + [Fact] + public void WriteToLoggerWithRestrictedToMinimumLevelIsSupported() + { + var json = @"{ ""Serilog"": { ""Using"": [""TestDummies""], ""WriteTo"": [{ @@ -760,22 +758,22 @@ public void WriteToLoggerWithRestrictedToMinimumLevelIsSupported() } }"; - var log = ConfigFromJson(json) - .CreateLogger(); + var log = ConfigFromJson(json) + .CreateLogger(); - DummyRollingFileSink.Reset(); + DummyRollingFileSink.Reset(); - log.Write(Some.InformationEvent()); - log.Write(Some.WarningEvent()); + log.Write(Some.InformationEvent()); + log.Write(Some.WarningEvent()); - Assert.Single(DummyRollingFileSink.Emitted); - } + Assert.Single(DummyRollingFileSink.Emitted); + } - [Trait("Bugfix", "#91")] - [Fact] - public void WriteToSubLoggerWithLevelSwitchIsSupported() - { - var json = @"{ + [Trait("Bugfix", "#91")] + [Fact] + public void WriteToSubLoggerWithLevelSwitchIsSupported() + { + var json = @"{ ""Serilog"": { ""Using"": [""TestDummies""], ""LevelSwitches"": {""$switch1"" : ""Warning"" }, @@ -795,22 +793,22 @@ public void WriteToSubLoggerWithLevelSwitchIsSupported() } }"; - var log = ConfigFromJson(json) - .CreateLogger(); + var log = ConfigFromJson(json) + .CreateLogger(); - DummyRollingFileSink.Reset(); + DummyRollingFileSink.Reset(); - log.Write(Some.InformationEvent()); - log.Write(Some.WarningEvent()); + log.Write(Some.InformationEvent()); + log.Write(Some.WarningEvent()); - Assert.Single(DummyRollingFileSink.Emitted); - } + Assert.Single(DummyRollingFileSink.Emitted); + } - [Trait("Bugfix", "#103")] - [Fact] - public void InconsistentComplexVsScalarArgumentValuesThrowsIOE() - { - var jsonDiscreteValue = @"{ + [Trait("Bugfix", "#103")] + [Fact] + public void InconsistentComplexVsScalarArgumentValuesThrowsIOE() + { + var jsonDiscreteValue = @"{ ""Serilog"": { ""Using"": [""TestDummies""], ""WriteTo"": [{ @@ -820,7 +818,7 @@ public void InconsistentComplexVsScalarArgumentValuesThrowsIOE() } }"; - var jsonComplexValue = @"{ + var jsonComplexValue = @"{ ""Serilog"": { ""Using"": [""TestDummies""], ""WriteTo"": [{ @@ -830,24 +828,24 @@ public void InconsistentComplexVsScalarArgumentValuesThrowsIOE() } }"; - // These will combine into a ConfigurationSection object that has both - // Value == "C:\" and GetChildren() == List. No configuration - // extension matching this exists (in theory an "object" argument could - // accept either value). ConfigurationReader should throw as soon as - // the multiple values are recognized; it will never attempt to locate - // a matching argument. + // These will combine into a ConfigurationSection object that has both + // Value == "C:\" and GetChildren() == List. No configuration + // extension matching this exists (in theory an "object" argument could + // accept either value). ConfigurationReader should throw as soon as + // the multiple values are recognized; it will never attempt to locate + // a matching argument. - var ex = Assert.Throws(() - => ConfigFromJson(jsonDiscreteValue, jsonComplexValue)); + var ex = Assert.Throws(() + => ConfigFromJson(jsonDiscreteValue, jsonComplexValue)); - Assert.Contains("The value for the argument", ex.Message); - Assert.Contains("'Serilog:WriteTo:0:Args:pathFormat'", ex.Message); - } + Assert.Contains("The value for the argument", ex.Message); + Assert.Contains("'Serilog:WriteTo:0:Args:pathFormat'", ex.Message); + } - [Fact] - public void DestructureLimitsNestingDepth() - { - var json = @"{ + [Fact] + public void DestructureLimitsNestingDepth() + { + var json = @"{ ""Serilog"": { ""Destructure"": [ { @@ -857,30 +855,30 @@ public void DestructureLimitsNestingDepth() } }"; - var NestedObject = new + var NestedObject = new + { + A = new { - A = new + B = new { - B = new + C = new { - C = new - { - D = "F" - } + D = "F" } } - }; + } + }; - var msg = GetDestructuredProperty(NestedObject, json); + var msg = GetDestructuredProperty(NestedObject, json); - Assert.Contains("C", msg); - Assert.DoesNotContain("D", msg); - } + Assert.Contains("C", msg); + Assert.DoesNotContain("D", msg); + } - [Fact] - public void DestructureLimitsStringLength() - { - var json = @"{ + [Fact] + public void DestructureLimitsStringLength() + { + var json = @"{ ""Serilog"": { ""Destructure"": [ { @@ -890,16 +888,16 @@ public void DestructureLimitsStringLength() } }"; - var inputString = "ABCDEFGH"; - var msg = GetDestructuredProperty(inputString, json); + var inputString = "ABCDEFGH"; + var msg = GetDestructuredProperty(inputString, json); - Assert.Equal("\"AB…\"", msg); - } + Assert.Equal("\"AB…\"", msg); + } - [Fact] - public void DestructureLimitsCollectionCount() - { - var json = @"{ + [Fact] + public void DestructureLimitsCollectionCount() + { + var json = @"{ ""Serilog"": { ""Destructure"": [ { @@ -909,28 +907,28 @@ public void DestructureLimitsCollectionCount() } }"; - var collection = new[] { 1, 2, 3, 4, 5, 6 }; - var msg = GetDestructuredProperty(collection, json); + var collection = new[] { 1, 2, 3, 4, 5, 6 }; + var msg = GetDestructuredProperty(collection, json); - Assert.Contains("3", msg); - Assert.DoesNotContain("4", msg); - } + Assert.Contains("3", msg); + Assert.DoesNotContain("4", msg); + } - private static string GetDestructuredProperty(object x, string json) - { - LogEvent evt = null; - var log = ConfigFromJson(json) - .WriteTo.Sink(new DelegatingSink(e => evt = e)) - .CreateLogger(); - log.Information("{@X}", x); - var result = evt.Properties["X"].ToString(); - return result; - } - - [Fact] - public void DestructuringWithCustomExtensionMethodIsApplied() - { - var json = @"{ + private static string GetDestructuredProperty(object x, string json) + { + LogEvent evt = null; + var log = ConfigFromJson(json) + .WriteTo.Sink(new DelegatingSink(e => evt = e)) + .CreateLogger(); + log.Information("{@X}", x); + var result = evt.Properties["X"].ToString(); + return result; + } + + [Fact] + public void DestructuringWithCustomExtensionMethodIsApplied() + { + var json = @"{ ""Serilog"": { ""Using"": [""TestDummies""], ""Destructure"": [ @@ -941,20 +939,20 @@ public void DestructuringWithCustomExtensionMethodIsApplied() } }"; - 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(); + 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); - } + Assert.Equal("\"hardcoded\"", formattedProperty); + } - [Fact] - public void DestructuringAsScalarIsAppliedWithShortTypeName() - { - var json = @"{ + [Fact] + public void DestructuringAsScalarIsAppliedWithShortTypeName() + { + var json = @"{ ""Serilog"": { ""Destructure"": [ { @@ -964,21 +962,21 @@ public void DestructuringAsScalarIsAppliedWithShortTypeName() } }"; - LogEvent evt = null; - var log = ConfigFromJson(json) - .WriteTo.Sink(new DelegatingSink(e => evt = e)) - .CreateLogger(); + 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"]; + log.Information("Destructuring as scalar {@Scalarized}", new Version(2, 3)); + var prop = evt.Properties["Scalarized"]; - Assert.IsType(prop); - } + Assert.IsType(prop); + } - [Fact] - public void DestructuringAsScalarIsAppliedWithAssemblyQualifiedName() - { - var json = $@"{{ + [Fact] + public void DestructuringAsScalarIsAppliedWithAssemblyQualifiedName() + { + var json = $@"{{ ""Serilog"": {{ ""Destructure"": [ {{ @@ -988,21 +986,21 @@ public void DestructuringAsScalarIsAppliedWithAssemblyQualifiedName() }} }}"; - LogEvent evt = null; - var log = ConfigFromJson(json) - .WriteTo.Sink(new DelegatingSink(e => evt = e)) - .CreateLogger(); + 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"]; + log.Information("Destructuring as scalar {@Scalarized}", new Version(2, 3)); + var prop = evt.Properties["Scalarized"]; - Assert.IsType(prop); - } + Assert.IsType(prop); + } - [Fact] - public void WriteToSinkIsAppliedWithCustomSink() - { - var json = $@"{{ + [Fact] + public void WriteToSinkIsAppliedWithCustomSink() + { + var json = $@"{{ ""Serilog"": {{ ""Using"": [""TestDummies""], ""WriteTo"": [ @@ -1015,19 +1013,19 @@ public void WriteToSinkIsAppliedWithCustomSink() }} }}"; - var log = ConfigFromJson(json) - .CreateLogger(); + var log = ConfigFromJson(json) + .CreateLogger(); - DummyRollingFileSink.Reset(); - log.Write(Some.InformationEvent()); + DummyRollingFileSink.Reset(); + log.Write(Some.InformationEvent()); - Assert.Single(DummyRollingFileSink.Emitted); - } + Assert.Single(DummyRollingFileSink.Emitted); + } - [Fact] - public void WriteToSinkIsAppliedWithCustomSinkAndMinimumLevel() - { - var json = $@"{{ + [Fact] + public void WriteToSinkIsAppliedWithCustomSinkAndMinimumLevel() + { + var json = $@"{{ ""Serilog"": {{ ""Using"": [""TestDummies""], ""WriteTo"": [ @@ -1041,20 +1039,20 @@ public void WriteToSinkIsAppliedWithCustomSinkAndMinimumLevel() }} }}"; - var log = ConfigFromJson(json) - .CreateLogger(); + var log = ConfigFromJson(json) + .CreateLogger(); - DummyRollingFileSink.Reset(); - log.Write(Some.InformationEvent()); - log.Write(Some.WarningEvent()); + DummyRollingFileSink.Reset(); + log.Write(Some.InformationEvent()); + log.Write(Some.WarningEvent()); - Assert.Single(DummyRollingFileSink.Emitted); - } + Assert.Single(DummyRollingFileSink.Emitted); + } - [Fact] - public void WriteToSinkIsAppliedWithCustomSinkAndLevelSwitch() - { - var json = $@"{{ + [Fact] + public void WriteToSinkIsAppliedWithCustomSinkAndLevelSwitch() + { + var json = $@"{{ ""Serilog"": {{ ""Using"": [""TestDummies""], ""LevelSwitches"": {{""$switch1"": ""Warning"" }}, @@ -1069,20 +1067,20 @@ public void WriteToSinkIsAppliedWithCustomSinkAndLevelSwitch() }} }}"; - var log = ConfigFromJson(json) - .CreateLogger(); + var log = ConfigFromJson(json) + .CreateLogger(); - DummyRollingFileSink.Reset(); - log.Write(Some.InformationEvent()); - log.Write(Some.WarningEvent()); + DummyRollingFileSink.Reset(); + log.Write(Some.InformationEvent()); + log.Write(Some.WarningEvent()); - Assert.Single(DummyRollingFileSink.Emitted); - } + Assert.Single(DummyRollingFileSink.Emitted); + } - [Fact] - public void AuditToSinkIsAppliedWithCustomSink() - { - var json = $@"{{ + [Fact] + public void AuditToSinkIsAppliedWithCustomSink() + { + var json = $@"{{ ""Serilog"": {{ ""Using"": [""TestDummies""], ""AuditTo"": [ @@ -1095,19 +1093,19 @@ public void AuditToSinkIsAppliedWithCustomSink() }} }}"; - var log = ConfigFromJson(json) - .CreateLogger(); + var log = ConfigFromJson(json) + .CreateLogger(); - DummyRollingFileSink.Reset(); - log.Write(Some.InformationEvent()); + DummyRollingFileSink.Reset(); + log.Write(Some.InformationEvent()); - Assert.Single(DummyRollingFileSink.Emitted); - } + Assert.Single(DummyRollingFileSink.Emitted); + } - [Fact] - public void AuditToSinkIsAppliedWithCustomSinkAndMinimumLevel() - { - var json = $@"{{ + [Fact] + public void AuditToSinkIsAppliedWithCustomSinkAndMinimumLevel() + { + var json = $@"{{ ""Serilog"": {{ ""Using"": [""TestDummies""], ""AuditTo"": [ @@ -1121,20 +1119,20 @@ public void AuditToSinkIsAppliedWithCustomSinkAndMinimumLevel() }} }}"; - var log = ConfigFromJson(json) - .CreateLogger(); + var log = ConfigFromJson(json) + .CreateLogger(); - DummyRollingFileSink.Reset(); - log.Write(Some.InformationEvent()); - log.Write(Some.WarningEvent()); + DummyRollingFileSink.Reset(); + log.Write(Some.InformationEvent()); + log.Write(Some.WarningEvent()); - Assert.Single(DummyRollingFileSink.Emitted); - } + Assert.Single(DummyRollingFileSink.Emitted); + } - [Fact] - public void AuditToSinkIsAppliedWithCustomSinkAndLevelSwitch() - { - var json = $@"{{ + [Fact] + public void AuditToSinkIsAppliedWithCustomSinkAndLevelSwitch() + { + var json = $@"{{ ""Serilog"": {{ ""Using"": [""TestDummies""], ""LevelSwitches"": {{""$switch1"": ""Warning"" }}, @@ -1149,22 +1147,22 @@ public void AuditToSinkIsAppliedWithCustomSinkAndLevelSwitch() }} }}"; - var log = ConfigFromJson(json) - .CreateLogger(); + var log = ConfigFromJson(json) + .CreateLogger(); - DummyRollingFileSink.Reset(); - log.Write(Some.InformationEvent()); - log.Write(Some.WarningEvent()); + DummyRollingFileSink.Reset(); + log.Write(Some.InformationEvent()); + log.Write(Some.WarningEvent()); - Assert.Single(DummyRollingFileSink.Emitted); - } + Assert.Single(DummyRollingFileSink.Emitted); + } - [Fact] - public void EnrichWithIsAppliedWithCustomEnricher() - { - LogEvent evt = null; + [Fact] + public void EnrichWithIsAppliedWithCustomEnricher() + { + LogEvent evt = null; - var json = $@"{{ + var json = $@"{{ ""Serilog"": {{ ""Using"": [""TestDummies""], ""Enrich"": [ @@ -1177,22 +1175,22 @@ public void EnrichWithIsAppliedWithCustomEnricher() }} }}"; - var log = ConfigFromJson(json) - .WriteTo.Sink(new DelegatingSink(e => evt = e)) - .CreateLogger(); + var log = ConfigFromJson(json) + .WriteTo.Sink(new DelegatingSink(e => evt = e)) + .CreateLogger(); - log.Write(Some.InformationEvent()); + log.Write(Some.InformationEvent()); - Assert.NotNull(evt); - Assert.True(evt.Properties.ContainsKey("ThreadId"), "Event should have enriched property ThreadId"); - } + Assert.NotNull(evt); + Assert.True(evt.Properties.ContainsKey("ThreadId"), "Event should have enriched property ThreadId"); + } - [Fact] - public void FilterWithIsAppliedWithCustomFilter() - { - LogEvent evt = null; + [Fact] + public void FilterWithIsAppliedWithCustomFilter() + { + LogEvent evt = null; - var json = $@"{{ + var json = $@"{{ ""Serilog"": {{ ""Using"": [""TestDummies""], ""Filter"": [ @@ -1205,14 +1203,13 @@ public void FilterWithIsAppliedWithCustomFilter() }} }}"; - var log = ConfigFromJson(json) - .WriteTo.Sink(new DelegatingSink(e => evt = e)) - .CreateLogger(); + 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); - } + 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/Serilog.Settings.Configuration.Tests/DllScanningAssemblyFinderTests.cs b/test/Serilog.Settings.Configuration.Tests/DllScanningAssemblyFinderTests.cs index 050bf54..120ac3c 100644 --- a/test/Serilog.Settings.Configuration.Tests/DllScanningAssemblyFinderTests.cs +++ b/test/Serilog.Settings.Configuration.Tests/DllScanningAssemblyFinderTests.cs @@ -3,65 +3,62 @@ using System.IO; #endif -using Xunit; - using Serilog.Settings.Configuration.Assemblies; -namespace Serilog.Settings.Configuration.Tests +namespace Serilog.Settings.Configuration.Tests; + +public class DllScanningAssemblyFinderTests { - public class DllScanningAssemblyFinderTests - { - const string BinDir1 = "bin1"; - const string BinDir2 = "bin2"; - const string BinDir3 = "bin3"; + const string BinDir1 = "bin1"; + const string BinDir2 = "bin2"; + const string BinDir3 = "bin3"; - [Fact] - public void ShouldProbeCurrentDirectory() - { - var assemblyNames = new DllScanningAssemblyFinder().FindAssembliesContainingName("TestDummies"); - Assert.Single(assemblyNames); - } + [Fact] + public void ShouldProbeCurrentDirectory() + { + var assemblyNames = new DllScanningAssemblyFinder().FindAssembliesContainingName("TestDummies"); + Assert.Single(assemblyNames); + } #if NETFRAMEWORK - [Fact] - public void ShouldProbePrivateBinPath() - { - var d1 = GetOrCreateDirectory(BinDir1); - var d2 = GetOrCreateDirectory(BinDir2); - var d3 = GetOrCreateDirectory(BinDir3); - - DirectoryInfo GetOrCreateDirectory(string name) - => Directory.Exists(name) ? new DirectoryInfo(name) : Directory.CreateDirectory(name); + [Fact] + public void ShouldProbePrivateBinPath() + { + var d1 = GetOrCreateDirectory(BinDir1); + var d2 = GetOrCreateDirectory(BinDir2); + var d3 = GetOrCreateDirectory(BinDir3); - File.Copy("TestDummies.dll", $"{BinDir1}/customSink1.dll", true); - File.Copy("TestDummies.dll", $"{BinDir2}/customSink2.dll", true); - File.Copy("TestDummies.dll", $"{BinDir3}/thirdpartydependency.dll", true); + DirectoryInfo GetOrCreateDirectory(string name) + => Directory.Exists(name) ? new DirectoryInfo(name) : Directory.CreateDirectory(name); - var ad = AppDomain.CreateDomain("serilog", null, - new AppDomainSetup - { - ApplicationBase = AppDomain.CurrentDomain.BaseDirectory, - PrivateBinPath = $"{d1.Name};{d2.FullName};{d3.Name}" - }); + File.Copy("TestDummies.dll", $"{BinDir1}/customSink1.dll", true); + File.Copy("TestDummies.dll", $"{BinDir2}/customSink2.dll", true); + File.Copy("TestDummies.dll", $"{BinDir3}/thirdpartydependency.dll", true); - try + var ad = AppDomain.CreateDomain("serilog", null, + new AppDomainSetup { - ad.DoCallBack(DoTestInner); - } - finally - { - AppDomain.Unload(ad); - Directory.Delete(BinDir1, true); - Directory.Delete(BinDir2, true); - Directory.Delete(BinDir3, true); - } + ApplicationBase = AppDomain.CurrentDomain.BaseDirectory, + PrivateBinPath = $"{d1.Name};{d2.FullName};{d3.Name}" + }); - static void DoTestInner() - { - var assemblyNames = new DllScanningAssemblyFinder().FindAssembliesContainingName("customSink"); - Assert.Equal(2, assemblyNames.Count); - } + try + { + ad.DoCallBack(DoTestInner); + } + finally + { + AppDomain.Unload(ad); + Directory.Delete(BinDir1, true); + Directory.Delete(BinDir2, true); + Directory.Delete(BinDir3, true); + } + + static void DoTestInner() + { + var assemblyNames = new DllScanningAssemblyFinder().FindAssembliesContainingName("customSink"); + Assert.Equal(2, assemblyNames.Count); } -#endif } +#endif } diff --git a/test/Serilog.Settings.Configuration.Tests/DummyLoggerConfigurationExtensions.cs b/test/Serilog.Settings.Configuration.Tests/DummyLoggerConfigurationExtensions.cs index 9675446..774c8cb 100644 --- a/test/Serilog.Settings.Configuration.Tests/DummyLoggerConfigurationExtensions.cs +++ b/test/Serilog.Settings.Configuration.Tests/DummyLoggerConfigurationExtensions.cs @@ -1,29 +1,27 @@ -using System; -using Serilog.Configuration; +using Serilog.Configuration; using Serilog.Events; using Serilog.Formatting; -namespace Serilog.Settings.Configuration.Tests +namespace Serilog.Settings.Configuration.Tests; + +static class DummyLoggerConfigurationExtensions { - static class DummyLoggerConfigurationExtensions + public static LoggerConfiguration DummyRollingFile( + LoggerSinkConfiguration loggerSinkConfiguration, + string pathFormat, + LogEventLevel restrictedToMinimumLevel = LevelAlias.Minimum, + string outputTemplate = null, + IFormatProvider formatProvider = null) { - public static LoggerConfiguration DummyRollingFile( - LoggerSinkConfiguration loggerSinkConfiguration, - string pathFormat, - LogEventLevel restrictedToMinimumLevel = LevelAlias.Minimum, - string outputTemplate = null, - IFormatProvider formatProvider = null) - { - return null; - } + return null; + } - public static LoggerConfiguration DummyRollingFile( - LoggerSinkConfiguration loggerSinkConfiguration, - ITextFormatter formatter, - string pathFormat, - LogEventLevel restrictedToMinimumLevel = LevelAlias.Minimum) - { - return null; - } + public static LoggerConfiguration DummyRollingFile( + LoggerSinkConfiguration loggerSinkConfiguration, + ITextFormatter formatter, + string pathFormat, + LogEventLevel restrictedToMinimumLevel = LevelAlias.Minimum) + { + return null; } } diff --git a/test/Serilog.Settings.Configuration.Tests/DummyLoggerConfigurationWithMultipleMethodsExtensions.cs b/test/Serilog.Settings.Configuration.Tests/DummyLoggerConfigurationWithMultipleMethodsExtensions.cs index b6be570..5bc743f 100644 --- a/test/Serilog.Settings.Configuration.Tests/DummyLoggerConfigurationWithMultipleMethodsExtensions.cs +++ b/test/Serilog.Settings.Configuration.Tests/DummyLoggerConfigurationWithMultipleMethodsExtensions.cs @@ -1,42 +1,40 @@ -using System; -using Serilog.Configuration; +using Serilog.Configuration; using Serilog.Events; using Serilog.Formatting; -namespace Serilog.Settings.Configuration.Tests -{ - using System.Collections.Generic; +namespace Serilog.Settings.Configuration.Tests; + +using System.Collections.Generic; - static class DummyLoggerConfigurationWithMultipleMethodsExtensions +static class DummyLoggerConfigurationWithMultipleMethodsExtensions +{ + public static LoggerConfiguration DummyRollingFile( + LoggerSinkConfiguration loggerSinkConfiguration, + ITextFormatter formatter, + IEnumerable pathFormat, + LogEventLevel restrictedToMinimumLevel = LevelAlias.Minimum, + string outputTemplate = null, + IFormatProvider formatProvider = null) { - public static LoggerConfiguration DummyRollingFile( - LoggerSinkConfiguration loggerSinkConfiguration, - ITextFormatter formatter, - IEnumerable pathFormat, - LogEventLevel restrictedToMinimumLevel = LevelAlias.Minimum, - string outputTemplate = null, - IFormatProvider formatProvider = null) - { - return null; - } + return null; + } - public static LoggerConfiguration DummyRollingFile( - LoggerSinkConfiguration loggerSinkConfiguration, - ITextFormatter formatter, - string pathFormat, - LogEventLevel restrictedToMinimumLevel = LevelAlias.Minimum, - string outputTemplate = null, - IFormatProvider formatProvider = null) - { - return null; - } + public static LoggerConfiguration DummyRollingFile( + LoggerSinkConfiguration loggerSinkConfiguration, + ITextFormatter formatter, + string pathFormat, + LogEventLevel restrictedToMinimumLevel = LevelAlias.Minimum, + string outputTemplate = null, + IFormatProvider formatProvider = null) + { + return null; + } - public static LoggerConfiguration DummyRollingFile( - LoggerSinkConfiguration loggerSinkConfiguration, - string pathFormat, - LogEventLevel restrictedToMinimumLevel = LevelAlias.Minimum) - { - return null; - } + public static LoggerConfiguration DummyRollingFile( + LoggerSinkConfiguration loggerSinkConfiguration, + string pathFormat, + LogEventLevel restrictedToMinimumLevel = LevelAlias.Minimum) + { + return null; } } diff --git a/test/Serilog.Settings.Configuration.Tests/DynamicLevelChangeTests.cs b/test/Serilog.Settings.Configuration.Tests/DynamicLevelChangeTests.cs index 6b439f6..8df43fb 100644 --- a/test/Serilog.Settings.Configuration.Tests/DynamicLevelChangeTests.cs +++ b/test/Serilog.Settings.Configuration.Tests/DynamicLevelChangeTests.cs @@ -1,17 +1,15 @@ using Serilog.Core; using Serilog.Events; using Serilog.Settings.Configuration.Tests.Support; - -using Xunit; using Microsoft.Extensions.Configuration; using TestDummies.Console; -namespace Serilog.Settings.Configuration.Tests +namespace Serilog.Settings.Configuration.Tests; + +public class DynamicLevelChangeTests { - public class DynamicLevelChangeTests - { - const string DefaultConfig = @"{ + const string DefaultConfig = @"{ 'Serilog': { 'Using': [ 'TestDummies' ], 'MinimumLevel': { @@ -37,78 +35,77 @@ public class DynamicLevelChangeTests } }"; - readonly ReloadableConfigurationSource _configSource; + readonly ReloadableConfigurationSource _configSource; + + public DynamicLevelChangeTests() + { + _configSource = new ReloadableConfigurationSource(JsonStringConfigSource.LoadData(DefaultConfig)); + } - public DynamicLevelChangeTests() + [Fact] + public void ShouldRespectDynamicLevelChanges() + { + using (var logger = new LoggerConfiguration() + .ReadFrom + .Configuration(new ConfigurationBuilder().Add(_configSource).Build()) + .CreateLogger()) { - _configSource = new ReloadableConfigurationSource(JsonStringConfigSource.LoadData(DefaultConfig)); + DummyConsoleSink.Emitted.Clear(); + logger.Write(Some.DebugEvent()); + Assert.Empty(DummyConsoleSink.Emitted); + + DummyConsoleSink.Emitted.Clear(); + UpdateConfig(minimumLevel: LogEventLevel.Debug); + logger.Write(Some.DebugEvent()); + Assert.Empty(DummyConsoleSink.Emitted); + + DummyConsoleSink.Emitted.Clear(); + UpdateConfig(switchLevel: LogEventLevel.Debug); + logger.Write(Some.DebugEvent()); + logger.ForContext(Constants.SourceContextPropertyName, "Root.Test").Write(Some.DebugEvent()); + Assert.Single(DummyConsoleSink.Emitted); + + DummyConsoleSink.Emitted.Clear(); + UpdateConfig(overrideLevel: LogEventLevel.Debug); + logger.ForContext(Constants.SourceContextPropertyName, "Root.Test").Write(Some.DebugEvent()); + Assert.Single(DummyConsoleSink.Emitted); + + DummyConsoleSink.Emitted.Clear(); + UpdateConfig(filterExpression: "Prop = 'Val_1'"); + logger.Write(Some.DebugEvent()); + logger.ForContext("Prop", "Val_1").Write(Some.DebugEvent()); + Assert.Single(DummyConsoleSink.Emitted); + + DummyConsoleSink.Emitted.Clear(); + UpdateConfig(filterExpression: "Prop = 'Val_2'"); + logger.Write(Some.DebugEvent()); + logger.ForContext("Prop", "Val_1").Write(Some.DebugEvent()); + Assert.Empty(DummyConsoleSink.Emitted); } + } - [Fact] - public void ShouldRespectDynamicLevelChanges() + void UpdateConfig(LogEventLevel? minimumLevel = null, LogEventLevel? switchLevel = null, LogEventLevel? overrideLevel = null, string filterExpression = null) + { + if (minimumLevel.HasValue) { - using (var logger = new LoggerConfiguration() - .ReadFrom - .Configuration(new ConfigurationBuilder().Add(_configSource).Build()) - .CreateLogger()) - { - DummyConsoleSink.Emitted.Clear(); - logger.Write(Some.DebugEvent()); - Assert.Empty(DummyConsoleSink.Emitted); - - DummyConsoleSink.Emitted.Clear(); - UpdateConfig(minimumLevel: LogEventLevel.Debug); - logger.Write(Some.DebugEvent()); - Assert.Empty(DummyConsoleSink.Emitted); - - DummyConsoleSink.Emitted.Clear(); - UpdateConfig(switchLevel: LogEventLevel.Debug); - logger.Write(Some.DebugEvent()); - logger.ForContext(Constants.SourceContextPropertyName, "Root.Test").Write(Some.DebugEvent()); - Assert.Single(DummyConsoleSink.Emitted); - - DummyConsoleSink.Emitted.Clear(); - UpdateConfig(overrideLevel: LogEventLevel.Debug); - logger.ForContext(Constants.SourceContextPropertyName, "Root.Test").Write(Some.DebugEvent()); - Assert.Single(DummyConsoleSink.Emitted); - - DummyConsoleSink.Emitted.Clear(); - UpdateConfig(filterExpression: "Prop = 'Val_1'"); - logger.Write(Some.DebugEvent()); - logger.ForContext("Prop", "Val_1").Write(Some.DebugEvent()); - Assert.Single(DummyConsoleSink.Emitted); - - DummyConsoleSink.Emitted.Clear(); - UpdateConfig(filterExpression: "Prop = 'Val_2'"); - logger.Write(Some.DebugEvent()); - logger.ForContext("Prop", "Val_1").Write(Some.DebugEvent()); - Assert.Empty(DummyConsoleSink.Emitted); - } + _configSource.Set("Serilog:MinimumLevel:Default", minimumLevel.Value.ToString()); } - void UpdateConfig(LogEventLevel? minimumLevel = null, LogEventLevel? switchLevel = null, LogEventLevel? overrideLevel = null, string filterExpression = null) + if (switchLevel.HasValue) { - if (minimumLevel.HasValue) - { - _configSource.Set("Serilog:MinimumLevel:Default", minimumLevel.Value.ToString()); - } - - if (switchLevel.HasValue) - { - _configSource.Set("Serilog:LevelSwitches:$mySwitch", switchLevel.Value.ToString()); - } - - if (overrideLevel.HasValue) - { - _configSource.Set("Serilog:MinimumLevel:Override:Root.Test", overrideLevel.Value.ToString()); - } + _configSource.Set("Serilog:LevelSwitches:$mySwitch", switchLevel.Value.ToString()); + } - if (filterExpression != null) - { - _configSource.Set("Serilog:FilterSwitches:$myFilter", filterExpression); - } + if (overrideLevel.HasValue) + { + _configSource.Set("Serilog:MinimumLevel:Override:Root.Test", overrideLevel.Value.ToString()); + } - _configSource.Reload(); + if (filterExpression != null) + { + _configSource.Set("Serilog:FilterSwitches:$myFilter", filterExpression); } + + _configSource.Reload(); } } diff --git a/test/Serilog.Settings.Configuration.Tests/LoggerConfigurationExtensionsTests.cs b/test/Serilog.Settings.Configuration.Tests/LoggerConfigurationExtensionsTests.cs index f7eee44..c022aee 100644 --- a/test/Serilog.Settings.Configuration.Tests/LoggerConfigurationExtensionsTests.cs +++ b/test/Serilog.Settings.Configuration.Tests/LoggerConfigurationExtensionsTests.cs @@ -1,29 +1,27 @@ -using System; using Microsoft.Extensions.Configuration; using Serilog.Events; using Serilog.Settings.Configuration.Tests.Support; -using Xunit; -namespace Serilog.Settings.Configuration.Tests +namespace Serilog.Settings.Configuration.Tests; + +public class LoggerConfigurationExtensionsTests { - public class LoggerConfigurationExtensionsTests + [Fact] + public void ReadFromConfigurationShouldNotThrowOnEmptyConfiguration() + { + Action act = () => new LoggerConfiguration().ReadFrom.Configuration(new ConfigurationBuilder().Build()); + + // should not throw + act(); + } + + [Fact] + [Trait("BugFix", "https://github.com/serilog/serilog-settings-configuration/issues/143")] + public void ReadFromConfigurationSectionReadsFromAnArbitrarySection() { - [Fact] - public void ReadFromConfigurationShouldNotThrowOnEmptyConfiguration() - { - Action act = () => new LoggerConfiguration().ReadFrom.Configuration(new ConfigurationBuilder().Build()); - - // should not throw - act(); - } - - [Fact] - [Trait("BugFix", "https://github.com/serilog/serilog-settings-configuration/issues/143")] - public void ReadFromConfigurationSectionReadsFromAnArbitrarySection() - { - LogEvent evt = null; - - var json = @"{ + LogEvent evt = null; + + var json = @"{ ""NotSerilog"": { ""Properties"": { ""App"": ""Test"" @@ -31,28 +29,28 @@ public void ReadFromConfigurationSectionReadsFromAnArbitrarySection() } }"; - var config = new ConfigurationBuilder() - .AddJsonString(json) - .Build(); + var config = new ConfigurationBuilder() + .AddJsonString(json) + .Build(); #pragma warning disable CS0618 // Type or member is obsolete - var log = new LoggerConfiguration() - .ReadFrom.ConfigurationSection(config.GetSection("NotSerilog")) + var log = new LoggerConfiguration() + .ReadFrom.ConfigurationSection(config.GetSection("NotSerilog")) #pragma warning restore CS0618 // Type or member is obsolete - .WriteTo.Sink(new DelegatingSink(e => evt = e)) - .CreateLogger(); + .WriteTo.Sink(new DelegatingSink(e => evt = e)) + .CreateLogger(); - log.Information("Has a test property"); + log.Information("Has a test property"); - Assert.NotNull(evt); - Assert.Equal("Test", evt.Properties["App"].LiteralValue()); - } + Assert.NotNull(evt); + Assert.Equal("Test", evt.Properties["App"].LiteralValue()); + } - [Fact] - [Trait("BugFix", "https://github.com/serilog/serilog-settings-configuration/issues/143")] - public void ReadFromConfigurationSectionThrowsWhenTryingToCallConfigurationMethodWithIConfigurationParam() - { - var json = @"{ + [Fact] + [Trait("BugFix", "https://github.com/serilog/serilog-settings-configuration/issues/143")] + public void ReadFromConfigurationSectionThrowsWhenTryingToCallConfigurationMethodWithIConfigurationParam() + { + var json = @"{ ""NotSerilog"": { ""Using"": [""TestDummies""], ""WriteTo"": [{ @@ -62,28 +60,28 @@ public void ReadFromConfigurationSectionThrowsWhenTryingToCallConfigurationMetho } }"; - var config = new ConfigurationBuilder() - .AddJsonString(json) - .Build(); + var config = new ConfigurationBuilder() + .AddJsonString(json) + .Build(); - var exception = Assert.Throws(() => + var exception = Assert.Throws(() => #pragma warning disable CS0618 // Type or member is obsolete - new LoggerConfiguration() - .ReadFrom.ConfigurationSection(config.GetSection("NotSerilog")) + new LoggerConfiguration() + .ReadFrom.ConfigurationSection(config.GetSection("NotSerilog")) #pragma warning restore CS0618 // Type or member is obsolete - .CreateLogger()); + .CreateLogger()); - Assert.Equal("Trying to invoke a configuration method accepting a `IConfiguration` argument. " + - "This is not supported when only a `IConfigSection` has been provided. " + - "(method 'Serilog.LoggerConfiguration DummyWithConfiguration(Serilog.Configuration.LoggerSinkConfiguration, Microsoft.Extensions.Configuration.IConfiguration, Serilog.Events.LogEventLevel)')", - exception.Message); + Assert.Equal("Trying to invoke a configuration method accepting a `IConfiguration` argument. " + + "This is not supported when only a `IConfigSection` has been provided. " + + "(method 'Serilog.LoggerConfiguration DummyWithConfiguration(Serilog.Configuration.LoggerSinkConfiguration, Microsoft.Extensions.Configuration.IConfiguration, Serilog.Events.LogEventLevel)')", + exception.Message); - } + } - [Fact] - public void ReadFromConfigurationDoesNotThrowWhenTryingToCallConfigurationMethodWithIConfigurationParam() - { - var json = @"{ + [Fact] + public void ReadFromConfigurationDoesNotThrowWhenTryingToCallConfigurationMethodWithIConfigurationParam() + { + var json = @"{ ""NotSerilog"": { ""Using"": [""TestDummies""], ""WriteTo"": [{ @@ -93,21 +91,21 @@ public void ReadFromConfigurationDoesNotThrowWhenTryingToCallConfigurationMethod } }"; - var config = new ConfigurationBuilder() - .AddJsonString(json) - .Build(); + var config = new ConfigurationBuilder() + .AddJsonString(json) + .Build(); - _ = new LoggerConfiguration() - .ReadFrom.Configuration(config, "NotSerilog") - .CreateLogger(); + _ = new LoggerConfiguration() + .ReadFrom.Configuration(config, "NotSerilog") + .CreateLogger(); - } + } - [Fact] - [Trait("BugFix", "https://github.com/serilog/serilog-settings-configuration/issues/143")] - public void ReadFromConfigurationSectionDoesNotThrowWhenTryingToCallConfigurationMethodWithOptionalIConfigurationParam() - { - var json = @"{ + [Fact] + [Trait("BugFix", "https://github.com/serilog/serilog-settings-configuration/issues/143")] + public void ReadFromConfigurationSectionDoesNotThrowWhenTryingToCallConfigurationMethodWithOptionalIConfigurationParam() + { + var json = @"{ ""NotSerilog"": { ""Using"": [""TestDummies""], ""WriteTo"": [{ @@ -117,17 +115,16 @@ public void ReadFromConfigurationSectionDoesNotThrowWhenTryingToCallConfiguratio } }"; - var config = new ConfigurationBuilder() - .AddJsonString(json) - .Build(); + var config = new ConfigurationBuilder() + .AddJsonString(json) + .Build(); - // this should not throw because DummyWithOptionalConfiguration accepts an optional config + // this should not throw because DummyWithOptionalConfiguration accepts an optional config #pragma warning disable CS0618 // Type or member is obsolete - new LoggerConfiguration() - .ReadFrom.ConfigurationSection(config.GetSection("NotSerilog")) + new LoggerConfiguration() + .ReadFrom.ConfigurationSection(config.GetSection("NotSerilog")) #pragma warning restore CS0618 // Type or member is obsolete - .CreateLogger(); + .CreateLogger(); - } } } diff --git a/test/Serilog.Settings.Configuration.Tests/ObjectArgumentValueTests.cs b/test/Serilog.Settings.Configuration.Tests/ObjectArgumentValueTests.cs index 9772424..ee775e4 100644 --- a/test/Serilog.Settings.Configuration.Tests/ObjectArgumentValueTests.cs +++ b/test/Serilog.Settings.Configuration.Tests/ObjectArgumentValueTests.cs @@ -1,72 +1,67 @@ -using System; - -using Microsoft.Extensions.Configuration; - -using Xunit; +using Microsoft.Extensions.Configuration; // ReSharper disable UnusedMember.Local // ReSharper disable UnusedParameter.Local // ReSharper disable UnusedType.Local -namespace Serilog.Settings.Configuration.Tests +namespace Serilog.Settings.Configuration.Tests; + +public class ObjectArgumentValueTests { - public class ObjectArgumentValueTests - { - readonly IConfigurationRoot _config; + readonly IConfigurationRoot _config; - public ObjectArgumentValueTests() - { - _config = new ConfigurationBuilder() - .AddJsonFile("ObjectArgumentValueTests.json") - .Build(); - } + public ObjectArgumentValueTests() + { + _config = new ConfigurationBuilder() + .AddJsonFile("ObjectArgumentValueTests.json") + .Build(); + } - [Theory] - [InlineData("case_1", typeof(A), "new A(1, 23:59:59, http://dot.com/, \"d\")")] - [InlineData("case_2", typeof(B), "new B(2, new A(3, new D()), null)")] - [InlineData("case_3", typeof(E), "new E(\"1\", \"2\", \"3\")")] - [InlineData("case_4", typeof(F), "new F(\"paramType\", new E(1, 2, 3, 4))")] - [InlineData("case_5", typeof(G), "new G()")] - [InlineData("case_6", typeof(G), "new G(3, 4)")] - public void ShouldBindToConstructorArguments(string caseSection, Type targetType, string expectedExpression) - { - var testSection = _config.GetSection(caseSection); + [Theory] + [InlineData("case_1", typeof(A), "new A(1, 23:59:59, http://dot.com/, \"d\")")] + [InlineData("case_2", typeof(B), "new B(2, new A(3, new D()), null)")] + [InlineData("case_3", typeof(E), "new E(\"1\", \"2\", \"3\")")] + [InlineData("case_4", typeof(F), "new F(\"paramType\", new E(1, 2, 3, 4))")] + [InlineData("case_5", typeof(G), "new G()")] + [InlineData("case_6", typeof(G), "new G(3, 4)")] + public void ShouldBindToConstructorArguments(string caseSection, Type targetType, string expectedExpression) + { + var testSection = _config.GetSection(caseSection); - Assert.True(ObjectArgumentValue.TryBuildCtorExpression(testSection, targetType, new(), out var ctorExpression)); - Assert.Equal(expectedExpression, ctorExpression.ToString()); - } + Assert.True(ObjectArgumentValue.TryBuildCtorExpression(testSection, targetType, new(), out var ctorExpression)); + Assert.Equal(expectedExpression, ctorExpression.ToString()); + } - class A - { - public A(int a, TimeSpan b, Uri c, string d = "d") { } - public A(int a, C c) { } - } + class A + { + public A(int a, TimeSpan b, Uri c, string d = "d") { } + public A(int a, C c) { } + } - class B - { - public B(int b, A a, long? c = null) { } - } + class B + { + public B(int b, A a, long? c = null) { } + } - interface C { } + interface C { } - class D : C { } + class D : C { } - class E - { - public E(int a, int b, int c, int d = 4) { } - public E(int a, string b, string c) { } - public E(string a, string b, string c) { } - } + class E + { + public E(int a, int b, int c, int d = 4) { } + public E(int a, string b, string c) { } + public E(string a, string b, string c) { } + } - class F - { - public F(string type, E e) { } - } + class F + { + public F(string type, E e) { } + } - class G - { - public G() { } - public G(int a = 1, int b = 2) { } - } + class G + { + public G() { } + public G(int a = 1, int b = 2) { } } } diff --git a/test/Serilog.Settings.Configuration.Tests/Serilog.Settings.Configuration.Tests.csproj b/test/Serilog.Settings.Configuration.Tests/Serilog.Settings.Configuration.Tests.csproj index 1453c83..a08c9bb 100644 --- a/test/Serilog.Settings.Configuration.Tests/Serilog.Settings.Configuration.Tests.csproj +++ b/test/Serilog.Settings.Configuration.Tests/Serilog.Settings.Configuration.Tests.csproj @@ -28,4 +28,8 @@ + + + + diff --git a/test/Serilog.Settings.Configuration.Tests/StringArgumentValueTests.cs b/test/Serilog.Settings.Configuration.Tests/StringArgumentValueTests.cs index 642e85e..08599f1 100644 --- a/test/Serilog.Settings.Configuration.Tests/StringArgumentValueTests.cs +++ b/test/Serilog.Settings.Configuration.Tests/StringArgumentValueTests.cs @@ -1,238 +1,234 @@ -using System; -using Serilog.Core; +using Serilog.Core; using Serilog.Events; using Serilog.Formatting; using Serilog.Formatting.Json; using Serilog.Settings.Configuration.Tests.Support; -using Xunit; +namespace Serilog.Settings.Configuration.Tests; -namespace Serilog.Settings.Configuration.Tests +public class StringArgumentValueTests { - public class StringArgumentValueTests + [Fact] + public void StringValuesConvertToDefaultInstancesIfTargetIsInterface() { - [Fact] - public void StringValuesConvertToDefaultInstancesIfTargetIsInterface() - { - var stringArgumentValue = new StringArgumentValue("Serilog.Formatting.Json.JsonFormatter, Serilog"); + var stringArgumentValue = new StringArgumentValue("Serilog.Formatting.Json.JsonFormatter, Serilog"); - var result = stringArgumentValue.ConvertTo(typeof(ITextFormatter), new ResolutionContext()); + var result = stringArgumentValue.ConvertTo(typeof(ITextFormatter), new ResolutionContext()); - Assert.IsType(result); - } + Assert.IsType(result); + } - [Fact] - public void StringValuesConvertToDefaultInstancesIfTargetIsAbstractClass() - { - var stringArgumentValue = new StringArgumentValue("Serilog.Settings.Configuration.Tests.Support.ConcreteClass, Serilog.Settings.Configuration.Tests"); + [Fact] + public void StringValuesConvertToDefaultInstancesIfTargetIsAbstractClass() + { + var stringArgumentValue = new StringArgumentValue("Serilog.Settings.Configuration.Tests.Support.ConcreteClass, Serilog.Settings.Configuration.Tests"); - var result = stringArgumentValue.ConvertTo(typeof(AbstractClass), new ResolutionContext()); + var result = stringArgumentValue.ConvertTo(typeof(AbstractClass), new ResolutionContext()); - Assert.IsType(result); - } + Assert.IsType(result); + } - [Theory] - [InlineData("My.NameSpace.Class+InnerClass::Member", - "My.NameSpace.Class+InnerClass", "Member")] - [InlineData(" TrimMe.NameSpace.Class::NeedsTrimming ", - "TrimMe.NameSpace.Class", "NeedsTrimming")] - [InlineData("My.NameSpace.Class::Member", - "My.NameSpace.Class", "Member")] - [InlineData("My.NameSpace.Class::Member, MyAssembly", - "My.NameSpace.Class, MyAssembly", "Member")] - [InlineData("My.NameSpace.Class::Member, MyAssembly, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", - "My.NameSpace.Class, MyAssembly, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", "Member")] - [InlineData("Just a random string with :: in it", - null, null)] - [InlineData("Its::a::trapWithColonsAppearingTwice", - null, null)] - [InlineData("ThereIsNoMemberHere::", - null, null)] - [InlineData(null, - null, null)] - [InlineData(" ", - null, null)] - // a full-qualified type name should not be considered a static member accessor - [InlineData("My.NameSpace.Class, MyAssembly, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", - null, null)] - public void TryParseStaticMemberAccessorReturnsExpectedResults(string input, string expectedAccessorType, string expectedPropertyName) + [Theory] + [InlineData("My.NameSpace.Class+InnerClass::Member", + "My.NameSpace.Class+InnerClass", "Member")] + [InlineData(" TrimMe.NameSpace.Class::NeedsTrimming ", + "TrimMe.NameSpace.Class", "NeedsTrimming")] + [InlineData("My.NameSpace.Class::Member", + "My.NameSpace.Class", "Member")] + [InlineData("My.NameSpace.Class::Member, MyAssembly", + "My.NameSpace.Class, MyAssembly", "Member")] + [InlineData("My.NameSpace.Class::Member, MyAssembly, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", + "My.NameSpace.Class, MyAssembly, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", "Member")] + [InlineData("Just a random string with :: in it", + null, null)] + [InlineData("Its::a::trapWithColonsAppearingTwice", + null, null)] + [InlineData("ThereIsNoMemberHere::", + null, null)] + [InlineData(null, + null, null)] + [InlineData(" ", + null, null)] + // a full-qualified type name should not be considered a static member accessor + [InlineData("My.NameSpace.Class, MyAssembly, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", + null, null)] + public void TryParseStaticMemberAccessorReturnsExpectedResults(string input, string expectedAccessorType, string expectedPropertyName) + { + var actual = StringArgumentValue.TryParseStaticMemberAccessor(input, + out var actualAccessorType, + out var actualMemberName); + + if (expectedAccessorType == null) { - var actual = StringArgumentValue.TryParseStaticMemberAccessor(input, - out var actualAccessorType, - out var actualMemberName); - - if (expectedAccessorType == null) - { - Assert.False(actual, $"Should not parse {input}"); - } - else - { - Assert.True(actual, $"should successfully parse {input}"); - Assert.Equal(expectedAccessorType, actualAccessorType); - Assert.Equal(expectedPropertyName, actualMemberName); - } + Assert.False(actual, $"Should not parse {input}"); } - - [Theory] - [InlineData("Serilog.Formatting.Json.JsonFormatter", typeof(JsonFormatter))] - [InlineData("Serilog.Formatting.Json.JsonFormatter, Serilog", typeof(JsonFormatter))] - [InlineData("Serilog.ConfigurationLoggerConfigurationExtensions", typeof(ConfigurationLoggerConfigurationExtensions))] - public void FindTypeSupportsSimpleNamesForSerilogTypes(string input, Type targetType) + else { - var type = StringArgumentValue.FindType(input); - Assert.Equal(targetType, type); + Assert.True(actual, $"should successfully parse {input}"); + Assert.Equal(expectedAccessorType, actualAccessorType); + Assert.Equal(expectedPropertyName, actualMemberName); } + } - [Theory] - [InlineData("Serilog.Settings.Configuration.Tests.Support.ClassWithStaticAccessors::InterfaceProperty, Serilog.Settings.Configuration.Tests", typeof(IAmAnInterface))] - [InlineData("Serilog.Settings.Configuration.Tests.Support.ClassWithStaticAccessors::AbstractProperty, Serilog.Settings.Configuration.Tests", typeof(AnAbstractClass))] - [InlineData("Serilog.Settings.Configuration.Tests.Support.ClassWithStaticAccessors::InterfaceField, Serilog.Settings.Configuration.Tests", typeof(IAmAnInterface))] - [InlineData("Serilog.Settings.Configuration.Tests.Support.ClassWithStaticAccessors::AbstractField, Serilog.Settings.Configuration.Tests", typeof(AnAbstractClass))] - public void StaticMembersAccessorsCanBeUsedForAbstractTypes(string input, Type targetType) - { - var stringArgumentValue = new StringArgumentValue(input); + [Theory] + [InlineData("Serilog.Formatting.Json.JsonFormatter", typeof(JsonFormatter))] + [InlineData("Serilog.Formatting.Json.JsonFormatter, Serilog", typeof(JsonFormatter))] + [InlineData("Serilog.ConfigurationLoggerConfigurationExtensions", typeof(ConfigurationLoggerConfigurationExtensions))] + public void FindTypeSupportsSimpleNamesForSerilogTypes(string input, Type targetType) + { + var type = StringArgumentValue.FindType(input); + Assert.Equal(targetType, type); + } - var actual = stringArgumentValue.ConvertTo(targetType, new ResolutionContext()); + [Theory] + [InlineData("Serilog.Settings.Configuration.Tests.Support.ClassWithStaticAccessors::InterfaceProperty, Serilog.Settings.Configuration.Tests", typeof(IAmAnInterface))] + [InlineData("Serilog.Settings.Configuration.Tests.Support.ClassWithStaticAccessors::AbstractProperty, Serilog.Settings.Configuration.Tests", typeof(AnAbstractClass))] + [InlineData("Serilog.Settings.Configuration.Tests.Support.ClassWithStaticAccessors::InterfaceField, Serilog.Settings.Configuration.Tests", typeof(IAmAnInterface))] + [InlineData("Serilog.Settings.Configuration.Tests.Support.ClassWithStaticAccessors::AbstractField, Serilog.Settings.Configuration.Tests", typeof(AnAbstractClass))] + public void StaticMembersAccessorsCanBeUsedForAbstractTypes(string input, Type targetType) + { + var stringArgumentValue = new StringArgumentValue(input); - Assert.IsAssignableFrom(targetType, actual); - Assert.Equal(ConcreteImpl.Instance, actual); - } + var actual = stringArgumentValue.ConvertTo(targetType, new ResolutionContext()); - [Theory] - [InlineData("Serilog.Settings.Configuration.Tests.Support.ClassWithStaticAccessors::FuncIntParseField, Serilog.Settings.Configuration.Tests", typeof(Func))] - [InlineData("Serilog.Settings.Configuration.Tests.Support.ClassWithStaticAccessors::NamedIntParseField, Serilog.Settings.Configuration.Tests", typeof(NamedIntParse))] - [InlineData("Serilog.Settings.Configuration.Tests.Support.ClassWithStaticAccessors::FuncIntParseProperty, Serilog.Settings.Configuration.Tests", typeof(Func))] - [InlineData("Serilog.Settings.Configuration.Tests.Support.ClassWithStaticAccessors::NamedIntParseProperty, Serilog.Settings.Configuration.Tests", typeof(NamedIntParse))] - [InlineData("Serilog.Settings.Configuration.Tests.Support.ClassWithStaticAccessors::IntParseMethod, Serilog.Settings.Configuration.Tests", typeof(NamedIntParse))] - [InlineData("Serilog.Settings.Configuration.Tests.Support.ClassWithStaticAccessors::IntParseMethod, Serilog.Settings.Configuration.Tests", typeof(Func))] - public void StaticMembersAccessorsCanBeUsedForDelegateTypes(string input, Type targetType) - { - var stringArgumentValue = new StringArgumentValue(input); + Assert.IsAssignableFrom(targetType, actual); + Assert.Equal(ConcreteImpl.Instance, actual); + } - var actual = stringArgumentValue.ConvertTo(targetType, new ResolutionContext()); + [Theory] + [InlineData("Serilog.Settings.Configuration.Tests.Support.ClassWithStaticAccessors::FuncIntParseField, Serilog.Settings.Configuration.Tests", typeof(Func))] + [InlineData("Serilog.Settings.Configuration.Tests.Support.ClassWithStaticAccessors::NamedIntParseField, Serilog.Settings.Configuration.Tests", typeof(NamedIntParse))] + [InlineData("Serilog.Settings.Configuration.Tests.Support.ClassWithStaticAccessors::FuncIntParseProperty, Serilog.Settings.Configuration.Tests", typeof(Func))] + [InlineData("Serilog.Settings.Configuration.Tests.Support.ClassWithStaticAccessors::NamedIntParseProperty, Serilog.Settings.Configuration.Tests", typeof(NamedIntParse))] + [InlineData("Serilog.Settings.Configuration.Tests.Support.ClassWithStaticAccessors::IntParseMethod, Serilog.Settings.Configuration.Tests", typeof(NamedIntParse))] + [InlineData("Serilog.Settings.Configuration.Tests.Support.ClassWithStaticAccessors::IntParseMethod, Serilog.Settings.Configuration.Tests", typeof(Func))] + public void StaticMembersAccessorsCanBeUsedForDelegateTypes(string input, Type targetType) + { + var stringArgumentValue = new StringArgumentValue(input); - Assert.IsAssignableFrom(targetType, actual); - var parser = (Delegate)actual; - Assert.Equal(100, parser.DynamicInvoke("100")); - } + var actual = stringArgumentValue.ConvertTo(targetType, new ResolutionContext()); - [Theory] - [InlineData("Serilog.Settings.Configuration.Tests.Support.ClassWithStaticAccessors::ConcreteClassProperty, Serilog.Settings.Configuration.Tests", typeof(AConcreteClass))] - [InlineData("Serilog.Settings.Configuration.Tests.Support.ClassWithStaticAccessors::ConcreteClassField, Serilog.Settings.Configuration.Tests", typeof(AConcreteClass))] - public void StaticMembersAccessorsCanBeUsedForConcreteReferenceTypes(string input, Type targetType) - { - var stringArgumentValue = new StringArgumentValue(input); + Assert.IsAssignableFrom(targetType, actual); + var parser = (Delegate)actual; + Assert.Equal(100, parser.DynamicInvoke("100")); + } - var actual = stringArgumentValue.ConvertTo(targetType, new ResolutionContext()); + [Theory] + [InlineData("Serilog.Settings.Configuration.Tests.Support.ClassWithStaticAccessors::ConcreteClassProperty, Serilog.Settings.Configuration.Tests", typeof(AConcreteClass))] + [InlineData("Serilog.Settings.Configuration.Tests.Support.ClassWithStaticAccessors::ConcreteClassField, Serilog.Settings.Configuration.Tests", typeof(AConcreteClass))] + public void StaticMembersAccessorsCanBeUsedForConcreteReferenceTypes(string input, Type targetType) + { + var stringArgumentValue = new StringArgumentValue(input); - Assert.IsAssignableFrom(targetType, actual); - Assert.Equal(ConcreteImplOfConcreteClass.Instance, actual); - } + var actual = stringArgumentValue.ConvertTo(targetType, new ResolutionContext()); - [Theory] - [InlineData("Serilog.Settings.Configuration.Tests.Support.ClassWithStaticAccessors::IntProperty, Serilog.Settings.Configuration.Tests", typeof(int), 42)] - [InlineData("Serilog.Settings.Configuration.Tests.Support.ClassWithStaticAccessors::StringProperty, Serilog.Settings.Configuration.Tests", typeof(string), - "Serilog.Settings.Configuration.Tests.Support.ClassWithStaticAccessors::StringProperty, Serilog.Settings.Configuration.Tests")] - public void StaticMembersAccessorsCanBeUsedForBuiltInTypes(string input, Type targetType, object expected) - { - var stringArgumentValue = new StringArgumentValue(input); + Assert.IsAssignableFrom(targetType, actual); + Assert.Equal(ConcreteImplOfConcreteClass.Instance, actual); + } - var actual = stringArgumentValue.ConvertTo(targetType, new ResolutionContext()); + [Theory] + [InlineData("Serilog.Settings.Configuration.Tests.Support.ClassWithStaticAccessors::IntProperty, Serilog.Settings.Configuration.Tests", typeof(int), 42)] + [InlineData("Serilog.Settings.Configuration.Tests.Support.ClassWithStaticAccessors::StringProperty, Serilog.Settings.Configuration.Tests", typeof(string), + "Serilog.Settings.Configuration.Tests.Support.ClassWithStaticAccessors::StringProperty, Serilog.Settings.Configuration.Tests")] + public void StaticMembersAccessorsCanBeUsedForBuiltInTypes(string input, Type targetType, object expected) + { + var stringArgumentValue = new StringArgumentValue(input); - Assert.Equal(expected, actual); - } + var actual = stringArgumentValue.ConvertTo(targetType, new ResolutionContext()); - [Theory] - // unknown type - [InlineData("Namespace.ThisIsNotAKnownType::InterfaceProperty, Serilog.Settings.Configuration.Tests", typeof(IAmAnInterface))] - // good type name, but wrong namespace - [InlineData("Random.Namespace.ClassWithStaticAccessors::InterfaceProperty, Serilog.Settings.Configuration.Tests", typeof(IAmAnInterface))] - // good full type name, but missing or wrong assembly - [InlineData("Serilog.Settings.Configuration.Tests.Support.ClassWithStaticAccessors::InterfaceProperty", typeof(IAmAnInterface))] - public void StaticAccessorOnUnknownTypeThrowsTypeLoadException(string input, Type targetType) - { - var stringArgumentValue = new StringArgumentValue($"{input}"); - Assert.Throws(() => - stringArgumentValue.ConvertTo(targetType, new ResolutionContext()) - ); - } + Assert.Equal(expected, actual); + } - [Theory] - // unknown member - [InlineData("Serilog.Settings.Configuration.Tests.Support.ClassWithStaticAccessors::UnknownMember, Serilog.Settings.Configuration.Tests", typeof(IAmAnInterface))] - // static property exists but it's private - [InlineData("Serilog.Settings.Configuration.Tests.Support.ClassWithStaticAccessors::PrivateInterfaceProperty, Serilog.Settings.Configuration.Tests", typeof(IAmAnInterface))] - // static field exists but it's private - [InlineData("Serilog.Settings.Configuration.Tests.Support.ClassWithStaticAccessors::PrivateInterfaceField, Serilog.Settings.Configuration.Tests", typeof(IAmAnInterface))] - // public property exists but it's not static - [InlineData("Serilog.Settings.Configuration.Tests.Support.ClassWithStaticAccessors::InstanceInterfaceProperty, Serilog.Settings.Configuration.Tests", typeof(IAmAnInterface))] - // public field exists but it's not static - [InlineData("Serilog.Settings.Configuration.Tests.Support.ClassWithStaticAccessors::InstanceInterfaceField, Serilog.Settings.Configuration.Tests", typeof(IAmAnInterface))] - public void StaticAccessorWithInvalidMemberThrowsInvalidOperationException(string input, Type targetType) - { - var stringArgumentValue = new StringArgumentValue($"{input}"); - var exception = Assert.Throws(() => - stringArgumentValue.ConvertTo(targetType, new ResolutionContext()) - ); + [Theory] + // unknown type + [InlineData("Namespace.ThisIsNotAKnownType::InterfaceProperty, Serilog.Settings.Configuration.Tests", typeof(IAmAnInterface))] + // good type name, but wrong namespace + [InlineData("Random.Namespace.ClassWithStaticAccessors::InterfaceProperty, Serilog.Settings.Configuration.Tests", typeof(IAmAnInterface))] + // good full type name, but missing or wrong assembly + [InlineData("Serilog.Settings.Configuration.Tests.Support.ClassWithStaticAccessors::InterfaceProperty", typeof(IAmAnInterface))] + public void StaticAccessorOnUnknownTypeThrowsTypeLoadException(string input, Type targetType) + { + var stringArgumentValue = new StringArgumentValue($"{input}"); + Assert.Throws(() => + stringArgumentValue.ConvertTo(targetType, new ResolutionContext()) + ); + } - Assert.Contains("Could not find a public static property or field ", exception.Message); - Assert.Contains("on type `Serilog.Settings.Configuration.Tests.Support.ClassWithStaticAccessors, Serilog.Settings.Configuration.Tests`", exception.Message); - } + [Theory] + // unknown member + [InlineData("Serilog.Settings.Configuration.Tests.Support.ClassWithStaticAccessors::UnknownMember, Serilog.Settings.Configuration.Tests", typeof(IAmAnInterface))] + // static property exists but it's private + [InlineData("Serilog.Settings.Configuration.Tests.Support.ClassWithStaticAccessors::PrivateInterfaceProperty, Serilog.Settings.Configuration.Tests", typeof(IAmAnInterface))] + // static field exists but it's private + [InlineData("Serilog.Settings.Configuration.Tests.Support.ClassWithStaticAccessors::PrivateInterfaceField, Serilog.Settings.Configuration.Tests", typeof(IAmAnInterface))] + // public property exists but it's not static + [InlineData("Serilog.Settings.Configuration.Tests.Support.ClassWithStaticAccessors::InstanceInterfaceProperty, Serilog.Settings.Configuration.Tests", typeof(IAmAnInterface))] + // public field exists but it's not static + [InlineData("Serilog.Settings.Configuration.Tests.Support.ClassWithStaticAccessors::InstanceInterfaceField, Serilog.Settings.Configuration.Tests", typeof(IAmAnInterface))] + public void StaticAccessorWithInvalidMemberThrowsInvalidOperationException(string input, Type targetType) + { + var stringArgumentValue = new StringArgumentValue($"{input}"); + var exception = Assert.Throws(() => + stringArgumentValue.ConvertTo(targetType, new ResolutionContext()) + ); - [Fact] - public void LevelSwitchesCanBeLookedUpByName() - { - var @switch = new LoggingLevelSwitch(LogEventLevel.Verbose); - var switchName = "$theSwitch"; - var resolutionContext = new ResolutionContext(); - resolutionContext.AddLevelSwitch(switchName, @switch); + Assert.Contains("Could not find a public static property or field ", exception.Message); + Assert.Contains("on type `Serilog.Settings.Configuration.Tests.Support.ClassWithStaticAccessors, Serilog.Settings.Configuration.Tests`", exception.Message); + } - var stringArgumentValue = new StringArgumentValue(switchName); + [Fact] + public void LevelSwitchesCanBeLookedUpByName() + { + var @switch = new LoggingLevelSwitch(LogEventLevel.Verbose); + var switchName = "$theSwitch"; + var resolutionContext = new ResolutionContext(); + resolutionContext.AddLevelSwitch(switchName, @switch); - var resolvedSwitch = stringArgumentValue.ConvertTo(typeof(LoggingLevelSwitch), resolutionContext); + var stringArgumentValue = new StringArgumentValue(switchName); - Assert.IsType(resolvedSwitch); - Assert.Same(@switch, resolvedSwitch); - } + var resolvedSwitch = stringArgumentValue.ConvertTo(typeof(LoggingLevelSwitch), resolutionContext); + Assert.IsType(resolvedSwitch); + Assert.Same(@switch, resolvedSwitch); + } - [Fact] - public void ReferencingUndeclaredLevelSwitchThrows() - { - var resolutionContext = new ResolutionContext(); - resolutionContext.AddLevelSwitch("$anotherSwitch", new LoggingLevelSwitch(LogEventLevel.Verbose)); - var stringArgumentValue = new StringArgumentValue("$mySwitch"); + [Fact] + public void ReferencingUndeclaredLevelSwitchThrows() + { + var resolutionContext = new ResolutionContext(); + resolutionContext.AddLevelSwitch("$anotherSwitch", new LoggingLevelSwitch(LogEventLevel.Verbose)); - var ex = Assert.Throws(() => - stringArgumentValue.ConvertTo(typeof(LoggingLevelSwitch), resolutionContext) - ); + var stringArgumentValue = new StringArgumentValue("$mySwitch"); - Assert.Contains("$mySwitch", ex.Message); - Assert.Contains("\"LevelSwitches\":{\"$mySwitch\":", ex.Message); - } + var ex = Assert.Throws(() => + stringArgumentValue.ConvertTo(typeof(LoggingLevelSwitch), resolutionContext) + ); - [Fact] - public void StringValuesConvertToTypeFromShortTypeName() - { - var shortTypeName = "System.Version"; - var stringArgumentValue = new StringArgumentValue(shortTypeName); + Assert.Contains("$mySwitch", ex.Message); + Assert.Contains("\"LevelSwitches\":{\"$mySwitch\":", ex.Message); + } - var actual = (Type)stringArgumentValue.ConvertTo(typeof(Type), new ResolutionContext()); + [Fact] + public void StringValuesConvertToTypeFromShortTypeName() + { + var shortTypeName = "System.Version"; + var stringArgumentValue = new StringArgumentValue(shortTypeName); - Assert.Equal(typeof(Version), actual); - } + var actual = (Type)stringArgumentValue.ConvertTo(typeof(Type), new ResolutionContext()); - [Fact] - public void StringValuesConvertToTypeFromAssemblyQualifiedName() - { - var assemblyQualifiedName = typeof(Version).AssemblyQualifiedName; - var stringArgumentValue = new StringArgumentValue(assemblyQualifiedName); + Assert.Equal(typeof(Version), actual); + } - var actual = (Type)stringArgumentValue.ConvertTo(typeof(Type), new ResolutionContext()); + [Fact] + public void StringValuesConvertToTypeFromAssemblyQualifiedName() + { + var assemblyQualifiedName = typeof(Version).AssemblyQualifiedName; + var stringArgumentValue = new StringArgumentValue(assemblyQualifiedName); - Assert.Equal(typeof(Version), actual); - } + var actual = (Type)stringArgumentValue.ConvertTo(typeof(Type), new ResolutionContext()); + + Assert.Equal(typeof(Version), actual); } } diff --git a/test/Serilog.Settings.Configuration.Tests/Support/AbstractClass.cs b/test/Serilog.Settings.Configuration.Tests/Support/AbstractClass.cs index a894668..695f02e 100644 --- a/test/Serilog.Settings.Configuration.Tests/Support/AbstractClass.cs +++ b/test/Serilog.Settings.Configuration.Tests/Support/AbstractClass.cs @@ -1,6 +1,5 @@ -namespace Serilog.Settings.Configuration.Tests.Support -{ - public abstract class AbstractClass { } +namespace Serilog.Settings.Configuration.Tests.Support; - public class ConcreteClass : AbstractClass { } -} +public abstract class AbstractClass { } + +public class ConcreteClass : AbstractClass { } diff --git a/test/Serilog.Settings.Configuration.Tests/Support/ConfigurationBuilderExtensions.cs b/test/Serilog.Settings.Configuration.Tests/Support/ConfigurationBuilderExtensions.cs index 212cd0d..d63b3c7 100644 --- a/test/Serilog.Settings.Configuration.Tests/Support/ConfigurationBuilderExtensions.cs +++ b/test/Serilog.Settings.Configuration.Tests/Support/ConfigurationBuilderExtensions.cs @@ -1,12 +1,11 @@ using Microsoft.Extensions.Configuration; -namespace Serilog.Settings.Configuration.Tests.Support +namespace Serilog.Settings.Configuration.Tests.Support; + +public static class ConfigurationBuilderExtensions { - public static class ConfigurationBuilderExtensions + public static IConfigurationBuilder AddJsonString(this IConfigurationBuilder builder, string json) { - public static IConfigurationBuilder AddJsonString(this IConfigurationBuilder builder, string json) - { - return builder.Add(new JsonStringConfigSource(json)); - } + return builder.Add(new JsonStringConfigSource(json)); } -} \ No newline at end of file +} diff --git a/test/Serilog.Settings.Configuration.Tests/Support/ConfigurationReaderTestHelpers.cs b/test/Serilog.Settings.Configuration.Tests/Support/ConfigurationReaderTestHelpers.cs index d1fa618..4c78381 100644 --- a/test/Serilog.Settings.Configuration.Tests/Support/ConfigurationReaderTestHelpers.cs +++ b/test/Serilog.Settings.Configuration.Tests/Support/ConfigurationReaderTestHelpers.cs @@ -1,21 +1,17 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Configuration; using Serilog.Events; -using Xunit; -namespace Serilog.Settings.Configuration.Tests.Support +namespace Serilog.Settings.Configuration.Tests.Support; + +static class ConfigurationReaderTestHelpers { - static class ConfigurationReaderTestHelpers - { - public const string minimumLevelFlatTemplate = @" + public const string minimumLevelFlatTemplate = @" {{ 'Serilog': {{ 'MinimumLevel': '{0}' }} }}"; - public const string minimumLevelObjectTemplate = @" + public const string minimumLevelObjectTemplate = @" {{ 'Serilog': {{ 'MinimumLevel': {{ @@ -23,43 +19,42 @@ static class ConfigurationReaderTestHelpers }} }} }}"; - public const string minimumLevelFlatKey = "Serilog:MinimumLevel"; - public const string minimumLevelObjectKey = "Serilog:MinimumLevel:Default"; + public const string minimumLevelFlatKey = "Serilog:MinimumLevel"; + public const string minimumLevelObjectKey = "Serilog:MinimumLevel:Default"; - public static void AssertLogEventLevels(LoggerConfiguration loggerConfig, LogEventLevel expectedMinimumLevel) - { - var logger = loggerConfig.CreateLogger(); + public static void AssertLogEventLevels(LoggerConfiguration loggerConfig, LogEventLevel expectedMinimumLevel) + { + var logger = loggerConfig.CreateLogger(); - var logEventValues = Enum.GetValues(typeof(LogEventLevel)).Cast(); + var logEventValues = Enum.GetValues(typeof(LogEventLevel)).Cast(); - foreach (var logEvent in logEventValues) + foreach (var logEvent in logEventValues) + { + if (logEvent < expectedMinimumLevel) { - if (logEvent < expectedMinimumLevel) - { - Assert.False(logger.IsEnabled(logEvent), - $"The log level {logEvent} should be disabled as it's lower priority than the minimum level of {expectedMinimumLevel}."); - } - else - { - Assert.True(logger.IsEnabled(logEvent), - $"The log level {logEvent} should be enabled as it's {(logEvent == expectedMinimumLevel ? "the same" : "higher")} priority {(logEvent == expectedMinimumLevel ? "as" : "than")} the minimum level of {expectedMinimumLevel}."); - } + Assert.False(logger.IsEnabled(logEvent), + $"The log level {logEvent} should be disabled as it's lower priority than the minimum level of {expectedMinimumLevel}."); + } + else + { + Assert.True(logger.IsEnabled(logEvent), + $"The log level {logEvent} should be enabled as it's {(logEvent == expectedMinimumLevel ? "the same" : "higher")} priority {(logEvent == expectedMinimumLevel ? "as" : "than")} the minimum level of {expectedMinimumLevel}."); } } + } - // the naming is only to show priority as providers - public static IConfigurationRoot GetConfigRoot( - string appsettingsJsonLevel = null, - string appsettingsDevelopmentJsonLevel = null, - Dictionary envVariables = null) - { - var configBuilder = new ConfigurationBuilder(); + // the naming is only to show priority as providers + public static IConfigurationRoot GetConfigRoot( + string appsettingsJsonLevel = null, + string appsettingsDevelopmentJsonLevel = null, + Dictionary envVariables = null) + { + var configBuilder = new ConfigurationBuilder(); - configBuilder.AddJsonString(appsettingsJsonLevel ?? "{}"); - configBuilder.AddJsonString(appsettingsDevelopmentJsonLevel ?? "{}"); - configBuilder.Add(new ReloadableConfigurationSource(envVariables ?? new Dictionary())); + configBuilder.AddJsonString(appsettingsJsonLevel ?? "{}"); + configBuilder.AddJsonString(appsettingsDevelopmentJsonLevel ?? "{}"); + configBuilder.Add(new ReloadableConfigurationSource(envVariables ?? new Dictionary())); - return configBuilder.Build(); - } + return configBuilder.Build(); } } diff --git a/test/Serilog.Settings.Configuration.Tests/Support/CustomConsoleTheme.cs b/test/Serilog.Settings.Configuration.Tests/Support/CustomConsoleTheme.cs index 0e3030a..79050ce 100644 --- a/test/Serilog.Settings.Configuration.Tests/Support/CustomConsoleTheme.cs +++ b/test/Serilog.Settings.Configuration.Tests/Support/CustomConsoleTheme.cs @@ -1,8 +1,7 @@ using TestDummies.Console.Themes; -namespace Serilog.Settings.Configuration.Tests.Support +namespace Serilog.Settings.Configuration.Tests.Support; + +class CustomConsoleTheme : ConsoleTheme { - class CustomConsoleTheme : ConsoleTheme - { - } } diff --git a/test/Serilog.Settings.Configuration.Tests/Support/DelegatingSink.cs b/test/Serilog.Settings.Configuration.Tests/Support/DelegatingSink.cs index 07a848b..60096c0 100644 --- a/test/Serilog.Settings.Configuration.Tests/Support/DelegatingSink.cs +++ b/test/Serilog.Settings.Configuration.Tests/Support/DelegatingSink.cs @@ -1,33 +1,31 @@ -using System; -using Serilog.Core; +using Serilog.Core; using Serilog.Events; -namespace Serilog.Settings.Configuration.Tests.Support +namespace Serilog.Settings.Configuration.Tests.Support; + +public class DelegatingSink : ILogEventSink { - public class DelegatingSink : ILogEventSink - { - readonly Action _write; + readonly Action _write; - public DelegatingSink(Action write) - { - _write = write ?? throw new ArgumentNullException(nameof(write)); - } + public DelegatingSink(Action write) + { + _write = write ?? throw new ArgumentNullException(nameof(write)); + } - public void Emit(LogEvent logEvent) - { - _write(logEvent); - } + public void Emit(LogEvent logEvent) + { + _write(logEvent); + } - public static LogEvent GetLogEvent(Action writeAction) - { - LogEvent result = null; - var l = new LoggerConfiguration() - .MinimumLevel.Verbose() - .WriteTo.Sink(new DelegatingSink(le => result = le)) - .CreateLogger(); + public static LogEvent GetLogEvent(Action writeAction) + { + LogEvent result = null; + var l = new LoggerConfiguration() + .MinimumLevel.Verbose() + .WriteTo.Sink(new DelegatingSink(le => result = le)) + .CreateLogger(); - writeAction(l); - return result; - } + writeAction(l); + return result; } } diff --git a/test/Serilog.Settings.Configuration.Tests/Support/Extensions.cs b/test/Serilog.Settings.Configuration.Tests/Support/Extensions.cs index 1ea1f47..9353653 100644 --- a/test/Serilog.Settings.Configuration.Tests/Support/Extensions.cs +++ b/test/Serilog.Settings.Configuration.Tests/Support/Extensions.cs @@ -1,20 +1,19 @@ using Serilog.Events; -namespace Serilog.Settings.Configuration.Tests.Support +namespace Serilog.Settings.Configuration.Tests.Support; + +public static class Extensions { - public static class Extensions + public static object LiteralValue(this LogEventPropertyValue @this) { - public static object LiteralValue(this LogEventPropertyValue @this) - { - return ((ScalarValue)@this).Value; - } - - public static string ToValidJson(this string str) - { - str = str.Replace('\'', '"'); - return str; - } + return ((ScalarValue)@this).Value; + } - public static string Format(this string template, params object[] paramObjects) => string.Format(template, paramObjects); + public static string ToValidJson(this string str) + { + str = str.Replace('\'', '"'); + return str; } + + public static string Format(this string template, params object[] paramObjects) => string.Format(template, paramObjects); } diff --git a/test/Serilog.Settings.Configuration.Tests/Support/JsonStringConfigSource.cs b/test/Serilog.Settings.Configuration.Tests/Support/JsonStringConfigSource.cs index 1175ee4..4166708 100644 --- a/test/Serilog.Settings.Configuration.Tests/Support/JsonStringConfigSource.cs +++ b/test/Serilog.Settings.Configuration.Tests/Support/JsonStringConfigSource.cs @@ -1,63 +1,59 @@ -using System.Collections.Generic; -using System.IO; - -using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration.Json; -namespace Serilog.Settings.Configuration.Tests.Support +namespace Serilog.Settings.Configuration.Tests.Support; + +class JsonStringConfigSource : IConfigurationSource { - class JsonStringConfigSource : IConfigurationSource + readonly string _json; + + public JsonStringConfigSource(string json) + { + _json = json; + } + + public IConfigurationProvider Build(IConfigurationBuilder builder) + { + return new JsonStringConfigProvider(_json); + } + + public static IConfigurationSection LoadSection(string json, string section) + { + return new ConfigurationBuilder().Add(new JsonStringConfigSource(json)).Build().GetSection(section); + } + + public static IDictionary LoadData(string json) + { + var provider = new JsonStringConfigProvider(json); + provider.Load(); + return provider.Data; + } + + class JsonStringConfigProvider : JsonConfigurationProvider { readonly string _json; - public JsonStringConfigSource(string json) + public JsonStringConfigProvider(string json) : base(new JsonConfigurationSource { Optional = true }) { _json = json; } - public IConfigurationProvider Build(IConfigurationBuilder builder) - { - return new JsonStringConfigProvider(_json); - } + public new IDictionary Data => base.Data; - public static IConfigurationSection LoadSection(string json, string section) + public override void Load() { - return new ConfigurationBuilder().Add(new JsonStringConfigSource(json)).Build().GetSection(section); + Load(StringToStream(_json.ToValidJson())); } - public static IDictionary LoadData(string json) + static Stream StringToStream(string str) { - var provider = new JsonStringConfigProvider(json); - provider.Load(); - return provider.Data; - } + var memStream = new MemoryStream(); + var textWriter = new StreamWriter(memStream); + textWriter.Write(str); + textWriter.Flush(); + memStream.Seek(0, SeekOrigin.Begin); - class JsonStringConfigProvider : JsonConfigurationProvider - { - readonly string _json; - - public JsonStringConfigProvider(string json) : base(new JsonConfigurationSource { Optional = true }) - { - _json = json; - } - - public new IDictionary Data => base.Data; - - public override void Load() - { - Load(StringToStream(_json.ToValidJson())); - } - - static Stream StringToStream(string str) - { - var memStream = new MemoryStream(); - var textWriter = new StreamWriter(memStream); - textWriter.Write(str); - textWriter.Flush(); - memStream.Seek(0, SeekOrigin.Begin); - - return memStream; - } + return memStream; } } } diff --git a/test/Serilog.Settings.Configuration.Tests/Support/ReloadableConfigurationSource.cs b/test/Serilog.Settings.Configuration.Tests/Support/ReloadableConfigurationSource.cs index 8f90b34..22f2cb0 100644 --- a/test/Serilog.Settings.Configuration.Tests/Support/ReloadableConfigurationSource.cs +++ b/test/Serilog.Settings.Configuration.Tests/Support/ReloadableConfigurationSource.cs @@ -1,37 +1,35 @@ -using System.Collections.Generic; -using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Configuration; -namespace Serilog.Settings.Configuration.Tests.Support +namespace Serilog.Settings.Configuration.Tests.Support; + +class ReloadableConfigurationSource : IConfigurationSource { - class ReloadableConfigurationSource : IConfigurationSource + readonly ReloadableConfigurationProvider _configProvider; + readonly IDictionary _source; + + public ReloadableConfigurationSource(IDictionary source) { - readonly ReloadableConfigurationProvider _configProvider; - readonly IDictionary _source; + _source = source; + _configProvider = new ReloadableConfigurationProvider(source); + } - public ReloadableConfigurationSource(IDictionary source) - { - _source = source; - _configProvider = new ReloadableConfigurationProvider(source); - } + public IConfigurationProvider Build(IConfigurationBuilder builder) => _configProvider; - public IConfigurationProvider Build(IConfigurationBuilder builder) => _configProvider; + public void Reload() => _configProvider.Reload(); - public void Reload() => _configProvider.Reload(); + public void Set(string key, string value) => _source[key] = value; - public void Set(string key, string value) => _source[key] = value; + class ReloadableConfigurationProvider : ConfigurationProvider + { + readonly IDictionary _source; - class ReloadableConfigurationProvider : ConfigurationProvider + public ReloadableConfigurationProvider(IDictionary source) { - readonly IDictionary _source; - - public ReloadableConfigurationProvider(IDictionary source) - { - _source = source; - } + _source = source; + } - public override void Load() => Data = _source; + public override void Load() => Data = _source; - public void Reload() => OnReload(); - } + public void Reload() => OnReload(); } } diff --git a/test/Serilog.Settings.Configuration.Tests/Support/Some.cs b/test/Serilog.Settings.Configuration.Tests/Support/Some.cs index 9131b6d..226d749 100644 --- a/test/Serilog.Settings.Configuration.Tests/Support/Some.cs +++ b/test/Serilog.Settings.Configuration.Tests/Support/Some.cs @@ -1,101 +1,95 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Threading; -using Serilog.Core; +using Serilog.Core; using Serilog.Events; using Serilog.Parsing; -namespace Serilog.Settings.Configuration.Tests.Support +namespace Serilog.Settings.Configuration.Tests.Support; + +static class Some { - static class Some - { - static int Counter; - - public static int Int() - { - return Interlocked.Increment(ref Counter); - } - - public static decimal Decimal() - { - return Int() + 0.123m; - } - - public static string String(string tag = null) - { - return (tag ?? "") + "__" + Int(); - } - - public static TimeSpan TimeSpan() - { - return System.TimeSpan.FromMinutes(Int()); - } - - public static DateTime Instant() - { - return new DateTime(2012, 10, 28) + TimeSpan(); - } - - public static DateTimeOffset OffsetInstant() - { - return new DateTimeOffset(Instant()); - } - - public static LogEvent LogEvent(string sourceContext, DateTimeOffset? timestamp = null, LogEventLevel level = LogEventLevel.Information) - { - return new LogEvent(timestamp ?? OffsetInstant(), level, - null, MessageTemplate(), - new List { new LogEventProperty(Constants.SourceContextPropertyName, new ScalarValue(sourceContext)) }); - } - - public static LogEvent LogEvent(DateTimeOffset? timestamp = null, LogEventLevel level = LogEventLevel.Information) - { - return new LogEvent(timestamp ?? OffsetInstant(), level, - null, MessageTemplate(), Enumerable.Empty()); - } - - public static LogEvent InformationEvent(DateTimeOffset? timestamp = null) - { - return LogEvent(timestamp, LogEventLevel.Information); - } - - public static LogEvent DebugEvent(DateTimeOffset? timestamp = null) - { - return LogEvent(timestamp, LogEventLevel.Debug); - } - - public static LogEvent WarningEvent(DateTimeOffset? timestamp = null) - { - return LogEvent(timestamp, LogEventLevel.Warning); - } - - public static LogEventProperty LogEventProperty() - { - return new LogEventProperty(String(), new ScalarValue(Int())); - } - - public static string NonexistentTempFilePath() - { - return Path.Combine(Path.GetTempPath(), Guid.NewGuid() + ".txt"); - } - - public static string TempFilePath() - { - return Path.GetTempFileName(); - } - - public static string TempFolderPath() - { - var dir = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString()); - Directory.CreateDirectory(dir); - return dir; - } - - public static MessageTemplate MessageTemplate() - { - return new MessageTemplateParser().Parse(String()); - } + static int Counter; + + public static int Int() + { + return Interlocked.Increment(ref Counter); + } + + public static decimal Decimal() + { + return Int() + 0.123m; + } + + public static string String(string tag = null) + { + return (tag ?? "") + "__" + Int(); + } + + public static TimeSpan TimeSpan() + { + return System.TimeSpan.FromMinutes(Int()); + } + + public static DateTime Instant() + { + return new DateTime(2012, 10, 28) + TimeSpan(); + } + + public static DateTimeOffset OffsetInstant() + { + return new DateTimeOffset(Instant()); + } + + public static LogEvent LogEvent(string sourceContext, DateTimeOffset? timestamp = null, LogEventLevel level = LogEventLevel.Information) + { + return new LogEvent(timestamp ?? OffsetInstant(), level, + null, MessageTemplate(), + new List { new LogEventProperty(Constants.SourceContextPropertyName, new ScalarValue(sourceContext)) }); + } + + public static LogEvent LogEvent(DateTimeOffset? timestamp = null, LogEventLevel level = LogEventLevel.Information) + { + return new LogEvent(timestamp ?? OffsetInstant(), level, + null, MessageTemplate(), Enumerable.Empty()); + } + + public static LogEvent InformationEvent(DateTimeOffset? timestamp = null) + { + return LogEvent(timestamp, LogEventLevel.Information); + } + + public static LogEvent DebugEvent(DateTimeOffset? timestamp = null) + { + return LogEvent(timestamp, LogEventLevel.Debug); + } + + public static LogEvent WarningEvent(DateTimeOffset? timestamp = null) + { + return LogEvent(timestamp, LogEventLevel.Warning); + } + + public static LogEventProperty LogEventProperty() + { + return new LogEventProperty(String(), new ScalarValue(Int())); + } + + public static string NonexistentTempFilePath() + { + return Path.Combine(Path.GetTempPath(), Guid.NewGuid() + ".txt"); + } + + public static string TempFilePath() + { + return Path.GetTempFileName(); + } + + public static string TempFolderPath() + { + var dir = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString()); + Directory.CreateDirectory(dir); + return dir; + } + + public static MessageTemplate MessageTemplate() + { + return new MessageTemplateParser().Parse(String()); } } diff --git a/test/Serilog.Settings.Configuration.Tests/Support/StaticAccessorClasses.cs b/test/Serilog.Settings.Configuration.Tests/Support/StaticAccessorClasses.cs index 7db6f99..babd2d6 100644 --- a/test/Serilog.Settings.Configuration.Tests/Support/StaticAccessorClasses.cs +++ b/test/Serilog.Settings.Configuration.Tests/Support/StaticAccessorClasses.cs @@ -1,62 +1,59 @@ -using System; +namespace Serilog.Settings.Configuration.Tests.Support; -namespace Serilog.Settings.Configuration.Tests.Support +public delegate int NamedIntParse(string value); + +public interface IAmAnInterface { - public delegate int NamedIntParse(string value); +} - public interface IAmAnInterface - { - } +public abstract class AnAbstractClass +{ +} - public abstract class AnAbstractClass +class ConcreteImpl : AnAbstractClass, IAmAnInterface +{ + private ConcreteImpl() { } - class ConcreteImpl : AnAbstractClass, IAmAnInterface - { - private ConcreteImpl() - { - } - - public static ConcreteImpl Instance { get; } = new ConcreteImpl(); - } + public static ConcreteImpl Instance { get; } = new ConcreteImpl(); +} - public class AConcreteClass - { - } +public class AConcreteClass +{ +} - class ConcreteImplOfConcreteClass : AConcreteClass - { - public static ConcreteImplOfConcreteClass Instance { get; } = new ConcreteImplOfConcreteClass(); - } +class ConcreteImplOfConcreteClass : AConcreteClass +{ + public static ConcreteImplOfConcreteClass Instance { get; } = new ConcreteImplOfConcreteClass(); +} - public class ClassWithStaticAccessors - { - public static IAmAnInterface InterfaceProperty => ConcreteImpl.Instance; - public static AnAbstractClass AbstractProperty => ConcreteImpl.Instance; - public static AConcreteClass ConcreteClassProperty => ConcreteImplOfConcreteClass.Instance; - public static int IntProperty => 42; - public static string StringProperty => "don't see me"; +public class ClassWithStaticAccessors +{ + public static IAmAnInterface InterfaceProperty => ConcreteImpl.Instance; + public static AnAbstractClass AbstractProperty => ConcreteImpl.Instance; + public static AConcreteClass ConcreteClassProperty => ConcreteImplOfConcreteClass.Instance; + public static int IntProperty => 42; + public static string StringProperty => "don't see me"; - public static IAmAnInterface InterfaceField = ConcreteImpl.Instance; - public static AnAbstractClass AbstractField = ConcreteImpl.Instance; - public static AConcreteClass ConcreteClassField = ConcreteImplOfConcreteClass.Instance; + public static IAmAnInterface InterfaceField = ConcreteImpl.Instance; + public static AnAbstractClass AbstractField = ConcreteImpl.Instance; + public static AConcreteClass ConcreteClassField = ConcreteImplOfConcreteClass.Instance; - // ReSharper disable once UnusedMember.Local - private static IAmAnInterface PrivateInterfaceProperty => ConcreteImpl.Instance; + // ReSharper disable once UnusedMember.Local + private static IAmAnInterface PrivateInterfaceProperty => ConcreteImpl.Instance; #pragma warning disable 169 - private static IAmAnInterface PrivateInterfaceField = ConcreteImpl.Instance; + private static IAmAnInterface PrivateInterfaceField = ConcreteImpl.Instance; #pragma warning restore 169 - public IAmAnInterface InstanceInterfaceProperty => ConcreteImpl.Instance; - public IAmAnInterface InstanceInterfaceField = ConcreteImpl.Instance; - - public static Func FuncIntParseField = int.Parse; - public static NamedIntParse NamedIntParseField = int.Parse; - public static Func FuncIntParseProperty => int.Parse; - public static NamedIntParse NamedIntParseProperty => int.Parse; - public static int IntParseMethod(string value) => int.Parse(value); - public static int IntParseMethod(string value, string otherValue) => throw new NotImplementedException(); // will not be chosen, extra parameter - public static int IntParseMethod(object value) => throw new NotImplementedException(); // will not be chosen, wrong parameter type - } + public IAmAnInterface InstanceInterfaceProperty => ConcreteImpl.Instance; + public IAmAnInterface InstanceInterfaceField = ConcreteImpl.Instance; + + public static Func FuncIntParseField = int.Parse; + public static NamedIntParse NamedIntParseField = int.Parse; + public static Func FuncIntParseProperty => int.Parse; + public static NamedIntParse NamedIntParseProperty => int.Parse; + public static int IntParseMethod(string value) => int.Parse(value); + public static int IntParseMethod(string value, string otherValue) => throw new NotImplementedException(); // will not be chosen, extra parameter + public static int IntParseMethod(object value) => throw new NotImplementedException(); // will not be chosen, wrong parameter type } diff --git a/test/TestDummies/Console/DummyConsoleSink.cs b/test/TestDummies/Console/DummyConsoleSink.cs index 79816b8..67134e5 100644 --- a/test/TestDummies/Console/DummyConsoleSink.cs +++ b/test/TestDummies/Console/DummyConsoleSink.cs @@ -1,31 +1,27 @@ -using System; -using System.Collections.Generic; -using Serilog.Core; +using Serilog.Core; using Serilog.Events; using TestDummies.Console.Themes; -namespace TestDummies.Console +namespace TestDummies.Console; + +public class DummyConsoleSink : ILogEventSink { - public class DummyConsoleSink : ILogEventSink + public DummyConsoleSink(ConsoleTheme theme = null) { - public DummyConsoleSink(ConsoleTheme theme = null) - { - Theme = theme ?? ConsoleTheme.None; - } + Theme = theme ?? ConsoleTheme.None; + } - [ThreadStatic] - public static ConsoleTheme Theme; + [ThreadStatic] + public static ConsoleTheme Theme; - [ThreadStatic] - static List EmittedList; + [ThreadStatic] + static List EmittedList; - public static List Emitted => EmittedList ?? (EmittedList = new List()); + public static List Emitted => EmittedList ?? (EmittedList = new List()); - public void Emit(LogEvent logEvent) - { - Emitted.Add(logEvent); - } + public void Emit(LogEvent logEvent) + { + Emitted.Add(logEvent); } - } diff --git a/test/TestDummies/Console/Themes/ConcreteConsoleTheme.cs b/test/TestDummies/Console/Themes/ConcreteConsoleTheme.cs index 8b3b041..67d8343 100644 --- a/test/TestDummies/Console/Themes/ConcreteConsoleTheme.cs +++ b/test/TestDummies/Console/Themes/ConcreteConsoleTheme.cs @@ -1,6 +1,5 @@ -namespace TestDummies.Console.Themes +namespace TestDummies.Console.Themes; + +class ConcreteConsoleTheme : ConsoleTheme { - class ConcreteConsoleTheme : ConsoleTheme - { - } } diff --git a/test/TestDummies/Console/Themes/ConsoleTheme.cs b/test/TestDummies/Console/Themes/ConsoleTheme.cs index 1c5aaf5..ff14007 100644 --- a/test/TestDummies/Console/Themes/ConsoleTheme.cs +++ b/test/TestDummies/Console/Themes/ConsoleTheme.cs @@ -1,7 +1,6 @@ -namespace TestDummies.Console.Themes +namespace TestDummies.Console.Themes; + +public abstract class ConsoleTheme { - public abstract class ConsoleTheme - { - public static ConsoleTheme None { get; } = new EmptyConsoleTheme(); - } + public static ConsoleTheme None { get; } = new EmptyConsoleTheme(); } diff --git a/test/TestDummies/Console/Themes/ConsoleThemes.cs b/test/TestDummies/Console/Themes/ConsoleThemes.cs index 7bb414c..2804ba7 100644 --- a/test/TestDummies/Console/Themes/ConsoleThemes.cs +++ b/test/TestDummies/Console/Themes/ConsoleThemes.cs @@ -1,7 +1,6 @@ -namespace TestDummies.Console.Themes +namespace TestDummies.Console.Themes; + +public static class ConsoleThemes { - public static class ConsoleThemes - { - public static ConsoleTheme Theme1 { get; } = new ConcreteConsoleTheme(); - } + public static ConsoleTheme Theme1 { get; } = new ConcreteConsoleTheme(); } diff --git a/test/TestDummies/Console/Themes/EmptyConsoleTheme.cs b/test/TestDummies/Console/Themes/EmptyConsoleTheme.cs index 100e89e..f01847f 100644 --- a/test/TestDummies/Console/Themes/EmptyConsoleTheme.cs +++ b/test/TestDummies/Console/Themes/EmptyConsoleTheme.cs @@ -1,6 +1,5 @@ -namespace TestDummies.Console.Themes +namespace TestDummies.Console.Themes; + +class EmptyConsoleTheme : ConsoleTheme { - class EmptyConsoleTheme : ConsoleTheme - { - } } diff --git a/test/TestDummies/DummyAnonymousUserFilter.cs b/test/TestDummies/DummyAnonymousUserFilter.cs index a47dd11..89bae72 100644 --- a/test/TestDummies/DummyAnonymousUserFilter.cs +++ b/test/TestDummies/DummyAnonymousUserFilter.cs @@ -2,24 +2,23 @@ using Serilog.Core; using Serilog.Events; -namespace TestDummies +namespace TestDummies; + +public class DummyAnonymousUserFilter : ILogEventFilter { - public class DummyAnonymousUserFilter : ILogEventFilter + public bool IsEnabled(LogEvent logEvent) { - public bool IsEnabled(LogEvent logEvent) + if (logEvent.Properties.ContainsKey("User")) { - if (logEvent.Properties.ContainsKey("User")) + if (logEvent.Properties["User"] is ScalarValue sv) { - if (logEvent.Properties["User"] is ScalarValue sv) + if (sv.Value is string s && s == "anonymous") { - if (sv.Value is string s && s == "anonymous") - { - return false; - } + return false; } } - - return true; } + + return true; } } diff --git a/test/TestDummies/DummyConfigurationSink.cs b/test/TestDummies/DummyConfigurationSink.cs index d2250e7..c522f1b 100644 --- a/test/TestDummies/DummyConfigurationSink.cs +++ b/test/TestDummies/DummyConfigurationSink.cs @@ -1,46 +1,43 @@ -using System; -using System.Collections.Generic; -using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Configuration; using Serilog.Core; using Serilog.Events; -namespace TestDummies -{ - public class DummyConfigurationSink : ILogEventSink - { - [ThreadStatic] - static List _emitted; +namespace TestDummies; - [ThreadStatic] - static IConfiguration _configuration; +public class DummyConfigurationSink : ILogEventSink +{ + [ThreadStatic] + static List _emitted; - [ThreadStatic] - static IConfigurationSection _configSection; + [ThreadStatic] + static IConfiguration _configuration; - public static List Emitted => _emitted ?? (_emitted = new List()); + [ThreadStatic] + static IConfigurationSection _configSection; - public static IConfiguration Configuration => _configuration; + public static List Emitted => _emitted ?? (_emitted = new List()); - public static IConfigurationSection ConfigSection => _configSection; + public static IConfiguration Configuration => _configuration; + public static IConfigurationSection ConfigSection => _configSection; - public DummyConfigurationSink(IConfiguration configuration, IConfigurationSection configSection) - { - _configuration = configuration; - _configSection = configSection; - } - public void Emit(LogEvent logEvent) - { - Emitted.Add(logEvent); - } + public DummyConfigurationSink(IConfiguration configuration, IConfigurationSection configSection) + { + _configuration = configuration; + _configSection = configSection; + } - public static void Reset() - { - _emitted = null; - _configuration = null; - _configSection = null; - } + public void Emit(LogEvent logEvent) + { + Emitted.Add(logEvent); + } + public static void Reset() + { + _emitted = null; + _configuration = null; + _configSection = null; } + } diff --git a/test/TestDummies/DummyHardCodedStringDestructuringPolicy.cs b/test/TestDummies/DummyHardCodedStringDestructuringPolicy.cs index 25d2724..727a46e 100644 --- a/test/TestDummies/DummyHardCodedStringDestructuringPolicy.cs +++ b/test/TestDummies/DummyHardCodedStringDestructuringPolicy.cs @@ -1,22 +1,20 @@ -using System; -using Serilog.Core; +using Serilog.Core; using Serilog.Events; -namespace TestDummies +namespace TestDummies; + +public class DummyHardCodedStringDestructuringPolicy : IDestructuringPolicy { - public class DummyHardCodedStringDestructuringPolicy : IDestructuringPolicy - { - readonly string _hardCodedString; + readonly string _hardCodedString; - public DummyHardCodedStringDestructuringPolicy(string hardCodedString) - { - _hardCodedString = hardCodedString ?? throw new ArgumentNullException(nameof(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; - } + 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 2148e80..6d97379 100644 --- a/test/TestDummies/DummyLoggerConfigurationExtensions.cs +++ b/test/TestDummies/DummyLoggerConfigurationExtensions.cs @@ -4,159 +4,156 @@ using Serilog.Core; using Serilog.Events; using Serilog.Formatting; -using System; -using System.Collections.Generic; using TestDummies.Console; using TestDummies.Console.Themes; -namespace TestDummies +namespace TestDummies; + +public static class DummyLoggerConfigurationExtensions { - public static class DummyLoggerConfigurationExtensions + public static LoggerConfiguration WithDummyThreadId(this LoggerEnrichmentConfiguration enrich) { - public static LoggerConfiguration WithDummyThreadId(this LoggerEnrichmentConfiguration enrich) - { - return enrich.With(new DummyThreadIdEnricher()); - } - - public static LoggerConfiguration DummyRollingFile( - this LoggerSinkConfiguration loggerSinkConfiguration, - string pathFormat, - LogEventLevel restrictedToMinimumLevel = LevelAlias.Minimum, - string outputTemplate = null, - IFormatProvider formatProvider = null) - { - return loggerSinkConfiguration.Sink(new DummyRollingFileSink(), restrictedToMinimumLevel); - } - - public static LoggerConfiguration DummyRollingFile( - this LoggerSinkConfiguration loggerSinkConfiguration, - ITextFormatter formatter, - string pathFormat, - LogEventLevel restrictedToMinimumLevel = LevelAlias.Minimum) - { - return loggerSinkConfiguration.Sink(new DummyRollingFileSink(), restrictedToMinimumLevel); - } + return enrich.With(new DummyThreadIdEnricher()); + } - public static LoggerConfiguration DummyWithConfiguration( - this LoggerSinkConfiguration loggerSinkConfiguration, - IConfiguration appConfiguration, - LogEventLevel restrictedToMinimumLevel = LevelAlias.Minimum) - { - return loggerSinkConfiguration.Sink(new DummyConfigurationSink(appConfiguration, null), restrictedToMinimumLevel); - } + public static LoggerConfiguration DummyRollingFile( + this LoggerSinkConfiguration loggerSinkConfiguration, + string pathFormat, + LogEventLevel restrictedToMinimumLevel = LevelAlias.Minimum, + string outputTemplate = null, + IFormatProvider formatProvider = null) + { + return loggerSinkConfiguration.Sink(new DummyRollingFileSink(), restrictedToMinimumLevel); + } - public static LoggerConfiguration DummyWithOptionalConfiguration( - this LoggerSinkConfiguration loggerSinkConfiguration, - IConfiguration appConfiguration = null, - LogEventLevel restrictedToMinimumLevel = LevelAlias.Minimum) - { - return loggerSinkConfiguration.Sink(new DummyConfigurationSink(appConfiguration, null), restrictedToMinimumLevel); - } + public static LoggerConfiguration DummyRollingFile( + this LoggerSinkConfiguration loggerSinkConfiguration, + ITextFormatter formatter, + string pathFormat, + LogEventLevel restrictedToMinimumLevel = LevelAlias.Minimum) + { + return loggerSinkConfiguration.Sink(new DummyRollingFileSink(), restrictedToMinimumLevel); + } - public static LoggerConfiguration DummyWithConfigSection( - this LoggerSinkConfiguration loggerSinkConfiguration, - IConfigurationSection configurationSection, - LogEventLevel restrictedToMinimumLevel = LevelAlias.Minimum) - { - return loggerSinkConfiguration.Sink(new DummyConfigurationSink(null, configurationSection), restrictedToMinimumLevel); - } - - public static LoggerConfiguration DummyRollingFile( - this LoggerSinkConfiguration loggerSinkConfiguration, - List objectBinding, - string pathFormat, - LogEventLevel restrictedToMinimumLevel = LevelAlias.Minimum) - { - return loggerSinkConfiguration.Sink(new DummyRollingFileSink(), restrictedToMinimumLevel); - } + public static LoggerConfiguration DummyWithConfiguration( + this LoggerSinkConfiguration loggerSinkConfiguration, + IConfiguration appConfiguration, + LogEventLevel restrictedToMinimumLevel = LevelAlias.Minimum) + { + return loggerSinkConfiguration.Sink(new DummyConfigurationSink(appConfiguration, null), restrictedToMinimumLevel); + } - public class Binding - { - public string Foo { get; set; } + public static LoggerConfiguration DummyWithOptionalConfiguration( + this LoggerSinkConfiguration loggerSinkConfiguration, + IConfiguration appConfiguration = null, + LogEventLevel restrictedToMinimumLevel = LevelAlias.Minimum) + { + return loggerSinkConfiguration.Sink(new DummyConfigurationSink(appConfiguration, null), restrictedToMinimumLevel); + } - public string Abc { get; set; } - } + public static LoggerConfiguration DummyWithConfigSection( + this LoggerSinkConfiguration loggerSinkConfiguration, + IConfigurationSection configurationSection, + LogEventLevel restrictedToMinimumLevel = LevelAlias.Minimum) + { + return loggerSinkConfiguration.Sink(new DummyConfigurationSink(null, configurationSection), restrictedToMinimumLevel); + } - public static LoggerConfiguration DummyRollingFile( - this LoggerSinkConfiguration loggerSinkConfiguration, - string[] stringArrayBinding, - string pathFormat, - LogEventLevel restrictedToMinimumLevel = LevelAlias.Minimum) - { - return loggerSinkConfiguration.Sink(new DummyRollingFileSink(), restrictedToMinimumLevel); - } - - public static LoggerConfiguration DummyRollingFile( - this LoggerSinkConfiguration loggerSinkConfiguration, - int[] intArrayBinding, - string pathFormat, - LogEventLevel restrictedToMinimumLevel = LevelAlias.Minimum) - { - return loggerSinkConfiguration.Sink(new DummyRollingFileSink(), restrictedToMinimumLevel); - } - - public static LoggerConfiguration DummyRollingFile( - this LoggerAuditSinkConfiguration loggerSinkConfiguration, - string pathFormat, - LogEventLevel restrictedToMinimumLevel = LevelAlias.Minimum, - string outputTemplate = null, - IFormatProvider formatProvider = null) - { - return loggerSinkConfiguration.Sink(new DummyRollingFileAuditSink(), restrictedToMinimumLevel); - } + public static LoggerConfiguration DummyRollingFile( + this LoggerSinkConfiguration loggerSinkConfiguration, + List objectBinding, + string pathFormat, + LogEventLevel restrictedToMinimumLevel = LevelAlias.Minimum) + { + return loggerSinkConfiguration.Sink(new DummyRollingFileSink(), restrictedToMinimumLevel); + } - public static LoggerConfiguration DummyWithLevelSwitch( - this LoggerSinkConfiguration loggerSinkConfiguration, - LogEventLevel restrictedToMinimumLevel = LevelAlias.Minimum, - LoggingLevelSwitch controlLevelSwitch = null) - { - return loggerSinkConfiguration.Sink(new DummyWithLevelSwitchSink(controlLevelSwitch), restrictedToMinimumLevel); - } - - public static LoggerConfiguration DummyConsole( - this LoggerSinkConfiguration loggerSinkConfiguration, - LogEventLevel restrictedToMinimumLevel = LevelAlias.Minimum, - LoggingLevelSwitch levelSwitch = null, - ConsoleTheme theme = null) - { - return loggerSinkConfiguration.Sink(new DummyConsoleSink(theme), restrictedToMinimumLevel, levelSwitch); - } + public class Binding + { + public string Foo { get; set; } - public static LoggerConfiguration Dummy( - this LoggerSinkConfiguration loggerSinkConfiguration, - Action wrappedSinkAction) - { - return LoggerSinkConfiguration.Wrap( - loggerSinkConfiguration, - s => new DummyWrappingSink(s), - wrappedSinkAction, - LogEventLevel.Verbose, - levelSwitch: null); - } - - public static LoggerConfiguration WithDummyHardCodedString( - this LoggerDestructuringConfiguration loggerDestructuringConfiguration, - string hardCodedString - ) - { - return loggerDestructuringConfiguration.With(new DummyHardCodedStringDestructuringPolicy(hardCodedString)); - } - - public static LoggerConfiguration DummyArrayOfType(this LoggerDestructuringConfiguration loggerSinkConfiguration, - List list, - Type[] array = null, - Type type = null, - CustomCollection custom = null, - CustomCollection customString = null) - { - return loggerSinkConfiguration.With(DummyPolicy.Current = new DummyPolicy - { - List = list, - Array = array, - Type = type, - Custom = custom, - CustomStrings = customString, - }); - } + public string Abc { get; set; } + } + + public static LoggerConfiguration DummyRollingFile( + this LoggerSinkConfiguration loggerSinkConfiguration, + string[] stringArrayBinding, + string pathFormat, + LogEventLevel restrictedToMinimumLevel = LevelAlias.Minimum) + { + return loggerSinkConfiguration.Sink(new DummyRollingFileSink(), restrictedToMinimumLevel); + } + + public static LoggerConfiguration DummyRollingFile( + this LoggerSinkConfiguration loggerSinkConfiguration, + int[] intArrayBinding, + string pathFormat, + LogEventLevel restrictedToMinimumLevel = LevelAlias.Minimum) + { + return loggerSinkConfiguration.Sink(new DummyRollingFileSink(), restrictedToMinimumLevel); + } + + public static LoggerConfiguration DummyRollingFile( + this LoggerAuditSinkConfiguration loggerSinkConfiguration, + string pathFormat, + LogEventLevel restrictedToMinimumLevel = LevelAlias.Minimum, + string outputTemplate = null, + IFormatProvider formatProvider = null) + { + return loggerSinkConfiguration.Sink(new DummyRollingFileAuditSink(), restrictedToMinimumLevel); + } + + public static LoggerConfiguration DummyWithLevelSwitch( + this LoggerSinkConfiguration loggerSinkConfiguration, + LogEventLevel restrictedToMinimumLevel = LevelAlias.Minimum, + LoggingLevelSwitch controlLevelSwitch = null) + { + return loggerSinkConfiguration.Sink(new DummyWithLevelSwitchSink(controlLevelSwitch), restrictedToMinimumLevel); + } + + public static LoggerConfiguration DummyConsole( + this LoggerSinkConfiguration loggerSinkConfiguration, + LogEventLevel restrictedToMinimumLevel = LevelAlias.Minimum, + LoggingLevelSwitch levelSwitch = null, + ConsoleTheme theme = null) + { + return loggerSinkConfiguration.Sink(new DummyConsoleSink(theme), restrictedToMinimumLevel, levelSwitch); + } + + public static LoggerConfiguration Dummy( + this LoggerSinkConfiguration loggerSinkConfiguration, + Action wrappedSinkAction) + { + return LoggerSinkConfiguration.Wrap( + loggerSinkConfiguration, + s => new DummyWrappingSink(s), + wrappedSinkAction, + LogEventLevel.Verbose, + levelSwitch: null); + } + + public static LoggerConfiguration WithDummyHardCodedString( + this LoggerDestructuringConfiguration loggerDestructuringConfiguration, + string hardCodedString + ) + { + return loggerDestructuringConfiguration.With(new DummyHardCodedStringDestructuringPolicy(hardCodedString)); + } + + public static LoggerConfiguration DummyArrayOfType(this LoggerDestructuringConfiguration loggerSinkConfiguration, + List list, + Type[] array = null, + Type type = null, + CustomCollection custom = null, + CustomCollection customString = null) + { + return loggerSinkConfiguration.With(DummyPolicy.Current = new DummyPolicy + { + List = list, + Array = array, + Type = type, + Custom = custom, + CustomStrings = customString, + }); } } diff --git a/test/TestDummies/DummyPolicy.cs b/test/TestDummies/DummyPolicy.cs index ada4c2f..cf13832 100644 --- a/test/TestDummies/DummyPolicy.cs +++ b/test/TestDummies/DummyPolicy.cs @@ -1,48 +1,45 @@ using Serilog.Core; using Serilog.Events; -using System; using System.Collections; -using System.Collections.Generic; -namespace TestDummies +namespace TestDummies; + +public class DummyPolicy : IDestructuringPolicy { - public class DummyPolicy : IDestructuringPolicy - { - public static DummyPolicy Current { get; set; } + public static DummyPolicy Current { get; set; } - public Type[] Array { get; set; } + public Type[] Array { get; set; } - public List List { get; set; } + public List List { get; set; } - public CustomCollection Custom { get; set; } + public CustomCollection Custom { get; set; } - public CustomCollection CustomStrings { get; set; } + public CustomCollection CustomStrings { get; set; } - public Type Type { get; set; } + public Type Type { get; set; } - public bool TryDestructure(object value, ILogEventPropertyValueFactory propertyValueFactory, out LogEventPropertyValue result) - { - result = null; - return false; - } + public bool TryDestructure(object value, ILogEventPropertyValueFactory propertyValueFactory, out LogEventPropertyValue result) + { + result = null; + return false; } +} - public class CustomCollection : IEnumerable - { - private readonly List inner = new List(); +public class CustomCollection : IEnumerable +{ + private readonly List inner = new List(); - public void Add(T item) => inner.Add(item); + public void Add(T item) => inner.Add(item); - // wrong signature for collection initializer - public int Add() => 0; + // wrong signature for collection initializer + public int Add() => 0; - // wrong signature for collection initializer - public void Add(string a, byte b) { } + // wrong signature for collection initializer + public void Add(string a, byte b) { } - public T First => inner.Count > 0 ? inner[0] : default; + public T First => inner.Count > 0 ? inner[0] : default; - public IEnumerator GetEnumerator() => inner.GetEnumerator(); + public IEnumerator GetEnumerator() => inner.GetEnumerator(); - IEnumerator IEnumerable.GetEnumerator() => inner.GetEnumerator(); - } + IEnumerator IEnumerable.GetEnumerator() => inner.GetEnumerator(); } diff --git a/test/TestDummies/DummyRollingFileAuditSink.cs b/test/TestDummies/DummyRollingFileAuditSink.cs index 2ba17e3..28f794c 100644 --- a/test/TestDummies/DummyRollingFileAuditSink.cs +++ b/test/TestDummies/DummyRollingFileAuditSink.cs @@ -1,25 +1,22 @@ -using System; -using System.Collections.Generic; -using Serilog.Core; +using Serilog.Core; using Serilog.Events; -namespace TestDummies +namespace TestDummies; + +public class DummyRollingFileAuditSink : ILogEventSink { - public class DummyRollingFileAuditSink : ILogEventSink - { - [ThreadStatic] - static List _emitted; + [ThreadStatic] + static List _emitted; - public static List Emitted => _emitted ?? (_emitted = new List()); + public static List Emitted => _emitted ?? (_emitted = new List()); - public void Emit(LogEvent logEvent) - { - Emitted.Add(logEvent); - } + public void Emit(LogEvent logEvent) + { + Emitted.Add(logEvent); + } - public static void Reset() - { - _emitted = null; - } + public static void Reset() + { + _emitted = null; } } diff --git a/test/TestDummies/DummyRollingFileSink.cs b/test/TestDummies/DummyRollingFileSink.cs index 2f6f229..f7304cd 100644 --- a/test/TestDummies/DummyRollingFileSink.cs +++ b/test/TestDummies/DummyRollingFileSink.cs @@ -1,25 +1,22 @@ -using System; -using System.Collections.Generic; -using Serilog.Core; +using Serilog.Core; using Serilog.Events; -namespace TestDummies +namespace TestDummies; + +public class DummyRollingFileSink : ILogEventSink { - public class DummyRollingFileSink : ILogEventSink - { - [ThreadStatic] - static List _emitted; + [ThreadStatic] + static List _emitted; - public static List Emitted => _emitted ?? (_emitted = new List()); + public static List Emitted => _emitted ?? (_emitted = new List()); - public void Emit(LogEvent logEvent) - { - Emitted.Add(logEvent); - } + public void Emit(LogEvent logEvent) + { + Emitted.Add(logEvent); + } - public static void Reset() - { - _emitted = null; - } + public static void Reset() + { + _emitted = null; } } diff --git a/test/TestDummies/DummyThreadIdEnricher.cs b/test/TestDummies/DummyThreadIdEnricher.cs index a640d55..c9ae9d8 100644 --- a/test/TestDummies/DummyThreadIdEnricher.cs +++ b/test/TestDummies/DummyThreadIdEnricher.cs @@ -1,14 +1,13 @@ using Serilog.Core; using Serilog.Events; -namespace TestDummies +namespace TestDummies; + +public class DummyThreadIdEnricher : ILogEventEnricher { - public class DummyThreadIdEnricher : ILogEventEnricher + public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory) { - public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory) - { - logEvent.AddPropertyIfAbsent(propertyFactory - .CreateProperty("ThreadId", "SomeId")); - } + logEvent.AddPropertyIfAbsent(propertyFactory + .CreateProperty("ThreadId", "SomeId")); } } diff --git a/test/TestDummies/DummyWithLevelSwitchSink.cs b/test/TestDummies/DummyWithLevelSwitchSink.cs index 4e1d76f..90856d3 100644 --- a/test/TestDummies/DummyWithLevelSwitchSink.cs +++ b/test/TestDummies/DummyWithLevelSwitchSink.cs @@ -1,28 +1,25 @@ -using System; -using System.Collections.Generic; -using Serilog.Core; +using Serilog.Core; using Serilog.Events; -namespace TestDummies +namespace TestDummies; + +public class DummyWithLevelSwitchSink : ILogEventSink { - public class DummyWithLevelSwitchSink : ILogEventSink + public DummyWithLevelSwitchSink(LoggingLevelSwitch loggingControlLevelSwitch) { - public DummyWithLevelSwitchSink(LoggingLevelSwitch loggingControlLevelSwitch) - { - ControlLevelSwitch = loggingControlLevelSwitch; - } + ControlLevelSwitch = loggingControlLevelSwitch; + } - [ThreadStatic] - public static LoggingLevelSwitch ControlLevelSwitch; + [ThreadStatic] + public static LoggingLevelSwitch ControlLevelSwitch; - [ThreadStatic] - // ReSharper disable ThreadStaticFieldHasInitializer - public static List Emitted = new List(); - // ReSharper restore ThreadStaticFieldHasInitializer + [ThreadStatic] + // ReSharper disable ThreadStaticFieldHasInitializer + public static List Emitted = new List(); + // ReSharper restore ThreadStaticFieldHasInitializer - public void Emit(LogEvent logEvent) - { - Emitted.Add(logEvent); - } + public void Emit(LogEvent logEvent) + { + Emitted.Add(logEvent); } } diff --git a/test/TestDummies/DummyWrappingSink.cs b/test/TestDummies/DummyWrappingSink.cs index cb2f048..b4bc3dd 100644 --- a/test/TestDummies/DummyWrappingSink.cs +++ b/test/TestDummies/DummyWrappingSink.cs @@ -1,33 +1,30 @@ -using System; -using Serilog.Core; +using Serilog.Core; using Serilog.Events; -using System.Collections.Generic; -namespace TestDummies +namespace TestDummies; + +public class DummyWrappingSink : ILogEventSink { - public class DummyWrappingSink : ILogEventSink - { - [ThreadStatic] - static List _emitted; + [ThreadStatic] + static List _emitted; - public static List Emitted => _emitted ?? (_emitted = new List()); + public static List Emitted => _emitted ?? (_emitted = new List()); - readonly ILogEventSink _sink; + readonly ILogEventSink _sink; - public DummyWrappingSink(ILogEventSink sink) - { - _sink = sink; - } + public DummyWrappingSink(ILogEventSink sink) + { + _sink = sink; + } - public void Emit(LogEvent logEvent) - { - Emitted.Add(logEvent); - _sink.Emit(logEvent); - } + public void Emit(LogEvent logEvent) + { + Emitted.Add(logEvent); + _sink.Emit(logEvent); + } - public static void Reset() - { - _emitted = null; - } + public static void Reset() + { + _emitted = null; } } diff --git a/test/TestDummies/TestDummies.csproj b/test/TestDummies/TestDummies.csproj index 24f9c25..93ea6cc 100644 --- a/test/TestDummies/TestDummies.csproj +++ b/test/TestDummies/TestDummies.csproj @@ -16,4 +16,8 @@ + + + +