Gereksinimler ve Ön Hazırlık
Bu sistemi kurabilmek için sisteminizde PHP 8.2 veya üzeri bir sürümün ve Laravel 11.x veya 12.x sürümünün yüklü olması gerekmektedir. Veritabanı yönetim sistemi olarak MySQL veya PostgreSQL kullanmanız önerilir.
- Laravel 11+ veya 12+ kurulumu.
- Veritabanı bağlantısı yapılandırılmış bir proje.
- Temel düzeyde Eloquent ORM ve Middleware bilgisi.
Adım 1: Etkinlik Günlüğü İçin Veritabanı Şemasını Oluşturma
Etkinlikleri saklamak için bir tabloya ihtiyacımız var. Bu tablo; işlemi yapan kullanıcıyı, yapılan işlemin türünü, etkilenen modeli ve değişen verileri içermelidir. İlk adım olarak migration dosyamızı oluşturalım.
php artisan make:migration create_activity_logs_table
Oluşturulan migration dosyasının içeriğini aşağıdaki gibi düzenleyerek veritabanı yapısını hazırlıyoruz:
public function up(): void
{
Schema::create('activity_logs', function (Blueprint $table) {
$table->id();
$table->foreignId('user_id')->nullable()->constrained()->onDelete('set null');
$table->string('event_type'); // Örn: 'created', 'updated', 'deleted'
$table->string('subject_type'); // Örn: 'App\Models\User'
$table->unsignedBigInteger('subject_id');
$table->json('old_values')->nullable();
$table->json('new_values')->nullable();
$table->string('ip_address', 45)->nullable();
$table->timestamps();
});
}
Adım 2: Etkinlik Günlüğü Modeli ve İlişkilendirme
Veritabanı tablomuz hazır olduğuna göre, bu tabloyu temsil edecek bir Eloquent modeli oluşturalım. Bu model, kayıtların kolayca yönetilmesini sağlayacaktır.
php artisan make:model ActivityLog
Model dosyasını açarak $fillable özelliklerini tanımlayalım:
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class ActivityLog extends Model
{
protected $fillable = [
'user_id', 'event_type', 'subject_type', 'subject_id', 'old_values', 'new_values', 'ip_address'
];
protected $casts = [
'old_values' => 'array',
'new_values' => 'array',
];
}
Adım 3: Laravel Observer İle Etkinlikleri Otomatik Yakalama
Her model için tek tek kod yazmak yerine, Laravel'in "Observer" (Gözlemci) yapısını kullanacağız. Bu sayede bir kayıt güncellendiğinde veya silindiğinde otomatik olarak log tutulacaktır.
php artisan make:observer ActivityObserver --model=User
Observer içerisinde updated metodunu şu şekilde güncelleyerek değişiklikleri yakalayalım:
public function updated(User $user): void
{
ActivityLog::create([
'user_id' => auth()->id(),
'event_type' => 'updated',
'subject_type' => get_class($user),
'subject_id' => $user->id,
'old_values' => $user->getOriginal(),
'new_values' => $user->getChanges(),
'ip_address' => request()->ip(),
]);
}
Kritik Güvenlik Uyarısı: Veritabanına hassas verileri (şifreler, API anahtarları vb.) kaydederkenold_valuesvenew_valuesiçerisinden bu alanları mutlaka filtreleyin.$user->getOriginal()kullanırken şifre gibi alanlarıarray_exceptile hariç tutmayı unutmayın.
Adım 4: Yöntemlerin Karşılaştırılması
Etkinlik günlüğü tutmak için farklı yaklaşımlar mevcuttur. Aşağıdaki tablo, projeniz için en uygun yöntemi seçmenize yardımcı olacaktır.
| Yöntem | Avantaj | Dezavantaj |
|---|---|---|
| Observer (Önerilen) | Merkezi ve otomatik | Karmaşık ilişkilerde yönetimi zor olabilir |
| Middleware | Tüm istekleri kapsar | Veri değişikliğini yakalamak zordur |
| Event Listeners | Düşük bağlılık (Decoupling) | Daha fazla dosya yönetimi gerektirir |
Adım 5: Günlükleri Görüntüleme ve Test Etme
Sistemin çalışıp çalışmadığını test etmek için basit bir rota ve controller üzerinden verileri çekelim. Aşağıdaki kod, son 10 etkinliği listeler:
Route::get('/logs', function () {
return App\Models\ActivityLog::latest()->paginate(10);
});
Test etmek için uygulamanızda bir kullanıcıyı güncelleyin ve /logs rotasına giderek JSON çıktısını kontrol edin. Eğer veriler doğru bir şekilde new_values sütununda görünüyorsa sisteminiz başarıyla çalışıyor demektir.
Adım 6: Performans İyileştirmeleri ve Ölçeklenebilirlik
Uygulamanız büyüdüğünde activity_logs tablosu hızla dolacaktır. Bu noktada "Queue" (Kuyruk) sistemini kullanmak, loglama işleminin kullanıcı deneyimini yavaşlatmamasını sağlar.
// Observer içerisinde loglama işlemini kuyruğa atma
dispatch(function () use ($data) {
ActivityLog::create($data);
})->onQueue('low');
Bu yapı, loglama işlemini arka plana atarak ana iş akışının kesintisiz devam etmesini sağlar.
Sıkça Sorulan Sorular
Etkinlik günlüğü sisteminde şifreleri nasıl gizlerim?
Observer içerisinde loglama yapmadan önce veriyi bir değişkene atayıp unset($data['password']) komutu ile şifre alanını diziden çıkararak veritabanına kaydedilmesini engelleyebilirsiniz.
Log tablosu çok büyürse ne yapmalıyım?
Laravel'in "Scheduled Tasks" (Zamanlanmış Görevler) özelliğini kullanarak, belirli bir tarihten eski logları otomatik olarak silen veya arşivleyen bir komut yazabilirsiniz.
Neden Middleware yerine Observer tercih etmeliyim?
Middleware sadece HTTP isteklerini görür, ancak Observer Eloquent üzerinden yapılan tüm değişiklikleri (CLI komutları dahil) yakalayabilir.
Bu sistemi tüm modellere nasıl uygularım?
Her model için tek tek Observer yazmak yerine, bir "Trait" oluşturup bu trait'i ilgili modellerinize ekleyerek kod tekrarından kaçınabilirsiniz.
Logları kullanıcıya göstermeli miyim?
Güvenlik nedeniyle, logları sadece yetkili yöneticilerin görebileceği bir admin panelinde sergilemeniz en doğrusudur.
Sorumluluk Reddi: Bu makalede paylaşılan kod örnekleri eğitim amaçlıdır. Üretim ortamında (production) kullanmadan önce mutlaka birim testleri (unit tests) ile doğrulayın ve veritabanı indekslemelerini (indexing) ihmal etmeyin.
İleri Düzey İpucu: Logları Asenkron Olarak İşleme
Etkinlik günlüğü sisteminiz büyüdükçe, her veritabanı işleminden sonra log kaydetmek, uygulamanızın yanıt süresini (response time) olumsuz etkileyebilir. Özellikle yoğun trafik alan sistemlerde, loglama işlemini ana istek döngüsünden ayırarak Laravel'in Queues (Kuyruklar) yapısını kullanmak en profesyonel yaklaşımdır.
Bu yöntemle, log verisi önce Redis veya veritabanı kuyruğuna atılır ve arka planda çalışan bir işçi (worker) tarafından işlenir. Böylece kullanıcı, logun kaydedilmesini beklemeden işlemini tamamlar.
// App/Observers/UserObserver.php içerisinde asenkron kullanım
public function updated(User $user)
{
// Loglama işlemini bir Job'a devrediyoruz
dispatch(new \App\Jobs\LogUserActivity($user, 'updated'));
}
// App/Jobs/LogUserActivity.php örneği
public function handle()
{
ActivityLog::create([
'user_id' => $this->user->id,
'action' => $this->action,
'payload' => json_encode($this->user->getChanges())
]);
}
Log Verilerini Hata Ayıklama İçin Kullanma
Etkinlik günlükleri sadece güvenlik denetimi için değil, aynı zamanda karmaşık hataları (bug) çözmek için de kritik bir kaynaktır. Kullanıcıların "bir şey oldu ama ne olduğunu bilmiyorum" dediği durumlarda, log tablonuzdaki payload sütunu, o anki verinin önceki ve sonraki halini karşılaştırarak sorunun kaynağını bulmanızı sağlar.
Hata ayıklama sürecini hızlandırmak için şu yardımcı metodu modelinize ekleyebilirsiniz:
// App/Models/User.php
public function getAuditTrail()
{
return $this->hasMany(ActivityLog::class)
->orderBy('created_at', 'desc')
->limit(10)
->get();
}
// Controller içerisinde kullanımı
public function debugUser(User $user)
{
$history = $user->getAuditTrail();
return view('admin.debug', compact('history'));
}
Veri Bütünlüğü ve Güvenlik Kontrolleri
Loglarınızın değiştirilemez olması, sistemin güvenilirliğini artırır. Eğer loglarınızın manipüle edilmediğinden emin olmak istiyorsanız, her log kaydına bir hash değeri ekleyebilirsiniz. Bu değer, bir önceki logun hash'i ve mevcut verinin birleşimiyle oluşturulur (Blockchain mantığına benzer).
| Yöntem | Avantaj | Dezavantaj |
|---|---|---|
| Senkron (Observer) | Anlık veri tutarlılığı | Yavaşlama riski |
| Asenkron (Queue) | Yüksek performans | Gecikmeli loglama |
| Event Sourcing | Tam geçmiş izlenebilirliği | Yüksek karmaşıklık |
Bu yaklaşımlardan hangisini seçeceğiniz, uygulamanızın ölçeğine ve verilerinizin kritiklik derecesine bağlıdır. Küçük ölçekli projelerde Observer yapısı yeterli olurken, kurumsal uygulamalarda mutlaka kuyruk yapısı kullanılmalıdır.
Sonuç
Laravel ile dinamik bir kullanıcı etkinlik günlüğü sistemi kurmak, uygulamanızın şeffaflığını ve güvenliğini artırır. Bu rehberde, Observer yapısını kullanarak veritabanı değişikliklerini nasıl izleyeceğinizi, verileri nasıl filtreleyeceğinizi ve performansı nasıl koruyacağınızı öğrendiniz. Bir sonraki adım olarak, bu logları görselleştiren bir admin paneli arayüzü geliştirmeyi veya logları Elasticsearch gibi bir arama motoruna aktarmayı deneyebilirsiniz.


Yorumlar (0)
Yorum Yaz