Created
March 29, 2018 11:16
-
-
Save ti24horas/30a0dfc81b3f2a233546af64a7edfabe to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
internal class ConfigurableLoggerFiltering : IFilterLoggerSettings | |
{ | |
private CancellationTokenSource cts; | |
private IChangeToken token; | |
private List<(string category, LogLevel level)> levels = new List<(string category, LogLevel level)>(); | |
public ConfigurableLoggerFiltering() | |
{ | |
this.Reload(); | |
} | |
public void Change(string key, LogLevel level) | |
{ | |
var list = levels.ToList(); | |
var exists = list.Where((s, idx) => string.Equals(s.category, key, StringComparison.OrdinalIgnoreCase)).Select((s, ix) => ix).ToArray(); | |
if (list.Any()) | |
{ | |
list.RemoveAt(exists.First()); | |
} | |
list.Add((key, level)); | |
Interlocked.Exchange(ref this.levels, list); | |
this.Reload(); | |
} | |
public bool TryGetSwitch(string name, out LogLevel level) | |
{ | |
var list = this.levels.FirstOrDefault(s => s.category.StartsWith(name)); | |
if (list.category == null) | |
{ | |
list = this.levels.FirstOrDefault(s => s.category == "Default"); | |
if (list.category == null) | |
{ | |
level = LogLevel.None; | |
return false; | |
} | |
level = list.level; | |
return true; | |
} | |
level = list.level; | |
return true; | |
} | |
public IFilterLoggerSettings Reload() | |
{ | |
var old = Interlocked.Exchange(ref this.cts, new CancellationTokenSource()); | |
Interlocked.Exchange(ref this.token, new CancellationChangeToken(cts.Token)); | |
old?.Cancel(); | |
return this; | |
} | |
public IChangeToken ChangeToken => this.token; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public static class ServiceCollectionExtensions | |
{ | |
public static KeyedServicesConfiguration<TKey, TService> AddKeyedServiceProvider<TKey, TService>( | |
this IServiceCollection services) | |
{ | |
services.TryAddSingleton<IKeyedServiceProvider<TKey, TService>, KeyedServiceProvider<TKey, TService>>(); | |
return new KeyedServicesConfiguration<TKey, TService>(services); | |
} | |
public class KeyedServicesConfiguration<TKey, TService> | |
{ | |
private readonly IServiceCollection _services; | |
public KeyedServicesConfiguration(IServiceCollection services) | |
{ | |
_services = services; | |
} | |
public KeyedServicesConfiguration<TKey, TService> AddSingleton<TImpl>(TKey key) | |
where TImpl : class, TService | |
{ | |
_services.TryAddSingleton<TImpl>(); | |
_services.TryAddSingleton(sp => new KeyedService<TKey, TService>(key, sp.GetRequiredService<TImpl>)); | |
return this; | |
} | |
public KeyedServicesConfiguration<TKey, TService> AddTransient<TImpl>(TKey key) | |
where TImpl : class, TService | |
{ | |
_services.TryAddTransient<TImpl>(); | |
_services.TryAddSingleton(sp => new KeyedService<TKey, TService>(key, sp.GetRequiredService<TImpl>)); | |
return this; | |
} | |
public KeyedServicesConfiguration<TKey, TService> AddScoped<TImpl>(TKey key) | |
where TImpl : class, TService | |
{ | |
_services.TryAddScoped<TImpl>(); | |
_services.TryAddSingleton(sp => new KeyedService<TKey, TService>(key, sp.GetRequiredService<TImpl>)); | |
return this; | |
} | |
public KeyedServicesConfiguration<TKey, TService> Add<TImpl>(TKey key, TImpl instance) | |
where TImpl : class, TService | |
{ | |
_services.TryAddSingleton(instance); | |
_services.TryAddSingleton(sp => new KeyedService<TKey, TService>(key, sp.GetRequiredService<TImpl>)); | |
return this; | |
} | |
public KeyedServicesConfiguration<TKey, TService> Add<TImpl>(TKey key, Func<TKey, IServiceProvider, TImpl> constructor) | |
where TImpl : class, TService | |
{ | |
_services.TryAddTransient(sp => constructor(key, sp)); | |
_services.TryAddSingleton(sp => new KeyedService<TKey, TService>(key, sp.GetRequiredService<TImpl>)); | |
return this; | |
} | |
public KeyedServicesConfiguration<TKey, TService> Add<TImpl>(TKey key, Func<IServiceProvider, TImpl> constructor) | |
where TImpl : class, TService | |
{ | |
_services.TryAddTransient(sp => constructor(sp)); | |
_services.TryAddSingleton(sp => new KeyedService<TKey, TService>(key, sp.GetRequiredService<TImpl>)); | |
return this; | |
} | |
} | |
private class KeyedServiceProvider<TKey, TService> : IKeyedServiceProvider<TKey, TService> | |
{ | |
private readonly IDictionary<TKey, KeyedService<TKey, TService>> _providedServices; | |
public KeyedServiceProvider(IEnumerable<KeyedService<TKey, TService>> providedServices) | |
{ | |
_providedServices = providedServices.ToDictionary(s => s.Key); | |
} | |
public TService GetRequiredNamed(TKey key) | |
{ | |
return this._providedServices[key].GetService(); | |
} | |
} | |
private class KeyedService<TKey, TService> | |
{ | |
private readonly Func<TService> _implFunction; | |
public KeyedService(TKey key, Func<TService> implFunction) | |
{ | |
_implFunction = implFunction; | |
this.Key = key; | |
} | |
public TKey Key { get; } | |
public TService GetService() => this._implFunction(); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class ReloadableLoggerFactory : ILoggerFactory | |
{ | |
private readonly ILoggerFactory parent; | |
private readonly IFilterLoggerSettings settings; | |
public ReloadableLoggerFactory(ILoggerFactory parent, IFilterLoggerSettings settings) | |
{ | |
this.parent = parent; | |
this.settings = settings; | |
} | |
public void Dispose() | |
{ | |
this.parent.Dispose(); | |
} | |
public ILogger CreateLogger(string categoryName) | |
{ | |
return this.parent.CreateLogger(categoryName); | |
} | |
public void AddProvider(ILoggerProvider provider) | |
{ | |
this.parent.AddProvider(new FilteredLoggerProvider(provider, this.settings)); | |
} | |
private class FilteredLoggerProvider : ILoggerProvider | |
{ | |
private readonly ILoggerProvider _parent; | |
private readonly IFilterLoggerSettings _settings; | |
public FilteredLoggerProvider(ILoggerProvider parent, IFilterLoggerSettings settings) | |
{ | |
_parent = parent; | |
_settings = settings; | |
} | |
public void Dispose() | |
{ | |
this._parent.Dispose(); | |
} | |
public ILogger CreateLogger(string categoryName) | |
{ | |
return new FilteredLogger(categoryName, this._parent.CreateLogger(categoryName), this._settings); | |
} | |
private class FilteredLogger : ILogger | |
{ | |
private readonly ILogger _parent; | |
private readonly IFilterLoggerSettings _settings; | |
private LogLevel currentLevel; | |
private IDisposable disposable; | |
~FilteredLogger() | |
{ | |
this.disposable?.Dispose(); | |
} | |
public FilteredLogger(string category, ILogger parent, IFilterLoggerSettings settings) | |
{ | |
_parent = parent; | |
_settings = settings; | |
disposable = ChangeToken.OnChange(() => settings.ChangeToken, () => | |
{ | |
if (_settings.TryGetSwitch(category, out var result)) | |
{ | |
this.currentLevel = result; | |
} | |
else | |
{ | |
this.currentLevel = LogLevel.Trace; | |
} | |
}); | |
if (_settings.TryGetSwitch(category, out var v)) | |
{ | |
this.currentLevel = v; | |
} | |
else | |
{ | |
this.currentLevel = LogLevel.Trace; | |
} | |
} | |
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, | |
Func<TState, Exception, string> formatter) | |
{ | |
if (this.IsEnabled(logLevel)) | |
{ | |
this._parent.Log(logLevel, eventId, state, exception, formatter); | |
} | |
} | |
public bool IsEnabled(LogLevel logLevel) | |
{ | |
return logLevel >= currentLevel; | |
} | |
public IDisposable BeginScope<TState>(TState state) | |
{ | |
return this._parent.BeginScope(state); | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment