Laravel İle Özelleştirilmiş Bir Aktivite Loglama Sistemi Nasıl Yapılır?

Laravel İle Özelleştirilmiş Bir Aktivite Loglama Sistemi Nasıl Yapılır?
Laravel İle Özelleştirilmiş Bir Aktivite Loglama Sistemi Nasıl Yapılır?

Gereksinimler ve Ön Hazırlık

Bu sistemi uygulamak için sisteminizde Laravel 10 veya üzeri bir sürümün yüklü olması gerekmektedir. Veritabanı işlemleri için Eloquent ORM yapısını kullanacağız. Ayrıca, log kayıtlarının performans kaybı yaratmaması için veritabanı indeksleme stratejilerine dikkat etmelisiniz.

  • PHP 8.2+ sürümü
  • Laravel 10.x veya 11.x framework
  • MySQL veya PostgreSQL veritabanı
  • Temel düzeyde Eloquent Model bilgisi

Adım 1: Log Tablosunun ve Modelin Oluşturulması

Log verilerini tutacağımız tabloyu oluşturmak için bir migration dosyasına ihtiyacımız var. Bu tablo; işlemin yapıldığı kullanıcıyı, etkilenen modeli, yapılan değişikliğin türünü ve eski/yeni verileri içermelidir.

php artisan make:migration create_activity_logs_table

Aşağıdaki kod bloğu, log tablomuzun yapısını tanımlar. JSON veri tipi kullanımı, eski ve yeni verileri esnek bir şekilde saklamamızı sağlar.

Schema::create('activity_logs', function (Blueprint $table) {
    $table->id();
    $table->foreignId('user_id')->nullable()->constrained()->onDelete('set null');
    $table->string('log_name'); // Örneğin: 'user_update'
    $table->string('subject_type'); // Model adı
    $table->unsignedBigInteger('subject_id');
    $table->json('old_values')->nullable();
    $table->json('new_values')->nullable();
    $table->timestamps();
});

Adım 2: Trait Kullanarak Loglama Mantığını Soyutlama

Her modelde loglama kodunu tekrar yazmak yerine, bir "Trait" (özellik kümesi) oluşturarak bu mantığı tüm modellere kolayca dahil edebiliriz. Bu yaklaşım, kod tekrarını önler ve temiz bir mimari sunar.

namespace App\Traits;

use App\Models\ActivityLog;
use Illuminate\Support\Facades\Auth;

trait LogsActivity
{
    public static function bootLogsActivity()
    {
        static::updated(function ($model) {
            $model->logActivity('updated', $model->getOriginal(), $model->getChanges());
        });
    }

    protected function logActivity($event, $old, $new)
    {
        ActivityLog::create([
            'user_id' => Auth::id(),
            'log_name' => $event,
            'subject_type' => get_class($this),
            'subject_id' => $this->id,
            'old_values' => json_encode(array_intersect_key($old, $new)),
            'new_values' => json_encode($new),
        ]);
    }
}

Adım 3: Modellerde Loglama Sistemini Aktif Etme

Oluşturduğumuz LogsActivity trait'ini, loglamak istediğiniz herhangi bir modele eklemeniz yeterlidir. Bu sayede model üzerinde gerçekleşen güncelleme işlemleri otomatik olarak veritabanına kaydedilecektir.

namespace App\Models;

use App\Traits\LogsActivity;
use Illuminate\Database\Eloquent\Model;

class Product extends Model
{
    use LogsActivity;

    protected $fillable = ['name', 'price', 'stock'];
}

Loglama Yöntemlerinin Karşılaştırılması

Yöntem Avantaj Dezavantaj
Trait Yaklaşımı Modüler ve tekrar kullanılabilir Her modelde tanımlanmalı
Observer Yaklaşımı Merkezi yönetim sağlar Karmaşık ilişkilerde zorlayıcı olabilir
Middleware Tüm HTTP isteklerini izler Veri düzeyinde değişiklikleri yakalayamaz

Adım 4: Güvenlik ve Veri Gizliliği Uyarıları

Kritik Güvenlik Uyarısı: Loglama sisteminizde asla kullanıcı şifreleri, kredi kartı bilgileri veya kişisel verileri (KVKK kapsamında) açık metin olarak saklamayın. Hassas sütunları loglamadan önce mutlaka filtreleyin.

Loglama sırasında hassas verileri hariç tutmak için trait içerisinde bir "exclude" listesi oluşturabilirsiniz. Bu, uygulamanızın güvenlik standartlarına uyumunu sağlar.

protected $dontLog = ['password', 'remember_token'];

// Loglama sırasında filtreleme mantığı
$newValues = array_diff_key($new, array_flip($this->dontLog));

Adım 5: Log Verilerini Görüntüleme ve Sorgulama

Logları kaydettikten sonra bunları yönetici panelinde listelemek önemlidir. Laravel'in Eloquent yapısını kullanarak, belirli bir modele ait tüm logları kolayca çekebilirsiniz.

$logs = ActivityLog::where('subject_type', Product::class)
                   ->where('subject_id', $productId)
                   ->latest()
                   ->get();

Sıkça Sorulan Sorular

Loglama sistemi uygulama performansını etkiler mi?

Evet, her işlemde veritabanına kayıt atmak ek yük getirir. Çok yoğun trafik alan uygulamalarda loglama işlemini "Queue" (kuyruk) yapısı ile arka planda çalıştırmanız önerilir.

Neden hazır paket kullanmıyoruz?

Hazır paketler bazen ihtiyaç duyulmayan karmaşık özellikler içerir. Kendi sisteminizi kurmak, uygulamanızın özel gereksinimlerine tam uyum sağlar ve bağımlılıkları azaltır.

Eski verileri nasıl temizleyebilirim?

Laravel'in "Scheduled Tasks" (Zamanlanmış Görevler) özelliğini kullanarak, örneğin 6 aydan eski logları otomatik silen bir komut oluşturabilirsiniz.

JSON verileri veritabanında nasıl sorgulanır?

Laravel'in whereJsonContains yöntemi ile JSON sütunları içerisinde kolayca arama yapabilirsiniz.

Loglama için neden veritabanı tercih etmeliyim?

Dosya tabanlı loglama (log dosyaları) sorgulama ve raporlama için verimsizdir. Veritabanı, logları ilişkilendirmek ve analiz etmek için yapısal bir ortam sunar.

Gelişmiş Senaryo: Kullanıcı Etkinliklerini Kuyruğa Alma (Queue)

Loglama işlemleri, özellikle yüksek trafikli uygulamalarda veritabanı üzerinde ek bir yük oluşturabilir. Her model değişikliğinde senkron bir şekilde veritabanına yazmak, HTTP yanıt süresini uzatabilir. Bu durumu engellemek için Laravel'in Queue (Kuyruk) sistemini kullanarak loglama işlemlerini arka plana atabiliriz.

Öncelikle, loglama işlemini gerçekleştiren bir Job sınıfı oluşturun:

php artisan make:job ProcessActivityLog

Ardından, oluşturduğunuz Job sınıfını şu şekilde düzenleyin:

namespace App\Jobs;

use App\Models\ActivityLog;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;

class ProcessActivityLog implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

    public function __construct(protected array $logData) {}

    public function handle()
    {
        ActivityLog::create($this->logData);
    }
}

Trait içerisindeki logActivity metodunu, artık veritabanına doğrudan yazmak yerine bu kuyruğu tetikleyecek şekilde güncelleyebilirsiniz:

protected function logActivity(string $event)
{
    \App\Jobs\ProcessActivityLog::dispatch([
        'user_id' => auth()->id(),
        'model' => get_class($this),
        'model_id' => $this->id,
        'event' => $event,
        'old_values' => $this->getOriginal(),
        'new_values' => $this->getChanges(),
    ]);
}

Loglama Sistemi İçin Birim Testleri (Unit Testing)

Loglama mekanizmanızın beklendiği gibi çalıştığından emin olmak için Laravel'in test araçlarını kullanmalısınız. Özellikle Event veya Observer yapılarını test ederken, veritabanına kayıt atılıp atılmadığını doğrulamak kritik öneme sahiptir.

Aşağıdaki test örneği, bir model güncellendiğinde log tablosuna veri eklenip eklenmediğini kontrol eder:

public function test_it_logs_activity_on_model_update()
{
    $user = User::factory()->create();
    $this->actingAs($user);

    $product = Product::factory()->create(['name' => 'Eski İsim']);

    $product->update(['name' => 'Yeni İsim']);

    $this->assertDatabaseHas('activity_logs', [
        'model_id' => $product->id,
        'event' => 'updated',
    ]);
}

Test Stratejileri

  • Veri Bütünlüğü: old_values ve new_values alanlarının JSON formatında doğru kaydedildiğini doğrulayın.
  • Yetkilendirme: Giriş yapmamış kullanıcıların loglama tetikleyip tetiklemediğini kontrol edin (genellikle auth()->id() null dönecektir).
  • İstisna Yönetimi: Veritabanı bağlantısı koptuğunda veya loglama işlemi başarısız olduğunda ana işlemin (örneğin ürün güncelleme) etkilenip etkilenmediğini test edin.
İpucu: Testlerinizde DatabaseTransactions trait'ini kullanarak her testten sonra veritabanının otomatik olarak temizlenmesini sağlayın. Bu, testlerinizin birbirinden bağımsız ve hızlı çalışmasını garanti eder.

Sonuç

Laravel ile özelleştirilmiş bir aktivite loglama sistemi kurmak, uygulamanızın şeffaflığını ve güvenliğini artıran en iyi pratiklerden biridir. Bu rehberde öğrendiğiniz trait yapısı ve veritabanı tasarımı, orta ve büyük ölçekli projelerinizde sağlam bir temel oluşturacaktır. Bir sonraki adım olarak, log kayıtlarını bir admin paneli üzerinden görselleştirmeyi ve "kim, neyi, ne zaman değiştirdi" raporlarını oluşturmayı deneyebilirsiniz.

Sorumluluk Reddi: Bu kılavuzdaki kod örnekleri genel eğitim amaçlıdır. Üretim ortamında (production) kullanmadan önce mutlaka birim testleri (unit tests) ile doğrulayın ve güvenlik taramalarından geçirin. Veri kaybını önlemek için veritabanı işlemlerinde her zaman transaction kullanmaya özen gösterin.
Bu yazıya tepkinizi paylaşın:
Zeynep Kaya

Adım adım rehber hazırlama ve kullanıcı deneyimi odaklı içerik mimarisi konusunda yetkinim. Okuyucuların sorunlarını hızlı çözen, net ve uygulanabilir metinler üretmeyi seviyorum.

Yorumlar (0)

Yorum Yaz