Reputation: 947
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
Reputation: 141665
What can be the reason? Maybe there are some additional configurations?
As of at least .net-6.0 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
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