Basit Kayıt

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.

Tavsiye

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.

Konfigürasyon

EF Core günlüklerine, LogTo kullanımı aracılığıyla herhangi bir uygulama türünden erişilebilir. Bu yapılandırma genellikle bir geçersiz kılma işleminde DbContext.OnConfiguring yapılır. Örneğin:

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    => optionsBuilder.LogTo(Console.WriteLine);

Alternatif olarak, LogTo, AddDbContext'in bir parçası olarak veya DbContextOptions oluşturucusuna geçmek üzere bir DbContext örneği oluşturulurken çağrılabilir.

Tavsiye

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.

Kayıtları yönlendirme

Konsola loglama

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. Sonra temsilciye, verilen mesajla ilgili bir şey yapma görevi düşer.

Console.WriteLine Yöntemi genellikle yukarıda gösterildiği gibi bu temsilci için kullanılır. Bunun sonucunda her ileti konsola yazılır.

Hata ayıklama penceresine kayıt yapma

Debug.WriteLine , Çıktıyı Visual Studio'daki Hata Ayıklama penceresine veya diğer IDE'lere göndermek için kullanılabilir. Bu durumda lambda söz dizimi kullanılmalıdır çünkü Debug sınıfı dağıtım derlemelerine dahil edilmemiştir. Örneğin:

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    => optionsBuilder.LogTo(message => Debug.WriteLine(message));

Dosyaya kaydetme

Bir dosyaya yazmak için, dosya için bir StreamWriter veya benzeri bir şey oluşturulması gerekir. Yöntemi WriteLine daha sonra yukarıdaki diğer örneklerde olduğu gibi kullanılabilir. Bağlam serbest bırakıldığında yazarı da yok ederek dosyanın düzgün şekilde kapatıldığından emin olun. Örneğin:

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

Tavsiye

Dosyalara günlük kaydı yapmak için üretim uygulamalarında Microsoft.Extensions.Logging kullanmayı düşünün.

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. EF Core'da EnableSensitiveDataLogging() çağrılarak etkinleştirilebilir. Örneğin:

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. Örneğin:

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    => optionsBuilder
        .LogTo(Console.WriteLine)
        .EnableDetailedErrors();

Filtreleme

Günlük düzeyleri

Her EF Core günlük iletisi, bir enum tarafından tanımlanan bir düzeye LogLevel atanır. Varsayılan olarak, EF Core basit günlüğü, Debug düzeyindeki veya daha yüksek düzeydeki tüm iletileri içerir. LogTo bazı iletileri elemek için daha yüksek bir eşik değerine ayarlanabilir. Örneğin, Information kullanıldığında, veritabanı erişimi ve bazı bakım mesajlarıyla sınırlı en az günlük kümesine ulaşılır.

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    => optionsBuilder.LogTo(Console.WriteLine, LogLevel.Information);

Belirli iletiler

Her günlük iletisine bir EventIdatanır. Bu kimlikler, ilişkisel özel iletilere erişim için CoreEventId sınıfı veya RelationalEventId sınıfı üzerinden erişilebilir. 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, başlatılan veya sonlandırılan bağlama yönelik iletileri yalnızca 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 Mesajlar
Microsoft.EntityFrameworkCore Tüm EF Core iletileri
Microsoft.EntityFrameworkCore.Database Tüm veritabanı etkileşimleri
Microsoft.EntityFrameworkCore.Database.Connection Veritabanı bağlantısının kullanımları
Microsoft.EntityFrameworkCore.Veritabanı.Komut 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 Göçler
Microsoft.EntityFrameworkCore.ChangeTracking Değişiklik izleme etkinlikleri

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.Connectionve Database.Commandalt kategorileri Database.Transactioniç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, Information düzeyinde veya daha yüksek düzeyde herhangi bir iletiyi kaydetmek ve bir bağlantıyı açma veya kapatma iletilerini günlüğe kaydetmek için:

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    => optionsBuilder
        .LogTo(
            Console.WriteLine,
            (eventId, logLevel) => logLevel >= LogLevel.Information
                                   || eventId == RelationalEventId.ConnectionOpened
                                   || eventId == RelationalEventId.ConnectionClosed);

Tavsiye

Ö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 iletisi hiç oluşturulmaz.

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 kaydedildiği log seviyesini değiştir.
  • Olayı günlüğe kaydetmeyi tamamen atlayın
  • Olay gerçekleştiğinde istisna fırlatın

Olay için kayıt seviyesini değiştirme

Önceki örnekte, her iletiyi LogLevel.Information'de günlüğe kaydetmek için özel bir filtre ve LogLevel.Debug için tanımlanan iki olay kullanılmıştır. Aynı durum, iki Debug olayının günlük düzeyini Information olarak değiştirerek de 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. Özellikle gözden geçirilmiş ve idrak edilmiş bir uyarıyı yoksaymak için kullanışlıdır. Örneğin:

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    => optionsBuilder
        .ConfigureWarnings(b => b.Ignore(CoreEventId.DetachedLazyLoadingWarning))
        .LogTo(Console.WriteLine);

Etkinlik düzenlemek

Son olarak, EF Core belirli bir olay için istisna fırlatacak ş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.) Mesela:

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çerik LogTo çok sayıda satıra yayılarak biçimlendirilmiştir. İ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ı
  • Kopyalanabilir/yapıştırılabilir formda EventId, CoreEventId veya diğer EventId sınıflardan bir üye elde etmek için ve ham kimlik değeri ile.
  • Yukarıda açıklandığı gibi olay kategorisi.

Örneğin:

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.

Tavsiye

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. DbContextLoggerOptions.DefaultWithUtcTime kullanarak kültürden bağımsız UTC zaman damgaları kullanın, ancak diğer her şeyi aynı tutun. Örneğin:

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, DbContextLoggerOptions.SingleLine tarafından etkinleştirilebilir. Örneğin:

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

Diğer bayraklar DbContextLoggerOptions içinde, günlüğe eklenen meta veri miktarını azaltmak için kullanılabilir. Tek satırlı günlük kaydıyla birlikte bu çok yararlı olabilir. Örneğin:

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 geçiş

EF Core basit günlüğü, EF6'nın Database.Log ile 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 Log bir özellik oluşturup bunu yalnızca ayarlandığında kullanarak EF6'ya benzer bir DbContext davranış elde etmek yine de mümkündür. Örneğin:

public Action<string> Log { get; set; }

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    => optionsBuilder.LogTo(s => Log?.Invoke(s));