Skip to content

Commit 3e5677c

Browse files
committed
Refactor: rename SettingsValueResolver to ResolutionContext
and reduce number of arguments to pass around
1 parent cd457d0 commit 3e5677c

File tree

9 files changed

+126
-118
lines changed

9 files changed

+126
-118
lines changed

src/Serilog.Settings.Configuration/Settings/Configuration/ConfigurationReader.cs

Lines changed: 42 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -19,46 +19,40 @@ class ConfigurationReader : IConfigurationReader
1919
{
2020
const string LevelSwitchNameRegex = @"^\$[A-Za-z]+[A-Za-z0-9]*$";
2121

22-
readonly IConfiguration _configuration;
23-
2422
readonly IConfigurationSection _section;
25-
readonly AssemblyFinder _assemblyFinder;
2623
readonly IReadOnlyCollection<Assembly> _configurationAssemblies;
24+
readonly ResolutionContext _resolutionContext;
2725

2826
public ConfigurationReader(IConfigurationSection configSection, AssemblyFinder assemblyFinder, IConfiguration configuration = null)
2927
{
3028
_section = configSection ?? throw new ArgumentNullException(nameof(configSection));
31-
_assemblyFinder = assemblyFinder ?? throw new ArgumentNullException(nameof(assemblyFinder));
32-
_configuration = configuration;
33-
_configurationAssemblies = LoadConfigurationAssemblies(_section, _assemblyFinder);
29+
_configurationAssemblies = LoadConfigurationAssemblies(_section, assemblyFinder);
30+
_resolutionContext = new ResolutionContext(configuration);
3431
}
3532

3633
// Used internally for processing nested configuration sections -- see GetMethodCalls below.
37-
internal ConfigurationReader(IConfigurationSection configSection, IReadOnlyCollection<Assembly> configurationAssemblies, AssemblyFinder assemblyFinder, SettingValueResolver valueResolver)
34+
internal ConfigurationReader(IConfigurationSection configSection, IReadOnlyCollection<Assembly> configurationAssemblies, ResolutionContext resolutionContext)
3835
{
3936
_section = configSection ?? throw new ArgumentNullException(nameof(configSection));
4037
_configurationAssemblies = configurationAssemblies ?? throw new ArgumentNullException(nameof(configurationAssemblies));
41-
_assemblyFinder = assemblyFinder ?? throw new ArgumentNullException(nameof(assemblyFinder));
42-
_configuration = valueResolver.AppConfiguration;
38+
_resolutionContext = resolutionContext ?? throw new ArgumentNullException(nameof(resolutionContext));
4339
}
4440

4541
public void Configure(LoggerConfiguration loggerConfiguration)
4642
{
47-
var declaredLevelSwitches = ProcessLevelSwitchDeclarations();
48-
var settingsValueResolver = new SettingValueResolver(declaredLevelSwitches, _configuration);
49-
50-
ApplyMinimumLevel(loggerConfiguration, settingsValueResolver);
51-
ApplyEnrichment(loggerConfiguration, settingsValueResolver);
52-
ApplyFilters(loggerConfiguration, settingsValueResolver);
53-
ApplyDestructuring(loggerConfiguration, settingsValueResolver);
54-
ApplySinks(loggerConfiguration, settingsValueResolver);
55-
ApplyAuditSinks(loggerConfiguration, settingsValueResolver);
43+
ProcessLevelSwitchDeclarations();
44+
45+
ApplyMinimumLevel(loggerConfiguration);
46+
ApplyEnrichment(loggerConfiguration);
47+
ApplyFilters(loggerConfiguration);
48+
ApplyDestructuring(loggerConfiguration);
49+
ApplySinks(loggerConfiguration);
50+
ApplyAuditSinks(loggerConfiguration);
5651
}
5752

58-
IReadOnlyDictionary<string, LoggingLevelSwitch> ProcessLevelSwitchDeclarations()
53+
void ProcessLevelSwitchDeclarations()
5954
{
6055
var levelSwitchesDirective = _section.GetSection("LevelSwitches");
61-
var namedSwitches = new Dictionary<string, LoggingLevelSwitch>();
6256
foreach (var levelSwitchDeclaration in levelSwitchesDirective.GetChildren())
6357
{
6458
var switchName = levelSwitchDeclaration.Key;
@@ -78,12 +72,12 @@ IReadOnlyDictionary<string, LoggingLevelSwitch> ProcessLevelSwitchDeclarations()
7872
var initialLevel = ParseLogEventLevel(switchInitialLevel);
7973
newSwitch = new LoggingLevelSwitch(initialLevel);
8074
}
81-
namedSwitches.Add(switchName, newSwitch);
75+
// make them available later on when resolving argument values
76+
_resolutionContext.AddLevelSwitch(switchName, newSwitch);
8277
}
83-
return namedSwitches;
8478
}
8579

86-
void ApplyMinimumLevel(LoggerConfiguration loggerConfiguration, SettingValueResolver valueResolver)
80+
void ApplyMinimumLevel(LoggerConfiguration loggerConfiguration)
8781
{
8882
var minimumLevelDirective = _section.GetSection("MinimumLevel");
8983

@@ -96,7 +90,7 @@ void ApplyMinimumLevel(LoggerConfiguration loggerConfiguration, SettingValueReso
9690
var minLevelControlledByDirective = minimumLevelDirective.GetSection("ControlledBy");
9791
if (minLevelControlledByDirective.Value != null)
9892
{
99-
var globalMinimumLevelSwitch = valueResolver.LookUpSwitchByName(minLevelControlledByDirective.Value);
93+
var globalMinimumLevelSwitch = _resolutionContext.LookUpSwitchByName(minLevelControlledByDirective.Value);
10094
// not calling ApplyMinimumLevel local function because here we have a reference to a LogLevelSwitch already
10195
loggerConfiguration.MinimumLevel.ControlledBy(globalMinimumLevelSwitch);
10296
}
@@ -111,7 +105,7 @@ void ApplyMinimumLevel(LoggerConfiguration loggerConfiguration, SettingValueReso
111105
}
112106
else
113107
{
114-
var overrideSwitch = valueResolver.LookUpSwitchByName(overridenLevelOrSwitch);
108+
var overrideSwitch = _resolutionContext.LookUpSwitchByName(overridenLevelOrSwitch);
115109
// not calling ApplyMinimumLevel local function because here we have a reference to a LogLevelSwitch already
116110
loggerConfiguration.MinimumLevel.Override(overridePrefix, overrideSwitch);
117111
}
@@ -136,59 +130,59 @@ void ApplyMinimumLevel(IConfigurationSection directive, Action<LoggerMinimumLeve
136130
}
137131
}
138132

139-
void ApplyFilters(LoggerConfiguration loggerConfiguration, SettingValueResolver valueResolver)
133+
void ApplyFilters(LoggerConfiguration loggerConfiguration)
140134
{
141135
var filterDirective = _section.GetSection("Filter");
142136
if (filterDirective.GetChildren().Any())
143137
{
144138
var methodCalls = GetMethodCalls(filterDirective);
145-
CallConfigurationMethods(methodCalls, FindFilterConfigurationMethods(_configurationAssemblies), loggerConfiguration.Filter, valueResolver);
139+
CallConfigurationMethods(methodCalls, FindFilterConfigurationMethods(_configurationAssemblies), loggerConfiguration.Filter);
146140
}
147141
}
148142

149-
void ApplyDestructuring(LoggerConfiguration loggerConfiguration, SettingValueResolver valueResolver)
143+
void ApplyDestructuring(LoggerConfiguration loggerConfiguration)
150144
{
151145
var destructureDirective = _section.GetSection("Destructure");
152146
if (destructureDirective.GetChildren().Any())
153147
{
154148
var methodCalls = GetMethodCalls(destructureDirective);
155-
CallConfigurationMethods(methodCalls, FindDestructureConfigurationMethods(_configurationAssemblies), loggerConfiguration.Destructure, valueResolver);
149+
CallConfigurationMethods(methodCalls, FindDestructureConfigurationMethods(_configurationAssemblies), loggerConfiguration.Destructure);
156150
}
157151
}
158152

159-
void ApplySinks(LoggerConfiguration loggerConfiguration, SettingValueResolver valueResolver)
153+
void ApplySinks(LoggerConfiguration loggerConfiguration)
160154
{
161155
var writeToDirective = _section.GetSection("WriteTo");
162156
if (writeToDirective.GetChildren().Any())
163157
{
164158
var methodCalls = GetMethodCalls(writeToDirective);
165-
CallConfigurationMethods(methodCalls, FindSinkConfigurationMethods(_configurationAssemblies), loggerConfiguration.WriteTo, valueResolver);
159+
CallConfigurationMethods(methodCalls, FindSinkConfigurationMethods(_configurationAssemblies), loggerConfiguration.WriteTo);
166160
}
167161
}
168162

169-
void ApplyAuditSinks(LoggerConfiguration loggerConfiguration, SettingValueResolver valueResolver)
163+
void ApplyAuditSinks(LoggerConfiguration loggerConfiguration)
170164
{
171165
var auditToDirective = _section.GetSection("AuditTo");
172166
if (auditToDirective.GetChildren().Any())
173167
{
174168
var methodCalls = GetMethodCalls(auditToDirective);
175-
CallConfigurationMethods(methodCalls, FindAuditSinkConfigurationMethods(_configurationAssemblies), loggerConfiguration.AuditTo, valueResolver);
169+
CallConfigurationMethods(methodCalls, FindAuditSinkConfigurationMethods(_configurationAssemblies), loggerConfiguration.AuditTo);
176170
}
177171
}
178172

179-
void IConfigurationReader.ApplySinks(LoggerSinkConfiguration loggerSinkConfiguration, SettingValueResolver valueResolver)
173+
void IConfigurationReader.ApplySinks(LoggerSinkConfiguration loggerSinkConfiguration)
180174
{
181175
var methodCalls = GetMethodCalls(_section);
182-
CallConfigurationMethods(methodCalls, FindSinkConfigurationMethods(_configurationAssemblies), loggerSinkConfiguration, valueResolver);
176+
CallConfigurationMethods(methodCalls, FindSinkConfigurationMethods(_configurationAssemblies), loggerSinkConfiguration);
183177
}
184178

185-
void ApplyEnrichment(LoggerConfiguration loggerConfiguration, SettingValueResolver valueResolver)
179+
void ApplyEnrichment(LoggerConfiguration loggerConfiguration)
186180
{
187181
var enrichDirective = _section.GetSection("Enrich");
188182
if (enrichDirective.GetChildren().Any())
189183
{
190184
var methodCalls = GetMethodCalls(enrichDirective);
191-
CallConfigurationMethods(methodCalls, FindEventEnricherConfigurationMethods(_configurationAssemblies), loggerConfiguration.Enrich, valueResolver);
185+
CallConfigurationMethods(methodCalls, FindEventEnricherConfigurationMethods(_configurationAssemblies), loggerConfiguration.Enrich);
192186
}
193187

194188
var propertiesDirective = _section.GetSection("Properties");
@@ -243,7 +237,7 @@ IConfigurationArgumentValue GetArgumentValue(IConfigurationSection argumentSecti
243237
}
244238
else
245239
{
246-
argumentValue = new ObjectArgumentValue(argumentSection, _configurationAssemblies, _assemblyFinder);
240+
argumentValue = new ObjectArgumentValue(argumentSection, _configurationAssemblies);
247241
}
248242

249243
return argumentValue;
@@ -288,7 +282,7 @@ static IReadOnlyCollection<Assembly> LoadConfigurationAssemblies(IConfigurationS
288282
return assemblies.Values.ToList().AsReadOnly();
289283
}
290284

291-
static void CallConfigurationMethods(ILookup<string, Dictionary<string, IConfigurationArgumentValue>> methods, IList<MethodInfo> configurationMethods, object receiver, SettingValueResolver valueResolver)
285+
void CallConfigurationMethods(ILookup<string, Dictionary<string, IConfigurationArgumentValue>> methods, IList<MethodInfo> configurationMethods, object receiver)
292286
{
293287
foreach (var method in methods.SelectMany(g => g.Select(x => new { g.Key, Value = x })))
294288
{
@@ -299,8 +293,8 @@ static void CallConfigurationMethods(ILookup<string, Dictionary<string, IConfigu
299293
var call = (from p in methodInfo.GetParameters().Skip(1)
300294
let directive = method.Value.FirstOrDefault(s => ParameterNameMatches(p.Name, s.Key))
301295
select directive.Key == null
302-
? GetImplicitValueForNotSpecifiedKey(p, valueResolver, methodInfo)
303-
: directive.Value.ConvertTo(p.ParameterType, valueResolver)).ToList();
296+
? GetImplicitValueForNotSpecifiedKey(p, methodInfo)
297+
: directive.Value.ConvertTo(p.ParameterType, _resolutionContext)).ToList();
304298

305299
call.Insert(0, receiver);
306300
methodInfo.Invoke(null, call.ToArray());
@@ -315,7 +309,7 @@ static bool HasImplicitValueWhenNotSpecified(ParameterInfo paramInfo)
315309
|| paramInfo.ParameterType == typeof(IConfiguration);
316310
}
317311

318-
static object GetImplicitValueForNotSpecifiedKey(ParameterInfo parameter, SettingValueResolver valueResolver, MethodInfo methodToInvoke)
312+
object GetImplicitValueForNotSpecifiedKey(ParameterInfo parameter, MethodInfo methodToInvoke)
319313
{
320314
if (!HasImplicitValueWhenNotSpecified(parameter))
321315
{
@@ -325,13 +319,16 @@ static object GetImplicitValueForNotSpecifiedKey(ParameterInfo parameter, Settin
325319

326320
if (parameter.ParameterType == typeof(IConfiguration))
327321
{
322+
if (_resolutionContext.HasAppConfiguration)
323+
{
324+
return _resolutionContext.AppConfiguration;
325+
}
328326
if (parameter.HasDefaultValue)
329327
{
330-
return valueResolver.AppConfiguration ?? parameter.DefaultValue;
328+
return parameter.DefaultValue;
331329
}
332330

333-
return valueResolver.AppConfiguration
334-
?? throw new InvalidOperationException("Trying to invoke a configuration method accepting a `IConfiguration` argument. " +
331+
throw new InvalidOperationException("Trying to invoke a configuration method accepting a `IConfiguration` argument. " +
335332
$"This is not supported when only a `IConfigSection` has been provided. (method '{methodToInvoke}')");
336333
}
337334

src/Serilog.Settings.Configuration/Settings/Configuration/IConfigurationArgumentValue.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,6 @@ namespace Serilog.Settings.Configuration
44
{
55
interface IConfigurationArgumentValue
66
{
7-
object ConvertTo(Type toType, SettingValueResolver valueResolver);
7+
object ConvertTo(Type toType, ResolutionContext resolutionContext);
88
}
99
}

src/Serilog.Settings.Configuration/Settings/Configuration/IConfigurationReader.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,6 @@ namespace Serilog.Settings.Configuration
44
{
55
interface IConfigurationReader : ILoggerSettings
66
{
7-
void ApplySinks(LoggerSinkConfiguration loggerSinkConfiguration, SettingValueResolver valueResolver);
7+
void ApplySinks(LoggerSinkConfiguration loggerSinkConfiguration);
88
}
99
}

src/Serilog.Settings.Configuration/Settings/Configuration/ObjectArgumentValue.cs

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,26 +4,23 @@
44
using System.Reflection;
55

66
using Serilog.Configuration;
7-
using Serilog.Settings.Configuration.Assemblies;
87

98
namespace Serilog.Settings.Configuration
109
{
1110
class ObjectArgumentValue : IConfigurationArgumentValue
1211
{
1312
readonly IConfigurationSection _section;
1413
readonly IReadOnlyCollection<Assembly> _configurationAssemblies;
15-
readonly AssemblyFinder _assemblyFinder;
1614

17-
public ObjectArgumentValue(IConfigurationSection section, IReadOnlyCollection<Assembly> configurationAssemblies, AssemblyFinder assemblyFinder)
15+
public ObjectArgumentValue(IConfigurationSection section, IReadOnlyCollection<Assembly> configurationAssemblies)
1816
{
1917
_section = section ?? throw new ArgumentNullException(nameof(section));
2018

2119
// used by nested logger configurations to feed a new pass by ConfigurationReader
2220
_configurationAssemblies = configurationAssemblies ?? throw new ArgumentNullException(nameof(configurationAssemblies));
23-
_assemblyFinder = assemblyFinder ?? throw new ArgumentNullException(nameof(assemblyFinder));
2421
}
2522

26-
public object ConvertTo(Type toType, SettingValueResolver valueResolver)
23+
public object ConvertTo(Type toType, ResolutionContext resolutionContext)
2724
{
2825
// return the entire section for internal processing
2926
if (toType == typeof(IConfigurationSection)) return _section;
@@ -37,7 +34,7 @@ public object ConvertTo(Type toType, SettingValueResolver valueResolver)
3734
if (configType != typeof(LoggerConfiguration) && configType != typeof(LoggerSinkConfiguration))
3835
throw new ArgumentException($"Configuration for Action<{configType}> is not implemented.");
3936

40-
IConfigurationReader configReader = new ConfigurationReader(_section, _configurationAssemblies, _assemblyFinder, valueResolver);
37+
IConfigurationReader configReader = new ConfigurationReader(_section, _configurationAssemblies, resolutionContext);
4138

4239
if (configType == typeof(LoggerConfiguration))
4340
{
@@ -46,7 +43,7 @@ public object ConvertTo(Type toType, SettingValueResolver valueResolver)
4643

4744
if (configType == typeof(LoggerSinkConfiguration))
4845
{
49-
return new Action<LoggerSinkConfiguration>(loggerSinkConfig => configReader.ApplySinks(loggerSinkConfig, valueResolver));
46+
return new Action<LoggerSinkConfiguration>(loggerSinkConfig => configReader.ApplySinks(loggerSinkConfig));
5047
}
5148
}
5249

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using Microsoft.Extensions.Configuration;
4+
5+
using Serilog.Core;
6+
7+
namespace Serilog.Settings.Configuration
8+
{
9+
/// <summary>
10+
/// Keeps track of available elements that are useful when resolving values in the settings system.
11+
/// </summary>
12+
sealed class ResolutionContext
13+
{
14+
readonly IDictionary<string, LoggingLevelSwitch> _declaredLevelSwitches;
15+
readonly IConfiguration _appConfiguration;
16+
17+
public ResolutionContext(IConfiguration appConfiguration = null)
18+
{
19+
_declaredLevelSwitches = new Dictionary<string, LoggingLevelSwitch>();
20+
_appConfiguration = appConfiguration;
21+
}
22+
23+
/// <summary>
24+
/// Looks up a switch in the declared LoggingLevelSwitches
25+
/// </summary>
26+
/// <param name="switchName">the name of a switch to look up</param>
27+
/// <returns>the LoggingLevelSwitch registered with the name</returns>
28+
/// <exception cref="InvalidOperationException">if no switch has been registered with <paramref name="switchName"/></exception>
29+
public LoggingLevelSwitch LookUpSwitchByName(string switchName)
30+
{
31+
if (_declaredLevelSwitches.TryGetValue(switchName, out var levelSwitch))
32+
{
33+
return levelSwitch;
34+
}
35+
36+
throw new InvalidOperationException($"No LoggingLevelSwitch has been declared with name \"{switchName}\". You might be missing a section \"LevelSwitches\":{{\"{switchName}\":\"InitialLevel\"}}");
37+
}
38+
39+
public bool HasAppConfiguration => _appConfiguration != null;
40+
41+
public IConfiguration AppConfiguration
42+
{
43+
get
44+
{
45+
if (!HasAppConfiguration)
46+
{
47+
throw new InvalidOperationException("AppConfiguration is not available");
48+
}
49+
50+
return _appConfiguration;
51+
}
52+
}
53+
54+
public void AddLevelSwitch(string levelSwitchName, LoggingLevelSwitch levelSwitch)
55+
{
56+
if (levelSwitchName == null) throw new ArgumentNullException(nameof(levelSwitchName));
57+
if (levelSwitch == null) throw new ArgumentNullException(nameof(levelSwitch));
58+
_declaredLevelSwitches[levelSwitchName] = levelSwitch;
59+
}
60+
}
61+
}

0 commit comments

Comments
 (0)