Search code examples
c#nlog.net-5

How do I correctly add NLog to a .NET 5 Console App?


I am trying to add NLog to a .NET 5 console app.

I understand I will want to not hard code some of these settings, and link a appsettings file soon, but I jsut want to get everything logging first, with the bare minimum.

So far I have:

static void Main(string[] args)
{
    Console.WriteLine("Hello World!");

    var config = new LoggingConfiguration();

    var fileTarget = new FileTarget("fileTarget")
    {
        FileName = @"c:\AppLogs\TestApp\mylog-${shortdate}.log",
        Layout = "${longdate}|${event-properties:item=EventId_Id}|${uppercase:${level}}|${logger}|${message} ${exception:format=tostring}"
    };

    if (Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") == "Development")
    {
        fileTarget = new FileTarget("fileTarget")
        {
            FileName = @"c:\AppLogs\TestApp_UAT\mylog-${shortdate}.log",
            Layout = "${longdate}|${event-properties:item=EventId_Id}|${uppercase:${level}}|${logger}|${message} ${exception:format=tostring}"
        };
    }

    config.AddTarget(fileTarget);
    // rules
    config.AddRuleForOneLevel(NLog.LogLevel.Warn, fileTarget);
    config.AddRuleForOneLevel(NLog.LogLevel.Error, fileTarget);
    config.AddRuleForOneLevel(NLog.LogLevel.Fatal, fileTarget);
    LogManager.Configuration = config;

    var host = Host.CreateDefaultBuilder()
        .ConfigureServices((context, services) =>
        {
            services.AddTransient<TestService>();
        }).ConfigureLogging(logging =>
        {
            logging.ClearProviders();
            logging.SetMinimumLevel(Microsoft.Extensions.Logging.LogLevel.Trace);
            logging.AddNLog();
        }).Build();

    
    var svc = ActivatorUtilities.CreateInstance<TestService>(host.Services);
    svc.Run();
}

I then try to log something in TestService:

public class TestService
    {
        public TestService(ILogger<TestService> logger)
        {
            Logger = logger;
        }

        public ILogger<TestService> Logger { get; }

        public void Run()
        {
            Console.WriteLine("my first log");
            Logger.LogInformation("my first log");
        }
    }

I don't get any errors, but I don't get any logs created (file or contents) created either. The console outputs, so TestServices runs correctly.

According to the docs, I was expecting to see a method called "BuildServiceProvider()" to chain after "ConfigureLogging()", but I only have 'Build()". Is this something to do with it, or have I missed something?


Solution

  • Here is my complete and encapsulated NLog (for Console/CommandLine/DotNetCore) applications.

    using System;
    using System.Diagnostics.CodeAnalysis;
    using System.IO;
    using Microsoft.Extensions.Configuration;
    using Microsoft.Extensions.DependencyInjection;
    using Microsoft.Extensions.Hosting;
    using Microsoft.Extensions.Logging;
    using NLog;
    using NLog.Extensions.Logging;
    using LogLevel = Microsoft.Extensions.Logging.LogLevel;
    
    namespace Me.Configuration.DependencyInjection
    {
        [ExcludeFromCodeCoverage]
        public static class NlogSharedConfiguration
        {
            public const string NlogPerEnvironmentNameTemplate = "nlog.{0}.config";
            public const string NlogDefaultFileName = "nlog.config";
    
            public static IServiceCollection ConfigureSharedNlog(
                this IServiceCollection services,
                IConfiguration configuration,
                IHostEnvironment hostEnvironmentProxy)
            {
                NLogProviderOptions nlpopts = new NLogProviderOptions
                {
                    IgnoreEmptyEventId = true,
                    CaptureMessageTemplates = true,
                    CaptureMessageProperties = true,
                    ParseMessageTemplates = true,
                    IncludeScopes = true,
                    ShutdownOnDispose = true
                };
    
                /* Note, appsettings.json (or appsettings.ENVIRONMENT.json) control what gets sent to NLog.  So the .json files must have the same (or more) detailed LogLevel set (compared to the Nlog setting) 
                 * See https://stackoverflow.com/questions/47058036/nlog-not-logging-on-all-levels/47074246#47074246 */
                services.AddLogging(
                    builder =>
                    {
                        builder.AddConsole().SetMinimumLevel(LogLevel.Trace);
                        builder.SetMinimumLevel(LogLevel.Trace);
                        builder.AddNLog(nlpopts);
                    });
    
                string nlogPerEnvironmentName = string.Format(
                    NlogPerEnvironmentNameTemplate,
                    hostEnvironmentProxy.EnvironmentName);
                string nlogConfigName = File.Exists(nlogPerEnvironmentName) ? nlogPerEnvironmentName : NlogDefaultFileName;
                Console.WriteLine(string.Format("Nlog Configuration File. (FileName='{0}')", nlogConfigName));
    
                if (!File.Exists(nlogConfigName))
                {
                    throw new ArgumentOutOfRangeException(
                        string.Format("Nlog Configuration File NOT FOUND. (FileName='{0}')", nlogConfigName));
                }
    
                LogManager.LoadConfiguration(nlogConfigName);
    
                NLogLoggerProvider nlogProv = new NLogLoggerProvider(nlpopts);
                ILoggerProvider castLoggerProvider = nlogProv as ILoggerProvider;
    
                services.AddSingleton<ILoggerProvider>(castLoggerProvider);
                return services;
            }
        }
    }
    

    I have (in my rootfolder of my .exe.) the following files:

    nlog.config
    nlog.Development.config
    NLog.xsd
    

    nlog.Development.config is OPTIONAL, but this is how I have slightly different settings for a local developer vs everything else. You can see my "if file exists" code above.

    IHostEnvironment comes from here :

    https://learn.microsoft.com/en-us/aspnet/core/fundamentals/host/generic-host?view=aspnetcore-5.0#ihostenvironment