In this article let us find out how Logging in EF Core works. We use logging to Log SQL queries. Find out more about errors. Improve Performance of the SQL Queries etc. In the article, we will create an example application and show you how to log queries to console and also to the windows event log. We also show you how to filter the logs using the log levels & DbLogger Category.
Table of Contents
Why Logging
There are a lot of scenarios, where you would see the queries the EF Core generates. For Example, the Query may fail to bring the desired result or when the query itself is slow. Looking and analyzing the query that is sent to the back end server help us to write better queries and fine-tune performance bottlenecks.
EF Core has come with a lot of logging capabilities out of the box. All we need to capture it and direct it to a text file or console or another database.
Logging in .NET Core
.NET Core apps have built-in mechanisms for creating & managing various loggers. At the heart of the Logging API is three players LoggerProvider, Logger & LoggerFactory.
Logger is what writes the log entities to output. The output can be a console, database a text file etc. It must implement the interface ILogger
The LoggerProvider must implement the interface ILoggerProvider. The responsibility of the LoggerProvider to create the Logger. The re are many built-in LoggerProviders available for us to use. The following is the list of some of them.
| Logger Providers | Description |
|---|---|
| Microsoft.Extensions.Logging.Console | A simple console logger |
| Microsoft.Extensions.Logging.AzureAppServices | Supports Azure App Services 'Diagnostics logs' and 'Log stream' features. |
| Microsoft.Extensions.Logging.Debug | Logs to a debugger monitor using System.Diagnostics.Debug.WriteLine() |
| Microsoft.Extensions.Logging.EventLog | Logs to Windows Event Log |
| Microsoft.Extensions.Logging.EventSource | upports EventSource/EventListener |
| Microsoft.Extensions.Logging.TraceSource | Logs to a trace listener using System.Diagnostics.TraceSource.TraceEvent() |
The LoggerFactory contains the collection of LoggerProvider. We add the LoggerProvider to the LoggerFactory. Since it is a collection, it gives us the ability to log to multiple locations using different providers. It is the responsibility of the LoggerFactory to create the instance of the ILoggerProvider. The LoggerProvider then creates the instance of the Logger.
Logging To Console
The DBContext generates a lot of log information. All we need to do is tie up the LoggerProvider to it.
The way it is done in a console application is a little different from an ASP.NET Core application. In ASP.NET Core apps the LoggerFactory is already set up by the framework. It is also automatically tied up to the DBContext class.
EF Core Console App
First, create an EF Core Console Application as shown in the tutorial. The tutorial uses Visual Studio 2017. But you can also use the Visual Studio 2019 and Dot net core 3.x.
Console Logger Provider
The next step is to install the Logger Provider. The list above contains some of the built in loggers. Let us use the Console Logger Provider. Install it using the following command.
Install-Package Microsoft.Extensions.Logging.ConsoleLogger Factory & Logger Provider
First, we need to create the Logger Factory
Open the EFContext class and add the following at top
public static readonly ILoggerFactory MyLoggerFactory =
LoggerFactory.Create(
builder =>
{
builder.AddConsole();
}
);We LoggerFactory.Create is a static method, which creates the LoggerFactory. It gets the builder as its argument. The purpose of it is to configure the LoggerProvider.
We declare the MyLoggerFactory as static. Because the Context must use the same instance of the LoggerFactory for the entire duration of the application lifetime. Otherwise, it will have performance side effects
The AddConsole is an extension method from the Microsoft.Extensions.Logging.Console package. It configures the LoggerProvider and adds it the LoggerFactory.
With this our LoggerFactory is ready. Now time to hook it up to the DBContext. We do it while Configuring the DBContext using the OnConfiguring Method. Pass our LoggerFactory using the UseLoggerFactory method.
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder
.UseLoggerFactory(MyLoggerFactory)
.UseSqlServer(connectionString);
}Now, run the app and you will see the select query in your console screen.

Configure Logger
The above code logs everything, which is going to fill up the console. The logger provides a lot of filters to keep the log entries to minimum
EnableDetailedErrors
This EnableDetailedErrors option provides additional error details about the errors. Such errors most often about the misconfigured entity properties like int in place of string etc. This option is set to false by default. But when set to true it will include details of the specific entity property that generated the error. Enabling this option will incur a small performance hit.
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder
.UseLoggerFactory(MyLoggerFactory)
.EnableDetailedErrors(true)
.UseSqlServer(connectionString);
}EnableSensitiveDataLogging
The EnableSensitiveDataLogging enables application data to include sensitive information in the logs. The sensitive information include the values assigned to properties of your entity instances, parameter values for commands being sent to the database, etc
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder
.UseLoggerFactory(MyLoggerFactory)
.EnableSensitiveDataLogging(true)
.UseSqlServer(connectionString);
}Log Levels
The Logs are classified according to severity levels. The following table shows
| Name | Value | Description |
|---|---|---|
| Trace | 0 | Logs that contain the most detailed messages. These messages may contain sensitive application data. These messages are disabled by default and should never be enabled in a production environment. |
| Debug | 1 | Logs that are used for interactive investigation during development. These logs should primarily contain information useful for debugging and have no long-term value. |
| Information | 2 | Logs that track the general flow of the application. These logs should have long-term value. |
| Warning | 3 | Logs that highlight an abnormal or unexpected event in the application flow, but do not otherwise cause the application execution to stop. |
| Error | 4 | Logs that highlight when the current flow of execution is stopped due to a failure. These should indicate a failure in the current activity, not an application-wide failure. |
| Critical | 5 | Logs that describe an unrecoverable application or system crash, or a catastrophic failure that requires immediate attention. |
| None | 6 | Not used for writing log messages. Specifies that a logging category should not write any messages |
Use the AddFilter method to filter our the desired log level.
public static readonly ILoggerFactory MyLoggerFactory =
LoggerFactory.Create(
builder => {
builder.AddConsole()
.AddFilter(level => level == LogLevel.Information);
}
);DBLogger Category
Apart from the Log Levels, the logger API defines several DBLogger categories. We can use them to filter out the log.
| DBLogger Category | Description |
|---|---|
| DbLoggerCategory.ChangeTracking.Name | Logger category for messages from change detection and tracking. |
| DbLoggerCategory.Database.Name | Logger categories for messages related to database interactions. |
| DbLoggerCategory.Database.Connection.Name | Logger category for messages related to connection operations. |
| DbLoggerCategory.Database.Transaction.Name | Logger category for messages related to transaction operations. |
| DbLoggerCategory.Database.Command.Name | Logger category for command execution, including SQL sent to the database. |
| DbLoggerCategory.Infrastructure.Name | Logger category for miscellaneous messages from the Entity Framework infrastructure. |
| DbLoggerCategory.Migrations.Name | Logger category messages from Migrations. |
| DbLoggerCategory.Query.Name | Logger category for messages related to queries, excluding the generated SQL, which is in the DbLoggerCategory.Database.Command category. |
| DbLoggerCategory.Scaffolding.Name | Logger category for messages from scaffolding/reverse engineering. |
| DbLoggerCategory.Update.Name | Logger category for messages related to SaveChanges(), excluding messages specifically relating to database interactions which are covered by the DbLoggerCategory.Database categories. |
| DbLoggerCategory.Model.Name | Logger categories for messages related to model building and metadata. |
| DbLoggerCategory.Model.Validation.Name | Logger category for messages from model validation. |
public static readonly ILoggerFactory MyLoggerFactory2 =
LoggerFactory.Create(
builder => {
builder.AddConsole()
.AddFilter((category, level)
=> category == DbLoggerCategory.Database.Command.Name
&& level == LogLevel.Information);
});Logging To EventLog
Now, you have understood how to implement the logging in EF Core Console Application, we can easily use any other provider. For Example install the following package, which is a LoggerProvider to EventLog
install-package Microsoft.Extensions.Logging.EventLogNow, use the AddEventLog extension method to send the logs to the windows event log along with the console. You can also use the addfilter method to filter out the logs.
public static readonly ILoggerFactory MyLoggerFactory1 =
LoggerFactory.Create(
builder =>
{
builder.AddConsole();
builder.AddEventLog();
}
);
Summary
Logging in EF core helps us find out more information about the errors. It helps to fine tune our queries, thus helping us in improving the performance.

What should I do to log to whatever logger factory is registered in the application services?
The above code is limited to capturing the logs from the EF Core (i.e DBContext only).
If you want to use the log other info then
public class MyLog
{
public static ILoggerFactory factory = LoggerFactory.Create(
builder =>
{
builder.AddConsole();
builder.AddEventLog();
}
);
public static ILogger logger = factory.CreateLogger("EF");
}
And then can use it as
MyLog.logger.LogInformation("Log Whatever you want");If you want to implement Logging in Console Apps, then it is better to use the DI to inject into the factory and use it.