Ollama ile Otomatik Log Analizi: Sunucu Hatalarını Yapay Zeka ile Yorumlama
Sunucu loglarına baktığında ne hissediyorsun? Çoğu sysadmin için bu, binlerce satır arasında iğne aramak gibi bir his. Özellikle gece 2’de production’da bir şeyler patladığında ve siz stack trace’lerin arasında kaybolduğunuzda, “keşke biri bana bunları açıklayabilse” diye düşünürsünüz. İşte tam bu noktada Ollama ile yerel LLM kurulumu devreye giriyor. Bu yazıda, sunucu loglarınızı otomatik olarak analiz eden, hataları yorumlayan ve çözüm önerileri sunan bir sistem kuracağız. Hem de her şey kendi sunucunuzda, hiçbir veri dışarı çıkmadan.
Neden Yerel LLM ile Log Analizi?
Pek çok sysadmin “ChatGPT’e yapıştırırım logları” diye düşünüyor. Evet, bu da işe yarıyor ancak production logları genellikle hassas bilgiler içeriyor: IP adresleri, kullanıcı adları, iç ağ yapısı, servis isimleri. Bunları dış bir API’ye göndermek ciddi bir güvenlik açığı.
Ollama’nın güzelliği tam burada: model tamamen lokalde çalışıyor, internet bağlantısına gerek yok, veri dışarı çıkmıyor ve API maliyeti sıfır. Üstelik Llama 3, Mistral veya CodeLlama gibi modeller log analizi için gayet yetenekli.
Gerçek dünya senaryomuz şu: Bir web uygulamamız var, nginx + Node.js + PostgreSQL stack’i. Zaman zaman 500 hataları, zaman zaman yavaşlamalar, zaman zaman database bağlantı sorunları yaşıyor. Bir script yazacağız, bu script logları toplayacak, Ollama’ya gönderecek ve bize anlamlı bir özet + öneri sunacak.
Ollama Kurulumu ve Model Hazırlığı
Eğer henüz Ollama kurulu değilse, bir satırla halledelim:
curl -fsSL https://ollama.ai/install.sh | sh
Kurulum sonrası servisi başlatalım ve log analizi için uygun bir model çekelim. Ben bu iş için Mistral 7B veya Llama 3.1 8B öneriyorum. Makul bir donanımda (16GB RAM) rahat çalışıyorlar:
# Servisi başlat
sudo systemctl start ollama
sudo systemctl enable ollama
# Log analizi için iyi bir model çek
ollama pull mistral
# Ya da daha yetenekli ama daha ağır olan
ollama pull llama3.1
# Kurulumu test et
ollama run mistral "Merhaba, çalışıyor musun?"
Model indikten sonra Ollama’nın API’sini test edelim. Scriptlerimizde bu API’yi kullanacağız:
curl http://localhost:11434/api/generate
-d '{
"model": "mistral",
"prompt": "nginx 502 Bad Gateway hatasının olası nedenleri nelerdir?",
"stream": false
}'
Bu komut çalışıyorsa, artık script yazmaya hazırız.
Log Toplama ve Ön İşleme
Ham logları doğrudan LLM’e atmak verimsiz. Önce logları filtrelemek, sıkıştırmak ve anlamlı parçalara ayırmak gerekiyor. Aksi halde model token limitine takılıyor ya da gereksiz bilgiyle boğuluyor.
Önce basit bir log toplayıcı yazalım:
#!/bin/bash
# /usr/local/bin/collect_logs.sh
LOG_DIR="/var/log"
OUTPUT_DIR="/tmp/log_analysis"
TIME_WINDOW="${1:-60}" # Varsayılan: son 60 dakika
mkdir -p "$OUTPUT_DIR"
echo "=== SISTEM LOG ANALIZI ===" > "$OUTPUT_DIR/collected.log"
echo "Tarih: $(date)" >> "$OUTPUT_DIR/collected.log"
echo "Zaman Penceresi: Son $TIME_WINDOW dakika" >> "$OUTPUT_DIR/collected.log"
echo "" >> "$OUTPUT_DIR/collected.log"
# Nginx error logları
echo "--- NGINX HATALARI ---" >> "$OUTPUT_DIR/collected.log"
if [ -f "$LOG_DIR/nginx/error.log" ]; then
# Son TIME_WINDOW dakikanın loglarını çek, sadece error ve critical
find "$LOG_DIR/nginx" -name "*.log" -newer /tmp/check_time
-exec grep -h "error|crit|alert|emerg" {} ; 2>/dev/null |
tail -100 >> "$OUTPUT_DIR/collected.log"
fi
# Syslog'dan kritik mesajlar
echo "" >> "$OUTPUT_DIR/collected.log"
echo "--- SISTEM MESAJLARI ---" >> "$OUTPUT_DIR/collected.log"
journalctl --since "$TIME_WINDOW minutes ago"
-p err..emerg
--no-pager
-o short
2>/dev/null | tail -50 >> "$OUTPUT_DIR/collected.log"
# PostgreSQL logları
echo "" >> "$OUTPUT_DIR/collected.log"
echo "--- POSTGRESQL HATALARI ---" >> "$OUTPUT_DIR/collected.log"
if [ -f "$LOG_DIR/postgresql/postgresql-$(date +%Y-%m-%d).log" ]; then
grep -E "ERROR|FATAL|PANIC"
"$LOG_DIR/postgresql/postgresql-$(date +%Y-%m-%d).log" |
tail -30 >> "$OUTPUT_DIR/collected.log"
fi
echo "Log toplama tamamlandi: $OUTPUT_DIR/collected.log"
wc -l "$OUTPUT_DIR/collected.log"
Ollama API ile Entegrasyon
Asıl sihir burada başlıyor. Python ile bir analiz scripti yazacağız çünkü string manipülasyonu ve JSON işleme için Bash’ten daha uygun:
#!/usr/bin/env python3
# /usr/local/bin/analyze_logs.py
import requests
import json
import sys
import os
from datetime import datetime
OLLAMA_URL = "http://localhost:11434/api/generate"
MODEL = "mistral"
MAX_LOG_SIZE = 4000 # Token limitini aşmamak için karakter sınırı
def read_logs(log_file):
"""Log dosyasını oku ve boyutunu kontrol et."""
try:
with open(log_file, 'r', encoding='utf-8', errors='ignore') as f:
content = f.read()
# Çok büyükse, en önemli kısımları al
if len(content) > MAX_LOG_SIZE:
# Baştan 500, sondan 3500 karakter al
# Genellikle son hatalar daha önemli
content = content[:500] + "n...[orta kisimlar atildi]...n" + content[-3500:]
return content
except FileNotFoundError:
return "Log dosyasi bulunamadi."
def analyze_with_ollama(log_content, analysis_type="general"):
"""Ollama API'sine log gönder ve analiz iste."""
prompts = {
"general": f"""Sen bir Linux sistem yöneticisi asistanısın. Aşağıdaki sunucu loglarını analiz et.
GÖREVLER:
1. Kritik hataları listele (varsa)
2. Her hatanın olası nedenini açıkla
3. Acil müdahale gerektiren durumlar varsa belirt
4. Kısa ve pratik çözüm önerileri sun
LOGLAR:
{log_content}
Analizini Türkçe olarak yap. Teknik terimleri koru ama Türkçe açıklamalar ekle.""",
"security": f"""Sen bir güvenlik uzmanısın. Bu logları güvenlik açısından analiz et.
ODAK NOKTALARI:
- Başarısız giriş denemeleri
- Olağandışı IP adresleri veya istek kalıpları
- Potansiyel injection veya exploit denemeleri
- Yetki ihlali girişimleri
LOGLAR:
{log_content}
Türkçe analiz yap, kritiklik seviyesi (DÜŞÜK/ORTA/YÜKSEK/KRİTİK) belirt.""",
"performance": f"""Sen bir performans analisti olarak bu logları incele.
ODAK NOKTALARI:
- Yavaş sorgular veya işlemler
- Timeout hataları
- Kaynak tükenmesi belirtileri
- Bottleneck noktaları
LOGLAR:
{log_content}
Türkçe özet sun ve öncelik sırasına göre önerileri listele."""
}
prompt = prompts.get(analysis_type, prompts["general"])
payload = {
"model": MODEL,
"prompt": prompt,
"stream": False,
"options": {
"temperature": 0.3, # Daha tutarlı, daha az yaratıcı çıktı
"top_p": 0.9,
"num_predict": 1024 # Maksimum çıktı token sayısı
}
}
try:
response = requests.post(OLLAMA_URL, json=payload, timeout=120)
response.raise_for_status()
result = response.json()
return result.get('response', 'Yanit alinamadi.')
except requests.exceptions.Timeout:
return "HATA: Ollama yanit vermedi (timeout). Model yuklu mu kontrol edin."
except requests.exceptions.ConnectionError:
return "HATA: Ollama servisine baglanılamadi. 'systemctl status ollama' kontrol edin."
except Exception as e:
return f"HATA: {str(e)}"
def format_report(analysis, analysis_type, log_file):
"""Analiz sonucunu rapor formatına çevir."""
separator = "=" * 60
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
report = f"""
{separator}
OTOMATIK LOG ANALIZ RAPORU
Tarih: {timestamp}
Dosya: {log_file}
Analiz Tipi: {analysis_type.upper()}
Model: {MODEL}
{separator}
{analysis}
{separator}
"""
return report
if __name__ == "__main__":
log_file = sys.argv[1] if len(sys.argv) > 1 else "/tmp/log_analysis/collected.log"
analysis_type = sys.argv[2] if len(sys.argv) > 2 else "general"
print(f"[*] Log dosyasi okunuyor: {log_file}")
log_content = read_logs(log_file)
print(f"[*] Ollama ile analiz yapiliyor (model: {MODEL})...")
analysis = analyze_with_ollama(log_content, analysis_type)
report = format_report(analysis, analysis_type, log_file)
# Ekrana yaz
print(report)
# Dosyaya kaydet
report_file = f"/tmp/log_analysis/report_{datetime.now().strftime('%Y%m%d_%H%M%S')}.txt"
with open(report_file, 'w', encoding='utf-8') as f:
f.write(report)
print(f"[+] Rapor kaydedildi: {report_file}")
Otomatik Çalıştırma: Cron ve Systemd Timer
Scripti her saat başı otomatik çalıştıralım. İki yöntem var, ben systemd timer tercih ediyorum çünkü daha iyi loglama yapıyor:
# /etc/systemd/system/log-analyzer.service
[Unit]
Description=Ollama Log Analyzer
After=ollama.service network.target
[Service]
Type=oneshot
User=root
ExecStartPre=/usr/local/bin/collect_logs.sh 60
ExecStart=/usr/bin/python3 /usr/local/bin/analyze_logs.py
/tmp/log_analysis/collected.log general
StandardOutput=journal
StandardError=journal
# /etc/systemd/system/log-analyzer.timer
[Unit]
Description=Run Log Analyzer Every Hour
Requires=log-analyzer.service
[Timer]
OnCalendar=hourly
Persistent=true
[Install]
WantedBy=timers.target
# Servisleri etkinleştir
sudo systemctl daemon-reload
sudo systemctl enable log-analyzer.timer
sudo systemctl start log-analyzer.timer
# Durumu kontrol et
sudo systemctl status log-analyzer.timer
# Manuel tetikle
sudo systemctl start log-analyzer.service
# Logları izle
sudo journalctl -u log-analyzer.service -f
Slack/Discord Entegrasyonu ile Bildirimler
Analiz raporunu üretmek güzel, ama okumak için dosyaya bakmak zorunda kalmak pratik değil. Kritik hatalar bulunduğunda Slack’e bildirim atalım:
#!/usr/bin/env python3
# /usr/local/bin/notify_analysis.py
import requests
import sys
import re
SLACK_WEBHOOK = os.environ.get('SLACK_WEBHOOK_URL', '')
DISCORD_WEBHOOK = os.environ.get('DISCORD_WEBHOOK_URL', '')
def detect_severity(analysis_text):
"""Analiz metninden ciddiyet seviyesi belirle."""
critical_keywords = ['kritik', 'acil', 'panic', 'fatal', 'crash', 'down', 'failed']
warning_keywords = ['uyari', 'warning', 'yavaş', 'timeout', 'retry']
text_lower = analysis_text.lower()
critical_count = sum(1 for kw in critical_keywords if kw in text_lower)
warning_count = sum(1 for kw in warning_keywords if kw in text_lower)
if critical_count >= 2:
return "KRITIK", "#FF0000"
elif critical_count >= 1 or warning_count >= 3:
return "UYARI", "#FFA500"
else:
return "NORMAL", "#00FF00"
def send_slack_notification(analysis_text, hostname, severity, color):
"""Slack webhook ile bildirim gönder."""
if not SLACK_WEBHOOK:
print("Slack webhook URL bulunamadi, bildirim atlanıyor.")
return
# Analizi 500 karaktere kıs
short_analysis = analysis_text[:500] + "..." if len(analysis_text) > 500 else analysis_text
payload = {
"attachments": [{
"color": color,
"title": f"Log Analiz Raporu - {hostname}",
"text": short_analysis,
"fields": [
{"title": "Seviye", "value": severity, "short": True},
{"title": "Sunucu", "value": hostname, "short": True}
],
"footer": "Ollama Log Analyzer",
"ts": __import__('time').time()
}]
}
response = requests.post(SLACK_WEBHOOK, json=payload)
if response.status_code == 200:
print("[+] Slack bildirimi gönderildi.")
else:
print(f"[-] Slack bildirimi basarisiz: {response.status_code}")
if __name__ == "__main__":
report_file = sys.argv[1]
hostname = __import__('socket').gethostname()
with open(report_file, 'r') as f:
analysis = f.read()
severity, color = detect_severity(analysis)
# Sadece uyarı veya kritik durumlarda bildirim gönder
if severity != "NORMAL":
send_slack_notification(analysis, hostname, severity, color)
else:
print(f"[i] Seviye NORMAL, bildirim gönderilmiyor.")
Gerçek Dünya Senaryosu: Nginx + PostgreSQL Sorunu
Diyelim ki böyle bir log chunk’ınız var ve ne anlama geldiğini hızlıca anlamak istiyorsunuz:
# Hızlı tek satır analiz - test veya CI/CD için ideal
echo "2024-01-15 03:42:17 [error] connect() to unix:/var/run/php-fpm.sock failed (11: Resource temporarily unavailable) while connecting to upstream, client: 192.168.1.100, server: example.com" |
python3 -c "
import requests, sys
log = sys.stdin.read()
r = requests.post('http://localhost:11434/api/generate',
json={'model': 'mistral',
'prompt': f'Bu nginx hatasını 3 cümleyle açıkla ve çözümü söyle: {log}',
'stream': False})
print(r.json()['response'])
"
Bu tek satır komut, o karmaşık unix socket hatasını şöyle açıklıyor: PHP-FPM worker havuzu dolmuş, yeni bağlantılar kabul edilemiyor. Çözüm: pm.max_children değerini artır veya pm = dynamic modunda pm.max_spare_servers değerini düzenle.
Özelleştirilmiş Sistem Kontrol Scripti
Her şeyi bir araya getiren, tek çalıştırmada tüm sistemi taran bir wrapper hazırlayalım:
#!/bin/bash
# /usr/local/bin/syscheck-ai.sh
# Kullanim: syscheck-ai.sh [quick|full|security]
MODE="${1:-quick}"
HOSTNAME=$(hostname)
REPORT_DIR="/var/log/ai-reports"
mkdir -p "$REPORT_DIR"
echo "==================================="
echo " AI Destekli Sistem Kontrolu"
echo " Mod: $MODE | Host: $HOSTNAME"
echo "==================================="
# Sistem metrikleri topla
METRICS=$(cat << 'EOF'
CPU: $(top -bn1 | grep "Cpu(s)" | awk '{print $2}')%
RAM: $(free -h | awk '/^Mem:/{print $3"/"$2}')
DISK: $(df -h / | awk 'NR==2{print $5}')
LOAD: $(uptime | awk -F'load average:' '{print $2}')
EOF
)
case "$MODE" in
quick)
TIME_WINDOW=30
/usr/local/bin/collect_logs.sh $TIME_WINDOW
python3 /usr/local/bin/analyze_logs.py
/tmp/log_analysis/collected.log general
;;
full)
TIME_WINDOW=240
/usr/local/bin/collect_logs.sh $TIME_WINDOW
# Önce genel analiz
python3 /usr/local/bin/analyze_logs.py
/tmp/log_analysis/collected.log general
# Sonra güvenlik analizi
python3 /usr/local/bin/analyze_logs.py
/tmp/log_analysis/collected.log security
# Performans analizi
python3 /usr/local/bin/analyze_logs.py
/tmp/log_analysis/collected.log performance
;;
security)
TIME_WINDOW=1440 # 24 saat
/usr/local/bin/collect_logs.sh $TIME_WINDOW
python3 /usr/local/bin/analyze_logs.py
/tmp/log_analysis/collected.log security
;;
*)
echo "Bilinmeyen mod: $MODE"
echo "Kullanim: $0 [quick|full|security]"
exit 1
;;
esac
# Raporlari arsivle
cp /tmp/log_analysis/report_*.txt "$REPORT_DIR/" 2>/dev/null
find "$REPORT_DIR" -name "*.txt" -mtime +30 -delete # 30 günden eski raporları sil
echo "[+] Tamamlandi. Raporlar: $REPORT_DIR"
İpuçları ve Dikkat Edilmesi Gerekenler
Prodüksiyon ortamında bu sistemi kullanırken birkaç önemli noktaya dikkat etmek gerekiyor:
- Token limitleri: Mistral 7B için yaklaşık 4000-6000 token güvenli sınır. Daha büyük loglar için özetleme aşaması ekleyin.
- Hallucination riski: LLM bazen olmayan bir çözüm önerebilir. Önerileri her zaman doğrulayın, kör kör uygulamayın.
- Model seçimi: Log analizi için
mistralveyallama3.1iyi çalışıyor.codellamaözellikle stack trace’ler için daha iyi sonuç verebiliyor. - Sıcaklık (temperature) değeri: 0.1-0.3 arası tutun. Yüksek temperature, tutarsız ve yaratıcı (yani hatalı olabilecek) çıktılar üretiyor.
- RAM kullanımı: Mistral 7B, 8-10GB RAM yiyor. Analiz sırasında sisteminizin sıkışmaması için cron’u düşük yük saatlerine ayarlayın.
- Log maskeleme: IP adresleri veya kullanıcı bilgileri hassassa, script’e bir maskeleme aşaması ekleyin. Yerel LLM kullanıyor olsak da log hijyeni iyi pratik.
- Çıktı kalitesi: Türkçe prompt verdiğinizde model Türkçe yanıt veriyor ama teknik terimler İngilizce kalıyor. Bu aslında doğru davranış, değiştirmeye çalışmayın.
Sonuç
Yapay zeka destekli log analizi, sysadmin’lerin hayatını gerçekten kolaylaştıran pratik bir araç. Gece yarısı alarm geldiğinde, birkaç saniye içinde “ne oldu, neden oldu, ne yapmalıyım” sorularına cevap alabilmek, saatlerce log kazmaktan çok daha verimli.
Burada kurduğumuz sistemin en güçlü yanı, tamamen lokal çalışması. Hassas veriler, iç ağ bilgileri, kullanıcı logları hiçbir şekilde dışarı çıkmıyor. Ollama bu konuda gerçek bir game-changer.
Başlangıç için quick modunu günlük cron’a ekleyin, bir hafta kullanın, sonra kendi ortamınıza göre prompt’ları özelleştirin. Zamanla sistemin hangi tür hataları ne kadar iyi yakaladığını görecek ve buna göre fine-tune edebileceksiniz. Unutmayın: LLM bir asistan, yerine geçemez. Ama doğru kullanıldığında, en deneyimli sysadmin’in bile işini hızlandıran güçlü bir araç.
