Skip to content

Commit cef73eb

Browse files
snakefoot304NotModified
authored andcommitted
NLogLoggingConfiguration - Added support for default-wrapper, default-target-parameter & autoReload (#283)
* NLogLoggingConfiguration - Added support for default-wrapper and default-target-parameters * NLogLoggingConfiguration - Added support for AutoReload with LogFactory integration * Default wrapper and default target on root level * context * cleanuo * refactor * fix MemoryConfig * small refactor * fixup * casing tests * revert casing
1 parent 2b9b021 commit cef73eb

File tree

3 files changed

+316
-39
lines changed

3 files changed

+316
-39
lines changed

examples/NetCore2/ConsoleExample/Program.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
namespace ConsoleExample
99
{
10-
internal class Program
10+
internal static class Program
1111
{
1212
private static void Main()
1313
{

src/NLog.Extensions.Logging/Config/NLogLoggingConfiguration.cs

Lines changed: 226 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using System.Collections.Generic;
33
using System.Linq;
44
using Microsoft.Extensions.Configuration;
5+
using NLog.Common;
56
using NLog.Config;
67

78
namespace NLog.Extensions.Logging
@@ -11,10 +12,12 @@ namespace NLog.Extensions.Logging
1112
/// </summary>
1213
public class NLogLoggingConfiguration : LoggingConfigurationParser
1314
{
14-
private readonly Action<object> _reloadConfiguration;
15+
private readonly IConfigurationSection _originalConfigSection;
16+
private bool _autoReload;
17+
private Action<object> _reloadConfiguration;
1518

1619
/// <summary>
17-
/// Initializes a new instance of the <see cref="NLogLoggingConfiguration"/> class.
20+
/// Initializes a new instance of the <see cref="NLogLoggingConfiguration" /> class.
1821
/// </summary>
1922
/// <param name="nlogConfig">Configuration section to be read</param>
2023
public NLogLoggingConfiguration(IConfigurationSection nlogConfig)
@@ -23,106 +26,294 @@ public NLogLoggingConfiguration(IConfigurationSection nlogConfig)
2326
}
2427

2528
/// <summary>
26-
/// Initializes a new instance of the <see cref="NLogLoggingConfiguration"/> class.
29+
/// Initializes a new instance of the <see cref="NLogLoggingConfiguration" /> class.
2730
/// </summary>
2831
/// <param name="nlogConfig">Configuration section to be read</param>
29-
/// <param name="logFactory">The <see cref="LogFactory"/> to which to apply any applicable configuration values.</param>
32+
/// <param name="logFactory">The <see cref="LogFactory" /> to which to apply any applicable configuration values.</param>
3033
public NLogLoggingConfiguration(IConfigurationSection nlogConfig, LogFactory logFactory)
3134
: base(logFactory)
3235
{
33-
_reloadConfiguration = (state) => LoadConfigurationSection((IConfigurationSection)state, true);
34-
LoadConfigurationSection(nlogConfig, null);
36+
_originalConfigSection = nlogConfig;
37+
_autoReload = LoadConfigurationSection(nlogConfig);
3538
}
3639

37-
private void LoadConfigurationSection(IConfigurationSection nlogConfig, bool? autoReload)
40+
/// <summary>
41+
/// Gets the collection of file names which should be watched for changes by NLog.
42+
/// </summary>
43+
public override IEnumerable<string> FileNamesToWatch
44+
{
45+
get
46+
{
47+
if (_autoReload && _reloadConfiguration == null)
48+
{
49+
// Prepare for setting up reload notification handling
50+
_reloadConfiguration = state => ReloadConfigurationSection((IConfigurationSection) state);
51+
LogFactory.ConfigurationChanged += LogFactory_ConfigurationChanged;
52+
}
53+
54+
return Enumerable.Empty<string>();
55+
}
56+
}
57+
58+
/// <inheritdoc />
59+
public override LoggingConfiguration Reload()
60+
{
61+
return new NLogLoggingConfiguration(_originalConfigSection, LogFactory);
62+
}
63+
64+
private bool LoadConfigurationSection(IConfigurationSection nlogConfig)
3865
{
39-
var configElement = new LoggingConfigurationElement(nlogConfig, true);
66+
var configElement = new LoggingConfigurationElement(nlogConfig, new LoggingConfigurationElementContext(), true);
4067
LoadConfig(configElement, null);
41-
if (autoReload ?? configElement.AutoReload)
68+
return configElement.AutoReload;
69+
}
70+
71+
private void LogFactory_ConfigurationChanged(object sender, LoggingConfigurationChangedEventArgs e)
72+
{
73+
if (ReferenceEquals(e.DeactivatedConfiguration, this))
74+
{
75+
if (_autoReload)
76+
{
77+
_autoReload = false; // Cannot unsubscribe to reload event, but we can stop reacting to it
78+
LogFactory.ConfigurationChanged -= LogFactory_ConfigurationChanged;
79+
}
80+
}
81+
else if (ReferenceEquals(e.ActivatedConfiguration, this) && _autoReload && _reloadConfiguration != null)
82+
{
83+
// Setup reload notification
84+
LogFactory.ConfigurationChanged += LogFactory_ConfigurationChanged;
85+
MonitorForReload(_originalConfigSection);
86+
}
87+
}
88+
89+
private void ReloadConfigurationSection(IConfigurationSection nlogConfig)
90+
{
91+
try
92+
{
93+
if (!_autoReload)
94+
{
95+
return; // Should no longer react to reload events
96+
}
97+
98+
InternalLogger.Info("Reloading NLogLoggingConfiguration...");
99+
var newConfig = new NLogLoggingConfiguration(nlogConfig, LogFactory);
100+
if (LogFactory.Configuration != null)
101+
{
102+
LogFactory.Configuration = newConfig;
103+
}
104+
}
105+
catch (Exception ex)
42106
{
43-
nlogConfig.GetReloadToken().RegisterChangeCallback(_reloadConfiguration, nlogConfig);
107+
InternalLogger.Warn(ex, "NLogLoggingConfiguration failed to reload");
108+
MonitorForReload(nlogConfig); // Continue watching this file
44109
}
45110
}
46111

112+
private void MonitorForReload(IConfigurationSection nlogConfig)
113+
{
114+
nlogConfig.GetReloadToken().RegisterChangeCallback(_reloadConfiguration, nlogConfig);
115+
}
116+
117+
private class LoggingConfigurationElementContext
118+
{
119+
public IConfigurationSection DefaultTargetParametersSection;
120+
public IConfigurationSection DefaultWrapperSection;
121+
}
122+
47123
private class LoggingConfigurationElement : ILoggingConfigurationElement
48124
{
49-
private const string VariablesKey = "Variables";
50-
private const string VariableKey = "Variable";
51125
private const string TargetKey = "target";
126+
private const string DefaultTargetParameters = "Default-target-parameters";
127+
private const string VariableKey = "Variable";
128+
private const string DefaultWrapper = "Default-wrapper";
52129
private readonly IConfigurationSection _configurationSection;
130+
private readonly LoggingConfigurationElementContext _context;
53131
private readonly string _nameOverride;
54132
private readonly bool _topElement;
55133

56-
public string Name => _nameOverride ?? _configurationSection.Key;
57-
public IEnumerable<KeyValuePair<string, string>> Values => GetValues();
58-
public IEnumerable<ILoggingConfigurationElement> Children => GetChildren();
59-
public bool AutoReload { get; }
60-
61-
public LoggingConfigurationElement(IConfigurationSection configurationSection, bool topElement, string nameOverride = null)
134+
public LoggingConfigurationElement(IConfigurationSection configurationSection, LoggingConfigurationElementContext context, bool topElement, string nameOverride = null)
62135
{
63136
_configurationSection = configurationSection;
137+
_context = context;
64138
_nameOverride = nameOverride;
65139
_topElement = topElement;
66-
if (topElement)
140+
if (topElement && bool.TryParse(configurationSection["autoreload"], out var autoreload))
67141
{
68-
if (bool.TryParse(configurationSection["autoreload"], out var autoreload))
69-
{
70-
AutoReload = autoreload;
71-
}
142+
AutoReload = autoreload;
72143
}
73144
}
74145

146+
public bool AutoReload { get; }
147+
148+
public string Name => _nameOverride ?? _configurationSection.Key;
149+
public IEnumerable<KeyValuePair<string, string>> Values => GetValues();
150+
public IEnumerable<ILoggingConfigurationElement> Children => GetChildren();
151+
75152
private IEnumerable<KeyValuePair<string, string>> GetValues()
76153
{
77154
var children = _configurationSection.GetChildren();
78155
foreach (var child in children)
79156
{
80157
if (!child.GetChildren().Any())
158+
{
81159
yield return new KeyValuePair<string, string>(child.Key, child.Value);
160+
}
82161
}
162+
83163
if (_nameOverride != null)
84164
{
85-
yield return new KeyValuePair<string, string>("name", _configurationSection.Key);
165+
if (ReferenceEquals(_nameOverride, DefaultTargetParameters))
166+
{
167+
yield return new KeyValuePair<string, string>("type", _configurationSection.Key);
168+
}
169+
else
170+
{
171+
yield return new KeyValuePair<string, string>("name", _configurationSection.Key);
172+
}
173+
86174
if (ReferenceEquals(_nameOverride, VariableKey))
175+
{
87176
yield return new KeyValuePair<string, string>("value", _configurationSection.Value);
177+
}
88178
}
89179
}
90180

91181
private IEnumerable<ILoggingConfigurationElement> GetChildren()
92182
{
93-
var variables = _topElement ? _configurationSection.GetSection(VariablesKey) : null;
183+
var variables = GetVariablesSection();
94184
if (variables != null)
95185
{
96186
foreach (var variable in variables.GetChildren())
97-
yield return new LoggingConfigurationElement(variable, false, VariableKey);
187+
{
188+
yield return new LoggingConfigurationElement(variable, _context, false, VariableKey);
189+
}
190+
}
191+
192+
var targetsSection = !_topElement && _nameOverride == null && _configurationSection.Key.EqualsOrdinalIgnoreCase("targets");
193+
var defaultWrapper = GetDefaultWrapperSection();
194+
if (defaultWrapper != null)
195+
{
196+
_context.DefaultWrapperSection = defaultWrapper;
197+
}
198+
199+
var defaultTargetParameters = GetDefaultTargetParametersSection();
200+
if (defaultTargetParameters != null)
201+
{
202+
_context.DefaultTargetParametersSection = defaultTargetParameters;
203+
}
204+
if (targetsSection)
205+
{
206+
foreach (var loggingConfigurationElement in YieldCapturedContextSections())
207+
{
208+
yield return loggingConfigurationElement;
209+
}
98210
}
99211

100212
var children = _configurationSection.GetChildren();
101213
foreach (var child in children)
102214
{
103215
var firstChildValue = child?.GetChildren()?.FirstOrDefault();
104216
if (firstChildValue == null)
105-
continue; // Simple value without children
217+
{
218+
continue; // Simple value without children
219+
}
106220

107-
if (_nameOverride == TargetKey && child.Key.EqualsOrdinalIgnoreCase(TargetKey) && child.GetChildren().Count() == 1)
221+
if (IsTargetWithinWrapper(child))
108222
{
109-
// Target-config inside Wrapper-Target
110-
yield return new LoggingConfigurationElement(firstChildValue, false, TargetKey);
223+
yield return new LoggingConfigurationElement(firstChildValue, _context, false, TargetKey);
111224
}
112225
else
113226
{
114-
if (variables != null && string.Equals(child.Key, VariablesKey, StringComparison.OrdinalIgnoreCase))
227+
string nameOverride = null;
228+
if (AlreadReadChild(child, variables, defaultWrapper, defaultTargetParameters))
229+
{
115230
continue;
231+
}
116232

117-
string nameOverride = null;
118-
if (_configurationSection.Key.EqualsOrdinalIgnoreCase("targets"))
233+
if (targetsSection)
119234
{
120235
nameOverride = TargetKey;
121236
}
122-
yield return new LoggingConfigurationElement(child, false, nameOverride);
237+
238+
yield return new LoggingConfigurationElement(child, _context, false, nameOverride);
123239
}
124240
}
125241
}
242+
243+
private IEnumerable<ILoggingConfigurationElement> YieldCapturedContextSections()
244+
{
245+
if (_context.DefaultWrapperSection != null)
246+
{
247+
yield return new LoggingConfigurationElement(_context.DefaultWrapperSection, _context, true, DefaultWrapper);
248+
_context.DefaultWrapperSection = null;
249+
}
250+
251+
if (_context.DefaultTargetParametersSection != null)
252+
{
253+
foreach (var targetParameters in _context.DefaultTargetParametersSection.GetChildren())
254+
{
255+
yield return new LoggingConfigurationElement(targetParameters, _context, true, DefaultTargetParameters);
256+
}
257+
258+
_context.DefaultTargetParametersSection = null;
259+
}
260+
}
261+
262+
/// <summary>
263+
/// Target-config inside Wrapper-Target
264+
/// </summary>
265+
/// <param name="child"></param>
266+
/// <returns></returns>
267+
private bool IsTargetWithinWrapper(IConfigurationSection child)
268+
{
269+
return _nameOverride == TargetKey && child.Key.EqualsOrdinalIgnoreCase(TargetKey) && child.GetChildren().Count() == 1;
270+
}
271+
272+
private bool AlreadReadChild(IConfigurationSection child, IConfigurationSection variables, IConfigurationSection defaultWrapper, IConfigurationSection defaultTargetParameters)
273+
{
274+
if (variables != null && child.Key.EqualsOrdinalIgnoreCase(variables.Key))
275+
{
276+
return true;
277+
}
278+
279+
if (_topElement)
280+
{
281+
if (defaultWrapper != null && child.Key.EqualsOrdinalIgnoreCase(defaultWrapper.Key))
282+
{
283+
return true;
284+
}
285+
286+
if (defaultTargetParameters != null && child.Key.EqualsOrdinalIgnoreCase(defaultTargetParameters.Key))
287+
{
288+
return true;
289+
}
290+
}
291+
292+
return false;
293+
}
294+
295+
private IConfigurationSection GetVariablesSection()
296+
{
297+
var variables = _topElement ? _configurationSection.GetSection("Variables") : null;
298+
return variables;
299+
}
300+
301+
private IConfigurationSection GetDefaultTargetParametersSection()
302+
{
303+
var defaultTargetParameters = _topElement ? _configurationSection.GetSection(DefaultTargetParameters) : null;
304+
return defaultTargetParameters;
305+
}
306+
307+
private IConfigurationSection GetDefaultWrapperSection()
308+
{
309+
var defaultWrapper = _topElement ? _configurationSection.GetSection(DefaultWrapper) : null;
310+
if (defaultWrapper != null && defaultWrapper.GetChildren().Any())
311+
{
312+
return defaultWrapper;
313+
}
314+
315+
return null;
316+
}
126317
}
127318
}
128-
}
319+
}

0 commit comments

Comments
 (0)