diff --git a/README.md b/README.md index 18b5638..21e7e34 100644 --- a/README.md +++ b/README.md @@ -91,3 +91,39 @@ For example, to set the minimum log level using the _Windows_ command prompt: set Serilog:MinimumLevel=Debug dotnet run ``` + +### Nested configuration sections + +Some Serilog packages require a reference to a logger configuration object. The sample program in this project illustrates this with the following entry configuring the _Serilog.Sinks.Async_ package to wrap the _Serilog.Sinks.File_ package. The `configure` parameter references the File sink configuration: + +```json +"WriteTo:Async": { + "Name": "Async", + "Args": { + "configure": [ + { + "Name": "File", + "Args": { + "path": "%TEMP%\\Logs\\serilog-configuration-sample.txt", + "outputTemplate": "{Timestamp:o} [{Level:u3}] ({Application}/{MachineName}/{ThreadId}) {Message}{NewLine}{Exception}" + } + } + ] + } +}, +``` + +### IConfiguration parameter + +If a Serilog package requires additional external configuration information (for example, access to a `ConnectionStrings` section, which would be outside of the `Serilog` section), the sink should include an `IConfiguration` parameter in the configuration extension method. This package will automatically populate that parameter. It should not be declared in the argument list in the configuration source. + +### Complex parameter value binding + +When the configuration specifies a discrete value for a parameter (such as a string literal), the package will attempt to convert that value to the target method's declared CLR type of the parameter. Additional explicit handling is provided for parsing strings to `Uri` and `TimeSpan` objects and `enum` elements. + +If the parameter value is not a discrete value, the package will use the configuration binding system provided by _Microsoft.Extensions.Options.ConfigurationExtensions_ to attempt to populate the parameter. Almost anything that can be bound by `IConfiguration.Get` should work with this package. An example of this is the optional `List` parameter used to configure the .NET Standard version of the _Serilog.Sinks.MSSqlServer_ package. + +### IConfigurationSection parameters + +Certain Serilog packages may require configuration information that can't be easily represented by discrete values or direct binding-friendly representations. An example might be lists of values to remove from a collection of default values. In this case the method can accept an entire `IConfigurationSection` as a call parameter and this package will recognize that and populate the parameter. In this way, Serilog packages can support arbitrarily complex configuration scenarios. + diff --git a/src/Serilog.Settings.Configuration/ConfigurationLoggerConfigurationExtensions.cs b/src/Serilog.Settings.Configuration/ConfigurationLoggerConfigurationExtensions.cs index b4e9d34..9f007fa 100644 --- a/src/Serilog.Settings.Configuration/ConfigurationLoggerConfigurationExtensions.cs +++ b/src/Serilog.Settings.Configuration/ConfigurationLoggerConfigurationExtensions.cs @@ -26,13 +26,18 @@ namespace Serilog /// public static class ConfigurationLoggerConfigurationExtensions { - const string DefaultSectionName = "Serilog"; + /// + /// Configuration section name required by this package. + /// + public const string DefaultSectionName = "Serilog"; /// - /// Reads logger settings from the provided configuration object using the default section name. + /// 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 with a Serilog section. + /// 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. @@ -42,28 +47,32 @@ public static LoggerConfiguration Configuration( DependencyContext dependencyContext = null) { if (configuration == null) throw new ArgumentNullException(nameof(configuration)); - return settingConfiguration.ConfigurationSection(configuration.GetSection(DefaultSectionName), dependencyContext); + return settingConfiguration.Settings( + new ConfigurationReader( + configuration, + dependencyContext ?? (Assembly.GetEntryAssembly() != null ? DependencyContext.Default : null))); } /// - /// Reads logger settings from the provided configuration section. + /// 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 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. public static LoggerConfiguration ConfigurationSection( this LoggerSettingsConfiguration settingConfiguration, - IConfigurationSection configuration, + IConfigurationSection configSection, DependencyContext dependencyContext = null) { if (settingConfiguration == null) throw new ArgumentNullException(nameof(settingConfiguration)); - if (configuration == null) throw new ArgumentNullException(nameof(configuration)); + if (configSection == null) throw new ArgumentNullException(nameof(configSection)); return settingConfiguration.Settings( new ConfigurationReader( - configuration, + configSection, dependencyContext ?? (Assembly.GetEntryAssembly() != null ? DependencyContext.Default : null))); } } diff --git a/src/Serilog.Settings.Configuration/Serilog.Settings.Configuration.csproj b/src/Serilog.Settings.Configuration/Serilog.Settings.Configuration.csproj index 1e24c68..7de6782 100644 --- a/src/Serilog.Settings.Configuration/Serilog.Settings.Configuration.csproj +++ b/src/Serilog.Settings.Configuration/Serilog.Settings.Configuration.csproj @@ -26,10 +26,12 @@ + + diff --git a/src/Serilog.Settings.Configuration/Settings/Configuration/ConfigurationReader.cs b/src/Serilog.Settings.Configuration/Settings/Configuration/ConfigurationReader.cs index 3514237..a5eb331 100644 --- a/src/Serilog.Settings.Configuration/Settings/Configuration/ConfigurationReader.cs +++ b/src/Serilog.Settings.Configuration/Settings/Configuration/ConfigurationReader.cs @@ -20,20 +20,33 @@ class ConfigurationReader : IConfigurationReader { const string LevelSwitchNameRegex = @"^\$[A-Za-z]+[A-Za-z0-9]*$"; - readonly IConfigurationSection _configuration; + static IConfiguration _configuration; + + readonly IConfigurationSection _section; readonly DependencyContext _dependencyContext; readonly IReadOnlyCollection _configurationAssemblies; - public ConfigurationReader(IConfigurationSection configuration, DependencyContext dependencyContext) + public ConfigurationReader(IConfiguration configuration, DependencyContext dependencyContext) { _configuration = configuration ?? throw new ArgumentNullException(nameof(configuration)); + _section = configuration.GetSection(ConfigurationLoggerConfigurationExtensions.DefaultSectionName); _dependencyContext = dependencyContext; _configurationAssemblies = LoadConfigurationAssemblies(); } - ConfigurationReader(IConfigurationSection configuration, IReadOnlyCollection configurationAssemblies, DependencyContext dependencyContext) + // Generally the initial call should use IConfiguration rather than IConfigurationSection, otherwise + // IConfiguration parameters in the target methods will not be populated. + ConfigurationReader(IConfigurationSection configSection, DependencyContext dependencyContext) { - _configuration = configuration ?? throw new ArgumentNullException(nameof(configuration)); + _section = configSection ?? throw new ArgumentNullException(nameof(configSection)); + _dependencyContext = dependencyContext; + _configurationAssemblies = LoadConfigurationAssemblies(); + } + + // Used internally for processing nested configuration sections -- see GetMethodCalls below. + internal ConfigurationReader(IConfigurationSection configSection, IReadOnlyCollection configurationAssemblies, DependencyContext dependencyContext) + { + _section = configSection ?? throw new ArgumentNullException(nameof(configSection)); _dependencyContext = dependencyContext; _configurationAssemblies = configurationAssemblies ?? throw new ArgumentNullException(nameof(configurationAssemblies)); } @@ -50,40 +63,35 @@ public void Configure(LoggerConfiguration loggerConfiguration) IReadOnlyDictionary ProcessLevelSwitchDeclarations() { - var levelSwitchesDirective = _configuration.GetSection("LevelSwitches"); + var levelSwitchesDirective = _section.GetSection("LevelSwitches"); var namedSwitches = new Dictionary(); - if (levelSwitchesDirective != null) + foreach (var levelSwitchDeclaration in levelSwitchesDirective.GetChildren()) { - 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. Level switch must be declared with a '$' sign, like \"LevelSwitches\" : {{\"$switchName\" : \"InitialLevel\"}}"); - } - LoggingLevelSwitch newSwitch; - if (string.IsNullOrEmpty(switchInitialLevel)) - { - newSwitch = new LoggingLevelSwitch(); - } - else - { - var initialLevel = ParseLogEventLevel(switchInitialLevel); - newSwitch = new LoggingLevelSwitch(initialLevel); - } - namedSwitches.Add(switchName, newSwitch); + throw new FormatException($"\"{switchName}\" is not a valid name for a Level Switch declaration. Level switch must be declared with a '$' sign, like \"LevelSwitches\" : {{\"$switchName\" : \"InitialLevel\"}}"); } + LoggingLevelSwitch newSwitch; + if (string.IsNullOrEmpty(switchInitialLevel)) + { + newSwitch = new LoggingLevelSwitch(); + } + else + { + var initialLevel = ParseLogEventLevel(switchInitialLevel); + newSwitch = new LoggingLevelSwitch(initialLevel); + } + namedSwitches.Add(switchName, newSwitch); } - return namedSwitches; } - void ApplyMinimumLevel(LoggerConfiguration loggerConfiguration, - IReadOnlyDictionary declaredLevelSwitches) + void ApplyMinimumLevel(LoggerConfiguration loggerConfiguration, IReadOnlyDictionary declaredLevelSwitches) { - var minimumLevelDirective = _configuration.GetSection("MinimumLevel"); + var minimumLevelDirective = _section.GetSection("MinimumLevel"); var defaultMinLevelDirective = minimumLevelDirective.Value != null ? minimumLevelDirective : minimumLevelDirective.GetSection("Default"); if (defaultMinLevelDirective.Value != null) @@ -92,7 +100,7 @@ void ApplyMinimumLevel(LoggerConfiguration loggerConfiguration, } var minLevelControlledByDirective = minimumLevelDirective.GetSection("ControlledBy"); - if (minLevelControlledByDirective?.Value != null) + if (minLevelControlledByDirective.Value != null) { var globalMinimumLevelSwitch = declaredLevelSwitches.LookUpSwitchByName(minLevelControlledByDirective.Value); // not calling ApplyMinimumLevel local function because here we have a reference to a LogLevelSwitch already @@ -134,60 +142,53 @@ void ApplyMinimumLevel(IConfigurationSection directive, Action declaredLevelSwitches) + void ApplyFilters(LoggerConfiguration loggerConfiguration, IReadOnlyDictionary declaredLevelSwitches) { - var filterDirective = _configuration.GetSection("Filter"); - if (filterDirective != null) + var filterDirective = _section.GetSection("Filter"); + if (filterDirective.GetChildren().Any()) { var methodCalls = GetMethodCalls(filterDirective); CallConfigurationMethods(methodCalls, FindFilterConfigurationMethods(_configurationAssemblies), loggerConfiguration.Filter, declaredLevelSwitches); } } - void ApplySinks(LoggerConfiguration loggerConfiguration, - IReadOnlyDictionary declaredLevelSwitches) + void ApplySinks(LoggerConfiguration loggerConfiguration, IReadOnlyDictionary declaredLevelSwitches) { - var writeToDirective = _configuration.GetSection("WriteTo"); - if (writeToDirective != null) + var writeToDirective = _section.GetSection("WriteTo"); + if (writeToDirective.GetChildren().Any()) { var methodCalls = GetMethodCalls(writeToDirective); CallConfigurationMethods(methodCalls, FindSinkConfigurationMethods(_configurationAssemblies), loggerConfiguration.WriteTo, declaredLevelSwitches); } } - void ApplyAuditSinks(LoggerConfiguration loggerConfiguration, - IReadOnlyDictionary declaredLevelSwitches) + void ApplyAuditSinks(LoggerConfiguration loggerConfiguration, IReadOnlyDictionary declaredLevelSwitches) { - var auditToDirective = _configuration.GetSection("AuditTo"); - if (auditToDirective != null) + var auditToDirective = _section.GetSection("AuditTo"); + if (auditToDirective.GetChildren().Any()) { var methodCalls = GetMethodCalls(auditToDirective); CallConfigurationMethods(methodCalls, FindAuditSinkConfigurationMethods(_configurationAssemblies), loggerConfiguration.AuditTo, declaredLevelSwitches); } } - void IConfigurationReader.ApplySinks(LoggerSinkConfiguration loggerSinkConfiguration, - IReadOnlyDictionary declaredLevelSwitches) + void IConfigurationReader.ApplySinks(LoggerSinkConfiguration loggerSinkConfiguration, IReadOnlyDictionary declaredLevelSwitches) { - var methodCalls = GetMethodCalls(_configuration); + var methodCalls = GetMethodCalls(_section); CallConfigurationMethods(methodCalls, FindSinkConfigurationMethods(_configurationAssemblies), loggerSinkConfiguration, declaredLevelSwitches); } - void ApplyEnrichment(LoggerConfiguration loggerConfiguration, - IReadOnlyDictionary declaredLevelSwitches) + void ApplyEnrichment(LoggerConfiguration loggerConfiguration, IReadOnlyDictionary declaredLevelSwitches) { - var enrichDirective = _configuration.GetSection("Enrich"); - if (enrichDirective != null) + var enrichDirective = _section.GetSection("Enrich"); + if (enrichDirective.GetChildren().Any()) { var methodCalls = GetMethodCalls(enrichDirective); CallConfigurationMethods(methodCalls, FindEventEnricherConfigurationMethods(_configurationAssemblies), loggerConfiguration.Enrich, declaredLevelSwitches); } - var propertiesDirective = _configuration.GetSection("Properties"); - if (propertiesDirective != null) + var propertiesDirective = _section.GetSection("Properties"); + if (propertiesDirective.GetChildren().Any()) { foreach (var enrichProperyDirective in propertiesDirective.GetChildren()) { @@ -226,7 +227,7 @@ IConfigurationArgumentValue GetArgumentValue(IConfigurationSection argumentSecti } else { - argumentValue = new ConfigurationSectionArgumentValue(new ConfigurationReader(argumentSection, _configurationAssemblies, _dependencyContext)); + argumentValue = new ObjectArgumentValue(argumentSection, _configurationAssemblies, _dependencyContext); } return argumentValue; @@ -246,8 +247,8 @@ IReadOnlyCollection LoadConfigurationAssemblies() { var assemblies = new Dictionary(); - var usingSection = _configuration.GetSection("Using"); - if (usingSection != null) + var usingSection = _section.GetSection("Using"); + if (usingSection.GetChildren().Any()) { foreach (var simpleName in usingSection.GetChildren().Select(c => c.Value)) { @@ -307,6 +308,9 @@ static void CallConfigurationMethods(ILookup s.Key == p.Name) select directive.Key == null ? p.DefaultValue : directive.Value.ConvertTo(p.ParameterType, declaredLevelSwitches)).ToList(); + var parm = methodInfo.GetParameters().FirstOrDefault(i => i.ParameterType == typeof(IConfiguration)); + if(parm != null) call[parm.Position - 1] = _configuration; + call.Insert(0, receiver); methodInfo.Invoke(null, call.ToArray()); @@ -399,5 +403,6 @@ internal static LogEventLevel ParseLogEventLevel(string value) throw new InvalidOperationException($"The value {value} is not a valid Serilog level."); return parsedLevel; } + } } diff --git a/src/Serilog.Settings.Configuration/Settings/Configuration/ConfigurationSectionArgumentValue.cs b/src/Serilog.Settings.Configuration/Settings/Configuration/ConfigurationSectionArgumentValue.cs deleted file mode 100644 index b7f6825..0000000 --- a/src/Serilog.Settings.Configuration/Settings/Configuration/ConfigurationSectionArgumentValue.cs +++ /dev/null @@ -1,41 +0,0 @@ -using Serilog.Configuration; -using System; -using System.Collections.Generic; -using System.Reflection; -using Serilog.Core; - -namespace Serilog.Settings.Configuration -{ - class ConfigurationSectionArgumentValue : IConfigurationArgumentValue - { - readonly IConfigurationReader _configReader; - - public ConfigurationSectionArgumentValue(IConfigurationReader configReader) - { - _configReader = configReader ?? throw new ArgumentNullException(nameof(configReader)); - } - - public object ConvertTo(Type toType, IReadOnlyDictionary declaredLevelSwitches) - { - var typeInfo = toType.GetTypeInfo(); - if (!typeInfo.IsGenericType || - typeInfo.GetGenericTypeDefinition() is Type genericType && genericType != typeof(Action<>)) - { - throw new InvalidOperationException("Argument value should be of type Action<>."); - } - - var configurationType = typeInfo.GenericTypeArguments[0]; - if (configurationType == typeof(LoggerSinkConfiguration)) - { - return new Action(loggerSinkConfig => _configReader.ApplySinks(loggerSinkConfig, declaredLevelSwitches)); - } - - if (configurationType == typeof(LoggerConfiguration)) - { - return new Action(_configReader.Configure); - } - - throw new ArgumentException($"Handling {configurationType} is not implemented."); - } - } -} diff --git a/src/Serilog.Settings.Configuration/Settings/Configuration/ObjectArgumentValue.cs b/src/Serilog.Settings.Configuration/Settings/Configuration/ObjectArgumentValue.cs new file mode 100644 index 0000000..8242476 --- /dev/null +++ b/src/Serilog.Settings.Configuration/Settings/Configuration/ObjectArgumentValue.cs @@ -0,0 +1,57 @@ +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyModel; +using Serilog.Configuration; +using Serilog.Core; +using System; +using System.Collections.Generic; +using System.Reflection; + +namespace Serilog.Settings.Configuration +{ + class ObjectArgumentValue : IConfigurationArgumentValue + { + readonly IConfigurationSection section; + readonly IReadOnlyCollection configurationAssemblies; + readonly DependencyContext dependencyContext; + + public ObjectArgumentValue(IConfigurationSection section, IReadOnlyCollection configurationAssemblies, DependencyContext dependencyContext) + { + this.section = section; + + // used by nested logger configurations to feed a new pass by ConfigurationReader + this.configurationAssemblies = configurationAssemblies; + this.dependencyContext = dependencyContext; + } + + public object ConvertTo(Type toType, IReadOnlyDictionary declaredLevelSwitches) + { + // return the entire section for internal processing + if(toType == typeof(IConfigurationSection)) return section; + + // 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<>)) + { + var configType = typeInfo.GenericTypeArguments[0]; + if(configType != typeof(LoggerConfiguration) && configType != typeof(LoggerSinkConfiguration)) + throw new ArgumentException($"Configuration for Action<{configType}> is not implemented."); + + IConfigurationReader configReader = new ConfigurationReader(section, configurationAssemblies, dependencyContext); + + if(configType == typeof(LoggerConfiguration)) + { + return new Action(configReader.Configure); + } + + if(configType == typeof(LoggerSinkConfiguration)) + { + return new Action(loggerSinkConfig => configReader.ApplySinks(loggerSinkConfig, declaredLevelSwitches)); + } + } + + // MS Config binding + return section.Get(toType); + } + } +} diff --git a/test/Serilog.Settings.Configuration.Tests/ConfigurationSettingsTests.cs b/test/Serilog.Settings.Configuration.Tests/ConfigurationSettingsTests.cs index bdb5c6a..40435f3 100644 --- a/test/Serilog.Settings.Configuration.Tests/ConfigurationSettingsTests.cs +++ b/test/Serilog.Settings.Configuration.Tests/ConfigurationSettingsTests.cs @@ -199,7 +199,6 @@ public void SinksAreConfiguredWithStaticMember() Assert.Equal(ConsoleThemes.Theme1, DummyConsoleSink.Theme); } - [Theory] [InlineData("$switchName", true)] [InlineData("$SwitchName", true)] @@ -391,6 +390,105 @@ public void LoggingLevelSwitchCanBeUsedForMinimumLevelOverrides() // ReSharper restore HeuristicUnreachableCode } + [Fact] + public void SinkWithIConfigurationArguments() + { + var json = @"{ + ""Serilog"": { + ""Using"": [""TestDummies""], + ""WriteTo"": [{ + ""Name"": ""DummyRollingFile"", + ""Args"": {""pathFormat"" : ""C:\\"", + ""configurationSection"" : { ""foo"" : ""bar"" } } + }] + } + }"; + + // IConfiguration and IConfigurationSection arguments do not have + // default values so they will throw if they are not populated + + var log = ConfigFromJson(json) + .CreateLogger(); + + DummyRollingFileSink.Emitted.Clear(); + + log.Write(Some.InformationEvent()); + + Assert.Equal(1, DummyRollingFileSink.Emitted.Count); + } + + [Fact] + public void SinkWithConfigurationBindingArgument() + { + var json = @"{ + ""Serilog"": { + ""Using"": [""TestDummies""], + ""WriteTo"": [{ + ""Name"": ""DummyRollingFile"", + ""Args"": {""pathFormat"" : ""C:\\"", + ""objectBinding"" : [ { ""foo"" : ""bar"" }, { ""abc"" : ""xyz"" } ] } + }] + } + }"; + + var log = ConfigFromJson(json) + .CreateLogger(); + + DummyRollingFileSink.Emitted.Clear(); + + log.Write(Some.InformationEvent()); + + Assert.Equal(1, DummyRollingFileSink.Emitted.Count); + } + + [Fact] + public void SinkWithStringArrayArgument() + { + var json = @"{ + ""Serilog"": { + ""Using"": [""TestDummies""], + ""WriteTo"": [{ + ""Name"": ""DummyRollingFile"", + ""Args"": {""pathFormat"" : ""C:\\"", + ""stringArrayBinding"" : [ ""foo"", ""bar"", ""baz"" ] } + }] + } + }"; + + var log = ConfigFromJson(json) + .CreateLogger(); + + DummyRollingFileSink.Emitted.Clear(); + + log.Write(Some.InformationEvent()); + + Assert.Equal(1, DummyRollingFileSink.Emitted.Count); + } + + [Fact] + public void SinkWithIntArrayArgument() + { + var json = @"{ + ""Serilog"": { + ""Using"": [""TestDummies""], + ""WriteTo"": [{ + ""Name"": ""DummyRollingFile"", + ""Args"": {""pathFormat"" : ""C:\\"", + ""intArrayBinding"" : [ 1,2,3,4,5 ] } + }] + } + }"; + + var log = ConfigFromJson(json) + .CreateLogger(); + + DummyRollingFileSink.Emitted.Clear(); + + log.Write(Some.InformationEvent()); + + Assert.Equal(1, DummyRollingFileSink.Emitted.Count); + } + [Trait("Bugfix", "#91")] [Fact] 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 deb329a..3a88c1b 100644 --- a/test/Serilog.Settings.Configuration.Tests/Serilog.Settings.Configuration.Tests.csproj +++ b/test/Serilog.Settings.Configuration.Tests/Serilog.Settings.Configuration.Tests.csproj @@ -26,10 +26,12 @@ + + diff --git a/test/TestDummies/DummyLoggerConfigurationExtensions.cs b/test/TestDummies/DummyLoggerConfigurationExtensions.cs index b01c422..5f1e039 100644 --- a/test/TestDummies/DummyLoggerConfigurationExtensions.cs +++ b/test/TestDummies/DummyLoggerConfigurationExtensions.cs @@ -6,6 +6,8 @@ using Serilog.Core; using TestDummies.Console; using TestDummies.Console.Themes; +using Microsoft.Extensions.Configuration; +using System.Collections.Generic; namespace TestDummies { @@ -35,6 +37,43 @@ public static LoggerConfiguration DummyRollingFile( return loggerSinkConfiguration.Sink(new DummyRollingFileSink(), restrictedToMinimumLevel); } + public static LoggerConfiguration DummyRollingFile( + this LoggerSinkConfiguration loggerSinkConfiguration, + IConfiguration appConfiguration, + IConfigurationSection configurationSection, + string pathFormat, + LogEventLevel restrictedToMinimumLevel = LevelAlias.Minimum) + { + return loggerSinkConfiguration.Sink(new DummyRollingFileSink(), 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 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, diff --git a/test/TestDummies/TestDummies.csproj b/test/TestDummies/TestDummies.csproj index b0d89c0..5c212f5 100644 --- a/test/TestDummies/TestDummies.csproj +++ b/test/TestDummies/TestDummies.csproj @@ -16,9 +16,14 @@ + + + + +