Sistem Bilgisi Toplayan Bash Script: CPU, RAM ve Disk Raporu

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.

Yorum yapın