Skip to content
This repository was archived by the owner on Dec 13, 2018. It is now read-only.

Commit eecb8e2

Browse files
Make AddFilter chainable, add some doc comments, add UseConfiguration… (#597)
* Make AddFilter chainable, add some doc comments, add UseConfiguration to LoggerFactory
1 parent 0a00602 commit eecb8e2

File tree

4 files changed

+262
-198
lines changed

4 files changed

+262
-198
lines changed

samples/SampleApp/Program.cs

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -21,15 +21,16 @@ public Program()
2121
.AddJsonFile("logging.json", optional: false, reloadOnChange: true)
2222
.Build();
2323

24-
// A dependency injection based application would get ILoggerFactory injected instead.
24+
// A Web App based program would configure logging via the WebHostBuilder.
2525
// Create a logger factory with filters that can be applied across all logger providers.
26-
var factory = new LoggerFactory(loggingConfiguration.GetSection("Logging"));
27-
factory.AddFilter(new Dictionary<string, LogLevel>
28-
{
29-
{ "Microsoft", LogLevel.Warning },
30-
{ "System", LogLevel.Warning },
31-
{ "SampleApp.Program", LogLevel.Debug }
32-
});
26+
var factory = new LoggerFactory()
27+
.UseConfiguration(loggingConfiguration.GetSection("Logging"))
28+
.AddFilter(new Dictionary<string, LogLevel>
29+
{
30+
{ "Microsoft", LogLevel.Warning },
31+
{ "System", LogLevel.Warning },
32+
{ "SampleApp.Program", LogLevel.Debug }
33+
});
3334

3435
// providers may be added to a LoggerFactory before any loggers are created
3536
#if NET46

src/Microsoft.Extensions.Logging/LoggerFactory.cs

Lines changed: 121 additions & 144 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,9 @@ public class LoggerFactory : ILoggerFactory
1818
private KeyValuePair<ILoggerProvider, string>[] _providers = new KeyValuePair<ILoggerProvider, string>[0];
1919
private readonly object _sync = new object();
2020
private volatile bool _disposed;
21-
private readonly IConfiguration _configuration;
21+
private IConfiguration _configuration;
2222
private IChangeToken _changeToken;
23+
private IDisposable _changeTokenRegistration;
2324
private Dictionary<string, LogLevel> _defaultFilter;
2425
private Func<string, string, LogLevel, bool> _genericFilters;
2526
private Dictionary<string, Func<string, LogLevel, bool>> _providerFilters = new Dictionary<string, Func<string, LogLevel, bool>>();
@@ -41,11 +42,40 @@ public LoggerFactory(IConfiguration configuration)
4142
throw new ArgumentNullException(nameof(configuration));
4243
}
4344

45+
UseConfiguration(configuration);
46+
}
47+
48+
/// <summary>
49+
/// Replaces the <see cref="IConfiguration"/> used for filtering.
50+
/// </summary>
51+
/// <param name="configuration">The new configuration to use.</param>
52+
/// <returns>The <see cref="LoggerFactory"/> so that additional calls can be chained.</returns>
53+
public LoggerFactory UseConfiguration(IConfiguration configuration)
54+
{
55+
if (configuration == _configuration)
56+
{
57+
return this;
58+
}
59+
60+
// unregister the previous configuration callback if there was one
61+
_changeTokenRegistration?.Dispose();
62+
4463
_configuration = configuration;
45-
_changeToken = configuration.GetReloadToken();
46-
_changeToken.RegisterChangeCallback(OnConfigurationReload, null);
64+
65+
if (configuration == null)
66+
{
67+
_changeToken = null;
68+
_changeTokenRegistration = null;
69+
}
70+
else
71+
{
72+
_changeToken = _configuration.GetReloadToken();
73+
_changeTokenRegistration = _changeToken?.RegisterChangeCallback(OnConfigurationReload, null);
74+
}
4775

4876
LoadDefaultConfigValues();
77+
78+
return this;
4979
}
5080

5181
public ILogger CreateLogger(string categoryName)
@@ -132,8 +162,22 @@ public void AddProvider(string providerName, ILoggerProvider provider)
132162
}
133163
}
134164

135-
public void AddFilter(string providerName, string categoryName, Func<LogLevel, bool> filter)
165+
/// <summary>
166+
/// Adds a filter that applies to <paramref name="providerName"/> and <paramref name="categoryName"/> with the given
167+
/// <paramref name="filter"/>.
168+
/// </summary>
169+
/// <param name="providerName">The name of the provider.</param>
170+
/// <param name="categoryName">The name of the logger category.</param>
171+
/// <param name="filter">The filter that applies to logs for <paramref name="providerName"/> and <paramref name="categoryName"/>.
172+
/// Returning true means allow log through, false means reject log.</param>
173+
/// <returns>The <see cref="LoggerFactory"/> so that additional calls can be chained.</returns>
174+
public LoggerFactory AddFilter(string providerName, string categoryName, Func<LogLevel, bool> filter)
136175
{
176+
if (filter == null)
177+
{
178+
throw new ArgumentNullException(nameof(filter));
179+
}
180+
137181
lock (_sync)
138182
{
139183
if (_categoryFilters.TryGetValue(categoryName, out var previousFilter))
@@ -166,46 +210,25 @@ public void AddFilter(string providerName, string categoryName, Func<LogLevel, b
166210
};
167211
}
168212
}
213+
214+
return this;
169215
}
170216

171-
public void AddFilter(string providerName, string categoryName, LogLevel minLevel)
217+
/// <summary>
218+
/// Adds a filter that applies to <paramref name="providerName"/> with the given <paramref name="filter"/>.
219+
/// </summary>
220+
/// <param name="providerName">The name of the provider.</param>
221+
/// <param name="filter">The filter that applies to logs for <paramref name="providerName"/>.
222+
/// The string argument is the category being logged to.
223+
/// Returning true means allow log through, false means reject log.</param>
224+
/// <returns>The <see cref="LoggerFactory"/> so that additional calls can be chained.</returns>
225+
public LoggerFactory AddFilter(string providerName, Func<string, LogLevel, bool> filter)
172226
{
173-
lock (_sync)
227+
if (filter == null)
174228
{
175-
if (_categoryFilters.TryGetValue(categoryName, out var previousFilter))
176-
{
177-
_categoryFilters[categoryName] = (currentProviderName, level) =>
178-
{
179-
if (previousFilter(currentProviderName, level))
180-
{
181-
if (string.Equals(providerName, currentProviderName))
182-
{
183-
return level >= minLevel;
184-
}
185-
186-
return true;
187-
}
188-
189-
return false;
190-
};
191-
}
192-
else
193-
{
194-
_categoryFilters[categoryName] = (currentProviderName, level) =>
195-
{
196-
if (string.Equals(providerName, currentProviderName))
197-
{
198-
return level >= minLevel;
199-
}
200-
201-
return true;
202-
};
203-
}
229+
throw new ArgumentNullException(nameof(filter));
204230
}
205-
}
206231

207-
public void AddFilter(string providerName, Func<string, LogLevel, bool> filter)
208-
{
209232
lock (_sync)
210233
{
211234
if (_providerFilters.TryGetValue(providerName, out var value))
@@ -225,46 +248,24 @@ public void AddFilter(string providerName, Func<string, LogLevel, bool> filter)
225248
_providerFilters[providerName] = (category, level) => filter(category, level);
226249
}
227250
}
251+
252+
return this;
228253
}
229254

230-
public void AddFilter(string providerName, Func<LogLevel, bool> filter)
255+
/// <summary>
256+
/// Adds a filter that applies to all logs.
257+
/// </summary>
258+
/// <param name="filter">The filter that applies to logs.
259+
/// The first string is the provider name and the second string is the category name being logged to.
260+
/// Returning true means allow log through, false means reject log.</param>
261+
/// <returns>The <see cref="LoggerFactory"/> so that additional calls can be chained.</returns>
262+
public LoggerFactory AddFilter(Func<string, string, LogLevel, bool> filter)
231263
{
232-
lock (_sync)
264+
if (filter == null)
233265
{
234-
if (_categoryFilters.TryGetValue("Default", out var value))
235-
{
236-
_categoryFilters["Default"] = (currentProviderName, level) =>
237-
{
238-
if (value(currentProviderName, level))
239-
{
240-
if (string.Equals(providerName, currentProviderName))
241-
{
242-
return filter(level);
243-
}
244-
245-
return true;
246-
}
247-
248-
return false;
249-
};
250-
}
251-
else
252-
{
253-
_categoryFilters["Default"] = (currentProviderName, level) =>
254-
{
255-
if (string.Equals(providerName, currentProviderName))
256-
{
257-
return filter(level);
258-
}
259-
260-
return true;
261-
};
262-
}
266+
throw new ArgumentNullException(nameof(filter));
263267
}
264-
}
265268

266-
public void AddFilter(Func<string, string, LogLevel, bool> filter)
267-
{
268269
lock (_sync)
269270
{
270271
var previousFilters = _genericFilters;
@@ -278,10 +279,23 @@ public void AddFilter(Func<string, string, LogLevel, bool> filter)
278279
return false;
279280
};
280281
}
282+
283+
return this;
281284
}
282285

283-
public void AddFilter(IDictionary<string, LogLevel> filter)
286+
/// <summary>
287+
/// Adds a filter to all logs.
288+
/// </summary>
289+
/// <param name="filter">The filter that applies to logs.
290+
/// The key is the category and the <see cref="LogLevel"/> is the minimum level allowed.</param>
291+
/// <returns>The <see cref="LoggerFactory"/> so that additional calls can be chained.</returns>
292+
public LoggerFactory AddFilter(IDictionary<string, LogLevel> filter)
284293
{
294+
if (filter == null)
295+
{
296+
throw new ArgumentNullException(nameof(filter));
297+
}
298+
285299
lock (_sync)
286300
{
287301
foreach (var kvp in filter)
@@ -304,84 +318,39 @@ public void AddFilter(IDictionary<string, LogLevel> filter)
304318
}
305319
}
306320
}
321+
322+
return this;
307323
}
308324

309-
public void AddFilter(string providerName, IDictionary<string, LogLevel> filter)
325+
/// <summary>
326+
/// Adds a filter that applies to <paramref name="providerName"/> and <paramref name="categoryName"/>, allowing logs with the given
327+
/// minimum <see cref="LogLevel"/> or higher.
328+
/// </summary>
329+
/// <param name="providerName">The name of the provider.</param>
330+
/// <param name="categoryName">The name of the logger category.</param>
331+
/// <param name="minLevel">The minimum <see cref="LogLevel"/> that logs from
332+
/// <paramref name="providerName"/> and <paramref name="categoryName"/> are allowed.</param>
333+
public LoggerFactory AddFilter(string providerName, string categoryName, LogLevel minLevel)
310334
{
311-
lock (_sync)
312-
{
313-
foreach (var kvp in filter)
314-
{
315-
if (_categoryFilters.TryGetValue(kvp.Key, out var currentFilter))
316-
{
317-
_categoryFilters[kvp.Key] = (currentProviderName, level) =>
318-
{
319-
if (currentFilter(currentProviderName, level))
320-
{
321-
if (string.Equals(providerName, currentProviderName))
322-
{
323-
return level >= kvp.Value;
324-
}
325-
326-
return true;
327-
}
328-
329-
return false;
330-
};
331-
}
332-
else
333-
{
334-
_categoryFilters[kvp.Key] = (currentProviderName, level) =>
335-
{
336-
if (string.Equals(providerName, currentProviderName))
337-
{
338-
return level >= kvp.Value;
339-
}
340-
341-
return true;
342-
};
343-
}
344-
}
345-
}
335+
return AddFilter(providerName, categoryName, level => level >= minLevel);
346336
}
347337

348-
public void AddFilter(Func<string, bool> providerNames, IDictionary<string, LogLevel> filter)
338+
/// <summary>
339+
/// Adds a filter that applies to <paramref name="providerName"/> with the given
340+
/// <paramref name="filter"/>.
341+
/// </summary>
342+
/// <param name="providerName">The name of the provider.</param>
343+
/// <param name="filter">The filter that applies to logs for <paramref name="providerName"/>.
344+
/// Returning true means allow log through, false means reject log.</param>
345+
public LoggerFactory AddFilter(string providerName, Func<LogLevel, bool> filter)
349346
{
350-
lock (_sync)
347+
if (filter == null)
351348
{
352-
foreach (var kvp in filter)
353-
{
354-
if (_categoryFilters.TryGetValue(kvp.Key, out var currentFilter))
355-
{
356-
_categoryFilters[kvp.Key] = (providerName, level) =>
357-
{
358-
if (providerNames(providerName))
359-
{
360-
if (currentFilter(providerName, level))
361-
{
362-
return level >= kvp.Value;
363-
}
364-
365-
return false;
366-
}
367-
368-
return true;
369-
};
370-
}
371-
else
372-
{
373-
_categoryFilters[kvp.Key] = (providerName, level) =>
374-
{
375-
if (providerNames(providerName))
376-
{
377-
return level >= kvp.Value;
378-
}
379-
380-
return true;
381-
};
382-
}
383-
}
349+
throw new ArgumentNullException(nameof(filter));
384350
}
351+
352+
// Using 'Default' for the category name means this filter will apply for all category names
353+
return AddFilter(providerName, "Default", filter);
385354
}
386355

387356
// TODO: Figure out how to do this better, perhaps a new IConfigurableLogger interface?
@@ -479,7 +448,7 @@ private void OnConfigurationReload(object state)
479448
finally
480449
{
481450
// The token will change each time it reloads, so we need to register again.
482-
_changeToken.RegisterChangeCallback(OnConfigurationReload, null);
451+
_changeTokenRegistration = _changeToken.RegisterChangeCallback(OnConfigurationReload, null);
483452
}
484453
}
485454

@@ -519,6 +488,12 @@ private static IEnumerable<string> GetKeyPrefixes(string name)
519488
private void LoadDefaultConfigValues()
520489
{
521490
var replacementDefaultFilters = new Dictionary<string, LogLevel>();
491+
if (_configuration == null)
492+
{
493+
_defaultFilter = replacementDefaultFilters;
494+
return;
495+
}
496+
522497
var logLevelSection = _configuration.GetSection("LogLevel");
523498

524499
if (logLevelSection != null)
@@ -547,6 +522,8 @@ public void Dispose()
547522
{
548523
_disposed = true;
549524

525+
_changeTokenRegistration?.Dispose();
526+
550527
foreach (var provider in _providers)
551528
{
552529
try

0 commit comments

Comments
 (0)