user3280560
user3280560

Reputation: 137

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?

Upvotes: 1

Views: 7298

Answers (2)

Rolf Kristensen
Rolf Kristensen

Reputation: 19867

You are doing LogInformation but you have only enabled Warn + Error + Fatal using AddRuleForOneLevel. Maybe replace with AddRule(NLog.LogLevel.Info, NLog.LogLevel.Fatal, fileTarget) instead ?

You can also try specifying RemoveLoggerFactoryFilter (To avoid Microsoft ILogger-filtering problems):

   .ConfigureLogging(logging =>
    {
        logging.ClearProviders();
        logging.AddNLog(new NLogProviderOptions { RemoveLoggerFactoryFilter = true );
    })

See also: https://github.com/NLog/NLog.Extensions.Logging/blob/master/src/NLog.Extensions.Logging/Logging/NLogProviderOptions.cs

Upvotes: 1

granadaCoder
granadaCoder

Reputation: 27852

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

Upvotes: 2

Related Questions