Entity Framework Core系列教程-25-Entity Framework Core日志
Entity Framework Core日志
我们经常需要在EF Core中记录SQL并更改跟踪信息以进行调试。
EF Core日志记录自动与.NET Core的日志记录机制集成。因此,在隐含使用EF Core的日志记录之前,了解有关.NET Core日志记录的基础知识。
Entity Framework Core与.NET Core日志记录集成在一起,以记录SQL并将跟踪信息更改为各种输出目标。首先,安装您选择的日志记录提供程序的Nuget程序包,然后将DbContext绑定到ILoggerFactory。
让我们安装日志记录提供程序的NuGet软件包。在这里,我们将在控制台上显示日志,因此从NuGet程序包管理器安装Microsoft.Extensions.Logging.Console NuGet程序包,或在程序包管理器控制台中执行以下命令:
Install-Package Microsoft.Extensions.Logging.Console
下图说明了DbContext如何与日志记录API和控制台日志记录提供程序一起使用。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-afUjJAU3-1581165281344)(d:\note\efcore\pic\27.png)]
在安装控制台记录器提供程序之后,您需要创建LoggerFactory的静态/单个实例,然后将其与DbContext绑定,如下所示。
public class SchoolContext : DbContext
{
//static LoggerFactory object
public static readonly ILoggerFactory loggerFactory = new LoggerFactory(new[] {
new ConsoleLoggerProvider((_, __) => true, true)
});
//or
// public static readonly ILoggerFactory loggerFactory = new LoggerFactory().AddConsole((_,___) => true);
public SchoolContext():base()
{
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseLoggerFactory(loggerFactory) //tie-up DbContext with LoggerFactory object
.EnableSensitiveDataLogging()
.UseSqlServer(@"Server=.\SQLEXPRESS;Database=SchoolDB;Trusted_Connection=True;");
}
public DbSet<Student> Students { get; set; }
}
在上面的示例中,我们创建了LoggerFactory类的对象,并将其分配给ILoggerFactory类型的静态变量。然后,我们在OnConfiguring()方法的optionsBuilder.UseLoggerFactory()方法中传递了此对象。这将使DbContext与loggerFactory对象共享信息,该对象又将在控制台上显示所有日志记录信息。
默认情况下,EF Core将不记录敏感数据,例如过滤器参数值。因此,调用EnableSensitiveDataLogging()记录敏感数据。
注意:
EF团队建议在应用程序生存期内,将同一个logger工厂对象与DbContext类的所有实例一起使用。否则,可能会导致内存泄漏和性能下降。您还可以创建一个单独的工厂类,为您提供LoggerFactory类的单例对象,以与DbContext一起使用。
让我们详细了解上面的示例。
首先,我们创建了LoggerFactory类的对象,并将其分配给ILoggerFactory类型的静态变量,如下所示。
public static readonly ILoggerFactory loggerFactory = new LoggerFactory(
new[] { new ConsoleLoggerProvider ((_, __) => true, true) }
);
LoggerFactory可以包含一个或多个日志记录提供程序,可用于同时记录到多个介质。 LoggerFactory的构造函数接受一系列不同的记录器提供程序对象作为new [] {}。我们希望在控制台上显示日志,因此创建控制台记录器提供程序ConsoleLoggerProvider的对象。
ConsoleLoggerProvider有四个构造函数。使用允许lambda表达式(Func <>)进行日志过滤的方法,并使用includeScope布尔值,如下所示。
new ConsoleLoggerProvider((_, __) => true, true)
在这里,我们不想过滤任何信息,因此lambda表达式将始终返回true (_, __) => true.
创建ILoggerFactory对象之后,使用DbContextOptionsBuilder在OnConfiguring()方法中将DbContext与ILoggerFactory绑定在一起。
optionsBuilder.UseLoggerFactory(loggerFactory)
因此,我们将DbContext与包括控制台记录器提供程序的LoggerFactory绑定在一起。现在,每当DbContext实例执行任何操作时,我们都可以在控制台上看到所有日志。
考虑以下示例。
using (var context = new SchoolContext())
{
var std = new Student(){ StudentName = "Steve" };
context.Add(std);
context.SaveChanges();
Console.ReadLine();
}
上面的示例将在控制台上显示以下日志:
dbug: Microsoft.EntityFrameworkCore.Infrastructure[100401]
An 'IServiceProvider' was created for internal use by Entity Framework.
info: Microsoft.EntityFrameworkCore.Infrastructure[100403]
Entity Framework Core 2.0.0-rtm-26452 initialized 'SchoolContext' using pr
ovider 'Microsoft.EntityFrameworkCore.SqlServer' with options: SensitiveDataLoggingEnabled
dbug: Microsoft.EntityFrameworkCore.Database.Connection[200000]
Opening connection to database 'SchoolDB' on server '.\SQLEXPRESS'.
dbug: Microsoft.EntityFrameworkCore.Database.Connection[200001]
Opened connection to database 'SchoolDB' on server '.\SQLEXPRESS'.
dbug: Microsoft.EntityFrameworkCore.Database.Transaction[200200]
Beginning transaction with isolation level 'ReadCommitted'.
warn: Microsoft.EntityFrameworkCore.Database.Command[100400]
Sensitive data logging is enabled. Log entries and exception messages may
include sensitive application data, this mode should only be enabled during development.
dbug: Microsoft.EntityFrameworkCore.Database.Command[200100]
Executing DbCommand [Parameters=[@p0='' (DbType = DateTime2), @p1='' (DbTy
pe = Int32), @p2='0', @p3='' (Size = 8000) (DbType = Binary), @p4='Steve' (Size = 4000), @p5='0'], CommandType='Text', CommandTimeout='30']
SET NOCOUNT ON;
INSERT INTO [Students] ([DateOfBirth], [GradeId], [Height], [Photo], [Stud
entName], [Weight])
VALUES (@p0, @p1, @p2, @p3, @p4, @p5);
SELECT [StudentID]
FROM [Students]
WHERE @@ROWCOUNT = 1 AND [StudentID] = scope_identity();
info: Microsoft.EntityFrameworkCore.Database.Command[200101]
Executed DbCommand (68ms) [Parameters=[@p0='' (DbType = DateTime2), @p1=''
(DbType = Int32), @p2='0', @p3='' (Size = 8000) (DbType = Binary), @p4='Steve'
(Size = 4000), @p5='0'], CommandType='Text', CommandTimeout='30']
SET NOCOUNT ON;
INSERT INTO [Students] ([DateOfBirth], [GradeId], [Height], [Photo], [Stud
entName], [Weight])
VALUES (@p0, @p1, @p2, @p3, @p4, @p5);
SELECT [StudentID]
FROM [Students]
WHERE @@ROWCOUNT = 1 AND [StudentID] = scope_identity();
dbug: Microsoft.EntityFrameworkCore.Database.Command[200300]
A data reader was disposed.
dbug: Microsoft.EntityFrameworkCore.Database.Transaction[200202]
Committing transaction.
dbug: Microsoft.EntityFrameworkCore.Database.Connection[200002]
Closing connection to database 'SchoolDB' on server '.\SQLEXPRESS'.
dbug: Microsoft.EntityFrameworkCore.Database.Connection[200003]
Closed connection to database 'SchoolDB' on server '.\SQLEXPRESS'.
dbug: Microsoft.EntityFrameworkCore.Database.Transaction[200204]
Disposing transaction.
如您所见,它记录了所有信息。
过滤日志
在上面的示例中,DbContext在保存实体时记录了所有信息。有时您不想记录所有信息并过滤一些不需要的日志。在EF Core中,您可以通过指定记录器类别和日志级别来过滤日志。
日志分类
EF Core 2.x包含DbLoggerCategory类,以使用其Name属性获取Entity Framework Core记录器类别。下表列出了不同的记录器类别。
日志类别类 | 描述 |
---|---|
Database.Command | 命令执行的记录器类别,包括发送到数据库的SQL。 |
Database.Connection | 数据库连接操作的记录器类别。 |
Database.Transaction | 数据库事务的记录器类别。 |
Infrastructure | EF基础结构的其他消息的记录器类别。 |
Migration | 迁移的记录器类别。 |
Model | 用于模型构建和元数据的记录器类别。 |
Query | 查询的记录器类别(不包括生成的SQL)。 |
Scaffolding | 脚手架和逆向工程的记录仪类别。 |
Update | DbContext.SaveChanges()消息的记录器类别。 |
记录SQL查询
要仅记录SQL查询,请在ConsoleLoggerProvider的构造函数的lambda表达式中指定DbLoggerCategory.Database.Command类别和LogLevel.Information,如下所示。
public static readonly ILoggerFactory consoleLoggerFactory
= new LoggerFactory(new[] {
new ConsoleLoggerProvider((category, level) =>
category == DbLoggerCategory.Database.Command.Name &&
level == LogLevel.Information, true)
});
或者,默认情况下,只需在LoggerFactory上调用AddConsole()方法即可记录SQL查询。
public static readonly ILoggerFactory consoleLoggerFactory
= new LoggerFactory().AddConsole();
现在,这将记录以下查询信息,这些查询信息使用DbContext保存一个实体。
info: Microsoft.EntityFrameworkCore.Database.Command[200101]
Executed DbCommand (73ms) [Parameters=[@p0='' (DbType = DateTime2), @p1=''
(DbType = Int32), @p2='0', @p3='' (Size = 8000) (DbType = Binary), @p4='Steve'
(Size = 4000), @p5='0'], CommandType='Text', CommandTimeout='30']
SET NOCOUNT ON;
INSERT INTO [Students] ([DateOfBirth], [GradeId], [Height], [Photo], [Stud
entName], [Weight])
VALUES (@p0, @p1, @p2, @p3, @p4, @p5);
SELECT [StudentID]
FROM [Students]
WHERE @@ROWCOUNT = 1 AND [StudentID] = scope_identity();