systemd Journal ile Süreç ve Servis Loglarını Gerçek Zamanlı Filtreleme ve Analiz Etme
Gece 2’de production sunucusu alarm veriyor, servislerden biri sessiz sedasız ölmüş ve kimse fark etmemiş. İşte tam o anda journalctl komutunu doğru kullanıp kullanmadığınız, saatler ile dakikalar arasındaki farkı belirliyor. systemd’nin getirdiği en güçlü araçlardan biri olan Journal sistemi, doğru sorgulanmadığında sadece ekrana kayan anlamsız satırlar yığınına dönüşüyor. Bu yazıda journalctl‘yi gerçekten işe yarar biçimde, filtreleyerek, analiz ederek ve gerçek zamanlı izleme modunda nasıl kullanacağınızı anlatacağım.
journalctl Nedir ve Neden Önemlidir?
Eski dünyada /var/log/syslog, /var/log/messages, /var/log/daemon.log gibi onlarca dosyaya dağılmış loglar vardı. Her servis kendi dosyasına yazardı, bir şeyleri birbirine bağlamak için grep, awk, sed kombinasyonlarıyla saatler geçirirdiniz. systemd bu kaotik yapıyı binary bir veritabanında topladı: Journal.
Journal’ın avantajları salt bir log deposundan çok daha derin:
- Structured logging destekliyor, her log kaydı anahtar-değer çiftiyle zenginleştirilebiliyor
- Kernel logları, servis logları, kullanıcı logları tek çatı altında
- Zaman damgaları monotonic clock ile de tutuluyor, sistem saati değişse bile tutarlı sıralama sağlanıyor
- Rate limiting ve kompresyon built-in geliyor
- Metadatalar otomatik ekleniyor: PID, UID, GID, servis adı, cgroup bilgisi
Dezavantajı mı? Binary format, direkt cat ile okuyamıyorsunuz. Ama journalctl bu konuda son derece yetenekli.
Temel Filtreleme: Servise Göre Log Çekme
En sık ihtiyaç duyduğunuz senaryo belirli bir servise ait logları görmek. Bunun için -u parametresini kullanıyorsunuz:
journalctl -u nginx.service
journalctl -u postgresql.service
journalctl -u sshd.service
Birden fazla servis aynı anda izlenebilir. Örneğin nginx ile php-fpm arasındaki etkileşimi araştırıyorsanız:
journalctl -u nginx.service -u php-fpm.service
Bu komut her iki servisin loglarını zaman damgasına göre birleştirilmiş biçimde gösterir. Birinin isteği diğerinin hatasıyla nasıl örtüştüğünü görmek için bulunmaz bir yöntem.
Gerçek Zamanlı İzleme: -f ile Tail Modu
tail -f alışkanlığından geliyorsanız, journalctl’nin eşdeğeri -f parametresi:
journalctl -f
journalctl -fu nginx.service
journalctl -fu postgresql.service -fu pgbouncer.service
-f parametresi yeni gelen logları anlık olarak ekrana yansıtır. Bir deployment yapıyorsunuz, servis ayağa kalkıyor mu, hata mı fırlatıyor, gerçek zamanlı görüyorsunuz. Production’da bir müdahale yaparken bu modu açık tutmak neredeyse zorunlu hale geliyor.
Daha da güçlü bir kullanım: servis restart attığınızda journalctl -f çıktısında hem önceki kapanış loglarını hem yeniden başlama sürecini görürsünüz. systemctl restart nginx && journalctl -fu nginx.service kombinasyonu rutin hale gelmeli.
Zaman Bazlı Filtreleme
Dün gece saat 03:00 ile 04:00 arasında ne oldu sorusuna cevap vermek için --since ve --until parametreleri kullanılır:
journalctl --since "2024-01-15 03:00:00" --until "2024-01-15 04:00:00"
Mutlak tarihler yanında göreli ifadeler de kabul ediliyor:
journalctl --since "1 hour ago"
journalctl --since "2 hours ago" --until "1 hour ago"
journalctl --since yesterday
journalctl --since today
journalctl --since "2024-01-15" --until "2024-01-16"
Servis bazlı filtrelemeyle birleştirince oldukça güçlü bir sorgu elde edilir:
journalctl -u mysql.service --since "2024-01-15 02:00:00" --until "2024-01-15 06:00:00"
Bu MySQL’in gece 2-6 arası ne yaptığını gösterir. Yavaş sorgu uyarıları, bağlantı sayısı aşım hataları, replikasyon gecikmeleri hepsini tek sorguyla yakalıyorsunuz.
Öncelik (Priority) Bazlı Filtreleme
Syslog seviyelerini biliyorsanız bu parametre doğrudan tanıdık gelecek. -p ile log önceliğine göre filtre uygulanır:
journalctl -p err
journalctl -p warning
journalctl -p crit
journalctl -p emerg
Öncelik seviyeleri şunlardır:
- emerg (0): Sistem kullanılamaz
- alert (1): Acil müdahale gerekiyor
- crit (2): Kritik durum
- err (3): Hata
- warning (4): Uyarı
- notice (5): Normal ama önemli
- info (6): Bilgi
- debug (7): Debug bilgisi
Sadece hata ve üzeri görmek istiyorsanız:
journalctl -p err..emerg
Bu “hata ve daha kritik her şeyi göster” anlamına geliyor. Production sunucusunda genel sağlık kontrolü yaparken şu kombinasyon çok işe yarar:
journalctl -p err --since today
Bugün kaç hata üretilmiş, hangi servislerden gelmiş, hızlıca görüyorsunuz.
PID ve UID Bazlı Filtreleme
Bazen belirli bir prosesin loglarına bakmanız gerekir. Özellikle ps aux çıktısında şüpheli bir PID tespit ettiğinizde:
journalctl _PID=1234
journalctl _UID=1000
journalctl _GID=33
Bu sözdizimi Journal’ın field matching özelliğini kullanıyor. Underscore ile başlayan alanlar trusted fields, yani systemd’nin kendisinin doldurduğu ve kullanıcı tarafından manipüle edilemeyen alanlar. Güvenlik analizlerinde bu ayrım önem taşıyor.
Belirli bir kullanıcının tüm süreçlerinin loglarını görmek için:
journalctl _UID=$(id -u www-data)
Web sunucu kullanıcısının sistemde ne yaptığını izlemek için kullanışlı bir yöntem.
Kernel Loglarını İzlemek
dmesg‘in yerini büyük ölçüde journalctl aldı. Kernel loglarına erişmek için -k parametresi kullanılır:
journalctl -k
journalctl -k --since "1 hour ago"
journalctl -k -p err
Bir donanım sorunu araştırıyorsunuz diyelim. Disk hataları, NIC drop’ları, bellek sorunları kernel seviyesinde loglanır. Şu kombinasyon kritik disk hatalarını anında tespit ettirir:
journalctl -k -p err --since "24 hours ago" | grep -i "error|fail|reset"
NVMe disk problemi mi var, SCSI hatası mı, hepsini bu şekilde yakalıyorsunuz.
Boot Bazlı Filtreleme
Journal her önyükleme için ayrı bir kayıt tutuyor. Önceki boot’larda ne olduğuna bakmak için -b parametresi kullanılır:
journalctl -b # Mevcut boot
journalctl -b -1 # Bir önceki boot
journalctl -b -2 # İki önceki boot
Sunucu beklenmedik şekilde restart attıysa, bir önceki boot’un son loglarına bakmak neden çöktüğünü anlatabilir:
journalctl -b -1 -p err
journalctl -b -1 -u postgresql.service
Tüm boot geçmişini görmek için:
journalctl --list-boots
Bu komut her boot’un ID’sini, başlangıç ve bitiş zamanını listeler. Planlı bir bakım penceresi dışında boot kaydı varsa, bunu hemen fark edersiniz.
JSON Çıktısı ile Programatik Analiz
Otomasyona entegrasyon veya daha derin analiz için JSON formatı kritik:
journalctl -u nginx.service -o json | head -5
journalctl -u nginx.service -o json-pretty | head -50
JSON çıktısını jq ile işleyerek çok güçlü sorgular yapılabilir:
journalctl -u nginx.service --since "1 hour ago" -o json |
jq -r 'select(.__PRIORITY <= "3") | [.__REALTIME_TIMESTAMP, .MESSAGE] | @tsv'
Bu komut son 1 saat içindeki hata seviyeli logları timestamp ve mesajıyla birlikte TSV formatında çıkarır. Bir monitoring scripti yazıyorsanız, bu çıktıyı parse etmek son derece kolaydır.
Başka bir senaryo: kaç farklı IP’den SSH brute-force denenmiş?
journalctl -u sshd.service --since "24 hours ago" -o json |
jq -r '.MESSAGE' |
grep "Failed password" |
grep -oP '(d+.){3}d+' |
sort | uniq -c | sort -rn | head -20
Bu tek satırlık pipeline son 24 saatte en çok brute-force deneyen IP’leri sıralar. Bir güvenlik raporu için buna ihtiyacınız varsa, journalctl + jq kombinasyonu işi halleder.
Çıktı Formatlarını Kontrol Etmek
-o parametresiyle çıktı formatı değiştirilebilir:
- short: Varsayılan, insan okunabilir kısa format
- short-precise: Mikrosaniye hassasiyetinde timestamp
- short-monotonic: Monotonic timestamp, boot başından itibaren geçen süre
- verbose: Tüm alanları gösterir
- json: Tek satır JSON
- json-pretty: Güzel biçimlendirilmiş JSON
- cat: Sadece mesaj, timestamp yok
- export: İkili dışa aktarma formatı
Verbose modu özellikle hangi metadata’nın kaydedildiğini görmek için faydalı:
journalctl -u nginx.service -n 1 -o verbose
Bu komutun çıktısında SELINUX_CONTEXT, SYSTEMD_CGROUP, SYSTEMD_UNIT, SYSTEMD_SLICE gibi onlarca alan göreceksiniz. Bunların hepsini filtrelemede kullanabilirsiniz.
Gerçek Dünya Senaryosu: Production Olayı Araştırması
Diyelim ki monitoring sisteminiz gece 03:47’de bir alert gönderdi. Web uygulaması yanıt vermiyor. Şöyle bir araştırma akışı izleyebilirsiniz:
# Önce genel resmi görün, o saat ne olmuş
journalctl --since "2024-01-15 03:40:00" --until "2024-01-15 04:00:00" -p warning
# nginx durumu
journalctl -u nginx.service --since "2024-01-15 03:40:00" --until "2024-01-15 04:00:00"
# Uygulama servisi
journalctl -u myapp.service --since "2024-01-15 03:40:00" --until "2024-01-15 04:00:00"
# Veritabanı bağlantı sorunları olabilir mi
journalctl -u postgresql.service --since "2024-01-15 03:40:00" --until "2024-01-15 04:00:00" -p err
# Kernel seviyesinde bir şey var mı (bellek, disk)
journalctl -k --since "2024-01-15 03:30:00" --until "2024-01-15 04:00:00" -p err
Bu sistematik yaklaşımla olayı 10 dakika içinde lokalize etmek mümkün. Rastgele log dosyalarında grep yapmanın aksine, journalctl sorguları size bağlamı hazır sunuyor.
Log Hacmini ve Disk Kullanımını Yönetmek
journalctl sadece okuma aracı değil, yönetim aracı da. Disk kullanımını kontrol etmek için:
journalctl --disk-usage
Eski logları temizlemek için birkaç yöntem var:
# Belirli süre öncesini sil
journalctl --vacuum-time=30d
# Belirli boyuta düşür
journalctl --vacuum-size=500M
# Belirli sayıda boot kaydını koru
journalctl --vacuum-files=5
/etc/systemd/journald.conf dosyasında kalıcı limitler tanımlayabilirsiniz:
journalctl --rotate # Mevcut journal dosyalarını arşivle
journalctl --flush # Runtime journal'ı diske aktar
Production’da journal boyutunu kontrol altında tutmak önemli. Özellikle verbose log basan uygulamalar varsa, /var/log/journal dizini hızla büyüyebilir.
Cursor Kullanımı: Kaldığınız Yerden Devam Edin
Uzun süreli izleme scriptleri yazarken cursor özelliği hayat kurtarır. Her log kaydının benzersiz bir cursor’ı var:
# Son kaydın cursor'ını öğren
journalctl -n 1 -o json | jq -r '.__CURSOR'
# Belirli bir cursor'dan sonrasını göster
journalctl --after-cursor="s=abc123..."
# Cursor'u dosyaya kaydet, scriptte kullan
CURSOR_FILE="/var/run/mymonitor.cursor"
journalctl --after-cursor=$(cat $CURSOR_FILE 2>/dev/null || echo "")
-u myapp.service -o json | while read line; do
echo $line | jq -r '.MESSAGE'
echo $line | jq -r '.__CURSOR' > $CURSOR_FILE
done
Bu pattern ile bir monitoring scripti her çalıştığında kaldığı yerden devam eder, log kaçırmaz, tekrar işlemez.
Uzak Sunucudan Journal Çekme
Bazı durumlarda ssh üzerinden remote journal’a erişmeniz gerekir. systemd-journal-remote ve systemd-journal-gatewayd servisleri bu iş için var, ama basit bir yöntem şu:
ssh user@remote-server "journalctl -u nginx.service --since '1 hour ago' -o json" |
journalctl --merge -o short
Ya da doğrudan:
ssh user@remote-server journalctl -fu nginx.service
Birden fazla sunucuyu izlemek için basit bir wrapper script yazabilirsiniz. Merkezi log toplama çözümü olmayan küçük ortamlarda bu yöntem hayat kolaylaştırır.
Önemli journalctl Parametrelerinin Özeti
Sık kullandığım parametrelerin hızlı referansı:
- -f: Gerçek zamanlı tail modu
- -u: Belirli bir unit/servis filtresi
- -k: Sadece kernel logları
- -b: Boot bazlı filtreleme, -1 bir önceki boot
- -p: Öncelik seviyesi filtresi
- -n: Son N satırı göster
- –since / –until: Zaman aralığı filtresi
- -o: Çıktı formatı (json, verbose, cat vb.)
- –no-pager: Pager olmadan çıktı, scripting için
- -e: Çıktının sonuna otomatik jump
- –grep: Mesaj içeriğinde regex arama
- –case-sensitive: Büyük/küçük harf duyarlı arama
- –disk-usage: Disk kullanım raporu
- –vacuum-time / –vacuum-size: Eski log temizleme
--grep parametresi özellikle vurgulamaya değer:
journalctl -u nginx.service --grep "upstream timed out" --since today
journalctl --grep "OOM" -k --since "1 week ago"
Bu parametre, grep’e pipe etmeye gerek kalmadan doğrudan journal query’si içinde regex arama yapmanızı sağlıyor. Büyük journal dosyalarında önemli performans farkı yaratıyor.
Sonuç
journalctl konusunda gördüğüm en büyük hata, sysadminlerin onu basit bir tail -f /var/log/syslog yedeği olarak kullanması. Oysa üstte anlattığım tekniklerin toplamı size merkezi, sorgulanabilir, structured bir log altyapısı sağlıyor.
Gerçek zamanlı izleme için -fu kombinasyonunu alışkanlık haline getirin. Olay araştırmalarında önce --since/--until ile zaman penceresini dar tutun, sonra servislere inin. JSON çıktısı ve jq kombinasyonunu scriptlerinize entegre edin.
Son olarak: journalctl hızlı çalışır ama yanlış sorgu yazarsanız büyük journal veritabanında boğulursunuz. Her zaman zaman filtresiyle başlayın, öncelik filtresiyle daraltın, servis filtresiyle lokalize edin. Bu sırayı takip etmek, müdahale sürelerinizi dramatik biçimde kısaltır. Gece 2’deki alarmda bunu hatırlarsınız.
