Sistem yöneticiliğinde en çok zaman kaybettiğimiz şeylerden biri, farklı sunuculara bağlanıp aynı komutları tekrar tekrar çalıştırmaktır. “Bu sunucuda ne kadar RAM var? Disk dolmak üzere mi? CPU ne durumda?” sorularının cevabını bulmak için free -h, df -h, top gibi komutları sürekli çalıştırırız. Oysa tüm bu bilgileri tek bir script ile derleyip güzel bir rapor haline getirebiliriz. Bu yazıda, gerçek dünya ihtiyaçlarına göre şekillenmiş, production ortamında kullanabileceğiniz kapsamlı bir sistem bilgisi toplama scripti yazacağız.
Neden Böyle Bir Script Gerekli?
Diyelim ki 20 sunucunuzun haftalık sağlık raporunu hazırlamanız gerekiyor. Her birine SSH ile bağlanıp manuel kontrol yapmak hem zaman alır hem de insan hatasına açıktır. Üstelik patronunuz ya da müşteriniz düzenli raporlar istiyorsa, bu işi otomasyona bağlamak şart haline gelir.
Bir başka senaryo: Gece 2’de alarm geldi, bir sunucu yavaşlamış. Hızlıca o sunucuya bağlandığınızda, mevcut durumu hızlıca özetleyen bir scriptin çıktısını görmek, tek tek komut çalıştırmaktan çok daha verimlidir.
Bu script şunları yapacak:
- CPU kullanımı ve yük ortalamasını raporlar
- RAM ve swap durumunu detaylı gösterir
- Disk kullanımını partition bazında listeler
- Kritik eşikleri aşan kaynaklar için uyarı verir
- Raporu hem ekrana hem de log dosyasına yazar
- E-posta ile bildirim gönderme seçeneği sunar
Temel Yapıyı Kuralım
Her iyi script gibi bu script de temiz bir yapıyla başlamalı. Shebang satırı, değişken tanımlamaları ve hata yönetimi temel iskeletimizi oluşturur.
#!/bin/bash
# sistem_raporu.sh - Sistem bilgisi toplama ve raporlama scripti
# Versiyon: 1.0
# Kullanim: ./sistem_raporu.sh [--email] [--log] [--verbose]
set -euo pipefail
# Renk kodlari
KIRMIZI='33[0;31m'
SARI='33[1;33m'
YESIL='33[0;32m'
MAVI='33[0;34m'
BOLD='33[1m'
SIFIRLA='33[0m'
# Esik degerleri (yuzde olarak)
CPU_ESIK=80
RAM_ESIK=85
DISK_ESIK=90
# Log dosyasi
LOG_DIR="/var/log/sistem_raporu"
LOG_DOSYA="${LOG_DIR}/rapor_$(date +%Y%m%d_%H%M%S).log"
# E-posta ayarlari
EMAIL_ALICI="[email protected]"
HOSTNAME_KISA=$(hostname -s)
TARIH=$(date '+%Y-%m-%d %H:%M:%S')
# Parametre kontrolleri
EMAIL_GONDER=false
LOG_KAYDET=false
VERBOSE=false
while [[ $# -gt 0 ]]; do
case $1 in
--email) EMAIL_GONDER=true ;;
--log) LOG_KAYDET=true ;;
--verbose) VERBOSE=true ;;
*) echo "Bilinmeyen parametre: $1"; exit 1 ;;
esac
shift
done
set -euo pipefail satırı önemli. Bu üç özellik bir arada çalışır:
- -e: Herhangi bir komut hata döndürürse script durur
- -u: Tanımlanmamış değişken kullanılırsa hata verir
- -o pipefail: Pipe zincirindeki herhangi bir komut başarısız olursa hata yakalar
CPU Bilgisi Toplama Fonksiyonu
CPU raporu için birkaç farklı kaynaktan veri toplayacağız. /proc/cpuinfo, mpstat ve uptime komutları birlikte kullanılırsa kapsamlı bir resim ortaya çıkar.
cpu_raporu() {
echo -e "n${BOLD}${MAVI}=== CPU RAPORU ===${SIFIRLA}"
# Fiziksel CPU ve core sayisi
FIZIKSEL_CPU=$(grep "physical id" /proc/cpuinfo | sort -u | wc -l)
CORE_SAYISI=$(grep "cpu cores" /proc/cpuinfo | head -1 | awk '{print $4}')
THREAD_SAYISI=$(nproc)
CPU_MODEL=$(grep "model name" /proc/cpuinfo | head -1 | cut -d: -f2 | sed 's/^ //')
echo -e " ${BOLD}Model:${SIFIRLA} ${CPU_MODEL}"
echo -e " ${BOLD}Fiziksel CPU:${SIFIRLA} ${FIZIKSEL_CPU}"
echo -e " ${BOLD}Core sayisi:${SIFIRLA} ${CORE_SAYISI}"
echo -e " ${BOLD}Thread sayisi:${SIFIRLA} ${THREAD_SAYISI}"
# Yuk ortalamasi
YUK_1=$(uptime | awk -F'load average:' '{print $2}' | cut -d, -f1 | tr -d ' ')
YUK_5=$(uptime | awk -F'load average:' '{print $2}' | cut -d, -f2 | tr -d ' ')
YUK_15=$(uptime | awk -F'load average:' '{print $2}' | cut -d, -f3 | tr -d ' ')
echo -e " ${BOLD}Yuk ortalamasi (1/5/15 dk):${SIFIRLA} ${YUK_1} / ${YUK_5} / ${YUK_15}"
# CPU kullanim yuzdesi (1 saniye ornekleme)
if command -v mpstat &>/dev/null; then
CPU_KULLANIM=$(mpstat 1 1 | tail -1 | awk '{print 100 - $NF}')
CPU_KULLANIM_INT=${CPU_KULLANIM%.*}
if [[ ${CPU_KULLANIM_INT} -ge ${CPU_ESIK} ]]; then
echo -e " ${BOLD}CPU Kullanim:${SIFIRLA} ${KIRMIZI}%${CPU_KULLANIM} (UYARI!)${SIFIRLA}"
UYARI_LISTESI+=("CPU kullanimi yuksek: %${CPU_KULLANIM}")
else
echo -e " ${BOLD}CPU Kullanim:${SIFIRLA} ${YESIL}%${CPU_KULLANIM}${SIFIRLA}"
fi
else
# mpstat yoksa /proc/stat ile hesapla
CPU_BOS=$(top -bn1 | grep "Cpu(s)" | awk '{print $8}' | cut -d% -f1)
CPU_KULLANIM=$(echo "100 - ${CPU_BOS}" | bc)
echo -e " ${BOLD}CPU Kullanim:${SIFIRLA} %${CPU_KULLANIM} (yaklasik)"
fi
# En cok CPU kullanan 5 proses
if [[ "${VERBOSE}" == true ]]; then
echo -e "n ${BOLD}En cok CPU kullanan prosesler:${SIFIRLA}"
ps aux --sort=-%cpu | awk 'NR==1 || NR<=6 {printf " %-10s %-6s %-6s %sn", $1, $2, $3, $11}' | tail -5
fi
}
RAM ve Swap Raporu
Bellek yönetimi, sistem sağlığının en kritik göstergelerinden biridir. Burada yalnızca kullanılan RAM’i değil, buffer/cache durumunu ve swap kullanımını da izlemeliyiz.
ram_raporu() {
echo -e "n${BOLD}${MAVI}=== BELLEK RAPORU ===${SIFIRLA}"
# /proc/meminfo dosyasindan ham veri al
TOPLAM_RAM=$(grep MemTotal /proc/meminfo | awk '{print $2}')
BOS_RAM=$(grep MemFree /proc/meminfo | awk '{print $2}')
KULLANILAN_RAM=$(grep MemAvailable /proc/meminfo | awk '{print $2}')
BUFFER=$(grep Buffers /proc/meminfo | awk '{print $2}')
CACHE=$(grep "^Cached:" /proc/meminfo | awk '{print $2}')
# KB'dan MB ve GB'a cevir
TOPLAM_RAM_MB=$((TOPLAM_RAM / 1024))
TOPLAM_RAM_GB=$(echo "scale=1; ${TOPLAM_RAM_MB} / 1024" | bc)
# Gercekten kullanilan RAM (buffer/cache haric)
GERCEK_KULLANIM=$((TOPLAM_RAM - KULLANILAN_RAM))
GERCEK_KULLANIM_MB=$((GERCEK_KULLANIM / 1024))
# Yuzde hesapla
RAM_YUZDE=$(echo "scale=1; (${GERCEK_KULLANIM} * 100) / ${TOPLAM_RAM}" | bc)
RAM_YUZDE_INT=${RAM_YUZDE%.*}
echo -e " ${BOLD}Toplam RAM:${SIFIRLA} ${TOPLAM_RAM_GB} GB (${TOPLAM_RAM_MB} MB)"
echo -e " ${BOLD}Kullanilan:${SIFIRLA} ${GERCEK_KULLANIM_MB} MB"
echo -e " ${BOLD}Buffer/Cache:${SIFIRLA} $(( (BUFFER + CACHE) / 1024 )) MB"
if [[ ${RAM_YUZDE_INT} -ge ${RAM_ESIK} ]]; then
echo -e " ${BOLD}Kullanim Orani:${SIFIRLA} ${KIRMIZI}%${RAM_YUZDE} (UYARI!)${SIFIRLA}"
UYARI_LISTESI+=("RAM kullanimi yuksek: %${RAM_YUZDE}")
else
echo -e " ${BOLD}Kullanim Orani:${SIFIRLA} ${YESIL}%${RAM_YUZDE}${SIFIRLA}"
fi
# Swap durumu
SWAP_TOPLAM=$(grep SwapTotal /proc/meminfo | awk '{print $2}')
SWAP_BOS=$(grep SwapFree /proc/meminfo | awk '{print $2}')
SWAP_KULLANIM=$((SWAP_TOPLAM - SWAP_BOS))
if [[ ${SWAP_TOPLAM} -gt 0 ]]; then
SWAP_YUZDE=$(echo "scale=1; (${SWAP_KULLANIM} * 100) / ${SWAP_TOPLAM}" | bc)
SWAP_MB=$((SWAP_KULLANIM / 1024))
SWAP_TOPLAM_MB=$((SWAP_TOPLAM / 1024))
echo -e " ${BOLD}Swap Toplam:${SIFIRLA} ${SWAP_TOPLAM_MB} MB"
if [[ ${SWAP_KULLANIM} -gt 0 ]]; then
echo -e " ${BOLD}Swap Kullanim:${SIFIRLA} ${SARI}${SWAP_MB} MB (%${SWAP_YUZDE})${SIFIRLA}"
UYARI_LISTESI+=("Swap kullaniliyor: ${SWAP_MB} MB")
else
echo -e " ${BOLD}Swap Kullanim:${SIFIRLA} ${YESIL}Kullanilmiyor${SIFIRLA}"
fi
else
echo -e " ${BOLD}Swap:${SIFIRLA} Yapılandırılmamis"
fi
# En cok bellek kullanan prosesler
if [[ "${VERBOSE}" == true ]]; then
echo -e "n ${BOLD}En cok RAM kullanan prosesler:${SIFIRLA}"
ps aux --sort=-%mem | awk 'NR>=2 && NR<=6 {printf " %-15s %-6s %-6s %sn", $1, $2, $4, $11}'
fi
}
Disk Raporu
Disk doluluk kontrolü, production ortamlarında en kritik izleme alanlarından biridir. Bir uygulama sunucusunda /var veya /tmp partitionunun dolması ciddi sorunlara yol açar.
disk_raporu() {
echo -e "n${BOLD}${MAVI}=== DISK RAPORU ===${SIFIRLA}"
# tmpfs ve devtmpfs gibi sanal dosya sistemlerini filtrele
while IFS= read -r satir; do
DOSYA_SISTEMI=$(echo "${satir}" | awk '{print $1}')
BOYUT=$(echo "${satir}" | awk '{print $2}')
KULLANILAN=$(echo "${satir}" | awk '{print $3}')
BOSTA=$(echo "${satir}" | awk '{print $4}')
YUZDE=$(echo "${satir}" | awk '{print $5}' | tr -d '%')
MOUNT=$(echo "${satir}" | awk '{print $6}')
# Renk belirle
if [[ ${YUZDE} -ge ${DISK_ESIK} ]]; then
RENK="${KIRMIZI}"
UYARI_LISTESI+=("Disk dolu uyarisi: ${MOUNT} - %${YUZDE}")
elif [[ ${YUZDE} -ge 75 ]]; then
RENK="${SARI}"
else
RENK="${YESIL}"
fi
printf " ${BOLD}%-25s${SIFIRLA} Boyut: %-8s Kullanilan: %-8s Bosta: %-8s ${RENK}%%%s${SIFIRLA}n"
"${MOUNT}" "${BOYUT}" "${KULLANILAN}" "${BOSTA}" "${YUZDE}"
done < <(df -h --output=source,size,used,avail,pcent,target |
grep -v "^Filesystem|tmpfs|devtmpfs|udev|run" |
sort -k5 -rn)
# Inode kullanimi da kontrol et
echo -e "n ${BOLD}Inode Kullanimi:${SIFIRLA}"
df -i | grep -v "^Filesystem|tmpfs|devtmpfs|udev" |
awk 'NR>1 {
yuzde=$5+0
if (yuzde >= 90) printf " 33[0;31m%-25s %s33[0mn", $6, $5
else if (yuzde >= 70) printf " 33[1;33m%-25s %s33[0mn", $6, $5
else printf " 33[0;32m%-25s %s33[0mn", $6, $5
}'
# En cok yer kaplayan dizinler (verbose modda)
if [[ "${VERBOSE}" == true ]]; then
echo -e "n ${BOLD}En cok yer kaplayan dizinler (/ altinda, top 10):${SIFIRLA}"
du -sh /* 2>/dev/null | sort -rh | head -10 |
awk '{printf " %-10s %sn", $1, $2}'
fi
}
Uyari Mekanizması ve Rapor Finali
Tüm bu verileri topladıktan sonra bir özet ve uyarı bölümü eklemek, raporun asıl değerini ortaya koyar.
# Global uyari listesi
declare -a UYARI_LISTESI=()
ozet_raporu() {
echo -e "n${BOLD}${MAVI}=== SISTEM OZETI ===${SIFIRLA}"
echo -e " ${BOLD}Sunucu:${SIFIRLA} $(hostname -f)"
echo -e " ${BOLD}IP Adresi:${SIFIRLA} $(hostname -I | awk '{print $1}')"
echo -e " ${BOLD}Isletim Sistemi:${SIFIRLA} $(cat /etc/os-release | grep PRETTY_NAME | cut -d= -f2 | tr -d '"')"
echo -e " ${BOLD}Kernel:${SIFIRLA} $(uname -r)"
echo -e " ${BOLD}Calisma Suresi:${SIFIRLA} $(uptime -p)"
echo -e " ${BOLD}Rapor Tarihi:${SIFIRLA} ${TARIH}"
# Aktif baglanti sayisi
BAGLANTI_SAYISI=$(ss -tn state established | grep -c ESTAB 2>/dev/null || echo "0")
echo -e " ${BOLD}Aktif TCP Baglantisi:${SIFIRLA} ${BAGLANTI_SAYISI}"
# Calismayen servisler (systemd varsa)
if command -v systemctl &>/dev/null; then
BASARISIZ_SERVIS=$(systemctl --failed --no-legend | wc -l)
if [[ ${BASARISIZ_SERVIS} -gt 0 ]]; then
echo -e " ${BOLD}Basarisiz Servis:${SIFIRLA} ${KIRMIZI}${BASARISIZ_SERVIS} servis calısmiyor!${SIFIRLA}"
UYARI_LISTESI+=("${BASARISIZ_SERVIS} systemd servisi basarisiz durumda")
else
echo -e " ${BOLD}Servis Durumu:${SIFIRLA} ${YESIL}Tum servisler calisiyor${SIFIRLA}"
fi
fi
}
uyari_ozeti() {
if [[ ${#UYARI_LISTESI[@]} -gt 0 ]]; then
echo -e "n${BOLD}${KIRMIZI}=== UYARILAR ===${SIFIRLA}"
for uyari in "${UYARI_LISTESI[@]}"; do
echo -e " ${KIRMIZI}[!]${SIFIRLA} ${uyari}"
done
else
echo -e "n${BOLD}${YESIL}=== TUM SISTEMLER NORMAL ===${SIFIRLA}"
echo -e " ${YESIL}[OK]${SIFIRLA} Esik degerlerin ustunde bir durum tespit edilmedi."
fi
}
E-posta Bildirimi
Uyarı varsa e-posta göndermek, cron job ile birleştirildiğinde güçlü bir izleme sistemi oluşturur.
email_gonder() {
local konu="[${HOSTNAME_KISA}] Sistem Raporu - ${TARIH}"
local icerik
if [[ ${#UYARI_LISTESI[@]} -gt 0 ]]; then
konu="[UYARI] [${HOSTNAME_KISA}] Sistem Raporu - ${TARIH}"
icerik="UYARI: Asagidaki sorunlar tespit edildi:nn"
for uyari in "${UYARI_LISTESI[@]}"; do
icerik+="- ${uyari}n"
done
icerik+="nnDetayli rapor log dosyasinda: ${LOG_DOSYA}"
else
icerik="Tum sistemler normal durumda.nnDetayli rapor: ${LOG_DOSYA}"
fi
if command -v mailx &>/dev/null; then
echo -e "${icerik}" | mailx -s "${konu}" "${EMAIL_ALICI}"
echo -e " ${YESIL}[OK]${SIFIRLA} E-posta gonderildi: ${EMAIL_ALICI}"
elif command -v sendmail &>/dev/null; then
echo -e "Subject: ${konu}nn${icerik}" | sendmail "${EMAIL_ALICI}"
else
echo -e " ${SARI}[!]${SIFIRLA} E-posta komutu bulunamadi (mailx veya sendmail gerekli)"
fi
}
Ana Akış ve Log Entegrasyonu
Tüm fonksiyonları bir araya getiren ana akış şu şekilde olmalı:
main() {
# Log dizinini olustur
if [[ "${LOG_KAYDET}" == true ]]; then
mkdir -p "${LOG_DIR}"
# Hem ekrana hem log dosyasina yaz
exec > >(tee -a "${LOG_DOSYA}") 2>&1
fi
echo -e "${BOLD}================================================${SIFIRLA}"
echo -e "${BOLD} Sistem Saglik Raporu - ${TARIH}${SIFIRLA}"
echo -e "${BOLD}================================================${SIFIRLA}"
# Fonksiyonlari calistir
ozet_raporu
cpu_raporu
ram_raporu
disk_raporu
uyari_ozeti
# E-posta gonder
if [[ "${EMAIL_GONDER}" == true ]]; then
email_gonder
fi
# Sadece uyari varsa exit code 1 don
if [[ ${#UYARI_LISTESI[@]} -gt 0 ]]; then
exit 1
fi
exit 0
}
# Scripti calistir
main "$@"
Cron Job ile Otomatikleştirme
Scripti cron job olarak zamanlamak için önce çalıştırma yetkisi verelim:
chmod +x /usr/local/sbin/sistem_raporu.sh
# Cron job eklemek icin:
crontab -e
Crontab içine şu satırları ekleyebilirsiniz:
- Her gün sabah 07:00’da rapor al ve logla:
0 7 * /usr/local/sbin/sistem_raporu.sh --log - Her gün sabah 07:00’da rapor al, logla ve e-posta gonder:
0 7 * /usr/local/sbin/sistem_raporu.sh --log --email - Her saat basinda sadece uyari varsa e-posta gonder:
0 /usr/local/sbin/sistem_raporu.sh --email 2>&1 - Detayli haftalik rapor (Pazartesi 09:00):
0 9 1 /usr/local/sbin/sistem_raporu.sh --log --email --verbose
Eski log dosyalarını temizlemek için ayrı bir cron eklemek iyi pratiktir:
# Her ayın 1'inde 30 günden eski logları sil
0 0 1 * * find /var/log/sistem_raporu -name "*.log" -mtime +30 -delete
Çoklu Sunucu Senaryosu
Bu scripti birden fazla sunucuya SSH ile çalıştırmak için basit bir wrapper yazabiliriz:
#!/bin/bash
# coklu_sunucu_raporu.sh
SUNUCULAR=(
"web01.sirket.com"
"web02.sirket.com"
"db01.sirket.com"
"cache01.sirket.com"
)
SSH_KULLANICI="sysadmin"
SCRIPT_YOL="/usr/local/sbin/sistem_raporu.sh"
RAPOR_DIZIN="/tmp/toplu_rapor_$(date +%Y%m%d)"
mkdir -p "${RAPOR_DIZIN}"
for sunucu in "${SUNUCULAR[@]}"; do
echo "[$sunucu] Rapor aliniyor..."
ssh -o ConnectTimeout=10
-o StrictHostKeyChecking=no
-o BatchMode=yes
"${SSH_KULLANICI}@${sunucu}"
"bash ${SCRIPT_YOL}" > "${RAPOR_DIZIN}/${sunucu}.txt" 2>&1
CIKIS_KODU=$?
if [[ ${CIKIS_KODU} -eq 0 ]]; then
echo " [OK] ${sunucu} - Normal"
elif [[ ${CIKIS_KODU} -eq 1 ]]; then
echo " [!] ${sunucu} - UYARI VAR!"
else
echo " [X] ${sunucu} - BAGLANTI HATASI"
fi
done
echo ""
echo "Tum raporlar: ${RAPOR_DIZIN}/"
Bu yaklaşım, SSH key tabanlı kimlik doğrulama ile birlikte kullanıldığında, 20-30 sunucunun durumunu dakikalar içinde değerlendirmenizi sağlar.
Dikkat Edilmesi Gereken Noktalar
Taşınabilirlik: Script büyük ölçüde /proc filesystem’e dayandığı için Linux’a özgüdür. macOS veya BSD sistemlerde bazı komutlar farklı çalışır. Eğer karma ortamınız varsa, uname -s ile OS kontrolü eklemek gerekir.
Performans etkisi: mpstat 1 1 komutu 1 saniye bekler. Çok sayıda sunucuya paralel çalıştırırken bu gecikme birikebilir. Paralel çalıştırma için & ve wait kombinasyonunu kullanın.
Güvenlik: Script’i root veya sudo yetkisi gerektiren komutlar için sudoers’a eklerken minimum yetki prensibine uyun. Sadece gerekli komutlar için izin verin.
Log rotasyonu: /var/log/sistem_raporu dizini zamanla büyüyebilir. Logrotate konfigürasyonu eklemek uzun vadede faydalıdır.
bc bağımlılığı: Bazı minimal kurulumda bc yüklü olmayabilir. Bu durumda awk ile aynı hesaplamaları yapabilirsiniz: awk "BEGIN {printf "%.1f", ${DEGER1}/${DEGER2}*100}"
Sonuç
Bu script, günlük sistem yönetimi rutinini ciddi ölçüde hızlandırır. Temel yapıyı anlayıp ihtiyaçlarınıza göre genişletmek kolaylaşır. Örneğin ağ trafiği izleme, belirli servislerin durum kontrolü veya özel uygulama metriklerini toplama gibi fonksiyonlar ekleyebilirsiniz.
Yazıyı kapatmadan önce şunu söylemek gerekir: En iyi monitoring aracı, ekibinizin gerçekten kullandığı ve güvendiği araçtır. Prometheus, Grafana, Zabbix gibi profesyonel çözümler çok daha kapsamlı özellikler sunsa da, basit bir bash scripti bazen en hızlı ve en az bağımlılıkla çalışan çözümdür. İkisini birbirinin alternatifi değil, tamamlayıcısı olarak düşünün.
Scripti GitHub’a koyup, farklı dağıtımlar ve ortamlarda test ettikçe geliştireceksiniz. Hata bulursanız ya da yeni fonksiyon fikirleri aklınıza gelirse, yorumlarda paylaşmaktan çekinmeyin.