Entity Framework 6.1
Turning on logging without recompiling
I already blogged about SQL logging in EF6. Part 3 of that series shows how to use EF with a logging framework such as NLog. If you do this then you can easily switch logging on and off using NLog or equivalent without any changes to the app. This is the approach I would use if I wanted to log SQL from EF. But what if logging was not considered at all when the app was created? Now with EF 6.1 you can switch logging on for any app without access to the source or recompiling.
How to do it
To log SQL to the console add the following entry to the entityFramework section in your application's web.config or app.config:<interceptors>
<interceptor type="System.Data.Entity.Infrastructure.Interception.DatabaseLogger, EntityFramework"/>
</interceptors>
(If you are just working with the compiled application then look for a file like “MyApplication.exe.config” since this is what app.config is compiled into.)
To log to a filename instead use something like:
<interceptors>
<interceptor type="System.Data.Entity.Infrastructure.Interception.DatabaseLogger, EntityFramework">
<parameters>
<parameter value="C:\Stuff\LogOutput.txt"/>
</parameters>
</interceptor>
</interceptors>
By default this will cause the log file to be overwritten with a new file each time the app starts. To instead append to the log file if it already exists use something like:
<interceptors>
<interceptor type="System.Data.Entity.Infrastructure.Interception.DatabaseLogger, EntityFramework">
<parameters>
<parameter value="C:\Stuff\LogOutput.txt"/>
<parameter value="true" type="System.Boolean"/>
</parameters>
</interceptor>
</interceptors>
What's going on
This is the part of the post where I describe what's going on in EF. You don't need to read any of this to use logging, but for those interested here it is.The built-in SQL logging uses a class called DatabaseLogFormatter. DatabaseLogFormatter is an EF interceptor that implements various interfaces which inform it of operations on commands, connections, transactions, etc. It creates log output based on these operations and sends this log output to a registered delegate—effectively sending the formatted log output to a stream. Changing what is logged can be customized as described in part 2 of the logging series.
EF 6.1 introduced IDbConfigurationInterceptor. This is an interception interface which lets code examine and/or modify EF configuration when the app starts. Using this hook we can write a simple version of DatabaseLogger:
public class ExampleDatabaseLogger : IDbConfigurationInterceptor
{
public void Loaded(
DbConfigurationLoadedEventArgs loadedEventArgs,
DbConfigurationInterceptionContext interceptionContext)
{
var formatterFactory = loadedEventArgs
.DependencyResolver
.GetService<Func<DbContext, Action<string>, DatabaseLogFormatter>>();
var formatter = formatterFactory(null, Console.Write);
DbInterception.Add(formatter);
}
}
This is basically the same as DatabaseLogger in the EntityFramework assembly except that I have simplified it a bit by only including the code that logs to the Console. The Loaded method is called when EF configuration (as represented by the DbConfiguration class) has been loaded. Let's look at the three lines of code in Loaded.
- The first line asks EF for the registered DatabaseLogFormatter factory. We could just new up a new DatabaseLogFormatter here instead, but if the app has customized log formatting then this line will get that customized logger instead of the default.
- The first line didn't actually get the DatabaseLogFormatter. It instead got a factory that can be used to create DatabaseLogFormatter instances. The second line invokes that factory to get an actual formatter instance. Null is passed for the context since we are going to log for all context instances. The second argument to the factory is a delegate for the Console output stream—in this case, just a pointer to the Console.Write method. If we were logging to a file we would pass the Write method from our StreamWriter instance instead.
- The third line registers the DatabaseLogFormatter as an interceptor, which is how logging in EF works as described above.