Logging EF Core actions to a file using Serilog
Image from Unsplash

Logging EF Core actions to a file using Serilog

Log Entity Framework Core using Serilog in .NET Core application

Logging is an essential part of the application. It gives you insights which allows you to see your application behavior or even user behaviour and actions taken by them in the application.
Serilog is most probably the most popular library for logging in .NET Core applications. It is easy to integrate it into your application by adding it to the dependency injection container at the very entry point of your application allowing you to log the whole application life cycle from it's start to it's exit.

Tracing the data operations can give you a insight what went wrong in the system and how some data got changed. If you are using Microsoft SQL Server you can use Change Data Capture (CDC) from which you can see all the CRUD operations on your data.

It does a great job, but with it your tight to the SQL Server and for different reasons you might decide to use some other data storage like Postgres for example. For this reason, tracking data changes from your application can be crucial for data analyses and trouble shooting. .NET Core with Serilog is doing a great job with logging, but EF Core does not come with logging configured out of the box.

For example, one you start you application with EF Core that uses Serilog file logging and you check the log files you will see that query execution which you see in console is not present in the file. Before we dive into the EF Core configuration let's first quickly see how to configure Serilog to write to file.

Serilog file logging configuration

First thing we need to do to engage Serilog in our application, we need to add NuGet packages in our project .csproj file

<Project Sdk="Microsoft.NET.Sdk.Web">
	<PropertyGroup>
	  <TargetFramework>netcoreapp2.1</TargetFramework>
	</PropertyGroup>
	...
	<ItemGroup>
		<PackageReference Include="Serilog.Extensions.Logging" Version="2.0.2" />
		<PackageReference Include="Serilog.Extensions.Logging.File" Version="1.1.0" />
		<PackageReference Include="Serilog.Settings.Configuration" Version="2.6.1" />
	</ItemGroup>
	...
</Project>
    

Once we have the NuGet packages added to our project, Visual Studio will take care of them being downloaded locally an we can now start adding Serilog to our DI container and pipeline. The changes have to be done in Startup.cs class file.

	public class Startup
    {
        public IConfiguration Configuration { get; private set; }
        public IHostingEnvironment HostingEnvironment { get; private set; }

        public Startup(IConfiguration configuration, IHostingEnvironment env)
        {
            Configuration = configuration;
            HostingEnvironment = env;
            Log.Logger = new LoggerConfiguration()
                                .ReadFrom.Configuration(configuration)
                                .CreateLogger();

        }    

        public void ConfigureServices(IServiceCollection services)
        {
            services.AddLogging();
        }

        public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
        {
           loggerFactory.AddSerilog();

           app.UseMvc();
        }
    }

    

You can configure Serilog either inline in your code or you can do it through appconfig.json file. I prefer using appconfig.json as my logging setting may be different depending on the environment so I might have one Serilog setting for development on appsettings.Development.json and a separate one in appsettings.Production.json for production environment.

The config section for Serilog to log to a file on the disk, configuration settings section looks something like this

{
  "Serilog": {
    "MinimumLevel": "Debug",
    "WriteTo": [
      {
        "Name": "RollingFile",
        "Args": {
          "logDirectory": ".\\Logs",
          "fileSizeLimitBytes": 104857600 ,
          "pathFormat": "Logs/MyApplication.{Date}.log",
          "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level}] {Message}{NewLine}{Exception}"
        }
      }
    ]
  }
}
    

We are pretty much ready to got with our file logging in place in our application. 

DbContext logging configuration

Now, as I mentioned above, although you have your logging in place, your EF core logs will not go to log file. You need to use injected Serilog ILoggerFactory which we injected in the startup already. We just need to reference it in our DbContext constructor

public class MySampleDbContext : DbContext
{
	private readonly ILoggerFactory _loggerFactory;

    public MySampleDbContext(DbContextOptions<BloggingContext> options, ILoggerFactory loggerFactory)
        : base(options)
    {
        _loggerFactory = loggerFactory;
    }
    
    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        optionsBuilder.UseLoggerFactory(_loggerFactory);
    }
}
    

Now when you start your application, all logs including EF Core executed queries against your data storage.

Note

Generated log files can be easily processed with elastic search and make your analyses and troubleshooting much more usable. More convenient and storage agnostic than using SQL Server CDC

Disclaimer

Purpose of the code contained in snippets or available for download in this article is solely for learning and demo purposes. Author will not be held responsible for any failure or damages caused due to any other usage.


About the author

DEJAN STOJANOVIC

Dejan is a passionate Software Architect/Developer. He is highly experienced in .NET programming platform including ASP.NET MVC and WebApi. He likes working on new technologies and exciting challenging projects

CONNECT WITH DEJAN  Loginlinkedin Logintwitter Logingoogleplus Logingoogleplus

JavaScript

read more

SQL/T-SQL

read more

Umbraco CMS

read more

PowerShell

read more

Comments for this article