Sistem yöneticiliğinde en can sıkıcı durumlardan biri, bir şeyler ters gittiğinde “ne zaman başladı?” sorusuna cevap verememektir. Sunucu yavaşlamış, disk dolmuş ya da bir process RAM’i yutmuş ama sen ancak kullanıcılar şikayet etmeye başladıktan sonra haberdar olmuşsundur. İşte bu yüzden kaynak izleme, reaktif değil proaktif bir yaklaşım gerektiriyor. Python’un psutil kütüphanesi bu noktada gerçekten hayat kurtaran bir araç haline geliyor.
psutil Nedir ve Neden Kullanmalıyız?
psutil (process and system utilities), Linux, Windows, macOS ve BSD sistemlerde çalışan, sistem kaynaklarını ve çalışan processleri sorgulamak için geliştirilmiş bir Python kütüphanesidir. top, htop, vmstat, netstat gibi araçların programatik karşılığı olarak düşünebilirsiniz.
Neden script yazmak yerine bu araçları doğrudan kullanmıyoruz? Çünkü:
- Shell komutlarının çıktısını parse etmek hem kırılgan hem de platforma özgü bir iştir
psutilile topladığınız veriyi doğrudan bir veritabanına yazabilir, alert gönderebilir ya da bir API’ye postlayabilirsiniz- Windows ve Linux’ta aynı kodu çalıştırmak istiyorsanız
psutilbunu sorunsuz halleder - Çıktı zaten Python nesnesi olarak gelir, ek parse işlemi gerekmez
Kurulum tek satır:
pip install psutil
Bir sanal ortamda çalışıyorsanız:
python3 -m venv monitoring-env
source monitoring-env/bin/activate
pip install psutil
CPU Kullanımını İzlemek
En temel ihtiyaçtan başlayalım. CPU kullanımını çekerken dikkat edilmesi gereken önemli bir nokta var: cpu_percent() fonksiyonu ilk çağrıldığında 0.0 döner çünkü bir önceki ölçümle karşılaştırma yapacak referans noktası yoktur. Bu yüzden interval parametresi kullanmak ya da bir başlangıç çağrısı yapmak gerekir.
import psutil
import time
# Tüm CPU çekirdeklerinin kullanımını ayrı ayrı göster
def cpu_monitor(interval=1, count=5):
print(f"CPU Çekirdek Sayısı (Fiziksel): {psutil.cpu_count(logical=False)}")
print(f"CPU Çekirdek Sayısı (Mantıksal): {psutil.cpu_count(logical=True)}")
print("-" * 40)
for i in range(count):
# interval parametresi iki ölçüm arasındaki süreyi belirler
overall = psutil.cpu_percent(interval=interval)
per_core = psutil.cpu_percent(interval=None, percpu=True)
print(f"[{time.strftime('%H:%M:%S')}] Genel CPU: {overall}%")
for idx, core in enumerate(per_core):
print(f" Core {idx}: {core}%")
print()
cpu_monitor()
CPU frekans bilgisini de almak mümkün. Özellikle laptop veya güç tasarrufu modunda çalışan sistemlerde throttling olup olmadığını kontrol etmek için kullanışlıdır:
import psutil
freq = psutil.cpu_freq()
if freq:
print(f"Mevcut Frekans: {freq.current:.0f} MHz")
print(f"Minimum Frekans: {freq.min:.0f} MHz")
print(f"Maksimum Frekans: {freq.max:.0f} MHz")
# CPU load average (sadece Unix sistemlerde)
try:
load = psutil.getloadavg()
print(f"Load Average (1/5/15 dk): {load[0]:.2f} / {load[1]:.2f} / {load[2]:.2f}")
except AttributeError:
print("Load average Windows'ta desteklenmiyor.")
RAM ve Swap Kullanımı
Bellek sorunları genellikle CPU sorunlarından daha sinsi olur. Yavaş yavaş büyüyen bir memory leak, sistemi saatler içinde çökertebilir. virtual_memory() ve swap_memory() fonksiyonları bu noktada oldukça detaylı bilgi verir.
import psutil
def memory_report():
vm = psutil.virtual_memory()
swap = psutil.swap_memory()
# Byte değerlerini okunabilir hale getir
def to_gb(bytes_val):
return bytes_val / (1024 ** 3)
print("=== RAM Durumu ===")
print(f"Toplam : {to_gb(vm.total):.2f} GB")
print(f"Kullanılan : {to_gb(vm.used):.2f} GB ({vm.percent}%)")
print(f"Boş : {to_gb(vm.available):.2f} GB")
print(f"Buffer : {to_gb(vm.buffers):.2f} GB")
print(f"Cache : {to_gb(vm.cached):.2f} GB")
print("n=== Swap Durumu ===")
print(f"Toplam : {to_gb(swap.total):.2f} GB")
print(f"Kullanılan : {to_gb(swap.used):.2f} GB ({swap.percent}%)")
print(f"Boş : {to_gb(swap.free):.2f} GB")
# Uyarı mekanizması
if vm.percent > 85:
print("n[UYARI] RAM kullanımı %85 üzerinde!")
if swap.percent > 50:
print("[UYARI] Swap kullanımı %50 üzerinde, bellek baskısı var!")
memory_report()
Disk Kullanımını İzlemek
Disk dolma problemleri sysadminlerin gecelerini bölen klasik senaryolardan biridir. /var/log dizininin patlaması, büyük bir dump dosyasının beklenmedik bir yere yazılması… Hepsini erken yakalamak için disk izleme şart.
import psutil
def disk_report():
print("=== Disk Partition Bilgileri ===n")
partitions = psutil.disk_partitions()
for partition in partitions:
print(f"Cihaz : {partition.device}")
print(f"Bağlama Noktası: {partition.mountpoint}")
print(f"Dosya Sistemi : {partition.fstype}")
try:
usage = psutil.disk_usage(partition.mountpoint)
total_gb = usage.total / (1024 ** 3)
used_gb = usage.used / (1024 ** 3)
free_gb = usage.free / (1024 ** 3)
print(f"Toplam : {total_gb:.1f} GB")
print(f"Kullanılan : {used_gb:.1f} GB")
print(f"Boş : {free_gb:.1f} GB")
print(f"Doluluk : {usage.percent}%")
if usage.percent >= 90:
print(f"[KRİTİK] {partition.mountpoint} dolmak üzere!")
elif usage.percent >= 75:
print(f"[UYARI] {partition.mountpoint} için yer açın.")
except PermissionError:
print("Erişim izni yok, atlanıyor.")
print("-" * 35)
disk_report()
Disk I/O istatistiklerine de bakabiliriz. Özellikle yüksek I/O wait değerleri yaşandığında hangi diskin sorun çıkardığını bulmak için kullanışlıdır:
import psutil
import time
# İki ölçüm arasındaki farkı alarak gerçek I/O hızını hesapla
def disk_io_rate(interval=1):
before = psutil.disk_io_counters(perdisk=True)
time.sleep(interval)
after = psutil.disk_io_counters(perdisk=True)
for disk_name in after:
if disk_name not in before:
continue
read_bytes = (after[disk_name].read_bytes - before[disk_name].read_bytes) / interval
write_bytes = (after[disk_name].write_bytes - before[disk_name].write_bytes) / interval
print(f"{disk_name}:")
print(f" Okuma : {read_bytes / 1024:.1f} KB/s")
print(f" Yazma : {write_bytes / 1024:.1f} KB/s")
disk_io_rate()
Network Bağlantılarını ve Trafiği İzlemek
Network tarafında hem trafik istatistikleri hem de aktif bağlantıları izlemek mümkün. Bir sunucuda beklenmedik outbound bağlantı mı var? Belirli bir porta aşırı bağlantı yağmuru mu geliyor? psutil bunları sorgulamak için pratik bir yol sunar.
import psutil
import time
def network_stats(interval=2):
before = psutil.net_io_counters(pernic=True)
time.sleep(interval)
after = psutil.net_io_counters(pernic=True)
print("=== Network Arayüz İstatistikleri ===n")
for iface in after:
if iface not in before:
continue
# Sadece aktif arayüzleri göster
sent_rate = (after[iface].bytes_sent - before[iface].bytes_sent) / interval
recv_rate = (after[iface].bytes_recv - before[iface].bytes_recv) / interval
if sent_rate == 0 and recv_rate == 0:
continue
print(f"Arayüz: {iface}")
print(f" Gönderme Hızı : {sent_rate / 1024:.2f} KB/s")
print(f" Alma Hızı : {recv_rate / 1024:.2f} KB/s")
print(f" Toplam Gönderilen: {after[iface].bytes_sent / (1024**2):.1f} MB")
print(f" Toplam Alınan : {after[iface].bytes_recv / (1024**2):.1f} MB")
print(f" Paket Hatası : {after[iface].errin + after[iface].errout}")
print()
network_stats()
Process Yönetimi ile Gerçek Dünya Senaryosu
Şimdi işin pratik kısmına gelelim. Diyelim ki bir production sunucusunda zaman zaman belirli bir process RAM kullanımını patlattıktan sonra sistemi yavaşlatıyor ve siz kill etmek zorunda kalıyorsunuz. Bu durumu otomatize etmek mümkün.
import psutil
import logging
import time
logging.basicConfig(
filename='/var/log/process_monitor.log',
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s'
)
def find_memory_hogs(threshold_percent=10.0):
"""RAM kullanımı eşik değerini aşan processleri bul."""
hogs = []
for proc in psutil.process_iter(['pid', 'name', 'username', 'memory_percent', 'cpu_percent', 'status']):
try:
info = proc.info
if info['memory_percent'] and info['memory_percent'] > threshold_percent:
hogs.append(info)
except (psutil.NoSuchProcess, psutil.AccessDenied):
# Process ölmüş olabilir ya da root yetkisi gerekebilir
continue
# RAM kullanımına göre sırala
hogs.sort(key=lambda x: x['memory_percent'], reverse=True)
return hogs
def monitor_processes(check_interval=30, mem_threshold=10.0):
print(f"Process izleme başladı. Eşik: %{mem_threshold} RAM")
print("Çıkmak için Ctrl+Cn")
while True:
hogs = find_memory_hogs(threshold_percent=mem_threshold)
if hogs:
print(f"[{time.strftime('%Y-%m-%d %H:%M:%S')}] Yüksek RAM kullanan processler:")
for proc in hogs:
msg = (f"PID: {proc['pid']} | Ad: {proc['name']} | "
f"Kullanıcı: {proc['username']} | "
f"RAM: {proc['memory_percent']:.2f}%")
print(f" {msg}")
logging.warning(msg)
else:
print(f"[{time.strftime('%H:%M:%S')}] Sistem normal, yüksek RAM kullanan process yok.")
time.sleep(check_interval)
if __name__ == '__main__':
monitor_processes()
Kapsamlı Sistem Raporu Scripti
Tüm bunları bir araya getiren, cronjob ile düzenli olarak çalıştırılabilecek ve sonuçları bir dosyaya yazan kapsamlı bir script örneği:
#!/usr/bin/env python3
"""
Sistem Kaynak Raporu
Kullanım: python3 sys_report.py [--output /path/to/report.log]
"""
import psutil
import json
import datetime
import argparse
import sys
def collect_metrics():
"""Tüm sistem metriklerini topla ve dict olarak döndür."""
metrics = {
'timestamp': datetime.datetime.now().isoformat(),
'hostname': '',
'cpu': {},
'memory': {},
'disk': [],
'network': {},
'top_processes': []
}
# Hostname
try:
import socket
metrics['hostname'] = socket.gethostname()
except Exception:
metrics['hostname'] = 'unknown'
# CPU
metrics['cpu'] = {
'percent': psutil.cpu_percent(interval=1),
'count_physical': psutil.cpu_count(logical=False),
'count_logical': psutil.cpu_count(logical=True),
}
try:
load = psutil.getloadavg()
metrics['cpu']['load_avg'] = {
'1min': round(load[0], 2),
'5min': round(load[1], 2),
'15min': round(load[2], 2)
}
except AttributeError:
pass
# Memory
vm = psutil.virtual_memory()
metrics['memory'] = {
'total_gb': round(vm.total / (1024**3), 2),
'used_gb': round(vm.used / (1024**3), 2),
'available_gb': round(vm.available / (1024**3), 2),
'percent': vm.percent
}
# Disk
for partition in psutil.disk_partitions():
try:
usage = psutil.disk_usage(partition.mountpoint)
metrics['disk'].append({
'device': partition.device,
'mountpoint': partition.mountpoint,
'fstype': partition.fstype,
'total_gb': round(usage.total / (1024**3), 2),
'used_gb': round(usage.used / (1024**3), 2),
'free_gb': round(usage.free / (1024**3), 2),
'percent': usage.percent,
'critical': usage.percent >= 90,
'warning': 75 <= usage.percent < 90
})
except (PermissionError, OSError):
continue
# Top 5 process (RAM'e göre)
procs = []
for proc in psutil.process_iter(['pid', 'name', 'memory_percent', 'cpu_percent']):
try:
procs.append(proc.info)
except (psutil.NoSuchProcess, psutil.AccessDenied):
continue
procs.sort(key=lambda x: x.get('memory_percent') or 0, reverse=True)
metrics['top_processes'] = procs[:5]
return metrics
def generate_text_report(metrics):
"""Metrics dict'inden okunabilir bir rapor oluştur."""
lines = []
lines.append("=" * 50)
lines.append(f"SİSTEM RAPORU - {metrics['hostname']}")
lines.append(f"Zaman: {metrics['timestamp']}")
lines.append("=" * 50)
cpu = metrics['cpu']
lines.append(f"n[CPU] Kullanim: %{cpu['percent']}")
if 'load_avg' in cpu:
la = cpu['load_avg']
lines.append(f"[CPU] Load Average: {la['1min']} / {la['5min']} / {la['15min']}")
mem = metrics['memory']
lines.append(f"n[RAM] Kullanan: {mem['used_gb']} GB / {mem['total_gb']} GB (%{mem['percent']})")
lines.append("n[DISK]")
for d in metrics['disk']:
status = "KRİTİK" if d['critical'] else ("UYARI" if d['warning'] else "OK")
lines.append(f" {d['mountpoint']}: %{d['percent']} dolu [{status}]")
lines.append("n[TOP 5 PROCESS - RAM]")
for p in metrics['top_processes']:
mem_pct = p.get('memory_percent') or 0
lines.append(f" PID {p['pid']:6d} | {p['name'][:20]:20s} | RAM: %{mem_pct:.2f}")
lines.append("")
return "n".join(lines)
def main():
parser = argparse.ArgumentParser(description='Sistem Kaynak Raporu')
parser.add_argument('--output', help='Rapor dosyası yolu', default=None)
parser.add_argument('--json', action='store_true', help='JSON formatında çıktı ver')
args = parser.parse_args()
metrics = collect_metrics()
if args.json:
output = json.dumps(metrics, indent=2, ensure_ascii=False)
else:
output = generate_text_report(metrics)
if args.output:
with open(args.output, 'a', encoding='utf-8') as f:
f.write(output + "n")
print(f"Rapor yazıldı: {args.output}")
else:
print(output)
# Kritik disk doluluk varsa exit code 1 döndür (cronjob alerting için)
critical_disks = [d for d in metrics['disk'] if d['critical']]
if critical_disks or metrics['memory']['percent'] > 90:
sys.exit(1)
sys.exit(0)
if __name__ == '__main__':
main()
Bu scripti cronjob ile çalıştırmak için:
# Her 15 dakikada bir çalıştır, kritik durumlarda mail gönder
*/15 * * * * /usr/bin/python3 /opt/scripts/sys_report.py --output /var/log/sys_report.log || mail -s "UYARI: Sistem Kaynak Alarmı" [email protected] < /var/log/sys_report.log
Sistem Uptime ve Boot Bilgisi
Monitoring senaryolarında uptime bilgisi de önemli. Beklenmedik bir reboot yaşandıysa bunu log’dan görmek yerine direkt sorgulamak isteyebilirsiniz:
import psutil
import datetime
boot_time = psutil.boot_time()
boot_dt = datetime.datetime.fromtimestamp(boot_time)
uptime_seconds = (datetime.datetime.now() - boot_dt).total_seconds()
days = int(uptime_seconds // 86400)
hours = int((uptime_seconds % 86400) // 3600)
minutes = int((uptime_seconds % 3600) // 60)
print(f"Son Başlangıç : {boot_dt.strftime('%Y-%m-%d %H:%M:%S')}")
print(f"Uptime : {days} gün, {hours} saat, {minutes} dakika")
Dikkat Edilmesi Gereken Noktalar
psutil kullanırken birkaç pratik noktaya dikkat etmek gerekir:
- AccessDenied istisnası: Root yetkisi olmadan bazı processlerin bilgilerine erişilemez. Her zaman
try/exceptbloğu kullanın. - NoSuchProcess istisnası: Process listesini çekerken bir process sonlanmış olabilir. Bu tamamen normaldir, yakalamanız yeterli.
- cpu_percent() ilk çağrı: İlk çağrıda
0.0dönebilir.intervalparametresi verip bloklamak ya da ardışık iki çağrı yapmak gerekir. - Windows’ta bazı özellikler eksik:
getloadavg(),sensors_temperatures()gibi fonksiyonlar Windows’ta ya yoktur ya da çok sınırlıdır. Platform kontrolü yapın. - Production’da interval seçimi: Çok kısa intervallerle çok sık polling yapmak, izlediğiniz sistemin kendisine yük bindirmeye başlar. 30 saniye ile 1 dakikalık aralıklar genellikle makuldür.
Sonuç
psutil, Python ile sistem otomasyonu yapan her sysadmin’in araç kutusunda olması gereken kütüphanelerin başında geliyor. Karmaşık shell scriptleri yazmaktan, platforma özgü komutların çıktısını parse etmekten kurtarıyor ve topladığınız veriyi doğrudan kullanılabilir Python nesneleri olarak sunuyor.
Burada anlattıklarımı başlangıç noktası olarak düşünün. Gerçek dünyada bu scriptleri Grafana/InfluxDB stack’iyle birleştirebilir, Prometheus exporter yazabilir ya da mevcut alerting sisteminize entegre edebilirsiniz. Ancak temel mantık hep aynı: veriyi topla, eşikleri kontrol et, zamanında uyar.
En pratik tavsiyem şu: Önce kendi ortamınızın “normal” değerlerini belirleyin. CPU’nuz genellikle %30’da mı çalışıyor, %70’te mi? RAM’inizin yüzde kaçı sürekli dolu? Bu baseline’ı bilmeden alert eşikleri koymak, ya hiç çalmayan ya da sürekli çalan alarm sistemleriyle sonuçlanır. psutil size veriyi verir, ama o veriyi yorumlamak hala sizin işiniz.