Skip to content

Commit

Permalink
Configure NLogProviderOptions from HostBuilder Configuration for Remo…
Browse files Browse the repository at this point in the history
…veLoggerFactoryFilter and ReplaceLoggerFactory
  • Loading branch information
snakefoot committed Mar 24, 2022
1 parent 9ed8683 commit 766d605
Show file tree
Hide file tree
Showing 5 changed files with 96 additions and 71 deletions.
31 changes: 4 additions & 27 deletions src/NLog.Extensions.Hosting/Extensions/ConfigureExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,29 +42,16 @@ public static IHostBuilder UseNLog(this IHostBuilder builder, NLogProviderOption
return builder;
}

private static void AddNLogLoggerProvider(IServiceCollection services, IConfiguration configuration, IHostEnvironment hostEnvironment, NLogProviderOptions options, Func<IServiceProvider, IConfiguration, IHostEnvironment, NLogProviderOptions, NLogLoggerProvider> factory)
private static void AddNLogLoggerProvider(IServiceCollection services, IConfiguration hostConfiguration, IHostEnvironment hostEnvironment, NLogProviderOptions options, Func<IServiceProvider, IConfiguration, IHostEnvironment, NLogProviderOptions, NLogLoggerProvider> factory)
{
ConfigurationItemFactory.Default.RegisterItemsFromAssembly(typeof(ConfigureExtensions).GetTypeInfo().Assembly);
LogManager.AddHiddenAssembly(typeof(ConfigureExtensions).GetTypeInfo().Assembly);
services.TryAddNLogLoggingProvider((svc, addlogging) => svc.AddLogging(addlogging), configuration, options, (provider, cfg, opt) => factory(provider, cfg, hostEnvironment, opt));
services.TryAddNLogLoggingProvider((svc, addlogging) => svc.AddLogging(addlogging), hostConfiguration, options ?? new NLogProviderOptions(), (provider, cfg, opt) => factory(provider, cfg, hostEnvironment, opt));
}

private static NLogLoggerProvider CreateNLogLoggerProvider(IServiceProvider serviceProvider, IConfiguration configuration, IHostEnvironment hostEnvironment, NLogProviderOptions options)
private static NLogLoggerProvider CreateNLogLoggerProvider(IServiceProvider serviceProvider, IConfiguration hostConfiguration, IHostEnvironment hostEnvironment, NLogProviderOptions options)
{
NLogLoggerProvider provider = new NLogLoggerProvider(options);

configuration = SetupConfiguration(serviceProvider, configuration);

if (serviceProvider != null && provider.Options.RegisterServiceProvider)
{
provider.LogFactory.ServiceRepository.RegisterService(typeof(IServiceProvider), serviceProvider);
}

if (configuration != null)
{
provider.Configure(configuration.GetSection("Logging:NLog"));
provider.TryLoadConfigurationFromSection(configuration);
}
NLogLoggerProvider provider = RegisterNLogLoggingProvider.CreateNLogLoggerProvider(serviceProvider, hostConfiguration, options, null);

var contentRootPath = hostEnvironment?.ContentRootPath;
if (!string.IsNullOrEmpty(contentRootPath))
Expand All @@ -80,16 +67,6 @@ private static NLogLoggerProvider CreateNLogLoggerProvider(IServiceProvider serv
return provider;
}

private static IConfiguration SetupConfiguration(IServiceProvider serviceProvider, IConfiguration configuration)
{
configuration = configuration ?? (serviceProvider?.GetService(typeof(IConfiguration)) as IConfiguration);
if (configuration != null)
{
ConfigSettingLayoutRenderer.DefaultConfiguration = configuration;
}
return configuration;
}

private static void TryLoadConfigurationFromContentRootPath(LogFactory logFactory, string contentRootPath)
{
logFactory.Setup().LoadConfiguration(config =>
Expand Down
64 changes: 27 additions & 37 deletions src/NLog.Extensions.Logging/Extensions/ConfigureExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,8 @@ public static ILoggingBuilder AddNLog(this ILoggingBuilder builder, Func<IServic
{
AddNLogLoggerProvider(builder, null, null, (serviceProvider, config, options) =>
{
config = SetupConfiguration(serviceProvider, config);
RegisterNLogLoggingProvider.SetupConfiguration(serviceProvider, config);

// Delay initialization of targets until we have loaded config-settings
var logFactory = factoryBuilder(serviceProvider);
var provider = CreateNLogLoggerProvider(serviceProvider, config, options, logFactory);
Expand All @@ -177,9 +178,9 @@ public static ILoggingBuilder AddNLog(this ILoggingBuilder builder, Func<IServic
return builder;
}

private static void AddNLogLoggerProvider(ILoggingBuilder builder, IConfiguration configuration, NLogProviderOptions options, Func<IServiceProvider, IConfiguration, NLogProviderOptions, NLogLoggerProvider> factory)
private static void AddNLogLoggerProvider(ILoggingBuilder builder, IConfiguration hostConfiguration, NLogProviderOptions options, Func<IServiceProvider, IConfiguration, NLogProviderOptions, NLogLoggerProvider> factory)
{
builder.Services.TryAddNLogLoggingProvider((svc, addlogging) => addlogging(builder), configuration, options ?? NLogProviderOptions.Default, factory);
builder.Services.TryAddNLogLoggingProvider((svc, addlogging) => addlogging(builder), hostConfiguration, options ?? NLogProviderOptions.Default, factory);
}
#endif

Expand Down Expand Up @@ -218,62 +219,51 @@ public static LoggingConfiguration ConfigureNLog(this ILoggerFactory loggerFacto
/// <returns></returns>
public static NLogLoggerProvider Configure(this NLogLoggerProvider nlogProvider, IConfigurationSection configurationSection)
{
if (configurationSection == null)
if (nlogProvider == null || configurationSection == null)
return nlogProvider;

var configProps = nlogProvider.Options.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public).Where(p => p.SetMethod?.IsPublic == true).ToDictionary(p => p.Name, StringComparer.OrdinalIgnoreCase);
Configure(nlogProvider.Options, configurationSection);
return nlogProvider;
}

/// <summary>
/// Factory method for <see cref="NLogProviderOptions"/>
/// </summary>
/// <param name="nlogProviderOptions"></param>
/// <param name="configurationSection">Microsoft Extension Configuration</param>
/// <returns></returns>
public static NLogProviderOptions Configure(this NLogProviderOptions nlogProviderOptions, IConfigurationSection configurationSection)
{
if (nlogProviderOptions == null || configurationSection == null || !(configurationSection.GetChildren()?.Any() ?? false))
return nlogProviderOptions ?? NLogProviderOptions.Default;

var configProps = nlogProviderOptions.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public).Where(p => p.SetMethod?.IsPublic == true).ToDictionary(p => p.Name, StringComparer.OrdinalIgnoreCase);
foreach (var configValue in configurationSection.GetChildren())
{
if (configProps.TryGetValue(configValue.Key, out var propertyInfo))
{
try
{
var result = Convert.ChangeType(configValue.Value, propertyInfo.PropertyType, System.Globalization.CultureInfo.InvariantCulture);
propertyInfo.SetMethod.Invoke(nlogProvider.Options, new[] { result });
propertyInfo.SetMethod.Invoke(nlogProviderOptions, new[] { result });
}
catch (Exception ex)
{
InternalLogger.Warn(ex, "NLogProviderOptions: Property {0} could not be assigned value: {1}", configValue.Key, configValue.Value);
}
}
}

return nlogProvider;
return nlogProviderOptions;
}

private static NLogLoggerProvider CreateNLogLoggerProvider(IServiceProvider serviceProvider, IConfiguration configuration, NLogProviderOptions options)
private static NLogLoggerProvider CreateNLogLoggerProvider(IServiceProvider serviceProvider, IConfiguration hostConfiguration, NLogProviderOptions options)
{
return CreateNLogLoggerProvider(serviceProvider, configuration, options, null);
return CreateNLogLoggerProvider(serviceProvider, hostConfiguration, options, null);
}

private static NLogLoggerProvider CreateNLogLoggerProvider(IServiceProvider serviceProvider, IConfiguration configuration, NLogProviderOptions options, LogFactory logFactory)
private static NLogLoggerProvider CreateNLogLoggerProvider(IServiceProvider serviceProvider, IConfiguration hostConfiguration, NLogProviderOptions options, LogFactory logFactory)
{
NLogLoggerProvider provider = new NLogLoggerProvider(options ?? NLogProviderOptions.Default, logFactory ?? LogManager.LogFactory);

configuration = SetupConfiguration(serviceProvider, configuration);

if (serviceProvider != null && provider.Options.RegisterServiceProvider)
{
provider.LogFactory.ServiceRepository.RegisterService(typeof(IServiceProvider), serviceProvider);
}

if (configuration != null)
{
provider.Configure(configuration.GetSection("Logging:NLog"));
provider.TryLoadConfigurationFromSection(configuration);
}

return provider;
}

private static IConfiguration SetupConfiguration(IServiceProvider serviceProvider, IConfiguration configuration)
{
configuration = configuration ?? (serviceProvider?.GetService(typeof(IConfiguration)) as IConfiguration);
if (configuration != null)
{
ConfigSettingLayoutRenderer.DefaultConfiguration = configuration;
}
return configuration;
return RegisterNLogLoggingProvider.CreateNLogLoggerProvider(serviceProvider, hostConfiguration, options, logFactory);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,22 +12,27 @@
internal static class RegisterNLogLoggingProvider
{
#if !NETCORE1_0
internal static void TryAddNLogLoggingProvider(this IServiceCollection services, Action<IServiceCollection, Action<ILoggingBuilder>> addLogging, IConfiguration configuration, NLogProviderOptions options, Func<IServiceProvider, IConfiguration, NLogProviderOptions, NLogLoggerProvider> factory)
internal static void TryAddNLogLoggingProvider(this IServiceCollection services, Action<IServiceCollection, Action<ILoggingBuilder>> addLogging, IConfiguration hostConfiguration, NLogProviderOptions options, Func<IServiceProvider, IConfiguration, NLogProviderOptions, NLogLoggerProvider> factory)
{
var sharedFactory = factory;

if (options?.ReplaceLoggerFactory == true)
if (hostConfiguration != null)
{
options.Configure(hostConfiguration.GetSection("Logging:NLog"));
}

if (options.ReplaceLoggerFactory)
{
NLogLoggerProvider singleInstance = null; // Ensure that registration of ILoggerFactory and ILoggerProvider shares the same single instance
sharedFactory = (provider, cfg, opt) => singleInstance ?? (singleInstance = factory(provider, cfg, opt));

addLogging?.Invoke(services, (builder) => builder?.ClearProviders()); // Cleanup the existing LoggerFactory, before replacing it with NLogLoggerFactory
services.Replace(ServiceDescriptor.Singleton<ILoggerFactory, NLogLoggerFactory>(serviceProvider => new NLogLoggerFactory(sharedFactory(serviceProvider, configuration, options))));
services.Replace(ServiceDescriptor.Singleton<ILoggerFactory, NLogLoggerFactory>(serviceProvider => new NLogLoggerFactory(sharedFactory(serviceProvider, hostConfiguration, options))));
}

services.TryAddEnumerable(ServiceDescriptor.Singleton<ILoggerProvider, NLogLoggerProvider>(serviceProvider => sharedFactory(serviceProvider, configuration, options)));
services.TryAddEnumerable(ServiceDescriptor.Singleton<ILoggerProvider, NLogLoggerProvider>(serviceProvider => sharedFactory(serviceProvider, hostConfiguration, options)));

if (options?.RemoveLoggerFactoryFilter == true)
if (options.RemoveLoggerFactoryFilter)
{
// Will forward all messages to NLog if not specifically overridden by user
addLogging?.Invoke(services, (builder) => builder?.AddFilter<NLogLoggerProvider>(null, Microsoft.Extensions.Logging.LogLevel.Trace));
Expand Down Expand Up @@ -56,5 +61,39 @@ internal static void TryLoadConfigurationFromSection(this NLogLoggerProvider log
Common.InternalLogger.Debug("Skip loading NLogLoggingConfiguration from empty config section: {0}", loggerProvider.Options.LoggingConfigurationSectionName);
}
}

internal static NLogLoggerProvider CreateNLogLoggerProvider(IServiceProvider serviceProvider, IConfiguration hostConfiguration, NLogProviderOptions options, LogFactory logFactory)
{
var provider = new NLogLoggerProvider(options, logFactory);

var configuration = SetupConfiguration(serviceProvider, hostConfiguration);

if (configuration != null && (!ReferenceEquals(configuration, hostConfiguration) || options == null))
{
provider.Configure(configuration.GetSection("Logging:NLog"));
}

if (serviceProvider != null && provider.Options.RegisterServiceProvider)
{
provider.LogFactory.ServiceRepository.RegisterService(typeof(IServiceProvider), serviceProvider);
}

if (configuration != null)
{
provider.TryLoadConfigurationFromSection(configuration);
}

return provider;
}

internal static IConfiguration SetupConfiguration(IServiceProvider serviceProvider, IConfiguration configuration)
{
configuration = configuration ?? (serviceProvider?.GetService(typeof(IConfiguration)) as IConfiguration);
if (configuration != null)
{
ConfigSettingLayoutRenderer.DefaultConfiguration = configuration;
}
return configuration;
}
}
}
2 changes: 0 additions & 2 deletions src/NLog.Extensions.Logging/Logging/NLogProviderOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -80,13 +80,11 @@ public class NLogProviderOptions
/// <summary>
/// Resets the default Microsoft LoggerFactory Filter for the <see cref="NLogLoggerProvider"/>, and instead only uses NLog LoggingRules.
/// </summary>
/// <remarks>This option affects the building of service configuration, so assigning it from appsettings.json has no effect (loaded after).</remarks>
public bool RemoveLoggerFactoryFilter { get; set; } = true;

/// <summary>
/// Replace Microsoft LoggerFactory with a pure <see cref="NLogLoggerFactory" />, and disables Microsoft Filter Logic and removes other LoggingProviders.
/// </summary>
/// <remarks>This option affects the building of service configuration, so assigning it from appsettings.json has no effect (loaded after).</remarks>
public bool ReplaceLoggerFactory { get; set; }

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using Xunit;
using Microsoft.Extensions.DependencyInjection;
using System.Collections.Generic;
using Microsoft.Extensions.Configuration;

namespace NLog.Extensions.Logging.Tests.Extensions
{
Expand Down Expand Up @@ -157,6 +158,26 @@ public void AddNLog_ReplaceLoggerFactory()
Assert.Equal(typeof(NLogLoggerProvider), loggerProvider.GetType());
}

[Fact]
public void AddNLog_WithConfig_ReplaceLoggerFactory()
{
// Arrange
ILoggingBuilder builder = new LoggingBuilderStub();
var memoryConfig = new Dictionary<string, string>();
memoryConfig["Logging:NLog:ReplaceLoggerFactory"] = "True";
memoryConfig["Logging:NLog:RemoveLoggerFactoryFilter"] = "True";
var configuration = new ConfigurationBuilder().AddInMemoryCollection(memoryConfig).Build();

// Act
builder.AddNLog(configuration);
var loggerFactory = builder.Services.BuildServiceProvider().GetService<ILoggerFactory>();
var loggerProvider = GetLoggerProvider(builder);

// Assert
Assert.Equal(typeof(NLogLoggerFactory), loggerFactory.GetType());
Assert.Equal(typeof(NLogLoggerProvider), loggerProvider.GetType());
}

private static ILoggerProvider GetLoggerProvider(ILoggingBuilder builder)
{
var services = builder.Services;
Expand Down

0 comments on commit 766d605

Please sign in to comment.