Problem
I’d like to write logs from within the startup.cs file to debug a.NET Core app that is failing on startup. I’ve got logging set up in the file that can be utilized outside of the startup.cs file, but I’m not sure how to write logs from within the startup.cs file.
Asked by Mark Redman
Solution #1
.Net Core 3.1
Unfortunately, the situation is slightly different for ASP.NET Core 3.0. The default templates use the HostBuilder (rather than the WebHostBuilder), which creates a new generic host that can host a variety of apps, not just web apps. The removal of the prior web host’s second dependency injection container is also a part of this new host. This means you won’t be able to inject any dependencies into the Startup class other than the IConfiguration. As a result, you won’t be able to log while the ConfigureServices function is running. However, you may inject the logger into the Configure function and log there instead:
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILogger<Startup> logger)
{
logger.LogInformation("Configure called");
// …
}
If you must log within ConfigureServices, you can use the WebHostBuilder to create a legacy WebHost that can inject the logger into the Startup class. It should be noted that the web host will most likely be deleted at some point in the future. So, instead of logging into ConfigureServices, you should try to discover a solution that works for you.
.NET Core 2.x
With the release of ASP.NET Core 2.0, this has altered dramatically. Logging is created at the host builder in ASP.NET Core 2.x. This means that logging is enabled by default using DI and may be injected into the Startup class as follows:
public class Startup
{
private readonly ILogger<Startup> _logger;
public IConfiguration Configuration { get; }
public Startup(ILogger<Startup> logger, IConfiguration configuration)
{
_logger = logger;
Configuration = configuration;
}
public void ConfigureServices(IServiceCollection services)
{
_logger.LogInformation("ConfigureServices called");
// …
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
_logger.LogInformation("Configure called");
// …
}
}
Answered by poke
Solution #2
Option 1: Use a log (such as Serilog) in the setup process.
public class Startup
{
public Startup(IHostingEnvironment env)
{
Log.Logger = new LoggerConfiguration()
.MinimumLevel.Debug()
.WriteTo.RollingFile(Path.Combine(env.ContentRootPath, "Serilog-{Date}.txt"))
.CreateLogger();
Log.Information("Inside Startup ctor");
....
}
public void ConfigureServices(IServiceCollection services)
{
Log.Information("ConfigureServices");
....
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
Log.Information("Configure");
....
}
Output:
Check out the Serilog.AspNetCore package on GitHub to set up Serilog in an asp.net-core application.
Option 2: Set up a program for logging in. This is something cs likes –
var host = new WebHostBuilder()
.UseKestrel()
.ConfigureServices(s => {
s.AddSingleton<IFormatter, LowercaseFormatter>();
})
.ConfigureLogging(f => f.AddConsole(LogLevel.Debug))
.UseStartup<Startup>()
.Build();
host.Run();
In a startup like this, the user loggerFactory-
public class Startup
{
ILogger _logger;
IFormatter _formatter;
public Startup(ILoggerFactory loggerFactory, IFormatter formatter)
{
_logger = loggerFactory.CreateLogger<Startup>();
_formatter = formatter;
}
public void ConfigureServices(IServiceCollection services)
{
_logger.LogDebug($"Total Services Initially: {services.Count}");
// register services
//services.AddSingleton<IFoo, Foo>();
}
public void Configure(IApplicationBuilder app, IFormatter formatter)
{
// note: can request IFormatter here as well as via constructor
_logger.LogDebug("Configure() started...");
app.Run(async (context) => await context.Response.WriteAsync(_formatter.Format("Hi!")));
_logger.LogDebug("Configure() complete.");
}
}
This link will take you to a page with all the information you need.
Answered by Sanket
Solution #3
You can use LogFactory to generate a logger in.NET Core 3.1.
var loggerFactory = LoggerFactory.Create(builder =>
{
builder.AddConsole();
});
ILogger logger = loggerFactory.CreateLogger<Startup>();
logger.LogInformation("Example log message");
Answered by Liang
Solution #4
Currently, the official option is to create a local LoggerFactory like this:
using var loggerFactory = LoggerFactory.Create(builder =>
{
builder.SetMinimumLevel(LogLevel.Information);
builder.AddConsole();
builder.AddEventSourceLogger();
});
var logger = loggerFactory.CreateLogger("Startup");
logger.LogInformation("Hello World");
See also: https://github.com/dotnet/aspnetcore/issues/9337#issuecomment-539859667
Answered by Rolf Kristensen
Solution #5
I implement a “logger buffer” with the ILogger interface to avoid using third-party loggers.
public class LoggerBuffered : ILogger
{
class Entry
{
public LogLevel _logLevel;
public EventId _eventId;
public string _message;
}
LogLevel _minLogLevel;
List<Entry> _buffer;
public LoggerBuffered(LogLevel minLogLevel)
{
_minLogLevel = minLogLevel;
_buffer = new List<Entry>();
}
public IDisposable BeginScope<TState>(TState state)
{
return null;
}
public bool IsEnabled(LogLevel logLevel)
{
return logLevel >= _minLogLevel;
}
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
{
if (IsEnabled(logLevel)) {
var str = formatter(state, exception);
_buffer.Add(new Entry { _logLevel = logLevel, _eventId = eventId, _message = str });
}
}
public void CopyToLogger (ILogger logger)
{
foreach (var entry in _buffer)
{
logger.Log(entry._logLevel, entry._eventId, entry._message);
}
_buffer.Clear();
}
}
It’s simple to use in startup.cs, and you’ll get log output after using Configure. But, well, it’s better than nothing.
public class Startup
{
ILogger _logger;
public Startup(IConfiguration configuration, IWebHostEnvironment env)
{
_logger = new LoggerBuffered(LogLevel.Debug);
_logger.LogInformation($"Create Startup {env.ApplicationName} - {env.EnvironmentName}");
}
public void ConfigureServices(IServiceCollection services)
{
_logger.LogInformation("ConfigureServices");
services.AddControllersWithViews();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILogger<Startup> logger)
{
(_logger as LoggerBuffered).CopyToLogger(logger);
_logger = logger; // Replace buffered by "real" logger
_logger.LogInformation("Configure");
if (env.IsDevelopment())
Answered by Christian Riedl
Post is based on https://stackoverflow.com/questions/41287648/how-do-i-write-logs-from-within-startup-cs