How do I configure the EventLog logging provider via my appsettings.json file

1.4k views Asked by At

In My .net core 6 console app I create a host builder

var builder = Host.CreateDefaultBuilder(args);

This gives me a HostBuilder instance with a logging factory set up for console, debug, event log, and event source providers, as well as configuration providers for user/system environment vars, appsettings.json, appsettings..json, etc.

I can inject ILogger or ILoggingFactory into my class and write to all the logging providers using the ILogger.Log function.

public class BusinessLogic
{
    private IHostEnvironment _env;
    private ILogger _logger;

    public BusinessLogic(
        IHostEnvironment env, 
        ILoggerFactory loggerFactor)
    {       
        _env = env;

        _logger = loggerFactor.CreateLogger<BusinessLogic>();
    }

    public void Run()
    {    
        foreach (var level in Enum.GetValues<LogLevel>())
        {
            _logger.Log(level, $"Test logging at level {level}.");
        }

        Console.WriteLine("Hello, World!  Press any key...");    
        Console.ReadLine();
    }
}

Now I want to configure the event log application name and source name that the event log provider will write to. I'd rather not hard code this, so I was hoping to do this throught he appsettings.json file. I can't seem to get it to take affect. My appsettings.json file looks like this:

{
    "Logging":
    {
        //Settings for the windows event log logging provider
        "EventLog":
        {
            "LogName": "Application",
            "SourceName": "MySource",
      
            "LogLevel":
            {
                "Default": "Trace"
            }
        }
    }
}

The above appsettings has no affect, so I thought I would try adding a new EventLog provider and pass it the configuration.

var builder = Host.CreateDefaultBuilder(args);
builder.ConfigureAppConfiguration((context, builder) =>
{
    var eventLogConfiguration = context.Configuration.GetSection("Logging:EventLog").Get<EventLogSettings>();
    builder.AddEventLog(eventLogConfiguration);
});

That didn't work either, so I tried clearing the logging providers, in case adding duplicates was an issue.

var builder = Host.CreateDefaultBuilder(args);
builder.ConfigureAppConfiguration((context, builder) =>
{
    builder.ClearProviders();
    var eventLogConfiguration = context.Configuration.GetSection("Logging:EventLog").Get<EventLogSettings>();
    builder.AddEventLog(eventLogConfiguration);
});

That works, but what if I want all the other existing providers to be retained? Can I just replace one, or somehow apply the configuration to an existing provider, or is there some other/better way to do this?

1

There are 1 answers

0
Keith On

If you look at the source for CreateDefaultBuilder it appears to already do all this:

// HostingHostBuilderExtensions.cs > AddDefaultServices
bool isWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
...

logging.AddConfiguration(hostingContext.Configuration.GetSection("Logging"));
...

if (isWindows)
    // Add the EventLogLoggerProvider on windows machines
    logging.AddEventLog();

Given that AddConfiguration call you shouldn't need GetSection("Logging:EventLog").

Given that AddEventLog call you shouldn't need to call it again.

As it only works when you call ClearProviders() first I think CreateDefaultBuilder must be misconfiguring the event log somehow. But, if that were the case GetSection("Logging:EventLog") would fail or you'd see an error (as happens if you use AddEventLog with an unrecognised source or log name).

I wonder if something in Logging that isn't in Logging:EventLog could be the problem?

I'm having a similar issue, but I don't have to call ClearProviders() - adding AddEventLog is enough for me, but that doesn't pick up anything from appsettings.json unless I add it explicitly.

Update

I think this might be a bug (or possibly LogName and SourceName just aren't supported from config). I have a workaround for now.

Basically, I manually set the config (like you), but with an OS check that code analysis understands and with the lambda that alters the config rather than applying it again.

[System.Runtime.Versioning.SupportedOSPlatform("windows")]
public static void SetEventLogConfig(WebApplicationBuilder builder) {
    string? eventLog = builder.Configuration["Logging:EventLog:SourceName"];
    if(eventLog is not null)
        builder.Logging.AddEventLog(c => c.SourceName = eventLog);
}

// then in program.cs
if(RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
    SetEventLogConfig(builder);

That works for my app, but I'm still not sure why you need to call ClearProviders in your implementation.