Mike Perrenoud
Mike Perrenoud

Reputation: 67948

.NET Core DI Logger on Console app not logging to Console

I've got a .NET Core console app. Pretty simple. At this point the goal was just to get DI and Configuration integrated. However, the LogDebug isn't logging to the console.

What could I have possibly done wrong here?

class Program
{
    static void Main(string[] args)
    {
        var topic = Environment.GetEnvironmentVariable("RECEIVER_TOPIC");
        var entity = Environment.GetEnvironmentVariable("RECEIVER_ENTITY");

        //setup our DI
        var serviceProvider = new ServiceCollection()
            .AddLogging()
            .BuildServiceProvider();

        //configure console logging
        serviceProvider
            .GetService<ILoggerFactory>()
            .AddConsole(LogLevel.Debug);

        var logger = serviceProvider
            .GetService<ILoggerFactory>()
            .CreateLogger<Program>();
        logger.LogDebug($"Starting application. Topic: {topic}. Entity: {entity}.");

        if (Debugger.IsAttached)
        {
            Console.ReadLine();
        }
    }

    static IConfigurationRoot GetConfiguration()
    {
        var builder = new ConfigurationBuilder()
            .SetBasePath(Directory.GetCurrentDirectory())
            .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true);

        return builder.Build();
    }
}

Update 1

I added the Microsoft.Extensions.Logging.Debug NuGet package, and modified the serviceProvider initialization to append the AddDebug like so:

serviceProvider
    .GetService<ILoggerFactory>()
    .AddConsole(LogLevel.Debug)
    .AddDebug();

But it's not even logging to the Debug window.

Upvotes: 5

Views: 11106

Answers (4)

hau_tran
hau_tran

Reputation: 1

Add logging.AddDebug(); works for me. Thanks a lot!

.ConfigureLogging(logging =>
                {
                    logging.ClearProviders();
                    logging.AddConsole();
                    logging.AddDebug();
                })

Updated: I've finally found the reason. In the Visual Studio, the output window is not the console, it is for the Debug provider. so that's why I could not see any logs inside it. When I published the project to a folder and then execute the .exe file, it opens a console, the is the place that the console provider take affect!

Upvotes: 0

onefootswill
onefootswill

Reputation: 4107

I just wanted to chip in with a revised ConfigureServices method which makes use of the logging section in an appsetting.json file.

First, I added an appsettings.json which looks like this:

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning"
    }
  }
}

The, my ConfigureServices method:

    static void ConfigureServices(IServiceCollection serviceCollection)
    {
        // Build configuration
        var configuration = new ConfigurationBuilder()
            .SetBasePath(AppContext.BaseDirectory)
            .AddJsonFile("appsettings.json", false)
            .Build();

        // Add logging
        serviceCollection.AddLogging(config =>
        {
            // clear out default configuration
            config.ClearProviders();

            config.AddConfiguration(configuration.GetSection("Logging"));
            config.AddDebug();
        });
    }

Note, no need to add ILogger and ILoggerFactory to the ServiceProvider.

I believe this is handled in the AddLogging extension method.

Upvotes: 0

Anton Pegushin
Anton Pegushin

Reputation: 470

I recently ran into the same exact problem, saw your answer, but did not understand why 'AddDebug()' was necessary. Removing it though stops the logger from logging to console. See Logging to Console with DI in C# if interested. My guess is that Console logger spins off a separate thread and tries to aggregate logs and flush on timer to not be as intrusive. The Debug logger logs immediately, but I only wanted one. Switching to having an App class with async Run() method solves all problems.

Upvotes: 2

Mike Perrenoud
Mike Perrenoud

Reputation: 67948

Got it working. I think the key was that I wasn't yet clear that concretes needed to be registered because I thought the extension was registering the concretes.

class Program
{
    static void Main(string[] args)
    {
        var topic = Environment.GetEnvironmentVariable("RECEIVER_TOPIC");
        var entity = Environment.GetEnvironmentVariable("RECEIVER_ENTITY");

        // Create service collection
        var serviceCollection = new ServiceCollection();
        ConfigureServices(serviceCollection);

        // Create service provider
        var serviceProvider = serviceCollection.BuildServiceProvider();

        var logger = serviceProvider
            .GetRequiredService<ILoggerFactory>()
            .CreateLogger<Program>();
        logger.LogDebug($"Starting application. Topic: {topic}. Entity: {entity}.");

        if (Debugger.IsAttached)
        {
            Console.ReadLine();
        }
    }

    static void ConfigureServices(IServiceCollection serviceCollection)
    {
        // Add logging
        serviceCollection.AddSingleton<ILoggerFactory, LoggerFactory>();
        serviceCollection.AddSingleton(typeof(ILogger<>), typeof(Logger<>));
        serviceCollection.AddLogging(loggingBuilder => loggingBuilder
            .AddConsole()
            .AddDebug()
            .SetMinimumLevel(LogLevel.Debug));

        // Build configuration
        var configuration = new ConfigurationBuilder()
            .SetBasePath(AppContext.BaseDirectory)
            .AddJsonFile("appsettings.json", false)
            .Build();

        // Add access to generic IConfigurationRoot
        serviceCollection.AddSingleton(configuration);
    }
}

Upvotes: 9

Related Questions