File logging on ASP.NET Core
ASP.NET Core introduces new framework level logging system. Although it is feature-rich it is not complex to use and it provides decent abstractions that fit well with the architecture of most web applications. This blog post shows how to set up and use Serilog file logging using framework-level dependency injection.
- ASP.NET Core: How log filtering works
- ASP.NET Core: Implementing Syslog logger
- File logging on ASP.NET Core
- Defensive logging on ASP.NET Core
Configuring logging
Logging is configured in ConfigureServices() method of Startup class. ASP.NET Core comes with console and debug loggers. For other logging targets like file system, log servers etc third-party loggers must be used. This blog post uses Serilog file logger.
"dependencies": {
// ...
"Serilog.Extensions.Logging.File": "1.0.0"
},
Project has now reference to Serilog file logger. Let’s introduce it to ASP.NET Core logging system. AddFile(string path) is the extension method that adds Serilog file logger to logger factory loggers collection. Notice that there can be multiple loggers active at same time.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
loggerFactory.AddDebug();
loggerFactory.AddFile("Logs/ts-{Date}.txt");
// ...
}
Serilog will write log files to Logs folder of web application. File names are like ts-20170108.txt.
Injecting logger factory
Loggers are not injected to other classes. It’s possible to inject logger factory and let it create new logger. If it sounds weird for you then just check internal loggers collection of logger factory to see that also other classes that need logger have their own intsances. The code below sowhs how to get logger to controller through framework level dependency injection.
public class DummyController : Controller
{
private ILogger _logger;
public DummyController(ILoggerFactory loggerFactory)
{
_logger = loggerFactory.CreateLogger(typeof(DummyController));
}
// ...
}
Why we have to inject logger factory and not single instance of ILogger? Reason is simple – application may use multiple loggers like shown above. This is the fact we don’t want to know in parts of application where logging is done. It’s external detail that si not related to code that uses logging.
Logging
Logging is done using extension methods for ILogger interface. All classic methods one can expect are there:
- LogDebug()
- LogInformation()
- LogWarning()
- LogError()
- LogCritical()
Now let’s write something to log.
public class DummyController : Controller
{
private ILogger _logger;
public DummyController(ILoggerFactory loggerFactory)
{
_logger = loggerFactory.CreateLogger(typeof(DummyController));
}
public void Index()
{
_logger.LogInformation("Hello from dummy controller!");
}
}
Making request to Dummy controller ends up with log message added to debug window and log file. The following image shows log message in output window.
And here is the same log message in log file.
If more loggers are added in the future then also these loggers will write this log message to their target when dummy controller is called.
Wrapping up
ASP.NET Core comes with powerful built-in logging framework. Although it comes only with condole and debug loggers there are third-party logging components available and they are also easy to use. Using Serilog for file logging was actually easy. We just added reference to file logger package and introduced new logger to logger factory. For actual logging the logger factory was injected to controller and new logger was added. Logging framework comes with many other features and to keep posts short and focused I will introduce other important logging features of ASP.NET Core in my future posts.
Hi,
you can directly inject the logger like this:
public DummyController(ILogger logger)
and avoid the factory call.
Furthermore if you have more than one logger in the class then you have more than one dependencies which should be explicit. This would help unit testing a lot.
On ASP.NET Core 1.1 it doesn’t work like this unless you register ILogger with framework-level dependency injection. LoggerFactory is “known” service automatically and there is no need to do anything additional at application start-up.
For everyone who are looking for simple FileLoggerProvider without dependencies on the logging frameworks (Serilog, NLog, log4net), here is an implementation that works very similar to standard ConsoleLogger but writes result to a file: https://github.com/nreco/logging (NReco.Logging.File nuget package)