Basit Günlüğe Kaydetme
Bahşiş
Bu makalenin örneğini GitHub'dan indirebilirsiniz.
Entity Framework Core (EF Core) basit günlük kaydı, uygulama geliştirme ve hata ayıklama sırasında günlükleri kolayca almak için kullanılabilir. Bu günlük kaydı biçimi için en az yapılandırma gerekir ve ek NuGet paketi gerekmez.
Bahşiş
EF Core, daha fazla yapılandırma gerektiren ancak genellikle üretim uygulamalarında oturum açmak için daha uygun olan Microsoft.Extensions.Logging ile de tümleşir.
Yapılandırma
EF Core günlüklerine, DbContext örneği oluştururken her türden uygulamadan LogTo kullanılarak erişilebilir. Bu yapılandırma genellikle DbContext.OnConfiguring geçersiz kılma işlemiyle gerçekleştirilir. Örnek:
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
=> optionsBuilder.LogTo(Console.WriteLine);
Alternatif olarak, LogTo
oluşturucuya geçirmek DbContext
üzere bir DbContextOptions örnek oluşturulurken veya bir parçası AddDbContext olarak çağrılabilir.
Bahşiş
AddDbContext kullanıldığında veya DbContextOptions örneği DbContext oluşturucusna geçirildiğinde OnConfiguring hala çağrılır. Bu, DbContext'in nasıl yapılandırıldığından bağımsız olarak bağlam yapılandırmasını uygulamak için ideal bir yer olmasını sağlar.
Günlükleri yönlendirme
Konsolda günlüğe kaydetme
LogTo
dizeyi kabul eden bir Action<T> temsilci gerektirir. EF Core, oluşturulan her günlük iletisi için bir dizeyle bu temsilciyi çağırır. Daha sonra verilen iletiyle bir şey yapmak temsilciye bağlı olur.
Console.WriteLine Yöntemi genellikle yukarıda gösterildiği gibi bu temsilci için kullanılır. Bu, her günlük iletisinin konsola yazılmasıyla sonuçlanıyor.
Hata ayıklama penceresinde günlüğe kaydetme
Debug.WriteLine , Çıktıyı Visual Studio'daki Hata Ayıklama penceresine veya diğer IDE'lere göndermek için kullanılabilir. Sınıfı yayın derlemeleri dışında derlendiğinden Debug
lambda söz dizimi bu durumda kullanılmalıdır. Örnek:
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
=> optionsBuilder.LogTo(message => Debug.WriteLine(message));
Dosyaya günlük kaydı yapma
Bir dosyaya yazmak için dosya için bir veya benzer bir StreamWriter dosya oluşturulması gerekir. Yöntemi WriteLine daha sonra yukarıdaki diğer örneklerde olduğu gibi kullanılabilir. Bağlam atıldığında yazıcıyı atarak dosyanın temiz bir şekilde kapatıldığından emin olun. Örnek:
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();
}
Bahşiş
Üretim uygulamalarında dosyalara günlük kaydı için Microsoft.Extensions.Logging kullanmayı göz önünde bulundurun.
Ayrıntılı iletiler alınıyor
Hassas veriler
Varsayılan olarak, EF Core özel durum iletilerine hiçbir verinin değerini içermez. Bunun nedeni, bu tür verilerin gizli olması ve bir özel durum işlenmezse üretim kullanımında ortaya çıkarılabilmesidir.
Ancak, özellikle anahtarlar için veri değerlerini bilmek hata ayıklama sırasında çok yararlı olabilir. Bu, çağrısıyla EnableSensitiveDataLogging()EF Core'da etkinleştirilebilir. Örnek:
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
=> optionsBuilder
.LogTo(Console.WriteLine)
.EnableSensitiveDataLogging();
Ayrıntılı sorgu özel durumları
Performans nedenleriyle EF Core, bir try-catch bloğundaki veritabanı sağlayıcısından bir değeri okumak için yapılan her çağrıyı sarmalamaz. Ancak, bu bazen özellikle veritabanı model tarafından izin verilmediğinde NULL döndürdüğünde tanılaması zor özel durumlarla sonuçlanıyor.
Bu ayarın açılması EnableDetailedErrors EF'in bu try-catch bloklarını tanıtmasına ve böylece daha ayrıntılı hatalar sağlamasına neden olur. Örnek:
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
=> optionsBuilder
.LogTo(Console.WriteLine)
.EnableDetailedErrors();
Filtreleme
Günlük düzeyleri
Her EF Core günlük iletisi, sabit listesi tarafından tanımlanan bir düzeye LogLevel atanır. Varsayılan olarak, EF Core basit günlüğü her iletiyi Debug
düzeyde veya daha yüksek bir düzeyde içerir. LogTo
bazı iletileri filtrelemek için daha yüksek bir minimum düzey geçirilebilir. Örneğin, geçiş Information
, veritabanı erişimi ve bazı temizlik iletileriyle sınırlı en az günlük kümesiyle sonuçlanır.
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
=> optionsBuilder.LogTo(Console.WriteLine, LogLevel.Information);
Belirli iletiler
Her günlük iletisine bir EventIdatanır. Bu kimliklere ilişkisel özel iletiler için sınıfından veya sınıfından RelationalEventId erişilebilirCoreEventId. Veritabanı sağlayıcısının da benzer bir sınıfta sağlayıcıya özgü kimlikleri olabilir. Örneğin, SqlServerEventId SQL Server sağlayıcısı için.
LogTo
yalnızca bir veya daha fazla olay kimlikleriyle ilişkili iletileri günlüğe kaydedecek şekilde yapılandırılabilir. Örneğin, yalnızca başlatılan veya atılan bağlama yönelik iletileri günlüğe kaydetmek için:
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
=> optionsBuilder
.LogTo(Console.WriteLine, new[] { CoreEventId.ContextDisposed, CoreEventId.ContextInitialized });
İleti kategorileri
Her günlük iletisi adlandırılmış hiyerarşik günlükçü kategorisine atanır. Kategoriler şunlardır:
Kategori | İletiler |
---|---|
Microsoft.EntityFrameworkCore | Tüm EF Core iletileri |
Microsoft.EntityFrameworkCore.Database | Tüm veritabanı etkileşimleri |
Microsoft.EntityFrameworkCore.Database. Bağlan ion | Veritabanı bağlantısının kullanımları |
Microsoft.EntityFrameworkCore.Database.Command | Veritabanı komutunun kullanımları |
Microsoft.EntityFrameworkCore.Database.Transaction | Veritabanı işleminin kullanımları |
Microsoft.EntityFrameworkCore.Update | Veritabanı etkileşimleri hariç varlıkları kaydetme |
Microsoft.EntityFrameworkCore.Model | Tüm model ve meta veri etkileşimleri |
Microsoft.EntityFrameworkCore.Model.Validation | Model doğrulaması |
Microsoft.EntityFrameworkCore.Query | Veritabanı etkileşimleri hariç sorgular |
Microsoft.EntityFrameworkCore.Infrastructure | Bağlam oluşturma gibi genel olaylar |
Microsoft.EntityFrameworkCore.Scaffolding | Veritabanı tersine mühendislik |
Microsoft.EntityFrameworkCore.Migrations | Geçişler |
Microsoft.EntityFrameworkCore.ChangeTracking | Değişiklik izleme etkileşimleri |
LogTo
yalnızca bir veya daha fazla kategorideki iletileri günlüğe kaydedecek şekilde yapılandırılabilir. Örneğin, yalnızca veritabanı etkileşimlerini günlüğe kaydetmek için:
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
=> optionsBuilder
.LogTo(Console.WriteLine, new[] { DbLoggerCategory.Database.Name });
DbLoggerCategory sınıfının bir kategoriyi bulmak için hiyerarşik bir API sağladığına ve dizeleri sabit kodlama gereğinden kaçındığını fark edin.
Kategoriler hiyerarşik olduğundan, kategoriyi Database
kullanan bu örnek , Database.Command
ve Database.Transaction
alt kategorileri Database.Connection
için tüm iletileri içerir.
Özel filtreler
LogTo
yukarıdaki filtreleme seçeneklerinden hiçbirinin yeterli olmadığı durumlarda özel bir filtrenin kullanılmasına izin verir. Örneğin, herhangi bir iletiyi hem düzeyde hem de daha yüksek bir düzeyde Information
günlüğe kaydetmek ve bir bağlantıyı açıp kapatmak için iletiler:
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
=> optionsBuilder
.LogTo(
Console.WriteLine,
(eventId, logLevel) => logLevel >= LogLevel.Information
|| eventId == RelationalEventId.ConnectionOpened
|| eventId == RelationalEventId.ConnectionClosed);
Bahşiş
Özel filtreler kullanarak filtreleme veya burada gösterilen diğer seçeneklerden herhangi birini kullanmak, temsilcide LogTo
filtrelemeden daha verimlidir. Bunun nedeni, filtre iletinin günlüğe kaydedilmemesi gerektiğini belirlerse günlük iletisinin oluşturulmamış olmasıdır.
Belirli iletiler için yapılandırma
EF Core ConfigureWarnings API'si, uygulamaların belirli bir olayla karşılaşıldığında ne olacağını değiştirmesine olanak tanır. Bu, aşağıdakiler için kullanılabilir:
- Olayın günlüğe kaydedildiği günlük düzeyini değiştirme
- Olayı günlüğe kaydetmeyi tamamen atlayın
- Olay gerçekleştiğinde özel durum oluşturma
Olay için günlük düzeyini değiştirme
Önceki örnekte her iletiyi LogLevel.Information
günlüğe kaydetmek için özel bir filtre ve için LogLevel.Debug
tanımlanan iki olay kullanılmıştır. İki olayın Information
günlük düzeyi Debug
olarak değiştirilerek de aynı durum elde edilebilir:
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
=> optionsBuilder
.ConfigureWarnings(
b => b.Log(
(RelationalEventId.ConnectionOpened, LogLevel.Information),
(RelationalEventId.ConnectionClosed, LogLevel.Information)))
.LogTo(Console.WriteLine, LogLevel.Information);
Bir olayın günlüğe kaydedilmesini gizleme
Benzer şekilde, tek bir olay günlük kaydından gizlenebilir. Bu, özellikle gözden geçirilmiş ve anlaşılmış bir uyarıyı yoksaymak için kullanışlıdır. Örnek:
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
=> optionsBuilder
.ConfigureWarnings(b => b.Ignore(CoreEventId.DetachedLazyLoadingWarning))
.LogTo(Console.WriteLine);
Olay için oluşturma
Son olarak, EF Core belirli bir olay için oluşturacak şekilde yapılandırılabilir. Bu, özellikle uyarıyı hataya dönüştürmede kullanışlıdır. (Aslında, yöntemin ConfigureWarnings
özgün amacı budur, dolayısıyla addır.) Örneğin:
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
=> optionsBuilder
.ConfigureWarnings(b => b.Throw(RelationalEventId.MultipleCollectionIncludeWarning))
.LogTo(Console.WriteLine);
İleti içeriği ve biçimlendirme
varsayılan içeriği LogTo
birden çok satır arasında biçimlendirilir. İlk satır ileti meta verilerini içerir:
- LogLevel Dört karakterli ön ek olarak
- Geçerli kültür için biçimlendirilmiş yerel bir zaman damgası
- EventId Üyeyi veya diğer
EventId
sınıflardan CoreEventId birini almak için kopyalanabilir/yapıştırılabilir formda, artı ham kimlik değeri - Yukarıda açıklandığı gibi olay kategorisi.
Örnek:
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.
Bu içerik, aşağıdaki bölümlerde gösterildiği gibi 'den DbContextLoggerOptionsdeğerler geçirilerek özelleştirilebilir.
Bahşiş
Günlük biçimlendirmesi üzerinde daha fazla denetim için Microsoft.Extensions.Logging kullanmayı göz önünde bulundurun.
UTC saatini kullanma
Varsayılan olarak, zaman damgaları hata ayıklama sırasında yerel tüketim için tasarlanmıştır. Bunun yerine kültürden bağımsız UTC zaman damgalarını kullanmak, ancak diğer her şeyi aynı tutmak için kullanın DbContextLoggerOptions.DefaultWithUtcTime . Örnek:
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
=> optionsBuilder.LogTo(
Console.WriteLine,
LogLevel.Debug,
DbContextLoggerOptions.DefaultWithUtcTime);
Bu örnek aşağıdaki günlük biçimlendirmesine neden olur:
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.
Tek satırlı günlük kaydı
Bazen günlük iletisi başına tam olarak bir satır almak yararlı olabilir. Bu, tarafından DbContextLoggerOptions.SingleLineetkinleştirilebilir. Örnek:
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
=> optionsBuilder.LogTo(
Console.WriteLine,
LogLevel.Debug,
DbContextLoggerOptions.DefaultWithLocalTime | DbContextLoggerOptions.SingleLine);
Bu örnek aşağıdaki günlük biçimlendirmesine neden olur:
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.
Diğer içerik seçenekleri
içindeki DbContextLoggerOptions diğer bayraklar, günlüğe eklenen meta veri miktarını kırpmak için kullanılabilir. Bu, tek satırlı günlük kaydıyla birlikte yararlı olabilir. Örnek:
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
=> optionsBuilder.LogTo(
Console.WriteLine,
LogLevel.Debug,
DbContextLoggerOptions.UtcTime | DbContextLoggerOptions.SingleLine);
Bu örnek aşağıdaki günlük biçimlendirmesine neden olur:
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'dan taşıma
EF Core basit günlüğü EF6'dan Database.Log iki önemli şekilde farklıdır:
- Günlük iletileri yalnızca veritabanı etkileşimleriyle sınırlı değildir
- Günlük, bağlam başlatma zamanında yapılandırılmalıdır
İlk fark için, yukarıda açıklanan filtreleme hangi iletilerin günlüğe kaydedileceklerini sınırlamak için kullanılabilir.
İkinci fark, gerekli olmadığında günlük iletileri oluşturmayarak performansı iyileştirmeye yönelik kasıtlı bir değişikliktir. Ancak, üzerinde DbContext
bir özellik oluşturup bunu yalnızca ayarlandığında kullanarak EF6'ya benzer bir Log
davranış elde etmek yine de mümkündür. Örnek:
public Action<string> Log { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
=> optionsBuilder.LogTo(s => Log?.Invoke(s));