Tom Regan
Tom Regan

Reputation: 3841

Log Entity Framework .Net Core 2.2 EF to debug output window

Using Entity Framework in .Net Core 2.2, I'd like to log all SQL statements generated by EF to the Debug Output window in Visual Studio.

In .Net Framework I simply had to add this line to the DbContext constructor:

Database.Log = s => System.Diagnostics.Debug.WriteLine(s);

In EF I'm trying the following. It compiles, and the OnConfiguring method does get called, but no database calls are logged to my Debug Output window. What am I missing?

public class MyContext : DbContext
{
    private ILoggerFactory GetLoggerFactory()
    {
        IServiceCollection serviceCollection = new ServiceCollection();
        serviceCollection.AddLogging(builder => builder
            .AddDebug()
            .AddFilter(DbLoggerCategory.Database.Command.Name, LogLevel.Debug));
        return serviceCollection.BuildServiceProvider()
                .GetService<ILoggerFactory>();
    }

    public MyContext(DbContextOptions<MembershipContext> options) : base(options)
    {
    }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        optionsBuilder.UseLoggerFactory(GetLoggerFactory());
    }
}

My appsettings.json contains this:

  "Logging": {
"LogLevel": {
  "Default": "Debug"
}

},

And my Startup.cs contains this line in the ConfigureServices method:

services.AddDbContext<MyContext>(options =>
            options.UseSqlServer(Configuration.GetConnectionString("MyConnectionSTring")));

Startup.cs also contains this per one of the answer below, but it does not cause EF SQL to get printed to the output window:

    public ILogger<Startup> Logger { get; set; }

    public Startup(IConfiguration configuration, ILogger<Startup> logger)
    {
        Configuration = configuration;
        Logger = logger;

        //the following line gets printed to my debug output window:
        logger.LogDebug("this is a debug message");
    }

Upvotes: 6

Views: 9794

Answers (4)

CANDIMAN
CANDIMAN

Reputation: 139

I could not use .AddDebug() in my EFCore 3 application. I added nuget package Microsoft.Extensions.Logging.Debug To my project and was able to use it. I now see the generated SQL commands in the Output Window (Show output from Debug).

Create a field in the context:

public static readonly ILoggerFactory _loggerFactory
                    = LoggerFactory.Create(builder => builder.AddDebug().AddFilter((category, level) => level == LogLevel.Information && !category.EndsWith("Connection")));

and add the field to your optionsBuilder:

 optionsBuilder.UseLoggerFactory(_loggerFactory);

Upvotes: 9

Tom Regan
Tom Regan

Reputation: 3841

Thank you for the comments and answers. The issue here was between my ears. The code I originally posted in my question works; it logs raw SQL to the debug output window for Entity SQL queries.

In fact, a lot less is needed if the application uses asp.net core (which this one does, it is a web api application). By default Visual Studio 2017 inserts the following bit of code in Program.cs as part of the project template:

public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
        WebHost.CreateDefaultBuilder(args)  
            .UseStartup<Startup>();

The call to CreateDefaultBuilder adds 3 types of logging--Console, Debug, EventSource--and also fetches the "Logging" section from appsettings.json. The "LoggerFactory" stuff in my original question is redundant and not needed.

The code I was testing and failing with, while it used the database context, was executing a stored procedure using System.Data.Common.DbCommand, which does not pass information to the logger hooked up to the DbContext. I need to log System.Data.Common.DbCommand sql statements manually (this is also needed in .Net Framework, but it has been so many years since I've touched this I'd forgotten).

When I created a DbSet in my DbContext and did a select against it using Entity SQL, eg:

var log = _myContext.Log.FirstOrDefault(o => o.Id > 0);

this successfully logs the raw SQL to my debug output window, eg:

Microsoft.EntityFrameworkCore.Database.Command:Information: 
Executed DbCommand (6ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
SELECT TOP(1) [o].[Id], [o].[Browser], [o].[Client], [o].[Date], [o].[Exception], 
[o].[Host], [o].[Level], [o].[Logger], [o].[Message], [o].[StackTrace], [o].[Thread], 
[o].[User]
FROM [Log] AS [o]
WHERE [o].[Id] > 0

Upvotes: 2

Samuel Akosile
Samuel Akosile

Reputation: 339

You can try this if it will help. Thanks

 public static void Main(string[] args)
    {
        CreateWebHostBuilder(args).Build().Run();
    }

    public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
        WebHost.CreateDefaultBuilder(args)
            .UseStartup<Startup>()
            .ConfigureLogging(logger => {
                logger.AddDebug()
                      .AddFilter(DbLoggerCategory.Database.Command.Name, LogLevel.Information);
                //logger.AddConsole(); //UnComment out this line if you did not use CreateDefaultBuilder
            });

enter image description here

Upvotes: 2

weiky
weiky

Reputation: 140

you also need to add the ILogger Interface to the Startup.cs

     public Startup(IConfiguration configuration, ILogger<Startup> logger, IHostingEnvironment hostingEnvironment)
        {   
            Configuration = configuration;
            Logger = logger;
            HostingEnvironment = hostingEnvironment;
        }

        public ILogger<Startup> Logger { get; }

I use Serilog and it works with following options in the appsetting just fine

    "Serilog": {
    "MinimumLevel": {
      "Default": "Debug"
    }

Upvotes: 2

Related Questions