HomeNikola Knezevic

In this article

Banner

EF Core Simple Logging in .NET

27 May 2025
5 min

Special Thanks to Our Sponsors:

Sponsor Logo

EF Core is too slow? Discover how you can easily insert 14x faster (reducing saving time by 94%).

Boost your performance with our method within EF Core: Bulk Insert, update, delete and merge.

Thousands of satisfied customers have trusted our library since 2014.

👉 Learn more

Sponsor Newsletter

Logging is an essential part of every application, it helps us understand what’s happening under the hood, trace errors, monitor performance and debug issues.

When it comes to data access, logging can be especially valuable.

You can see what queries are being executed, how long they take and whether they're behaving as expected.

If you're using Entity Framework Core, you can easily log and inspect everything with a powerful feature called Simple Logging.

Simple Logging

Simple Logging is a lightweight way to see how your LINQ queries are translated into raw SQL.

It doesn’t require any advanced configuration or third-party packages, just a few lines of setup.

Use cases for Simple Logging:

  • Inspect the SQL queries generated by EF Core
  • Monitor query performance locally
  • Debug issues with incorrect or inefficient queries

It's a great tool for learning, debugging and optimizing during development.

NOTE: EF Core also integrates with Microsoft.Extensions.Logging, which requires more configuration, but is often more suitable for logging in production applications.

Simple Logging Configuration

Enabling Simple Logging in EF Core is straightforward. All you need to do is configure logging when setting up your DbContext.

EF Core logs are accessible from any type of application by using the LogTo method when configuring a DbContext instance. Based on your preferences and requirements, you can log to:

  • Console
  • Debug window
  • File

The LogTo method requires an Action delegate, which EF Core invokes for each generated log message. This delegate is responsible for handling the message, whether that's writing it to the console or a file.

Logging to the Console

Logging directly to the console is one of my personal favorites. Simply pass Console.WriteLine to the LogTo method, and EF Core will write each log message to the console.

csharp
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) =>
    optionsBuilder.LogTo(Console.WriteLine);

Logging to the Debug Window

Just like console logging, you can direct EF Core log messages to the Debug window in your IDE using Debug.WriteLine.

csharp
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) =>
    optionsBuilder.LogTo(message => Debug.WriteLine(message));

Lambda syntax must be used in this case because the Debug class is compiled out of release builds.

Logging to a File

Logging to a file requires a bit more setup, as you'll need to create a StreamWriter to write logs to a file.

Once the stream is set up, you can pass its WriteLine method to LogTo, just like in the previous examples:

csharp
private readonly StreamWriter _logStream = new StreamWriter("mylog.txt", append: true);

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) =>
    optionsBuilder.LogTo(_logStream.WriteLine);

public override void Dispose()
{
    base.Dispose();
    _logStream.Dispose();
}

public override async ValueTask DisposeAsync()
{
    await base.DisposeAsync();
    await _logStream.DisposeAsync();
}

NOTE: It's important to properly dispose of the StreamWriter when the DbContext is disposed.

Sensitive Data

By default, EF Core excludes data values such as parameters and keys from messages and logs:

log
Executed DbCommand (12ms) [Parameters=[@p0='?' (DbType = Guid), @p1='?', @p2='?', @p3='?' (DbType = Decimal)], CommandType='Text', CommandTimeout='30']
    INSERT INTO "Products" ("Id", "Description", "Name", "Price")
    VALUES (@p0, @p1, @p2, @p3);

This is a security conscious choice, as such information may be sensitive and shouldn't be exposed.

However, when debugging, having access to these values can be incredibly useful. To include this information in logs, you can explicitly enable it using EnableSensitiveDataLogging():

csharp
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) =>
    optionsBuilder
        .LogTo(Console.WriteLine)
        .EnableSensitiveDataLogging();
log
Executed DbCommand (30ms) [Parameters=[@p0='c8485bd1-dcb7-42a0-b0d7-518a379c02c6', @p1='string' (Nullable = false), @p2='string' (Nullable = false), @p3='2'], CommandType='Text', CommandTimeout='30']
    INSERT INTO "Products" ("Id", "Description", "Name", "Price")
    VALUES (@p0, @p1, @p2, @p3);

NOTE: Only enable sensitive data logging in debugging environments.

Detailed query exceptions

EF Core does not wrap every value read from the database in a try-catch block by default.

To improve error messages in such cases, you can enable EnableDetailedErrors(). This instructs EF Core to wrap individual reads in try-catch blocks and provide more context when exceptions occur:

csharp
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) =>
    optionsBuilder
        .LogTo(Console.WriteLine)
        .EnableDetailedErrors();

Filtering

Every EF Core log message is associated with a severity level from the LogLevel enum.

By default, EF Core logs all messages at Debug level and above, however, you can reduce the noise by specifying a higher minimum log level.

csharp
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) =>
    optionsBuilder.LogTo(Console.WriteLine, LogLevel.Information);

For more granular control, LogTo also supports a custom filtering function.

This allows you to specify exactly which messages should be logged based on both LogLevel and EventId:

csharp
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) =>
    optionsBuilder
        .LogTo(
            Console.WriteLine,
            (eventId, logLevel) => logLevel >= LogLevel.Information
                                   || eventId == RelationalEventId.ConnectionOpened
                                   || eventId == RelationalEventId.ConnectionClosed);

Conclusion

EF Core's Simple Logging is a powerful yet lightweight feature that gives you deep insight into how your application interacts with the database.

Whether you're inspecting generated SQL, debugging query issues, or optimizing performance, it provides valuable transparency with minimal configuration.

With features like EnableSensitiveDataLogging, EnableDetailedErrors, and flexible log filtering, you can fine-tune your logging experience to match your development needs.

If you want to check out examples I created, you can find the source code here:

Source Code

I hope you enjoyed it, subscribe and get a notification when a new blog is up!

Subscribe

Stay tuned for valuable insights every Thursday morning.