C# İle Veritabanı Kayıt Loglama Sistemi Nasıl Yapılır?

C# İle Veritabanı Kayıt Loglama Sistemi Nasıl Yapılır?
C# İle Veritabanı Kayıt Loglama Sistemi Nasıl Yapılır?

Gereksinimler ve Ön Hazırlık

Uygulamayı geliştirmek için .NET 8 veya 9 SDK yüklü bir geliştirme ortamına ihtiyacınız vardır. Veritabanı yönetim sistemi olarak Microsoft SQL Server kullanacağız. Projenizde Entity Framework Core (EF Core) paketlerinin yüklü olduğundan emin olun.

  • Visual Studio 2022 veya VS Code
  • .NET 8/9 SDK
  • Entity Framework Core NuGet paketleri
  • SQL Server Management Studio (SSMS)

Projenizi oluşturduktan sonra, NuGet paket yöneticisi konsolundan şu komutları çalıştırarak gerekli bağımlılıkları ekleyin:

dotnet add package Microsoft.EntityFrameworkCore.SqlServer
dotnet add package Microsoft.EntityFrameworkCore.Design

Veritabanı Log Tablosunun Tasarlanması

Loglama sisteminin temeli, tutulan verilerin düzenli bir şekilde saklandığı bir tablodur. "AuditLogs" adında bir tablo oluşturarak, her işlemin kimliğini, tablosunu, işlem türünü (Insert, Update, Delete) ve eski/yeni değerlerini saklayacağız.

public class AuditLog
{
    public int Id { get; set; }
    public string TableName { get; set; }
    public string Action { get; set; } // Insert, Update, Delete
    public string OldValues { get; set; } // JSON formatında
    public string NewValues { get; set; } // JSON formatında
    public DateTime ChangeDate { get; set; } = DateTime.UtcNow;
    public string UserId { get; set; }
}

Bu model sınıfı, veritabanındaki her değişikliği izlemek için kullanılacak temel yapıdır. JSON formatında veri saklamak, veritabanı şemasını her tablo değişikliğinde güncelleme zorunluluğunu ortadan kaldırır.

DbContext Üzerinde SaveChanges Metodunu Özelleştirme

EF Core'da veritabanına yapılan her kayıt işlemi SaveChanges metodu üzerinden geçer. Bu metodu override ederek, veritabanına gitmeden hemen önce değişiklikleri yakalayabilir ve log tablosuna yazabiliriz.

public override async Task SaveChangesAsync(CancellationToken cancellationToken = default)
{
    var auditEntries = OnBeforeSaveChanges();
    var result = await base.SaveChangesAsync(cancellationToken);
    await OnAfterSaveChanges(auditEntries);
    return result;
}

Bu yöntem, "Interception" (araya girme) mantığıyla çalışır. İşlem gerçekleşmeden önce verinin durumunu alır, işlem bittikten sonra ise logları kalıcı hale getirir.

Değişiklikleri İzleme ve JSON Serileştirme

Hangi verilerin değiştiğini tespit etmek için ChangeTracker sınıfını kullanırız. Aşağıdaki kod bloğu, Entity'nin durumunu analiz eder ve değişen alanları JSON olarak hazırlar.

private List OnBeforeSaveChanges()
{
    ChangeTracker.DetectChanges();
    var auditEntries = new List();
    foreach (var entry in ChangeTracker.Entries())
    {
        if (entry.Entity is AuditLog || entry.State == EntityState.Detached || entry.State == EntityState.Unchanged)
            continue;

        var auditEntry = new AuditEntry(entry)
        {
            TableName = entry.Metadata.GetTableName(),
            Action = entry.State.ToString()
        };
        auditEntries.Add(auditEntry);
    }
    return auditEntries;
}

Bu adım, uygulamanın performansını doğrudan etkiler. Çok sayıda verinin güncellendiği durumlarda, ChangeTracker üzerindeki yükü optimize etmek için sadece izlenmesi gereken tabloları filtreleyebilirsiniz.

Loglama Stratejileri Karşılaştırması

Yöntem Avantaj Dezavantaj
EF Core Interceptor Merkezi ve otomatik Karmaşık sorgularda performans kaybı
Database Trigger Veritabanı seviyesinde garanti Koddan bağımsız, yönetimi zor
Repository Pattern Kontrollü ve esnek Her metoda manuel ekleme gerektirir

Güvenlik ve Performans Uyarıları

Kritik Uyarı: Loglama sistemleri, hassas verileri (şifreler, kredi kartı bilgileri) asla düz metin olarak saklamamalıdır. Log verilerini serileştirirken, "Password" veya "Secret" içeren alanları filtrelediğinizden emin olun. Ayrıca, log tablosunun aşırı büyümesini önlemek için periyodik temizleme (archiving) stratejileri uygulayın.

Sıkça Sorulan Sorular

Loglama sistemi uygulamayı yavaşlatır mı?

Evet, her kayıtta ek bir veritabanı işlemi yapıldığı için küçük bir gecikme yaşanabilir. Bunu aşmak için loglama işlemlerini asenkron (async) olarak arka planda kuyruğa alarak çalıştırabilirsiniz.

Log verilerini nasıl şifrelemeliyim?

Veritabanı seviyesinde "Transparent Data Encryption" (TDE) kullanabilir veya uygulama katmanında veriyi serileştirmeden önce AES gibi simetrik şifreleme algoritmalarıyla şifreleyebilirsiniz.

Hangi tabloları loglamalıyım?

Sadece kritik verilerin olduğu (Kullanıcılar, Siparişler, Finansal kayıtlar) tabloları loglamanız önerilir. Tüm tabloları loglamak disk alanını hızla tüketir.

Log tablosu silinirse ne olur?

Log tablosu, ana veritabanı operasyonundan bağımsız bir işlem olarak tasarlanmalıdır. Hata durumunda loglama başarısız olsa bile ana işlem devam etmelidir (Try-Catch blokları ile yönetilmelidir).

Logları nasıl raporlayabilirim?

Log verileri JSON formatında olduğu için, bunları bir "Log Viewer" arayüzü ile okumak için Newtonsoft.Json veya System.Text.Json kütüphanelerini kullanarak kolayca deserialize edebilirsiniz.

Loglama Sistemlerinde Hata Ayıklama ve İzlenebilirlik

Loglama mekanizmalarınızın düzgün çalışıp çalışmadığını doğrulamak, sistemin güvenilirliği için kritiktir. Özellikle karmaşık ilişkisel verilerde (Entity Framework Core ile 1-N veya N-N ilişkiler), ChangeTracker üzerinden yakalanan veriler bazen beklenenden farklı sonuçlar verebilir. Hata ayıklama sürecinde şu adımları izlemek, sistemin sağlığını korumanıza yardımcı olur:

  • Log Kayıtlarını Doğrulama: Loglama işlemini gerçekleştiren SaveChangesAsync metodunuzun içine bir try-catch bloğu ekleyerek, loglama sırasında oluşabilecek veritabanı hatalarının ana işlemi (business logic) kesmesini engelleyin.
  • Kullanıcı Bağlamını İzleme: Log kayıtlarına mutlaka UserId veya RequestID gibi tanımlayıcılar ekleyin. Bu, bir hata anında hangi kullanıcının hangi işlemi tetiklediğini takip etmenizi sağlar.
public override async Task SaveChangesAsync(CancellationToken cancellationToken = default)
{
    try
    {
        return await base.SaveChangesAsync(cancellationToken);
    }
    catch (DbUpdateException ex)
    {
        // Loglama hatasını ayrı bir dosyaya veya konsola yazdırın
        Console.WriteLine($"Loglama sırasında hata oluştu: {ex.Message}");
        throw;
    }
}

Performans Optimizasyonu İçin Asenkron Loglama

Veritabanı loglama işlemleri, özellikle yüksek trafikli uygulamalarda ana veritabanı üzerinde yük oluşturabilir. Performans kaybını minimize etmek için loglama işlemlerini ana işlemden ayırmak (decoupling) en iyi yaklaşımdır. Bu noktada Background Service veya Message Queue (RabbitMQ, Azure Service Bus) kullanımı önerilir.

Eğer veritabanı üzerinde doğrudan loglama yapıyorsanız, log tablonuzun indeksleme stratejisini gözden geçirmeniz gerekir. CreatedDate veya EntityName gibi sık sorgulanan kolonlar üzerinde indeks oluşturmak, raporlama hızınızı ciddi oranda artıracaktır.

Strateji Avantaj Dezavantaj
Senkron Loglama Veri tutarlılığı garantidir. İstek süresini uzatır.
Asenkron/Background Loglama Performans kaybı minimumdur. Hata durumunda log kaybı riski olabilir.

İleri Düzey İpucu: Log Verilerini Arşivleme

Log tabloları zamanla milyonlarca satıra ulaşabilir. Bu durum veritabanı performansını düşürür. Belirli bir süreden (örneğin 6 ay) eski logları otomatik olarak bir "LogArchive" tablosuna veya düşük maliyetli bir depolama birimine (Blob Storage gibi) taşıyan bir Hangfire görevi tanımlamak, sisteminizin uzun vadeli sürdürülebilirliği için hayati önem taşır.

// Hangfire ile örnek bir temizleme görevi
RecurringJob.AddOrUpdate(() => ArchiveOldLogs(), Cron.Monthly);

public void ArchiveOldLogs()
{
    var threshold = DateTime.Now.AddMonths(-6);
    var oldLogs = _context.AuditLogs.Where(x => x.CreatedAt < threshold).ToList();
    // Verileri arşiv tablosuna taşı ve ana tablodan sil
    _context.AuditLogs.RemoveRange(oldLogs);
    _context.SaveChanges();
}

Sonuç

C# ile profesyonel bir veritabanı kayıt loglama sistemi oluşturmak, uygulamanızın izlenebilirliğini ve güvenliğini bir üst seviyeye taşır. Bu rehberde öğrendiğiniz DbContext override yöntemleri ve ChangeTracker kullanımı, kurumsal projelerin vazgeçilmez bir parçasıdır. Bir sonraki adım olarak, bu logları merkezi bir log sunucusuna (Elasticsearch veya Serilog gibi) göndererek daha gelişmiş analizler yapabilirsiniz.

Yasal Sorumluluk Reddi: Bu makaledeki kod örnekleri eğitim amaçlıdır. Üretim ortamında kullanmadan önce güvenlik açıklarını (SQL Injection, XSS) göz önünde bulundurarak gerekli testleri yapınız. Veri gizliliği yasalarına uygunluk sağlamak, geliştiricinin sorumluluğundadır.

Bu yazıya tepkinizi paylaşın:
Deniz Arslan

On yıldır pratik ev çözümleri ve hayat kolaylaştıran teknikler üzerine içerik üretiyorum. Okuyucuların karmaşık süreçleri en basit adımlarla çözmelerine yardımcı oluyorum.

Yorumlar (0)

Yorum Yaz