journalctl ile Linux Sistem ve Servis Günlüklerini Filtreleme, İzleme ve Analiz Etme
Yıllar geçti, kaç tane “sunucu çöktü, log yok, ne olduğunu bilmiyoruz” anı yaşadım sayamam. Özellikle syslog döneminden journald’ye geçiş sürecinde, bir sürü meslektaşım “bu ne biçim sistem, logları nereye attı?” diye şikayet ediyordu. Gerçek şu ki journald, alışınca syslog’dan çok daha güçlü bir araç. Ama alışmak biraz zaman alıyor.
Bu yazıda journalctl komutunu gerçekten işe yarar biçimde kullanmayı anlatacağım. Teori değil, üretim ortamında günlük kullandığım filtreler, sorgular ve izleme teknikleri.
journald Nedir, Neden Önemsemeli?
systemd ile birlikte gelen systemd-journald servisi, sistem loglarını merkezi bir yapıda tutar. Klasik /var/log/messages veya /var/log/syslog dosyalarının aksine, journald logları ikili (binary) formatta /run/log/journal/ veya kalıcı yapılandırmada /var/log/journal/ dizininde saklar.
Bu yapının avantajları şunlar:
- Yapısal loglama: Her log girdisi metadata içerir. Servis adı, PID, UID, boot ID gibi alanlar otomatik eklenir
- Hızlı sorgulama: İkili format sayesinde büyük log kütlelerinde filtreleme çok daha hızlı çalışır
- Boyut yönetimi: journald log rotasyonunu otomatik yönetir, disk kotası tanımlayabilirsiniz
- Güvenli imzalama: Log girdilerinin manipüle edilip edilmediğini kontrol edebilirsiniz
Tek dezavantajı? cat /var/log/syslog gibi düz okuyamazsınız. Bunun için journalctl var.
Temel Kullanım ve Gezinme
En sade kullanımda journalctl komutunu çalıştırdığınızda tüm logları baştan gösterir. Yüzlerce bin satır geliyor, kimse okuyamaz.
# Tüm logları göster (less ile sayfalandırılmış)
journalctl
# Son 50 satırı göster
journalctl -n 50
# Gerçek zamanlı takip (tail -f gibi)
journalctl -f
# Son 100 satırı gerçek zamanlı takip et
journalctl -n 100 -f
-f parametresi production ortamında en çok kullandığım seçenek. Bir deployment sırasında servis loglarını canlı izlemek için biçilmiş kaftan.
Servis ve Unit Bazlı Filtreleme
Günlük işlerin yüzde sekseni belirli bir servisle ilgili. nginx mı patladı, postgresql mi takıldı, kendi yazdığınız uygulama servisi mi garip davranıyor? Bunların hepsine -u parametresiyle ulaşırsınız.
# Belirli bir servisin loglarını göster
journalctl -u nginx.service
# Birden fazla servis
journalctl -u nginx.service -u php-fpm.service
# Servis loglarını gerçek zamanlı izle
journalctl -u postgresql.service -f
# Son 1 saatin logları
journalctl -u nginx.service --since "1 hour ago"
Bir keresinde production’da nginx aniden 502 döndürmeye başladı. journalctl -u nginx.service -f açtım, aynı anda journalctl -u php-fpm.service -f açtım. İki terminal, iki log akışı. PHP-FPM’in worker havuzunun dolduğunu 30 saniyede tespit ettim. Klasik log dosyalarıyla aynı işi yapmak için 5 farklı dosyayı grep’lemem gerekirdi.
Zaman Bazlı Filtreleme
Log analizi yapıyorsanız zaman aralığı belirtmek zorundasınız. journalctl bu konuda oldukça esnek.
# Belirli tarihten itibaren
journalctl --since "2024-01-15"
# Tarih ve saat aralığı
journalctl --since "2024-01-15 08:00:00" --until "2024-01-15 10:30:00"
# Görece zaman ifadeleri
journalctl --since "2 hours ago"
journalctl --since "yesterday"
journalctl --since "today"
# Belirli bir servis için dün sabah 06:00-08:00 arası
journalctl -u sshd.service --since "yesterday 06:00" --until "yesterday 08:00"
Görece zaman ifadeleri özellikle sabah 09:00’da “gece ne oldu?” sorusunu yanıtlarken çok işe yarıyor. --since "yesterday 22:00" yazıp gece yarısı olan olayları anında çekebiliyorsunuz.
Öncelik Seviyesine Göre Filtreleme
Bu konuyu pek çok sysadmin göz ardı ediyor ama hata ayıklamada kritik. -p parametresi ile log önceliği belirtebilirsiniz.
Öncelik seviyeleri şunlar:
- 0 (emerg): Sistem kullanılamaz durumda
- 1 (alert): Derhal müdahale gerekiyor
- 2 (crit): Kritik hata
- 3 (err): Hata
- 4 (warning): Uyarı
- 5 (notice): Normal ama dikkat çekici
- 6 (info): Bilgi mesajı
- 7 (debug): Debug bilgisi
# Sadece hata ve üzeri
journalctl -p err
# Kritik ve üzeri (emerg, alert, crit)
journalctl -p crit
# Belirli aralık: warning'den err'e kadar
journalctl -p warning..err
# Bir servis için sadece hatalar
journalctl -u myapp.service -p err --since "today"
Production sunucularında genellikle şunu çalıştırıyorum: journalctl -p err --since "today". Bugün sistemde kaç hata oluşmuş, tek satırda görüyorum. Rutin sabah kontrolünün vazgeçilmezi.
Boot Bazlı Sorgulama
Bu özellik bana göre journald’yi syslog’dan kesinlikle üstün kılan şey. Her sistem başlatması (boot) ayrı bir ID ile kayıt altına alınır.
# Mevcut boot'un logları
journalctl -b
# Bir önceki boot
journalctl -b -1
# İki boot öncesi
journalctl -b -2
# Tüm boot'ların listesi
journalctl --list-boots
# Belirli bir boot ID'siyle sorgulama
journalctl -b 7f3a2b1c4d5e6f7a
Gerçek bir senaryo: Bir müşteri sunucusu haftada bir kez beklenmedik biçimde yeniden başlıyordu. Kimse görmemişti, DMESG’e bakıyorduk ama neden olduğunu bulamıyorduk. journalctl --list-boots ile son 10 boot’u listeledim, journalctl -b -1 -p err ile bir önceki boot’un hata loglarını çektim. Kernel OOM killer devreye girmişti ve kritik bir sistem servisi sonlandırılmıştı. journalctl -b -1 -k ile sadece kernel mesajlarına bakınca bellek baskısının ne zaman başladığını dakika dakika izleyebildim.
# Sadece kernel mesajları (dmesg gibi)
journalctl -k
# Önceki boot'un kernel mesajları
journalctl -k -b -1
Alan Bazlı Filtreleme
journald’nin güçlü taraflarından biri her log girdisinin yapısal alanlar içermesi. Bu alanlara doğrudan filtre uygulayabilirsiniz.
# Belirli bir kullanıcının logları (UID ile)
journalctl _UID=1000
# Belirli bir PID'in logları
journalctl _PID=1234
# Belirli bir çalıştırılabilir dosyanın logları
journalctl _EXE=/usr/sbin/sshd
# Belirli bir hostname (merkezi log toplama senaryosunda)
journalctl _HOSTNAME=webserver01
# Kullanılabilir tüm alanları gör
journalctl -o verbose | head -100
_EXE alanı özellikle container dışı ortamlarda, aynı binary’nin farklı servis isimleriyle çalıştığı durumlarda işe yarıyor.
Çıktı Formatları
Farklı durumlar farklı çıktı formatları gerektirir. journalctl bu konuda oldukça geniş seçenekler sunuyor.
# Kısa format (varsayılan)
journalctl -u nginx.service -n 20
# JSON çıktısı (log analiz araçlarına entegrasyon için)
journalctl -u nginx.service -n 20 -o json
# Okunabilir JSON
journalctl -u nginx.service -n 20 -o json-pretty
# Sadece mesaj metni (grep ile işleme için ideal)
journalctl -u nginx.service -n 20 -o cat
# Tam detay (tüm alanlar)
journalctl -u nginx.service -n 5 -o verbose
# Short-monotonic: relatif zaman damgaları
journalctl -u nginx.service -n 20 -o short-monotonic
JSON çıktısı özellikle log analizi otomasyonunda çok işe yarıyor. Mesela bir script içinde:
# Son 1 saatin nginx hatalarını JSON olarak çek, jq ile işle
journalctl -u nginx.service --since "1 hour ago" -p err -o json |
jq -r '.MESSAGE' |
sort | uniq -c | sort -rn | head -20
Bu komut size son 1 saatte nginx’in hangi hata mesajını kaç kez ürettiğini gösterir. Bir anda tekrar eden hataları tespit etmek için birebir.
Grep ve Metin Filtresi
journalctl’nin kendi içinde grep benzeri filtreleme özelliği var. Ama birleşik kullanım daha güçlü.
# journalctl içinde metin araması
journalctl -u nginx.service -g "upstream timed out"
# Büyük/küçük harf duyarsız arama
journalctl -u nginx.service -g "connection refused" -i
# Pipe ile grep kullanımı
journalctl -u nginx.service --since "today" -o cat | grep "502"
# Birden fazla pattern
journalctl --since "today" -o cat | grep -E "(ERROR|CRITICAL|FATAL)"
-g parametresi POSIX extended regex destekliyor. Ama karmaşık pattern’lar için genellikle pipe + grep kombinasyonunu tercih ediyorum, daha öngörülebilir davranıyor.
Disk Kullanımı ve Log Yönetimi
journald logları zamanla büyür. Büyük sistemlerde gigabyte’lara ulaşabilir. Yönetim komutlarını bilmek şart.
# Toplam journal disk kullanımı
journalctl --disk-usage
# Eski logları temizle (2 GB üzerindeki kısmı sil)
journalctl --vacuum-size=2G
# 30 günden eski logları sil
journalctl --vacuum-time=30d
# Sadece son 5 boot'u tut
journalctl --vacuum-files=5
/etc/systemd/journald.conf dosyasında kalıcı kota tanımlayabilirsiniz:
# /etc/systemd/journald.conf içinde
# SystemMaxUse=2G
# SystemKeepFree=500M
# MaxRetentionSec=1month
# Değişikliği uygula
systemctl restart systemd-journald
Uzak Sunucu ve Konteyner Senaryoları
Birden fazla sunucu yönetiyorsanız merkezi log toplamanın önemi tartışılmaz. journald bu konuda da çözüm sunuyor.
# Belirli bir container'ın logları (systemd-nspawn)
journalctl -M mycontainer
# Export formatında logları başka sisteme aktar
journalctl --since "today" -o export > today_logs.export
# Export edilen logları oku
journalctl --file=today_logs.export
# Belirli bir journal dosyasını oku
journalctl --file=/var/log/journal/abc123/system.journal
Kubernetes veya Docker kullanıyorsanız journald log driver’ı ile container loglarını journal’a yönlendirebilirsiniz. Bu şekilde tüm loglarınız tek yerden sorgulanabilir hale gelir.
Pratik Hata Ayıklama Senaryoları
Teoriden çıkıp gerçek hayata girelim. Sık karşılaşılan durumlar ve bunlara verilen journalctl cevapları.
Senaryo 1: Servis başlamıyor
# Servisin son başlatma girişiminin logları
journalctl -u myapp.service -n 50 --no-pager
# Daha detaylı, verbose modda
journalctl -u myapp.service -o verbose -n 20
Senaryo 2: SSH brute force şüphesi
# Başarısız SSH girişimleri
journalctl -u sshd.service --since "today" -o cat |
grep "Failed password" |
awk '{print $11}' |
sort | uniq -c | sort -rn | head -20
Bu komut size bugün hangi IP adresinin kaç başarısız giriş denemesi yaptığını sıralar. fail2ban kurmadan önce durumu anlamak için idealdir.
Senaryo 3: OOM killer takibi
# Kernel tarafından sonlandırılan processleri bul
journalctl -k --since "today" | grep -i "killed process"
# Detaylı OOM bilgisi
journalctl -k -p warning --since "today" | grep -i "oom|out of memory"
Senaryo 4: Cron job sorunları
# Tüm cron logları
journalctl -u cron.service --since "today"
# Belirli bir cron job'ın çıktısı (systemd timer kullanıyorsanız)
journalctl -u backup-job.timer --since "yesterday"
journalctl -u backup-job.service --since "yesterday"
Monitoring Script’lerine Entegrasyon
Basit bir monitoring script’i örneği. Cron ile çalıştırıp kritik hataları e-posta veya Slack’e gönderebilirsiniz:
#!/bin/bash
# /usr/local/bin/check-critical-logs.sh
THRESHOLD=10
SINCE="15 minutes ago"
# Son 15 dakikadaki kritik hata sayısı
ERROR_COUNT=$(journalctl -p err --since "$SINCE" -q --no-pager -o cat | wc -l)
if [ "$ERROR_COUNT" -gt "$THRESHOLD" ]; then
ERRORS=$(journalctl -p err --since "$SINCE" -q --no-pager -o cat | head -20)
# Slack webhook veya mail komutu ile bildirim
echo "UYARI: Son 15 dakikada $ERROR_COUNT kritik hata oluştu"
echo "---"
echo "$ERRORS"
fi
Bu script’i crontab’a /15 * şeklinde ekleyip çıktısını istediğiniz bildirim kanalına yönlendirebilirsiniz.
Yararlı Parametreler Özeti
Sık kullandığım parametrelerin kısa listesi:
- -u [unit]: Belirli bir systemd servisinin logları
- -f: Gerçek zamanlı takip
- -n [sayı]: Son N satır
- -p [seviye]: Öncelik filtresi
- -b [n]: Boot bazlı filtreleme
- -k: Sadece kernel mesajları
- -g [pattern]: Regex ile metin araması
- -o [format]: Çıktı formatı (json, cat, verbose)
- –since / –until: Zaman aralığı
- –no-pager: Sayfalandırmayı devre dışı bırak (script’lerde şart)
- –disk-usage: Disk kullanımını göster
- –vacuum-size: Disk temizliği
- -q: Sessiz mod, yalnızca log çıktısı
Sonuç
journalctl, alışkanlık meselesi. Yıllarca tail -f /var/log/syslog | grep nginx yazan biri için ilk başta yabancı geliyor. Ama boot bazlı sorgulama, yapısal alanlar ve JSON çıktısı gibi özellikleri bir kez kullandıktan sonra geriye dönmek zor.
Benim rutinimde şu üç komut her şeyin başlangıç noktası:
Sabah sisteme bakışta journalctl -p err --since "yesterday" --no-pager ile dün ne olmuş görüyorum. Bir servis sorununda journalctl -u servis_adi -f ile canlı takibe başlıyorum. Tarihsel analiz gerektiğinde journalctl -u servis_adi --since "..." --until "..." -o json | jq kombinasyonuyla işi bitiriyorum.
Sistemleriniz ne kadar karmaşık olursa olsun, loglar her zaman en dürüst bilgi kaynağıdır. journalctl o bilgiye ulaşmanın en doğrudan yolu.
