Logging EF Core’s memory operations and SQL operations has evolved a few times since EF Core arrived. It takes advantage of the same underlying features that ASP.NET Core uses. If you are using ASP.NET Core, logging is baked in and it is really simple to turn it on for EF Core and add filtering. See Shawn Wildermuth’s blog post about EF Core logging in ASP.NET Core.
But if you aren’t using ASP.NET Core, it’s a little more complicated. Not terribly, but still there’s some extra work to do. It involves setting up an ILoggerFactory in your DbContext and defining any filters at the same time.
I wrote an article about this (with the focus being on taking advantage of the various available filters for EF Core logging) in MSDN Magazine earlier this …oh wait, it’s Jan 1, so I can say “last year”. Data Points – Logging SQL and Change-Tracking Events in EF Core. I also used it heavily in my EF Core 2 Getting Started course, EF Core 2:Mappings and EF Core 2.1: What’s New courses on Pluralsight. (Note that I’ve updated the sample code for the Getting Started course to EF Core 2.2 and put it on GitHub at github.com/julielerman/PluralsightEFCore2GettingStarted)
My article and courses were using Console apps to demonstrate EF Core behavior and therefore the ConsoleLoggerProvider to tie the logger to the console. Note that the Data Points article contains a lot of good details about the various types of filtering. So you can use the new syntax (below) to specify that there should be a filter, but be sure to read the article to learn about the flavors of filtering and what type of details you’ll be able to see based on the choices you make.
But the logging API has continued to evolve and is providing some of the same shortcuts that ASP.NET had created. And the ConsoleLoggerProvider has been deprecated. The API is not part of EF Core. It’s part of .NET Core. Both EF Core and ASP.NET Core use it.
If you are using EF Core 2.2, the syntax has changed (simplified) and it’s going to get even more streamlined in 3.0.
In fact, if you use the earlier syntax with 2.2, you’ll get a warning about the ConsoleLoggerProvider:
Obsolete(“This method is obsolete and will be removed in a future version. The recommended alternative is using LoggerFactory to configure filtering and ConsoleLoggerOptions to configure logging options.”)
For a point of comparison, here is an example of using theold syntax to turn on logging, only show logs related to database commands and only show messages that are tagged as “Information”.
EF Core 2.0 & 2.1 Logic
public static readonly LoggerFactory MyConsoleLoggerFactory = new LoggerFactory(new[] { new ConsoleLoggerProvider((category, level) => category == DbLoggerCategory.Database.Command.Name && level == LogLevel.Information, true) });
Once your logger factory field is defined in the context class you tell the DbContext to use it when configuring.
protected override void OnConfiguring (DbContextOptionsBuilder optionsBuilder) { var connectionString = ConfigurationManager.ConnectionStrings["WPFDatabase"].ToString(); optionsBuilder .UseLoggerFactory(MyConsoleLoggerFactory) .EnableSensitiveDataLogging(true) .UseSqlServer(connectionString); }
So it’s the creation of the logger factory whose syntax is a little convoluded. The newer API follows how ASP.NET Core lets you filter with an AddFilter method that takes the filters as parameters. No lambdas needed. Also configuring the filter is a separate bit of logic that tellig the logger that it should be tied to the console.
EF Core 2.2 Logic
With EF Core 2.2, you can set up the logger factory in the constructor or another method as long as it’s available when you are configuring the option builder. I’m creating it in a method then using that method as a parameter of UseLoggerFactory. I’m still filtering on showing only database commands and log details flagged as Information.
private ILoggerFactory GetLoggerFactory() { IServiceCollection serviceCollection = new ServiceCollection(); serviceCollection.AddLogging(builder => builder.AddConsole() .AddFilter(DbLoggerCategory.Database.Command.Name, LogLevel.Information)); return serviceCollection.BuildServiceProvider() .GetService<ILoggerFactory>(); }
and then I’m calling GetLoggerFactory() in the UseLogging method on the optionsbuilder:
optionsBuilder.UseLoggerFactory(GetLoggerFactory())
Packages and References
In order to use the AddConsole() method, you still have to use the Microsoft.Extensions.Logging.Console package that the earlier ConsoleLoggerProvider was in. However, you do not need a using statement for the namespace (as you did for the ConsoleLoggerProvider).
Sign up for my newsletter so you don't miss my conference & Pluralsight course announcements!
Hi,
Please share a simple complete working sample for EF Core 2.2 Logging Logic. Tried to use EF Core 2.2 Logic in Xamarin Forms/EF core application DataBase Context class using VS 2017 Community and Console window is not even launching.
Apart from this piece of code, is there anything else that needed be added?
Hi Julie, Is there an extension to include extra description on the generated SQL statements. It would be helpful to include description for the SQL statement log.
Something like:
“Sql For fetching schedules…”
SELECT * FROM TABLE WHERE FILTER
Right now all I see is sql statements and when I’m running in a batch I can’t even tell which log entry to look at.
Thanks.
Oh, there is! EF Core 2.2 brought us “Query Tags”. Here’s more info: https://docs.microsoft.com/en-us/ef/core/querying/tags
private ILoggerFactory GetLoggerFactory()
{
IServiceCollection serviceCollection = new ServiceCollection();
serviceCollection.AddLogging(builder =>
builder.AddConsole()
.AddFilter(DbLoggerCategory.Database.Command.Name,
LogLevel.Information));
return serviceCollection.BuildServiceProvider()
.GetService();
}
There is a memory leak in this code.
The EF Core documentation very explicitly says that there should only be one instance of the ILoggerFactory that’s used by all DB Contexts, or else a memory leak will occur. I’m not completely sure if the EF 2.2 article is creating multiple instances, but if so that may be the cause. See https://docs.microsoft.com/en-us/ef/core/miscellaneous/logging?tabs=v3#other-applications
Thanks Tom!