EF Core - Logging

Logging trong Entity Framework Core

Chúng ta thường lưu vết lại SQL và thay đổi thông tin theo dõi cho mục đích gỡ lỗi trong EF Core.

Lưu vết trong EF Core tự động tích hợp với các cơ chế lưu vết của .NET Core. Vì vậy, hãy tìm hiểu về các nguyên tắc cơ bản về lưu vết  .NET Core trước khi bắt đầu lưu vết EF Core

Entity Framework Core tích hợp với lưu vết .NET Core để lưu vết SQL và thay đổi thông tin theo dõi cho các mục tiêu đầu ra khác nhau. Đầu tiên, hãy cài đặt gói Nuget dành cho nhà cung cấp dịch vụ lưu vết mà bạn chọn, sau đó liên kết DbContext với ILoggerFactory.

Cài đặt gói NuGet của nhà cung cấp dịch vụ lưu vết. Tại đây, chúng tôi sẽ hiển thị lưu vết  trên bảng điều khiển, vì vậy hãy cài đặt gói Microsoft.Extensions.Logging.Console NuGet từ Trình quản lý gói NuGet hoặc thực hiện lệnh sau trong Bảng điều khiển Trình quản lý Gói:

PM> Install-Package Microsoft.Extensions.Logging.Console

Hình sau minh họa cách DbContext hoạt động với API lưu vết và nhà cung cấp lưu vết bảng điều khiển.

Sau khi cài đặt trình cung cấp trình ghi bảng điều khiển, bạn cần tạo một phiên bản static / singleton của LoggerFactory và sau đó buộc nó với một DbContext, như được hiển thị bên dưới.

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; }
}

Trong ví dụ trên, chúng ta đã tạo một đối tượng của lớp LoggerFactory và gán nó cho biến tĩnh kiểu ILoggerFactory. Sau đó, chúng ta truyền đối tượng này vào phương thức optionsBuilder.UseLoggerFactory () trong phương thức OnConfiguring (). Điều này sẽ cho phép DbContext chia sẻ thông tin với đối tượng loggerFactory, đối tượng này sẽ hiển thị tất cả thông tin ghi nhật ký trên bảng điều khiển.

Theo mặc định, EF Core sẽ không ghi dữ liệu nhạy cảm, chẳng hạn như giá trị tham số bộ lọc. Vì vậy, hãy gọi EnableSensitiveDataLogging () để ghi dữ liệu nhạy cảm.

Chú ý:

Đội ngũ EF khuyên bạn nên sử dụng cùng một đối tượng gốc của trình ghi nhật ký với tất cả các phiên bản của lớp DbContext trong suốt thời gian tồn tại của ứng dụng. Nếu không, nó có thể dẫn đến rò rỉ bộ nhớ và hoạt động kém. Bạn cũng có thể tạo một lớp factory riêng biệt cung cấp cho bạn đối tượng singleton của lớp LoggerFactory để sử dụng với DbContext.

Chúng ta hãy hiểu ví dụ trên một cách chi tiết.

Đầu tiên, chúng tôi tạo một đối tượng của lớp LoggerFactory và gán nó cho biến tĩnh kiểu ILoggerFactory, như hình dưới đây.

public static readonly ILoggerFactory loggerFactory = new LoggerFactory(
    new[] { new ConsoleLoggerProvider ((_, __) => true, true) }
);

LoggerFactory có thể chứa một hoặc nhiều nhà cung cấp lưu vết có thể được sử dụng để đăng nhập đồng thời vào nhiều phương tiện. Hàm tạo của LoggerFactory chấp nhận một mảng các đối tượng trình cung cấp trình lưu vết khác nhau là mới [] {}. Chúng tôi muốn hiển thị nhật ký trên bảng điều khiển, vì vậy hãy tạo một đối tượng của nhà cung cấp trình lưu vết bảng điều khiển ConsoleLoggerProvider.

Có bốn hàm tạo của ConsoleLoggerProvider. Sử dụng hàm cho phép biểu thức lambda (Func <>) để lọc nhật ký và bao gồm Scope Boolean, như được hiển thị bên dưới.

new ConsoleLoggerProvider((_, __) => true, true)

Ở đây, chúng ta không muốn lọc bất kỳ thông tin nào để biểu thức lambda luôn trả về true (_, __) => true.

Sau khi tạo một đối tượng của ILoggerFactory, hãy liên kết DbContext với ILoggerFactory trong phương thức OnConfiguring () bằng cách sử dụng DbContextOptionsBuilder.

optionsBuilder.UseLoggerFactory(loggerFactory)

Do đó, chúng ta đã gắn kết DbContext với LoggerFactory bao gồm nhà cung cấp trình ghi bảng điều khiển. Bây giờ, chúng ta có thể xem tất cả nhật ký trên bảng điều khiển bất cứ khi nào một phiên bản của DbContext thực thi bất kỳ hành động nào.

Hãy xem xét ví dụ sau.

using (var context = new SchoolContext())
{
    var std = new Student(){ StudentName = "Steve" };
    context.Add(std);
                
    context.SaveChanges();
    Console.ReadLine();
}

Ví dụ trên sẽ hiển thị các bản ghi sau trên bảng điều khiển:

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.

Filter Logs

Trong ví dụ trên, DbContext đã ghi lại tất cả thông tin trong khi lưu một thực thể. Đôi khi bạn không muốn ghi lại tất cả thông tin và lọc một số nhật ký không mong muốn. Trong EF Core, bạn có thể lọc nhật ký bằng cách chỉ định danh mục trình lưu vết và cấp độ nhật ký.

Logger Categories

EF Core 2.x bao gồm lớp DbLoggerCategory để có được một danh mục  Entity Framework Core logger bằng cách sử dụng thuộc tính Name của nó. Bảng sau liệt kê các danh mục trình lưu vết khác nhau.

Logger Category Class Description
Database.Command Logger category for command execution, including SQL sent to database.
Database.Connection Logger category for db connection operations.
Database.Transaction Logger category for db transactions.
Infrastructure Logger category for miscellaneous messages for the EF infrastructure.
Migration Logger category for migrations.
Model Logger category for model building and metadata.
Query Logger category for queries (excluding generated SQL).
Scaffolding Logger category for scaffolding and reverse engineering.
Update Logger category for DbContext.SaveChanges() messages.

Lưu vết các truy vấn SQL 

Để lưu vết các truy vấn SQL, hãy khai báo danh mục DbLoggerCategory.Database.Command và LogLevel.Information trong biểu thức lambda trong hàm tạo của ConsoleLoggerProvider, như được hiển thị bên dưới.

public static readonly ILoggerFactory consoleLoggerFactory  
            = new LoggerFactory(new[] {
                  new ConsoleLoggerProvider((category, level) =>
                    category == DbLoggerCategory.Database.Command.Name &&
                    level == LogLevel.Information, true)
                });

Hoặc, chỉ cần gọi phương thức AddConsole () trên LoggerFactory để ghi các truy vấn SQL, theo mặc định.

public static readonly ILoggerFactory consoleLoggerFactory
         = new LoggerFactory().AddConsole();

Bây giờ, điều này sẽ lưu vết  thông tin truy vấn sau đây để lưu một thực thể bằng 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();