Ivan Khorin
Ivan Khorin

Reputation: 947

Logging in console application (.NET Core with DI)

guys. I try to add logging to my console app with DI (.NET Core 3.1) and seems that IoC container works fine for that, injects logger dependency to my classes, but LogXXX method doesn't log to output. What can be the reason? Maybe there are some additional configurations?

using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;

namespace DependencyInjection
{
    class Program
    {
        static void Main(string[] args)
        {
            var services = new ServiceCollection();
            ConfigureServices(services);

            var serviceProvider = services.BuildServiceProvider();

            var logger = serviceProvider.GetService<ILogger<Program>>();
            logger.LogInformation("Hello world!");
        }

        static void ConfigureServices(ServiceCollection services)
        {
            services.AddLogging(loggerBuilder =>
            {
                loggerBuilder.ClearProviders();
                loggerBuilder.AddConsole();
            });
        }
    }
}

Upvotes: 27

Views: 44614

Answers (2)

Guru Stron
Guru Stron

Reputation: 141665

What can be the reason? Maybe there are some additional configurations?

As of at least ConsoleLogger is actually asynchronous and utilizes currently internal ConsoleLoggerProcessor (in some previous versions seems that it was public) which utilizes a separate thread to process the messages and write them to console which can result in some unexpected behaviors (like missed messages on app exit or for example if you hit a breakpoint in simple console app). ConsoleLoggerProcessor implements IDisposable currently looking like the following:

public void Dispose()
{
    CompleteAdding();

    try
    {
        _outputThread.Join(1500); // with timeout in-case Console is locked by user input
    }
    catch (ThreadStateException) { }
}

So one workaround would be to dispose the service provider which will dispose the instantiated by it disposables (for debugging in some cases I've used some timeouts and steps throughs to "get" the message in the console):

var services = new ServiceCollection();
// optional if you want to read the config.
var cfg = new ConfigurationBuilder()
    .AddJsonFile("appsettings.json")
    .Build();
services.AddSingleton(cfg);

services.AddLogging(lb => lb.AddSimpleConsole());

// Dispose service provider
using var sp = services.BuildServiceProvider();
var requiredService = sp.GetRequiredService<ILogger<Program>>();
requiredService.LogError("Test");

Note that all of this is handled by hosting abstractions (like generic host nowadays used by worker templates or minimal hosting used for ASP.NET Core by default since .NET 6) out of the box.

Demo @dotnetfiddle.net (packages installed Microsoft.Extensions.Logging.Console and Microsoft.Extensions.Configuration.Json)

Upvotes: 2

Mark Nadig
Mark Nadig

Reputation: 5136

Docs have current example for Console App

class Program
{
    static void Main(string[] args)
    {
        using var loggerFactory = LoggerFactory.Create(builder =>
        {
            builder
                .AddFilter("Microsoft", LogLevel.Warning)
                .AddFilter("System", LogLevel.Warning)
                .AddFilter("LoggingConsoleApp.Program", LogLevel.Debug)
                .AddConsole();
        });
        ILogger logger = loggerFactory.CreateLogger<Program>();
        logger.LogInformation("Example log message");
    }
}

Of course you need to install the appropriate Nuget packages:

  • Microsoft.Extensions.Logging
  • Microsoft.Extensions.Logging.Console

Upvotes: 50

Related Questions