journald ile Yapılandırılmış Log Yönetimi
Modern Linux sistemlerinde log yönetimi, systemd’nin hayatımıza girmesiyle köklü bir dönüşüm geçirdi. Eski güzel syslog günleri geride kalırken, journald bize yapılandırılmış, sorgulanabilir ve merkezi bir log altyapısı sunuyor. Ancak birçok sysadmin hâlâ journald’yi sadece journalctl -f komutuyla sınırlı kullanıyor. Bu yazıda journald’nin gerçek gücünü ortaya çıkaracağız; production ortamlarında log yönetimini nasıl profesyonelce yapabileceğinizi, disk kullanımını nasıl kontrol altında tutacağınızı ve yapılandırılmış logları nasıl analiz edeceğinizi ele alacağız.
journald Nedir ve Neden Önemli?
journald, systemd ekosisteminin bir parçası olan systemd-journald servisinin kısaltmasıdır. Geleneksel syslog’dan temel farkı, logları düz metin yerine ikili formatta saklamasıdır. Bu sayede her log kaydı metadata ile birlikte gelir: hangi kullanıcı, hangi proses, hangi servis, kaçıncı PID, kernel mi userspace mi olduğu gibi bilgiler otomatik olarak eklenir.
Bunun pratikte ne anlama geldiğini düşünelim. Bir nginx servisinde hata araştırıyorsunuz ve binlerce log satırı içinden sadece belirli bir zaman aralığındaki kritik hataları filtrelemeniz gerekiyor. Syslog ile bunu grep zincirleriyle yapmak zorundayken, journald ile tek bir komutla bu işi halledebilirsiniz.
Temel Mimari
journald üç ana kaynaktan log toplar:
- Kernel logları:
/dev/kmsgüzerinden doğrudan kernel mesajları - Servis logları: systemd unit’lerinin stdout/stderr çıktıları
- Native journal API: Uygulama loglarını structured format’ta gönderen servisler
- Syslog socket: Geriye dönük uyumluluk için klasik syslog mesajları
Loglar varsayılan olarak /run/log/journal/ içinde tutulur ve sistem yeniden başladığında silinir. Kalıcı loglama için /var/log/journal/ dizinini oluşturmanız gerekir.
# Kalıcı log depolamayı aktifleştir
sudo mkdir -p /var/log/journal
sudo systemd-tmpfiles --create --prefix /var/log/journal
sudo systemctl restart systemd-journald
# Logların nerede tutulduğunu kontrol et
journalctl --disk-usage
journald Yapılandırması: /etc/systemd/journald.conf
journald’nin davranışını /etc/systemd/journald.conf dosyasından yönetirsiniz. Ancak production ortamlarında daha temiz bir yaklaşım, override dosyaları kullanmaktır. Bu sayede paket güncellemelerinde yapılandırmanız kaybolmaz.
# Drop-in yapılandırma dizini oluştur
sudo mkdir -p /etc/systemd/journald.conf.d/
# Production için önerilen yapılandırma
sudo cat > /etc/systemd/journald.conf.d/production.conf << 'EOF'
[Journal]
Storage=persistent
Compress=yes
MaxDiskUsage=2G
MaxFileSizeMB=128
MaxRetentionSec=3month
SystemMaxFiles=20
ForwardToSyslog=no
RateLimitIntervalSec=30s
RateLimitBurst=10000
EOF
sudo systemctl restart systemd-journald
Önemli parametreleri açıklayalım:
- Storage=persistent: Logları disk üzerinde kalıcı olarak saklar
- Compress=yes: LZ4 sıkıştırmasıyla disk kullanımını azaltır
- MaxDiskUsage=2G: Journal’ın toplam disk kullanımı üst sınırı
- MaxFileSizeMB=128: Tek bir journal dosyasının maksimum boyutu
- MaxRetentionSec=3month: 3 aydan eski logları otomatik sil
- SystemMaxFiles=20: Sistem logları için maksimum dosya sayısı
- ForwardToSyslog=no: rsyslog’a iletmeyi kapat, ikili kayıt önle
- RateLimitBurst=10000: Rate limiting eşiği, yoğun uygulamalar için artırılabilir
journalctl ile Etkili Log Sorgulama
journalctl’nin güzelliği, zengin filtreleme seçeneklerinde yatıyor. Gerçek dünya senaryolarına bakalım.
Zaman Bazlı Sorgular
# Son 1 saatin logları
journalctl --since "1 hour ago"
# Belirli zaman aralığı
journalctl --since "2024-01-15 08:00:00" --until "2024-01-15 09:30:00"
# Dün gece yarısından bu yana
journalctl --since yesterday
# Boot'a göre filtreleme
journalctl -b # Şu anki boot
journalctl -b -1 # Bir önceki boot
journalctl -b -2 # İki boot önce
# Tüm boot geçmişini listele
journalctl --list-boots
Servis ve Unit Bazlı Filtreleme
# Belirli bir servisin logları
journalctl -u nginx.service
journalctl -u nginx.service --since "2 hours ago"
# Birden fazla servis
journalctl -u nginx.service -u php-fpm.service
# Failed unit'lerin loglarını gör
for unit in $(systemctl --failed --no-legend | awk '{print $1}'); do
echo "=== $unit ==="
journalctl -u "$unit" --since "1 hour ago" -n 20
done
Priority Bazlı Filtreleme
journald, syslog priority seviyelerini kullanır:
- 0 (emerg): Sistem kullanılamaz
- 1 (alert): Hemen aksiyon alınmalı
- 2 (crit): Kritik durum
- 3 (err): Hata durumları
- 4 (warning): Uyarılar
- 5 (notice): Normal ama önemli
- 6 (info): Bilgi mesajları
- 7 (debug): Debug mesajları
# Sadece hata ve üzeri
journalctl -p err
# Warning ve üzeri, son 100 satır
journalctl -p warning -n 100
# Critical hatalar, son boot
journalctl -p crit -b
# Belirli servis için sadece hatalar
journalctl -u postgresql.service -p err --since "1 day ago"
Yapılandırılmış Loglama: Fields ve Metadata
journald’nin en güçlü özelliği, her log kaydına otomatik eklenen metadata alanlarıdır. Bu alanları kullanarak son derece hassas sorgular yapabilirsiniz.
# Log kaydının tüm metadata alanlarını gör
journalctl -u sshd.service -n 1 -o verbose
# JSON formatında çıktı (log analiz araçlarıyla entegrasyon için)
journalctl -u nginx.service --since "1 hour ago" -o json | head -5
# Tek satır JSON (pipeline için ideal)
journalctl -u nginx.service -o json-pretty -n 10
# Belirli bir _SYSTEMD_UNIT field'ına göre filtrele
journalctl _SYSTEMD_UNIT=docker.service
# _PID'e göre filtrele
journalctl _PID=1234
# Belirli kullanıcının başlattığı proseslerin logları
journalctl _UID=1000
# Kernel namespace'den gelen mesajlar
journalctl _TRANSPORT=kernel
Önemli journal alanları:
- _HOSTNAME: Mesajın geldiği host adı
- _SYSTEMD_UNIT: İlgili systemd unit adı
- _PID: Proses ID
- _UID / _GID: Kullanıcı ve grup ID
- _COMM: Proses adı
- _EXE: Çalıştırılabilir dosyanın tam yolu
- _TRANSPORT: Mesajın geldiği transport (journal, syslog, kernel, audit)
- PRIORITY: Log öncelik seviyesi
- MESSAGE: Asıl log mesajı
Gerçek Dünya Senaryosu: Web Sunucusu Sorun Tespiti
Diyelim ki production nginx sunucunuzda aralıklı 502 hataları alıyorsunuz. Klasik yaklaşım nginx access log’larını grep’lemek olurdu. Ancak journald ile daha kapsamlı bir sorun analizi yapabilirsiniz.
#!/bin/bash
# nginx-diagnosis.sh - Nginx sorun tespit scripti
SINCE_TIME="2 hours ago"
OUTPUT_DIR="/tmp/nginx-diagnosis-$(date +%Y%m%d-%H%M%S)"
mkdir -p "$OUTPUT_DIR"
echo "[*] Nginx error logları toplanıyor..."
journalctl -u nginx.service -p err --since "$SINCE_TIME"
-o json > "$OUTPUT_DIR/nginx-errors.json"
echo "[*] PHP-FPM hataları toplanıyor..."
journalctl -u php8.2-fpm.service -p warning --since "$SINCE_TIME"
-o json > "$OUTPUT_DIR/phpfpm-warnings.json"
echo "[*] Sistem kaynak sorunları kontrol ediliyor..."
journalctl -p err --since "$SINCE_TIME"
-k > "$OUTPUT_DIR/kernel-errors.txt"
echo "[*] OOM killer aktivitesi..."
journalctl -k --grep="Out of memory" --since "$SINCE_TIME"
> "$OUTPUT_DIR/oom-events.txt"
echo "[*] Toplam hata sayıları:"
echo "Nginx errors: $(wc -l < "$OUTPUT_DIR/nginx-errors.json")"
echo "PHPFPM warnings: $(wc -l < "$OUTPUT_DIR/phpfpm-warnings.json")"
echo "Kernel errors: $(wc -l < "$OUTPUT_DIR/kernel-errors.txt")"
echo "OOM events: $(wc -l < "$OUTPUT_DIR/oom-events.txt")"
echo "[+] Tanı dosyaları: $OUTPUT_DIR"
Log Rotasyonu ve Disk Yönetimi
Production ortamında disk dolmasına izin vermemek kritik öneme sahiptir. journald bu konuda güçlü araçlar sunar.
# Mevcut disk kullanımını kontrol et
journalctl --disk-usage
# Belirli bir boyutun üzerindeki eski logları temizle
sudo journalctl --vacuum-size=1G
# Belirli bir tarihten eski logları sil
sudo journalctl --vacuum-time=2weeks
# Dosya sayısını sınırla
sudo journalctl --vacuum-files=10
# Doğrulama: Journal tutarlılık kontrolü
sudo journalctl --verify
Otomatik temizlik için cron job veya sistemd timer kullanabilirsiniz. Timer yaklaşımı daha sağlıklıdır:
# /etc/systemd/system/journal-cleanup.service
sudo cat > /etc/systemd/system/journal-cleanup.service << 'EOF'
[Unit]
Description=Journal Log Cleanup
After=systemd-journald.service
[Service]
Type=oneshot
ExecStart=/usr/bin/journalctl --vacuum-size=1500M
ExecStart=/usr/bin/journalctl --vacuum-time=45days
EOF
# /etc/systemd/system/journal-cleanup.timer
sudo cat > /etc/systemd/system/journal-cleanup.timer << 'EOF'
[Unit]
Description=Weekly Journal Cleanup
Requires=journal-cleanup.service
[Timer]
OnCalendar=weekly
Persistent=true
[Install]
WantedBy=timers.target
EOF
sudo systemctl enable --now journal-cleanup.timer
sudo systemctl status journal-cleanup.timer
Uzak Log Toplama: journald Remote
Birden fazla sunucu yönetiyorsanız, journald’nin remote log toplama özelliğini kullanabilirsiniz. systemd-journal-remote paketi bu iş için tasarlanmıştır.
# Log collector sunucusunda kurulum
sudo apt install systemd-journal-remote
# Collector yapılandırması
sudo cat > /etc/systemd/journal-remote.conf << 'EOF'
[Remote]
Seal=false
SplitMode=host
ServerKeyFile=/etc/ssl/private/journal-remote.key
ServerCertificateFile=/etc/ssl/certs/journal-remote.pem
TrustedCertificateFile=/etc/ssl/certs/ca.pem
EOF
# Servisi aktifleştir (HTTPS üzerinden log kabul eder)
sudo systemctl enable --now systemd-journal-remote.socket
sudo systemctl enable --now systemd-journal-remote.service
# Gönderici (kaynak) sunucularda
sudo apt install systemd-journal-remote
sudo cat > /etc/systemd/journal-upload.conf << 'EOF'
[Upload]
URL=https://log-collector.internal:19532
ServerKeyFile=/etc/ssl/private/journal-upload.key
ServerCertificateFile=/etc/ssl/certs/journal-upload.pem
TrustedCertificateFile=/etc/ssl/certs/ca.pem
EOF
sudo systemctl enable --now systemd-journal-upload.service
Collector sunucusunda tüm kaynak sunucuların loglarını birleşik olarak sorgulayabilirsiniz:
# Belirli bir host'un loglarını sorgula
journalctl -D /var/log/journal/remote/ _HOSTNAME=web-server-01
# Tüm remote loglardan hata ara
journalctl -D /var/log/journal/remote/ -p err --since "1 hour ago"
Uygulamalardan Yapılandırılmış Log Gönderme
journald’nin gerçek gücü, uygulamaların native journal API’sini kullanmasıyla ortaya çıkar. Python ve Node.js’ten örnek görelim.
# Python ile structured logging
from systemd import journal
import logging
# systemd journal handler
logger = logging.getLogger('myapp')
logger.addHandler(journal.JournalHandler(SYSLOG_IDENTIFIER='myapp'))
logger.setLevel(logging.DEBUG)
# Basit mesaj
logger.info("Uygulama başlatıldı")
# Structured fields ile
journal.send(
"Kullanıcı giriş yaptı",
PRIORITY=journal.LOG_INFO,
SYSLOG_IDENTIFIER="myapp",
USER_ID="12345",
USER_EMAIL="[email protected]",
REQUEST_ID="req-abc-123",
REMOTE_ADDR="192.168.1.100"
)
Bu şekilde gönderilen logları journalctl ile kolayca sorgulayabilirsiniz:
# Özel field'lara göre filtrele
journalctl SYSLOG_IDENTIFIER=myapp USER_ID=12345
# Belirli bir request ID'yi takip et
journalctl SYSLOG_IDENTIFIER=myapp REQUEST_ID=req-abc-123
# JSON olarak dışa aktar ve jq ile işle
journalctl SYSLOG_IDENTIFIER=myapp -o json |
jq -r 'select(.PRIORITY <= "3") | [.REALTIME_TIMESTAMP, .MESSAGE] | @tsv'
Log Analizi İçin İleri Teknikler
journalctl çıktısını diğer araçlarla birleştirerek güçlü analiz pipeline’ları kurabilirsiniz.
#!/bin/bash
# log-analysis.sh - Günlük log analiz raporu
REPORT_DATE=$(date +%Y-%m-%d)
REPORT_FILE="/var/reports/log-report-${REPORT_DATE}.txt"
{
echo "=== Günlük Log Analiz Raporu: $REPORT_DATE ==="
echo ""
echo "--- Kritik Hata Özeti ---"
journalctl -p err --since "1 day ago"
-o json-pretty |
python3 -c "
import json, sys, collections
errors = []
for line in sys.stdin:
try:
entry = json.loads(line)
errors.append(entry.get('SYSLOG_IDENTIFIER', 'unknown'))
except:
pass
counter = collections.Counter(errors)
for name, count in counter.most_common(10):
print(f' {count:5d} {name}')
"
echo ""
echo "--- SSH Başarısız Giriş Denemeleri ---"
journalctl -u sshd.service --since "1 day ago"
--grep="Failed password" |
awk '{print $11}' | sort | uniq -c | sort -rn | head -10
echo ""
echo "--- Disk I/O Hataları ---"
journalctl -k --since "1 day ago" --grep="I/O error" | wc -l
echo ""
echo "--- Systemd Failed Units ---"
systemctl --failed --no-legend | awk '{print " "$1}'
echo ""
echo "--- Journal Disk Kullanımı ---"
journalctl --disk-usage
} > "$REPORT_FILE"
echo "Rapor hazırlandı: $REPORT_FILE"
# Raporu mail ile gönder (isteğe bağlı)
# mail -s "Günlük Log Raporu: $REPORT_DATE" [email protected] < "$REPORT_FILE"
journald ve Grafana/Prometheus Entegrasyonu
Modern monitoring stack’ine journald’yi entegre etmek için promtail veya vector gibi araçlar kullanabilirsiniz. Loki ile entegrasyon için temel promtail yapılandırması:
# /etc/promtail/config.yml
server:
http_listen_port: 9080
grpc_listen_port: 0
positions:
filename: /tmp/positions.yaml
clients:
- url: http://loki:3100/loki/api/v1/push
scrape_configs:
- job_name: journal
journal:
max_age: 12h
labels:
job: systemd-journal
host: __HOSTNAME__
relabel_configs:
- source_labels: ['__journal__systemd_unit']
target_label: 'unit'
- source_labels: ['__journal__hostname']
target_label: 'hostname'
- source_labels: ['__journal_priority_keyword']
target_label: 'level'
Bu yapılandırmayla tüm systemd servis loglarınız otomatik olarak Loki’ye akar ve Grafana üzerinden görselleştirebilirsiniz.
Güvenlik: Journal Sealing
Production ortamlarında log manipülasyonunu önlemek için journal sealing özelliğini aktifleştirebilirsiniz. Bu özellik, FSS (Forward Secure Sealing) kullanarak log kayıtlarını kriptografik olarak imzalar.
# Journal sealing için anahtar oluştur
sudo journalctl --setup-keys
# Çıktı örneği:
# /var/log/journal/[machine-id]/fss
# Sealing key: XXXX-XXXX-XXXX-XXXX/XXXX-XXXX-XXXX
# Anahtarı güvenli bir yere kaydedin!
# Doğrulama (sealing key gerektirir)
sudo journalctl --verify --verify-key=XXXX-XXXX-XXXX-XXXX/XXXX-XXXX-XXXX
Sealing aktifken /etc/systemd/journald.conf.d/production.conf dosyanıza şunu ekleyin:
- Seal=yes: FSS sealing’i aktifleştirir
Sonuç
journald, doğru yapılandırıldığında modern bir Linux sisteminin en değerli araçlarından biri haline gelir. Yapılandırılmış log formatı sayesinde hata tespiti dakikalar yerine saniyeler içinde tamamlanabiliyor. Disk yönetimi otomatize ediliyor ve merkezi log toplama altyapısı kurulabiliyor.
Öncelik olarak yapmanız gerekenler şunlardır: önce kalıcı loglama aktifleştirin, ardından disk kotalarını tanımlayın. Uygulamalarınızı native journal API kullanacak şekilde güncelleyin. Log analiz scriptlerinizi journalctl’nin JSON çıktısı üzerine kurun. Yüksek güvenlik gerektiren ortamlarda journal sealing’i devreye alın.
Eski syslog alışkanlıklarından vazgeçmek zor gelebilir ama journald’ye bir şans tanıdığınızda, grep zincirlerinden kurtulmanın ne kadar özgürleştirici olduğunu göreceksiniz. Yapılandırılmış loglar, hem günlük operasyonları hem de post-mortem analizleri ciddi ölçüde kolaylaştırıyor.
