Uptime Kuma API Kullanımı ve Otomasyon
Uptime Kuma’yı kurup monitörlerinizi arayüzden tıklaya tıklaya eklemeye başladığınızda her şey güzel görünür. Birkaç monitor, birkaç bildirim kanalı… Tamam. Ama sonra ekibiniz büyüyor, ortamlar çoğalıyor ve bir anda “şu 80 servisi elle tek tek eklemeye kalksam ölürüm” noktasına geliyorsunuz. İşte tam o anda API devreye giriyor.
Bu yazıda Uptime Kuma’nın REST API’sini ve Socket.IO tabanlı iletişim katmanını kullanarak monitoring otomasyonu nasıl kurarsınız, bunu gerçek senaryolar üzerinden anlatacağım. CI/CD pipeline’ınıza monitor oluşturmayı entegre etmek, yeni deploy sonrası otomatik uptime kontrolü yapmak, mevcut monitor listesini programatik olarak yönetmek… Hepsine bakacağız.
Uptime Kuma API’sine Genel Bakış
Uptime Kuma’nın API hikayesi biraz karmaşık. Proje başlangıçta tam anlamıyla bir REST API sunmuyordu; iletişim Socket.IO üzerinden gerçekleşiyordu. Zamanla community’nin baskısıyla bazı HTTP endpoint’leri eklendi ama hala temel operasyonların büyük kısmı Socket.IO protokolü üzerinden yürüyor.
Pratik açıdan iki seçeneğiniz var:
- Resmi HTTP API endpoint’leri: Sınırlı ama stabil. Genellikle status page ve bazı okuma işlemleri için kullanılır.
- uptime-kuma-api (Python kütüphanesi): Lucas Held tarafından geliştirilen ve Socket.IO’yu saran bu kütüphane, monitoring otomasyonu için fiilen standart haline geldi.
- Doğrudan Socket.IO: En esnek yol ama en zahmetli olanı da bu.
Ben çoğu zaman Python kütüphanesini tercih ediyorum. Production ortamında güvenilir davranış sergiliyor ve maintainer aktif.
Kurulum ve İlk Bağlantı
Önce ortamı hazırlayalım:
pip install uptime-kuma-api
# veya requirements.txt'e ekleyin:
# uptime-kuma-api==1.2.1
Basit bir bağlantı testi ile başlayalım:
from uptime_kuma_api import UptimeKumaApi
api = UptimeKumaApi("http://uptime-kuma.sirketim.local:3001")
try:
api.login("admin", "gizli-sifre")
print("Bağlantı başarılı")
# Tüm monitor listesini çek
monitors = api.get_monitors()
print(f"Toplam monitor sayısı: {len(monitors)}")
finally:
api.disconnect()
Bağlantı noktasında sık karşılaştığım bir sorun: Uptime Kuma bir reverse proxy arkasındaysa ve SSL termination yapılıyorsa, URL’yi doğru vermeniz gerekiyor. https:// prefix’i ile bağlanıyorsanız self-signed sertifika varsa:
import ssl
from uptime_kuma_api import UptimeKumaApi
# SSL doğrulamasını devre dışı bırak (sadece internal ağ için!)
api = UptimeKumaApi(
"https://uptime-kuma.internal.sirketim.com",
ssl_verify=False
)
api.login("admin", "sifre")
Monitor Oluşturma Otomasyonu
Gerçek dünya senaryosu: Microservice mimarinizde her yeni servis deploy edildiğinde otomatik olarak Uptime Kuma’da bir HTTP monitor oluşturulsun istiyorsunuz.
from uptime_kuma_api import UptimeKumaApi, MonitorType
def create_http_monitor(api, service_name, url, team="platform"):
"""
Yeni bir HTTP monitor oluşturur ve notification group'a atar.
"""
monitor_config = {
"type": MonitorType.HTTP,
"name": f"[{team.upper()}] {service_name}",
"url": url,
"interval": 60, # saniye cinsinden kontrol aralığı
"retryInterval": 60,
"maxretries": 3, # 3 başarısız deneme sonrası alarm
"timeout": 30,
"accepted_statuscodes": ["200-299"],
"upsideDown": False,
"active": True,
}
result = api.add_monitor(**monitor_config)
monitor_id = result.get("monitorID")
print(f"Monitor oluşturuldu: {service_name} (ID: {monitor_id})")
return monitor_id
Bu fonksiyonu CI/CD pipeline’ınıza entegre edebilirsiniz. GitLab CI örneği:
# .gitlab-ci.yml
stages:
- deploy
- register-monitor
register-uptime-monitor:
stage: register-monitor
image: python:3.11-slim
before_script:
- pip install uptime-kuma-api
script:
- python scripts/register_monitor.py
variables:
SERVICE_NAME: ${CI_PROJECT_NAME}
SERVICE_URL: "https://${CI_ENVIRONMENT_SLUG}.sirketim.com/health"
only:
- main
Script tarafında environment variable’lardan okuyarak dinamik monitor oluşturma:
#!/usr/bin/env python3
# scripts/register_monitor.py
import os
import sys
from uptime_kuma_api import UptimeKumaApi, MonitorType
KUMA_URL = os.environ["UPTIME_KUMA_URL"]
KUMA_USER = os.environ["UPTIME_KUMA_USER"]
KUMA_PASS = os.environ["UPTIME_KUMA_PASS"]
SERVICE_NAME = os.environ["SERVICE_NAME"]
SERVICE_URL = os.environ["SERVICE_URL"]
TEAM = os.environ.get("TEAM_NAME", "engineering")
def main():
api = UptimeKumaApi(KUMA_URL)
try:
api.login(KUMA_USER, KUMA_PASS)
# Aynı isimde monitor var mı kontrol et
existing = api.get_monitors()
monitor_names = [m["name"] for m in existing]
monitor_name = f"[{TEAM.upper()}] {SERVICE_NAME}"
if monitor_name in monitor_names:
print(f"Monitor zaten mevcut: {monitor_name}")
sys.exit(0)
result = api.add_monitor(
type=MonitorType.HTTP,
name=monitor_name,
url=SERVICE_URL,
interval=60,
maxretries=3,
timeout=30,
)
print(f"Yeni monitor eklendi: {monitor_name}")
print(f"Monitor ID: {result.get('monitorID')}")
except Exception as e:
print(f"Hata: {e}", file=sys.stderr)
sys.exit(1)
finally:
api.disconnect()
if __name__ == "__main__":
main()
Toplu Monitor Yönetimi: YAML’dan Import
Onlarca servisi tek tek API çağrısıyla eklemek yerine bir YAML tanım dosyası tutup bunu idempotent şekilde uygulayabilirsiniz. Terraform’un “desired state” yaklaşımını monitoring’e taşımak gibi düşünebilirsiniz.
# monitors.yaml
monitors:
- name: "[API] User Service"
url: "https://user-service.prod.sirketim.com/health"
type: http
interval: 30
team: backend
- name: "[API] Payment Service"
url: "https://payment-service.prod.sirketim.com/actuator/health"
type: http
interval: 30
team: backend
accepted_statuscodes:
- "200"
- name: "[TCP] PostgreSQL Master"
hostname: "pg-master.internal.sirketim.com"
port: 5432
type: tcp
interval: 60
team: dba
- name: "[DNS] Ana Domain"
url: "sirketim.com"
type: dns
interval: 120
team: platform
Bu YAML’ı işleyecek sync scripti:
#!/usr/bin/env python3
# sync_monitors.py
import yaml
import os
from uptime_kuma_api import UptimeKumaApi, MonitorType
TYPE_MAP = {
"http": MonitorType.HTTP,
"tcp": MonitorType.TCP,
"dns": MonitorType.DNS,
"ping": MonitorType.PING,
"keyword": MonitorType.KEYWORD,
}
def load_config(path="monitors.yaml"):
with open(path, "r", encoding="utf-8") as f:
return yaml.safe_load(f)
def sync_monitors(api, desired_monitors):
existing = {m["name"]: m for m in api.get_monitors()}
for monitor_def in desired_monitors:
name = monitor_def["name"]
monitor_type = TYPE_MAP.get(monitor_def.get("type", "http"))
base_params = {
"type": monitor_type,
"name": name,
"interval": monitor_def.get("interval", 60),
"maxretries": monitor_def.get("maxretries", 3),
"timeout": monitor_def.get("timeout", 30),
"active": monitor_def.get("active", True),
}
# Tip bazlı ek parametreler
if monitor_type == MonitorType.HTTP:
base_params["url"] = monitor_def["url"]
if "accepted_statuscodes" in monitor_def:
base_params["accepted_statuscodes"] = monitor_def["accepted_statuscodes"]
elif monitor_type == MonitorType.TCP:
base_params["hostname"] = monitor_def["hostname"]
base_params["port"] = monitor_def["port"]
elif monitor_type == MonitorType.DNS:
base_params["url"] = monitor_def["url"]
elif monitor_type == MonitorType.PING:
base_params["hostname"] = monitor_def["hostname"]
if name not in existing:
result = api.add_monitor(**base_params)
print(f"[EKLENDI] {name}")
else:
# Mevcut monitor güncelle
monitor_id = existing[name]["id"]
api.edit_monitor(id=monitor_id, **base_params)
print(f"[GUNCELLENDI] {name}")
# Fazlalık monitörleri raporla (silmiyoruz, raporluyoruz)
desired_names = {m["name"] for m in desired_monitors}
for existing_name in existing:
if existing_name not in desired_names:
print(f"[UYARI] Tanımda olmayan monitor: {existing_name}")
def main():
api = UptimeKumaApi(os.environ["UPTIME_KUMA_URL"])
try:
api.login(
os.environ["UPTIME_KUMA_USER"],
os.environ["UPTIME_KUMA_PASS"]
)
config = load_config()
sync_monitors(api, config["monitors"])
finally:
api.disconnect()
if __name__ == "__main__":
main()
Monitor Durumu Sorgulama ve Alerting
Uptime Kuma’nın kendi notification sistemi çoğu zaman yeterli ama bazen monitoring verilerini başka sistemlere aktarmanız, özel raporlar üretmeniz ya da harici bir alertmanager’a beslemeniz gerekiyor.
from uptime_kuma_api import UptimeKumaApi
from datetime import datetime, timedelta
def get_down_monitors(api):
"""
Şu an DOWN durumundaki monitörleri döndür.
"""
monitors = api.get_monitors()
down_list = []
for monitor in monitors:
# Heartbeat verisi çek
heartbeats = api.get_heartbeats()
monitor_id = str(monitor["id"])
if monitor_id in heartbeats:
latest = heartbeats[monitor_id]
if isinstance(latest, list) and latest:
last_beat = latest[-1]
if last_beat.get("status") == 0: # 0 = DOWN
down_list.append({
"id": monitor["id"],
"name": monitor["name"],
"url": monitor.get("url", ""),
"down_since": last_beat.get("time"),
})
return down_list
def generate_status_report(api):
monitors = api.get_monitors()
total = len(monitors)
active = sum(1 for m in monitors if m.get("active"))
heartbeats = api.get_heartbeats()
up_count = 0
down_count = 0
for monitor in monitors:
if not monitor.get("active"):
continue
mid = str(monitor["id"])
if mid in heartbeats:
beats = heartbeats[mid]
if beats and isinstance(beats, list):
if beats[-1].get("status") == 1:
up_count += 1
else:
down_count += 1
report = {
"timestamp": datetime.utcnow().isoformat(),
"total_monitors": total,
"active_monitors": active,
"up": up_count,
"down": down_count,
"health_percentage": round((up_count / active * 100), 2) if active > 0 else 0
}
return report
Bu raporu cron ile her saat çalıştırıp Slack’e ya da bir dahili dashboard’a gönderebilirsiniz.
Maintenance Window Otomasyonu
Deploy sırasında false positive alarm almamak için maintenance window açmak kritik. Bunu manuel yapmak hem unutulabiliyor hem de zaman kaybı. Pipeline’a gömmek çok daha güvenilir.
from uptime_kuma_api import UptimeKumaApi
import time
import os
def deploy_with_maintenance(api, monitor_ids, deploy_func, maintenance_duration=300):
"""
Deploy sürecini maintenance window içine alır.
monitor_ids: Susturulacak monitor ID listesi
deploy_func: Asıl deploy işlemini yapan callable
maintenance_duration: Saniye cinsinden bekleme süresi
"""
print(f"Maintenance window açılıyor ({len(monitor_ids)} monitor)...")
# Monitorları pause et
for mid in monitor_ids:
api.pause_monitor(mid)
print(f"Monitor {mid} duraklatıldı")
try:
print("Deploy başlatılıyor...")
deploy_func()
print("Deploy tamamlandı, servisler ayağa kalkıyor...")
time.sleep(30) # Servisin ayağa kalkması için bekle
finally:
# Her durumda monitörleri tekrar aktif et
for mid in monitor_ids:
api.resume_monitor(mid)
print(f"Monitor {mid} yeniden aktif")
print("Maintenance window kapatıldı.")
# Kullanım örneği:
# deploy_with_maintenance(api, [12, 13, 14], lambda: os.system("./deploy.sh prod"))
REST API ile Doğrudan Status Page Verisi Çekme
Bazı durumlarda Python kütüphanesi kullanmak istemezsiniz, örneğin bash scripti yazıyorsunuzdur ya da başka bir servisten HTTP isteği atmak daha pratiktir. Uptime Kuma’nın herkese açık status page API’si bunun için kullanılabilir:
#!/bin/bash
# Uptime Kuma status page verilerini JSON olarak çek
# Bu endpoint authentication gerektirmez (public status page)
KUMA_BASE="https://uptime-kuma.sirketim.com"
STATUS_PAGE_SLUG="production"
# Status page özet bilgisi
curl -s "${KUMA_BASE}/api/status-page/${STATUS_PAGE_SLUG}"
-H "Content-Type: application/json" |
python3 -c "
import sys, json
data = json.load(sys.stdin)
monitors = data.get('publicGroupList', [])
for group in monitors:
print(f"Grup: {group['name']}")
for monitor in group.get('monitorList', []):
status = 'UP' if monitor.get('active') else 'PAUSED'
print(f" - {monitor['name']}: {status}")
"
Authenticated endpoint’lerle çalışmak için önce token almanız gerekiyor. Ne var ki mevcut sürümlerde Bearer token bazlı auth tam olarak REST üzerinden desteklenmiyor; Socket.IO session üzerinden çalışıyor. Bu yüzden karmaşık bash senaryolarında Python kütüphanesini çağırmak daha temiz:
#!/bin/bash
# check_uptime.sh - Kritik servis down mu?
MONITOR_NAME="[API] Payment Service"
DOWN=$(python3 - <<'EOF'
import sys, os
from uptime_kuma_api import UptimeKumaApi
api = UptimeKumaApi(os.environ["UPTIME_KUMA_URL"])
api.login(os.environ["UPTIME_KUMA_USER"], os.environ["UPTIME_KUMA_PASS"])
monitors = api.get_monitors()
target = next((m for m in monitors if m["name"] == sys.argv[1] if False else m), None)
# İsme göre bul
for m in monitors:
if m["name"] == "$MONITOR_NAME":
heartbeats = api.get_heartbeats()
mid = str(m["id"])
if mid in heartbeats:
beats = heartbeats[mid]
if beats and beats[-1].get("status") == 0:
print("DOWN")
break
break
api.disconnect()
EOF
)
if [ "$DOWN" = "DOWN" ]; then
echo "KRITIK: Payment service down! PagerDuty'ye escalate ediliyor..."
# pagerduty-cli trigger ...
exit 1
fi
echo "Payment service UP, devam edilebilir."
Notification Channel Yönetimi
Yeni bir monitor oluştururken doğru notification channel’ına bağlamayı da otomatikleştirmek istersiniz. Ekiplere özel Slack kanalları, on-call rotasyonlarına göre farklı PagerDuty servisleri…
from uptime_kuma_api import UptimeKumaApi, NotificationType
def setup_notification_channels(api):
"""
Standart notification channel'larını kur.
İdempotent çalışır - mevcut olanı tekrar oluşturmaz.
"""
existing_notifs = api.get_notifications()
existing_names = {n["name"] for n in existing_notifs}
channels = [
{
"name": "Slack-Platform-Team",
"type": NotificationType.SLACK,
"isDefault": False,
"applyExisting": False,
"slackwebhookURL": os.environ["SLACK_PLATFORM_WEBHOOK"],
"slackchannel": "#platform-alerts",
"slackusername": "Uptime Kuma",
"slackiconemo": ":red_circle:",
},
{
"name": "Slack-Backend-Team",
"type": NotificationType.SLACK,
"isDefault": False,
"applyExisting": False,
"slackwebhookURL": os.environ["SLACK_BACKEND_WEBHOOK"],
"slackchannel": "#backend-alerts",
"slackusername": "Uptime Kuma",
"slackiconemo": ":warning:",
},
]
created_ids = {}
for channel in channels:
if channel["name"] not in existing_names:
result = api.add_notification(**channel)
created_ids[channel["name"]] = result.get("id")
print(f"Notification channel oluşturuldu: {channel['name']}")
else:
# Mevcut ID'yi al
for n in existing_notifs:
if n["name"] == channel["name"]:
created_ids[channel["name"]] = n["id"]
print(f"Mevcut channel kullanılıyor: {channel['name']}")
return created_ids
Sık Karşılaşılan Sorunlar ve Çözümleri
Üretimde bu araçları kullanırken birkaç gotcha ile karşılaştım, paylaşmak istiyorum:
Bağlantı timeout sorunları: Socket.IO bağlantısı bazen kurulmadan işlem yapmaya çalışırsanız sessizce hata verebiliyor. login() çağrısından önce küçük bir sleep ya da bağlantı doğrulaması ekleyin.
Rate limiting: Çok hızlı ardışık monitor ekleme işlemlerinde Uptime Kuma bazen yanıt vermeyi yavaşlatıyor. Toplu import yaparken her add_monitor() çağrısından sonra time.sleep(0.5) koymanızı öneririm.
Monitor ID tutarlılığı: Monitor silip tekrar oluşturduğunuzda ID değişiyor. ID’lere değil isimlere göre referans verin.
Docker environment’ta URL: Uptime Kuma container’ı başka container’larla aynı network’teyse localhost yerine container adını kullanın:
# docker-compose.yml'de
environment:
- UPTIME_KUMA_URL=http://uptime-kuma:3001
Büyük ortamlarda performans: get_heartbeats() tüm heartbeat verisini çekiyor, yüzlerce monitor varsa bu ağır olabilir. Sadece belirli bir monitörün heartbeat’ini çekmek için get_monitor_beats(monitor_id, hours=1) kullanın.
Sonuç
Uptime Kuma başlangıçta “kolayca kurulan küçük bir monitoring aracı” imajıyla geliyor ama API’si sayesinde kurumsal ortamlarda bile ciddi otomasyon altyapısı kurabiliyorsunuz. Benim önerdiğim yaklaşım: monitoring konfigürasyonunu da kod olarak yönetin. monitors.yaml dosyanızı Git’e koyun, değişiklikleri PR üzerinden geçirin, merge olunca otomatik sync çalışsın.
Bu yaklaşımla “acaba hangi servisler monitörde var?” sorusunun cevabı her zaman tek bir YAML dosyasında ve herkes tarafından görülebilir oluyor. Yeni bir developer ekibe katıldığında “production’da ne var?” sorusunu bu dosyaya bakarak cevaplayabiliyor. Monitoring da infrastructure as code felsefesinin bir parçası; bunu ne kadar erken benimserseniz o kadar az “ya bu servis kimse tarafından izlenmiyor muydu?” sürprizi yaşarsınız.
