簡單記錄
提示
您可以從 GitHub 下載本文的範例 。
Entity Framework Core (EF Core) 簡單的記錄可用來在開發和偵錯應用程式時輕鬆取得記錄。 此形式的記錄需要最少的設定,而且不需要額外的 NuGet 套件。
提示
EF Core 也與 需要更多設定的 Microsoft.Extensions.Logging 整合,但通常更適合在生產應用程式中記錄。
組態
在設定 DbCoNtext 執行個體時,可以使用 LogTo 從任何類型的應用程式存取 EF Core 記錄。 此設定通常是在 DbContext.OnConfiguring 的覆寫中完成。 例如:
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
=> optionsBuilder.LogTo(Console.WriteLine);
或者,在 建立實例以傳遞至建構函式時, LogTo
可以呼叫 作為 或 的 DbContext
一 DbContextOptions 部分 AddDbContext 。
提示
使用 AddDbCoNtext 或 DbCoNtextOptions 實例傳遞至 DbCoNtext 建構函式時,仍會呼叫 OnConfiguring。 不論 DbCoNtext 的建構方式為何,這都適合套用內容組態。
指示記錄
記錄至主控台
LogTo
Action<T>需要接受字串的委派。 EF Core 會針對產生的每個記錄訊息,使用字串呼叫此委派。 接著,委派即可使用指定的訊息執行某些動作。
方法 Console.WriteLine 通常用於此委派,如上所示。 這會導致每個記錄訊息寫入主控台。
記錄至偵錯視窗
Debug.WriteLine 可用來將輸出傳送至 Visual Studio 或其他 IDE 中的 [偵錯] 視窗。 在此案例中必須使用 Lambda 語法 , Debug
因為 類別是從發行組建編譯而來。 例如:
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
=> optionsBuilder.LogTo(message => Debug.WriteLine(message));
記錄至檔案
寫入檔案需要為檔案建立 StreamWriter 或類似的檔案。 WriteLine然後,方法可以和上述其他範例一樣使用。 請記得在處置內容時處置寫入器,以確保檔案完全關閉。 例如:
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();
}
提示
請考慮使用 Microsoft.Extensions.Logging 來記錄生產應用程式中的檔案。
取得詳細訊息
敏感性資料
根據預設,EF Core 不會在例外狀況訊息中包含任何資料的值。 這是因為這類資料可能是機密資料,而且如果未處理例外狀況,可能會顯示在生產環境中。
不過,瞭解資料值,尤其是索引鍵,在偵錯時可能會很有説明。 這可以在 EF Core 中藉由呼叫 EnableSensitiveDataLogging() 來啟用。 例如:
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
=> optionsBuilder
.LogTo(Console.WriteLine)
.EnableSensitiveDataLogging();
詳細的查詢例外狀況
基於效能考慮,EF Core 不會包裝每個呼叫,以從 try-catch 區塊中的資料庫提供者讀取值。 不過,這有時會導致難以診斷的例外狀況,特別是當模型不允許資料庫傳回 Null 時。
開啟 EnableDetailedErrors 會導致 EF 引進這些 try-catch 區塊,進而提供更詳細的錯誤。 例如:
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
=> optionsBuilder
.LogTo(Console.WriteLine)
.EnableDetailedErrors();
篩選
記錄層級
每個 EF Core 記錄訊息都會指派給列舉所 LogLevel 定義的層級。 根據預設,EF Core 簡單記錄包含層級 Debug
或更新層級的每個訊息。 LogTo
可以傳遞較高的最低層級來篩選掉某些訊息。 例如,傳遞 Information
會導致一組最低限度的記錄受限於資料庫存取和一些管家訊息。
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
=> optionsBuilder.LogTo(Console.WriteLine, LogLevel.Information);
特定訊息
每個記錄訊息都會指派 。 EventId 您可以從 類別或關聯式特定訊息的 RelationalEventId 類別存取 CoreEventId 這些識別碼。 資料庫提供者也可能在類似的類別中具有提供者特定的識別碼。 例如, SqlServerEventId 針對 SQL Server 提供者。
LogTo
可以設定為只記錄與一或多個事件識別碼相關聯的訊息。 例如,只記錄要初始化或處置之內容的訊息:
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
=> optionsBuilder
.LogTo(Console.WriteLine, new[] { CoreEventId.ContextDisposed, CoreEventId.ContextInitialized });
訊息類別
每個記錄訊息都會指派給具名階層式記錄器類別。 這些類別包括:
類別 | 訊息 |
---|---|
Microsoft.EntityFrameworkCore | 所有 EF Core 訊息 |
Microsoft.EntityFrameworkCore.Database | 所有資料庫互動 |
Microsoft.EntityFrameworkCore.Database。連線ion | 資料庫連線的使用 |
Microsoft.EntityFrameworkCore.Database.Command | 使用資料庫命令 |
Microsoft.EntityFrameworkCore.Database.Transaction | 資料庫交易的使用 |
Microsoft.EntityFrameworkCore.Update | 儲存實體,不包括資料庫互動 |
Microsoft.EntityFrameworkCore.Model | 所有模型和中繼資料互動 |
Microsoft.EntityFrameworkCore.Model.Validation | 模型驗證 |
Microsoft.EntityFrameworkCore.Query | 查詢,不包括資料庫互動 |
Microsoft.EntityFrameworkCore.Infrastructure | 一般事件,例如內容建立 |
Microsoft.EntityFrameworkCore.Scaffolding | 資料庫反向工程 |
Microsoft.EntityFrameworkCore.Migrations | 移轉 |
Microsoft.EntityFrameworkCore.ChangeTracking | 變更追蹤互動 |
LogTo
可以設定為只記錄來自一或多個類別的訊息。 例如,若要只記錄資料庫互動:
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
=> optionsBuilder
.LogTo(Console.WriteLine, new[] { DbLoggerCategory.Database.Name });
請注意,類別 DbLoggerCategory 會提供階層式 API 來尋找類別,並避免需要硬式程式碼字串。
由於類別是階層式的,因此使用類別的 Database
這個範例會包含子類別 Database.Connection
、 Database.Command
、 和 Database.Transaction
的所有訊息。
自訂篩選
LogTo
允許將自訂篩選用於上述篩選選項都不夠的情況。 例如,若要記錄層級或更新版本 Information
的任何訊息,以及開啟和關閉連線的訊息:
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
=> optionsBuilder
.LogTo(
Console.WriteLine,
(eventId, logLevel) => logLevel >= LogLevel.Information
|| eventId == RelationalEventId.ConnectionOpened
|| eventId == RelationalEventId.ConnectionClosed);
提示
使用自訂篩選或使用這裡顯示的任何其他選項進行篩選比委派中的 LogTo
篩選更有效率。 這是因為如果篩選準則決定不應該記錄訊息,則甚至不會建立記錄訊息。
特定訊息的設定
EF Core ConfigureWarnings API 可讓應用程式變更遇到特定事件時會發生什麼事。 這可以用來:
- 變更記錄檔層級,以記錄事件
- 完全略過記錄事件
- 事件發生時擲回例外狀況
變更事件的記錄層級
上述範例使用自訂篩選來記錄每個訊息, LogLevel.Information
以及針對 LogLevel.Debug
定義的兩個事件。 將兩 Debug
個事件的記錄層級變更為 Information
,即可達到相同的目的:
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
=> optionsBuilder
.ConfigureWarnings(
b => b.Log(
(RelationalEventId.ConnectionOpened, LogLevel.Information),
(RelationalEventId.ConnectionClosed, LogLevel.Information)))
.LogTo(Console.WriteLine, LogLevel.Information);
隱藏記錄事件
同樣地,個別事件可以從記錄中隱藏。 這特別適合忽略已檢閱和瞭解的警告。 例如:
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
=> optionsBuilder
.ConfigureWarnings(b => b.Ignore(CoreEventId.DetachedLazyLoadingWarning))
.LogTo(Console.WriteLine);
擲回事件
最後,EF Core 可以設定為針對指定的事件擲回。 這特別適用于將警告變更為錯誤。 (事實上,這是方法的原始 ConfigureWarnings
目的,因此是名稱。例如:
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
=> optionsBuilder
.ConfigureWarnings(b => b.Throw(RelationalEventId.MultipleCollectionIncludeWarning))
.LogTo(Console.WriteLine);
郵件內容和格式設定
的預設 LogTo
內容會跨多行格式化。 第一行包含訊息中繼資料:
- LogLevel做為四個字元前置詞的
- 針對目前文化特性格式化的本機時間戳
- EventId表單中的 ,可複製/貼上以取得成員或 CoreEventId 其中一個其他
EventId
類別的成員,加上原始識別碼值 - 事件類別目錄,如上所述。
例如:
info: 10/6/2020 10:52:45.581 RelationalEventId.CommandExecuted[20101] (Microsoft.EntityFrameworkCore.Database.Command)
Executed DbCommand (0ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
CREATE TABLE "Blogs" (
"Id" INTEGER NOT NULL CONSTRAINT "PK_Blogs" PRIMARY KEY AUTOINCREMENT,
"Name" INTEGER NOT NULL
);
dbug: 10/6/2020 10:52:45.582 RelationalEventId.TransactionCommitting[20210] (Microsoft.EntityFrameworkCore.Database.Transaction)
Committing transaction.
dbug: 10/6/2020 10:52:45.585 RelationalEventId.TransactionCommitted[20202] (Microsoft.EntityFrameworkCore.Database.Transaction)
Committed transaction.
您可以藉由傳遞 來自 DbContextLoggerOptions 的值來自訂此內容,如下列各節所示。
提示
請考慮使用 Microsoft.Extensions.Logging ,以進一步控制記錄格式設定。
使用 UTC 時間
根據預設,時間戳記是針對偵錯時的本機耗用量所設計。 請 DbContextLoggerOptions.DefaultWithUtcTime 改用與文化特性無關的 UTC 時間戳記,但保留其他所有專案。 例如:
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
=> optionsBuilder.LogTo(
Console.WriteLine,
LogLevel.Debug,
DbContextLoggerOptions.DefaultWithUtcTime);
此範例會產生下列記錄格式:
info: 2020-10-06T17:55:39.0333701Z RelationalEventId.CommandExecuted[20101] (Microsoft.EntityFrameworkCore.Database.Command)
Executed DbCommand (0ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
CREATE TABLE "Blogs" (
"Id" INTEGER NOT NULL CONSTRAINT "PK_Blogs" PRIMARY KEY AUTOINCREMENT,
"Name" INTEGER NOT NULL
);
dbug: 2020-10-06T17:55:39.0333892Z RelationalEventId.TransactionCommitting[20210] (Microsoft.EntityFrameworkCore.Database.Transaction)
Committing transaction.
dbug: 2020-10-06T17:55:39.0351684Z RelationalEventId.TransactionCommitted[20202] (Microsoft.EntityFrameworkCore.Database.Transaction)
Committed transaction.
單行記錄
有時候,每個記錄訊息只取得一行就很有用。 這可由 啟用 DbContextLoggerOptions.SingleLine 。 例如:
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
=> optionsBuilder.LogTo(
Console.WriteLine,
LogLevel.Debug,
DbContextLoggerOptions.DefaultWithLocalTime | DbContextLoggerOptions.SingleLine);
此範例會產生下列記錄格式:
info: 10/6/2020 10:52:45.723 RelationalEventId.CommandExecuted[20101] (Microsoft.EntityFrameworkCore.Database.Command) -> Executed DbCommand (0ms) [Parameters=[], CommandType='Text', CommandTimeout='30']CREATE TABLE "Blogs" ( "Id" INTEGER NOT NULL CONSTRAINT "PK_Blogs" PRIMARY KEY AUTOINCREMENT, "Name" INTEGER NOT NULL);
dbug: 10/6/2020 10:52:45.723 RelationalEventId.TransactionCommitting[20210] (Microsoft.EntityFrameworkCore.Database.Transaction) -> Committing transaction.
dbug: 10/6/2020 10:52:45.725 RelationalEventId.TransactionCommitted[20202] (Microsoft.EntityFrameworkCore.Database.Transaction) -> Committed transaction.
其他內容選項
中的 DbContextLoggerOptions 其他旗標可用來修剪記錄中包含的中繼資料數量。 這可以搭配單行記錄來使用。 例如:
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
=> optionsBuilder.LogTo(
Console.WriteLine,
LogLevel.Debug,
DbContextLoggerOptions.UtcTime | DbContextLoggerOptions.SingleLine);
此範例會產生下列記錄格式:
2020-10-06T17:52:45.7320362Z -> Executed DbCommand (0ms) [Parameters=[], CommandType='Text', CommandTimeout='30']CREATE TABLE "Blogs" ( "Id" INTEGER NOT NULL CONSTRAINT "PK_Blogs" PRIMARY KEY AUTOINCREMENT, "Name" INTEGER NOT NULL);
2020-10-06T17:52:45.7320531Z -> Committing transaction.
2020-10-06T17:52:45.7339441Z -> Committed transaction.
從 EF6 移動
EF Core 簡單記錄與 Database.Log EF6 不同,有兩個重要方式:
- 記錄訊息不限於資料庫互動
- 記錄必須在內容初始化時設定
針對第一個差異,上述篩選可用來限制記錄的訊息。
第二個差異是刻意變更,可藉由在不需要記錄訊息時產生記錄訊息來改善效能。 不過,您仍然可以藉由在您的 上 DbContext
建立 Log
屬性,然後只在設定屬性時,才能取得與 EF6 類似的行為。 例如:
public Action<string> Log { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
=> optionsBuilder.LogTo(s => Log?.Invoke(s));