Logging in ASP.NET Core – Connecting the pieces
Logging in ASP.NET Core 1
Logging has been a built-in feature since the first release of ASP.NET Core. Good thing about logging is that ASP.NET Core configures it to log internal events from the platform.
You can also easily connect it with most of the popular logging tools (NLog, log4net, Serilog, etc..).
Logging API has built-in providers that enable us to send logs to various outputs. Some of those are:
- and others
If you can’t find a one that suits your needs you can always create and connect your own custom providers for the output you need.
Key player in ASP.NET Core logging is ILoggerFactory. It represents an abstraction for a type used to work with the logging system. To be precise, we use ILoggerFactory to add various providers for logging. Also, we use it to create logger instances. Furthermore, it provides us with the means to capture built-in ASP.NET logging.
Logging in ASP.NET Core is extensible and we can give our own logging or use 3rd party loggers.
We can use Dependency Injection that comes with ASP.NET Core to get ILoggerFactory instance. Therefore, we would usually use that instance to set up logging outputs and log levels. We usually do the setup inside of a Configure method in Startup class:
In order to use these extension methods (AddConsole, AddDebug, etc..) we need to install and reference proper NuGet packages. They represent implementations for various outputs:
AddFile is an extension method provided by Serilog.Extensions.Logging.File NuGet package. In one line, it adds file logging to our ASP.NET Core application, which is pretty cool!
Just to make things clear, Serilog.Extensions.Logging.File NuGet package references other Serilog packages. And those packages are the ones that do real logging – saving logs to file.
Serilog.Extensions.Logging.File provides AddFile extension methods and connects logging baked into ASP.NET Core with Serilog logger.
Logging setup and ILoggerFactory instantiation
And what does get all this started? Well, it’s no magic. If we browse through ASP.NET Core 1.1.0 code we can find Build method inside of WebHostBuilder class:
If we navigate to BuildCommonServices method we can see the following code:
And that’s where the logging is initially set up and where ASP.NET Core creates LoggerFactory instance.
That means that the code inside of our application in the Main method of our Program class is what starts all this:
Do notice the Build() at the end of the expression. That’s the same method that we saw above. It calls BuildCommonServices which in turn sets up logging and creates ILoggerFactory instance.
Logging in controllers
We group logs by categories. Each log we create has a category defined. We can use any string for the category name but the convention is to use the fully qualified name of the class where are we doing our logging.
Two basic ways to make logging work in controller:
- injecting ILoggerFactory
- injecting ILogger with CategoryName as generic parameter.
We can use LoggerFactory instance to create ILogger instance:
But that seems like too much overhead. Luckily, we can simply inject ILogger instance directly:
Those two ILogger instances get to do the same thing and have a same category name.
Logging and Log Levels
How do we log things? We can use ILogger instance that we initialized in our controller:
Now, that’s NO fun. Luckily, we will rarely need to call Log method directly. We will usually call one of the extensions for the log level we intend to use.
The equal to the code above with LogCritical extension method:
That looks better. And what about log levels?
And what about log levels? You can use log levels to define how much of the logging you want for different environments. In production you probably do not want to log any logs with Trace or Debug log level.
Log levels in ASP.NET Core:
- Trace – 0
- Debug – 1
- Information – 2
- Warning – 3
- Error – 4
- Critical – 5
Using appsettings.json enables us to set different log levels for different environments:
Now, that could be used in development but definitely not in production. Back to the point, built-in logging will pick up configuration from appsettings.json by default.
We can also use WithFilter extension method provided by Microsoft.Extensions.Logging.Filter nuget package:
We create a new instance of FilterLoggerSettings and we provide category name and log level for the category. In the code above I used LogLevel.None which means there will be no logging for given category. It is important to notice that LoggerFactory applies the filter to all providers that we are using.