18

I am using Entity Framework Core on the nightly build channel (right now I'm using version EntityFramework.7.0.0-beta2-11524) and I'm trying to log the queries that EF generates just out of curiosity.

I'm writing a simple console program, I tried using the same logging technique that EF6 uses, but DbContext.Database.Logis not available on Entity Framework Core. Is there a way to log or just take a peek at the SQL generated by EF Core?

0

10 Answers 10

8

This is how I got it working based on Avi Cherry's comment:

You can actually just add an ILoggerFactory parameter to your "Configure" method in Startup.cs and call .AddConsole() to it right there.

In your Startup.cs you probably have a Configure method with a bunch of configurations in it. It should look like below (in addition to your stuff):

public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory)
{
    //this is the magic line
    loggerFactory.AddDebug(LogLevel.Debug); // formerly LogLevel.Verbose

    //your other stuff
}
Sign up to request clarification or add additional context in comments.

2 Comments

I wonder if there is a way of logging just the EF queries without everything else.
@MahmoudAli The EF Core documentation shows how to filter on certain log categories: learn.microsoft.com/en-us/ef/core/miscellaneous/logging
7

You can log to the console using this code, I am sure it will be wrapped in a simpler api later:

using System;
using Microsoft.Data.Entity.Infrastructure;
using Microsoft.Data.Entity.Utilities;
using Microsoft.Framework.Logging;

public static class SqlCeDbContextExtensions
{
    public static void LogToConsole(this DbContext context)
    {
        var loggerFactory = ((IAccessor<IServiceProvider>)context).GetService<ILoggerFactory>();
        loggerFactory.AddProvider(new DbLoggerProvider());
    }
}

And the DbLoggerProvider is implemented here: https://github.com/ErikEJ/EntityFramework7.SqlServerCompact/tree/master/src/Provider40/Extensions/Logging

3 Comments

It looks like the EF team just changed this again: github.com/aspnet/EntityFramework/commit/…
Has anyone found a way to log to the console with the current EF7 bits?
Where do you add this? Doesn't seem to work anymore.
5

If you are using MS SQL Server, one way I have used in the past is to make use of the SQL Server Profiler and capture all interaction with the SQL Server, this captures the exact SQL submitted and can be cut n pasted into the SQL Server Management Studio for further review/analysis. I know this does not directly answer your question on Entity Framework, but I have found this generic approach very useful for any language/tools.

One tip is in the Trace Properties when setting up a new trace, I have found it useful to adjust the default selection of events in the Events Selection tab. Mostly I turn off the Audit Login/Logout unless specifically tracking such an issue.

1 Comment

Very practical answer in case you have a problem NOW and no time to build & deploy :) Also you can copy-paste queries from SQL Profiler into SQL Management Studio to further diagnose what's wrong.
5

I struggled with all the above answers as the EF bits kept changing, so the code wouldn't compile. As of today (19Feb2016) with EF7.0.0-rc1-final (Prerelease) and SQLite, here's what works for me:

From the EF7 documentation:

using System;
using System.IO;
using Microsoft.Extensions.Logging;

namespace EFLogging
{
    public class EFLoggerProvider : ILoggerProvider
    {
        public ILogger CreateLogger(string categoryName)
        {
            return new EFLogger();
        }

        public void Dispose()
        {
            // N/A
        }

        private class EFLogger : ILogger
        {
            public IDisposable BeginScopeImpl(object state)
            {
                return null;
            }

            public bool IsEnabled(LogLevel logLevel)
            {
                return true;
            }

            public void Log(LogLevel logLevel, int eventId, object state, Exception exception, Func<object, Exception, string> formatter)
            {
                File.AppendAllText(@".\EF.LOG", formatter(state, exception));
                Console.WriteLine(formatter(state, exception));
            }
        }
    }
}

Using some ideas above and the EF7 Docs:

using System;
using Microsoft.Data.Entity;
using Microsoft.Data.Entity.Infrastructure;
using Microsoft.Extensions.DependencyInjection;  // Add this to EF7 docs code
using Microsoft.Extensions.Logging;

namespace DataAccessLayer
{
    public static class DbContextExtensions
    {
        public static void LogToConsole(this DbContext context)
        {
            var serviceProvider = context.GetInfrastructure<IServiceProvider>();
            var loggerFactory = serviceProvider.GetService<ILoggerFactory>();
            loggerFactory.AddProvider(new EFLoggerProvider(logLevel));
        }
    }
}

EDIT: @jnm2 pointed out if you add "using Microsoft.Extensions.DependencyInjection", the EF7 docs ARE correct. Thanks!

And finally, in my App.OnStartup method:

using (var db = new MyDbContext())
{
    db.LogToConsole();
}

This code will create a log file and also output logging info to the Visual Studio output window. I hope this helps -- I'm sure in a few weeks, the bits will change again.

4 Comments

GetInfrastructure<>() is now in namespace Microsoft.EntityFrameworkCore.Infrastructure in EF Core.
Yuck. This is wayyyy too much code just get the outputted sql.
@TheMuffinMan -- And you would use what instead?
@RandyB I should mention that my comment wasn't directed towards your code. What I meant was that Entity Framework makes it so difficult to get the generated sql. It's something that should be a first class citizen and brings up the fact that this ORM is not meant for any really serious applications.
4

With the latest version of EF7-beta8, Anthony's answer need a little tweaking. Here's what I did to get it to work.

internal static class DbContextExtensions
{
    public static void LogToConsole(this DbContext context)
    {
        var loggerFactory = context.GetService<ILoggerFactory>();
        loggerFactory.AddConsole(LogLevel.Verbose);
    }
}

Comments

3

I think I figured this out. With the current EF7 bits, ILoggerFactory is registered with the dependency injection container which EF is using. You can get a reference to the container, which is an IServiceProvider, via the ScopedServiceProvider property of DbContext when it is cast to IDbContextServices. From there, you can get the ILoggerFactory and configure it using the AddToConsole extension method from the Microsoft.Framework.Logging.Console NuGet package.

public static void LogToConsole(this DbContext context)
{
    // IServiceProvider represents registered DI container
    IServiceProvider contextServices = ((IDbContextServices)context).ScopedServiceProvider;

    // Get the registered ILoggerFactory from the DI container
    var loggerFactory = contextServices.GetRequiredService<ILoggerFactory>();

    // Add a logging provider with a console trace listener
    loggerFactory.AddConsole(LogLevel.Verbose);
}

Here is a gist I created for this snippet: https://gist.github.com/tonysneed/4cac4f4dae2b22e45ec4

2 Comments

You can actually just add an ILoggerFactory parameter to your "Configure" method in Startup.cs and call .AddConsole() to it right there.
While there is an overload of Configure that accepts an ILoggerFactory parameter, Startup.cs only applies to web apps, not console applications. :) However, web apps would benefit from logging SQL to the Debug Output window.
2

This worked for me with EF7 rc2-16485:

"EntityFramework.MicrosoftSqlServer": "7.0.0-rc2-16485",
"Microsoft.Extensions.Logging.Console": "1.0.0-rc2-15888",

public static class DbContextExtensions
{
    public static void LogToConsole(this DbContext context)
    {
        var contextServices = ((IInfrastructure<IServiceProvider>) context).Instance;
        var loggerFactory = contextServices.GetRequiredService<ILoggerFactory>();
        loggerFactory.AddConsole(LogLevel.Verbose);
    }
}

Comments

2

As an alternative to the above answers, I found this answer by far the easiest solution for me to reason about:

private readonly ILoggerFactory loggerFactory;

// Using dependency injection
public FooContext(ILoggerFactory loggerFactor) {
    this.loggerFactory = loggerFactory;
}

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) {
    optionsBuilder.UseLoggerFactory(loggerFactory);    // Register logger in context
}

1 Comment

Your link goes to a question, not an answer. Did you perhaps include the wrong link?
2

With ASP.NET Core 2.0 you get SQL logging automatically. No need to do anything extra.

Comments

0

For those who just want SQL queries to be logged (using Entity Framework Core with .NET Core 2.0 or above), use the following code in your DbContext class:

public static readonly LoggerFactory MyLoggerFactory
    = new LoggerFactory(new[]
    {
        new ConsoleLoggerProvider((category, level)
            => category == DbLoggerCategory.Database.Command.Name
               && level == LogLevel.Information, true)
    });

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    => optionsBuilder
        .UseLoggerFactory(MyLoggerFactory) // Warning: Do not create a new ILoggerFactory instance each time
        .UseSqlServer(
            @"Server=(localdb)\mssqllocaldb;Database=EFLogging;Trusted_Connection=True;ConnectRetryCount=0");

Reference: https://learn.microsoft.com/en-us/ef/core/miscellaneous/logging

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.