Grafana ile Özel Dashboard Oluşturma: İş Metriklerini Görselleştirme
Sunucu metriklerini izlemek bir noktaya kadar işe yarıyor. CPU kullanımı şu kadar, RAM doluluk oranı bu kadar, disk I/O falan filan. Ama iş gelip “bu rakamlar işe ne kadar yansıdı?” sorusuna dayandığında, standart node exporter grafikleri yetersiz kalıyor. İşte tam burada Grafana’nın gerçek gücü ortaya çıkıyor: veri kaynağından bağımsız, tamamen özelleştirilebilir dashboard’lar oluşturmak.
Bu yazıda sadece “şu paneli şuraya sürükle” seviyesinde bir rehber yazmıyorum. Gerçek bir e-ticaret senaryosu üzerinden ilerleyeceğiz. Sipariş başarı oranı, ödeme işlem süresi, API hata oranı, stok uyarı eşikleri gibi iş metriklerini Prometheus’tan çekip anlamlı görsel panellere dönüştüreceğiz. Ayrıca custom exporter yazmaktan alert kurallarına kadar her adımı ele alacağız.
Önce Kafayı Kuralım: İş Metriği Nedir?
Teknik metrikler altyapının sağlığını gösterir. İş metrikleri ise işin nabzını tutar. Fark şu:
- Teknik metrik: HTTP 500 hata sayısı saniyede 3’e çıktı
- İş metriği: Son 5 dakikada tamamlanan sipariş sayısı %40 düştü
İkisi birbiriyle ilişkili olabilir ama her zaman değil. Bir sunucu %95 CPU’da koşarken siparişler sorunsuz akıyor olabilir. Ya da CPU normal görünürken ödeme gateway timeout’ları nedeniyle müşteriler sepeti terk ediyor olabilir.
Bu yüzden izleme sistemini iki katmana ayırmak gerekiyor. Altyapı katmanı zaten Prometheus + node_exporter ile halloluyor. İş katmanı için ise uygulama tarafında metrikleri biz expose etmeliyiz.
Uygulama Tarafında Metrik Expose Etmek
Senaryomuzda Python tabanlı bir sipariş yönetim servisi var. Bu servise Prometheus client kütüphanesini entegre edip iş metriklerini expose edeceğiz.
pip install prometheus_client flask
Basit bir örnek servis yazalım:
from flask import Flask, request, jsonify
from prometheus_client import Counter, Histogram, Gauge, generate_latest, CONTENT_TYPE_LATEST
import time
import random
app = Flask(__name__)
# Counter: Sadece artar, hiç sıfırlanmaz
siparis_toplam = Counter(
'siparis_toplam',
'Toplam siparis sayisi',
['durum', 'odeme_yontemi']
)
# Histogram: İstek sürelerini ölçmek için
odeme_isleme_suresi = Histogram(
'odeme_isleme_suresi_saniye',
'Odeme isleminin tamamlanma suresi',
['gateway'],
buckets=[0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0]
)
# Gauge: Anlık değer, artabilir azalabilir
aktif_sepet_sayisi = Gauge(
'aktif_sepet_sayisi',
'Suan aktif olan sepet sayisi'
)
stok_kritik_urun = Gauge(
'stok_kritik_urun_sayisi',
'Stok seviyesi kritik esige ulasan urun sayisi',
['kategori']
)
@app.route('/siparis', methods=['POST'])
def siparis_olustur():
aktif_sepet_sayisi.inc()
baslangic = time.time()
# Simule edilmis islem
gateway = request.json.get('gateway', 'stripe')
sure = random.uniform(0.1, 3.0)
time.sleep(min(sure, 0.1)) # Demo icin kisalt
# Rastgele basari/basarisizlik
if random.random() > 0.15:
siparis_toplam.labels(durum='basarili', odeme_yontemi=gateway).inc()
aktif_sepet_sayisi.dec()
return jsonify({'status': 'ok'})
else:
siparis_toplam.labels(durum='basarisiz', odeme_yontemi=gateway).inc()
aktif_sepet_sayisi.dec()
return jsonify({'status': 'error'}), 500
@app.route('/metrics')
def metrics():
return generate_latest(), 200, {'Content-Type': CONTENT_TYPE_LATEST}
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000)
Bu servisi çalıştırdıktan sonra http://localhost:5000/metrics adresine gittiğinizde Prometheus’un anlayacağı formatta metrikler görünecek.
Prometheus Scrape Konfigürasyonu
Prometheus’un bu yeni endpoint’i scrape etmesi için prometheus.yml dosyasına job eklemek gerekiyor:
global:
scrape_interval: 15s
evaluation_interval: 15s
scrape_configs:
- job_name: 'prometheus'
static_configs:
- targets: ['localhost:9090']
- job_name: 'node_exporter'
static_configs:
- targets: ['localhost:9100']
- job_name: 'siparis_servisi'
static_configs:
- targets: ['localhost:5000']
metrics_path: '/metrics'
scrape_interval: 10s
# Is metriklerini daha sik cekelim
- job_name: 'odeme_servisi'
static_configs:
- targets: ['odeme-srv-01:5001', 'odeme-srv-02:5001']
relabel_configs:
- source_labels: [__address__]
target_label: instance
regex: '(.+):d+'
replacement: '$1'
Konfigürasyonu uyguladıktan sonra Prometheus’un hedefleri tanıyıp tanımadığını kontrol edin:
curl http://localhost:9090/api/v1/targets | python3 -m json.tool | grep -A3 "siparis_servisi"
Eğer her şey yolundaysa "health": "up" görmeniz gerekiyor.
Recording Rules ile Hesaplama Yükünü Azaltmak
Dashboard’daki her panel sorguyu gerçek zamanlı hesaplamak zorunda değil. Özellikle sipariş başarı oranı gibi sık kullanılan ve hesaplaması biraz ağır olan metrikler için recording rules kullanmak hem performans kazandırır hem de dashboard yükleme süresini düşürür.
/etc/prometheus/rules/is_metrikleri.yml dosyası oluşturun:
groups:
- name: is_metrikleri
interval: 1m
rules:
# 5 dakikalik siparis basari orani
- record: job:siparis_basari_orani:rate5m
expr: |
rate(siparis_toplam{durum="basarili"}[5m])
/
rate(siparis_toplam[5m])
# Odeme gateway bazinda hata orani
- record: job:odeme_hata_orani:rate5m
expr: |
rate(siparis_toplam{durum="basarisiz"}[5m])
/
rate(siparis_toplam[5m])
# Saatlik toplam siparis hacmi
- record: job:siparis_hacmi:rate1h
expr: increase(siparis_toplam{durum="basarili"}[1h])
# P95 odeme isleme suresi
- record: job:odeme_p95_sure:rate5m
expr: |
histogram_quantile(0.95,
rate(odeme_isleme_suresi_saniye_bucket[5m])
)
Prometheus’u bu dosyayı okuyacak şekilde güncelleyin ve reload edin:
curl -X POST http://localhost:9090/-/reload
Grafana Dashboard JSON Modeli
Grafana’da dashboard oluşturmanın iki yolu var: GUI üzerinden tıklayarak ya da JSON modelini doğrudan import ederek. Prodüksiyonda ikinci yöntem çok daha kullanışlı çünkü version control’e alabiliyorsunuz ve takım arkadaşlarınızla paylaşabiliyorsunuz.
Önce Grafana API üzerinden datasource’u kontrol edelim:
# Mevcut datasource listesi
curl -s -u admin:admin http://localhost:3000/api/datasources | python3 -m json.tool
# Prometheus datasource'u yoksa ekle
curl -X POST
-H "Content-Type: application/json"
-u admin:admin
http://localhost:3000/api/datasources
-d '{
"name": "Prometheus",
"type": "prometheus",
"url": "http://localhost:9090",
"access": "proxy",
"isDefault": true
}'
Panel Tasarımı: Sipariş Başarı Oranı Gauge
Gauge panel için en sık kullanılan panel türlerinden biri. Anlık bir değeri yüzde olarak göstermek için idealdir. Grafana API ile panel oluşturabiliriz ama önce PromQL sorgularını Explore sekmesinde test edin:
# Anlık basari orani - Grafana Explore'da test edin
rate(siparis_toplam{durum="basarili"}[5m])
/
rate(siparis_toplam[5m]) * 100
# Son 1 saatteki toplam basarili siparis
increase(siparis_toplam{durum="basarili"}[1h])
# Gateway bazinda hata orani karsilastirmasi
sum by (odeme_yontemi) (
rate(siparis_toplam{durum="basarisiz"}[5m])
)
/
sum by (odeme_yontemi) (
rate(siparis_toplam[5m])
) * 100
Alert Kuralları: Sadece Teknik Değil, İş Odaklı
Klasik uyarılar “CPU %90’ı geçti” gibi teknik eşikler üzerine kurulu. İş metriklerine dayalı alert’lar daha değerli. /etc/prometheus/rules/is_alertleri.yml dosyasını oluşturun:
groups:
- name: is_alertleri
rules:
# Siparis basari orani dusukse
- alert: SiparisBasariOraniDusuk
expr: job:siparis_basari_orani:rate5m < 0.85
for: 5m
labels:
severity: critical
takim: backend
annotations:
summary: "Siparis basari orani kritik seviyede"
description: |
Son 5 dakikadaki siparis basari orani {{ $value | humanizePercentage }}.
Normal deger 0.95 uzerinde olmali.
runbook_url: "https://wiki.sirket.com/runbooks/siparis-basari"
# Odeme isleme suresi cok uzunsa
- alert: OdemeIslemeYavas
expr: job:odeme_p95_sure:rate5m > 5
for: 3m
labels:
severity: warning
takim: odeme
annotations:
summary: "P95 odeme isleme suresi 5 saniyeyi asti"
description: >
{{ $labels.gateway }} gateway'inde P95 sure
{{ $value | humanizeDuration }}.
# Stok kritik esige ulastiysa
- alert: StokKritikSeviye
expr: stok_kritik_urun_sayisi > 10
for: 10m
labels:
severity: warning
takim: operasyon
annotations:
summary: "{{ $labels.kategori }} kategorisinde kritik stok uyarisi"
description: "{{ $value }} urun stok esiginin altinda."
Grafana’da Template Variables Kullanmak
Tek bir dashboard’u farklı ortamlar, farklı servisler ya da farklı zaman dilimleri için kullanmak istiyorsanız template variables şart. GUI üzerinden Settings > Variables yolunu izleyin ya da dashboard JSON’una direkt ekleyin.
Pratik bir örnek: Hangi ödeme gateway’ini izleyeceğimizi dropdown ile seçebiliriz.
# Grafana API ile variable tanimla (dashboard guncelleme islemi)
# Once dashboard JSON'unu cek
curl -s -u admin:admin
"http://localhost:3000/api/dashboards/uid/is-metrikleri"
| python3 -m json.tool > dashboard_backup.json
# Grafana provisioning ile dashboard deploy et
# /etc/grafana/provisioning/dashboards/is_metrikleri.yaml
apiVersion: 1
providers:
- name: 'is-metrikleri'
orgId: 1
folder: 'Is Metrikleri'
type: file
disableDeletion: false
updateIntervalSeconds: 30
allowUiUpdates: true
options:
path: /var/lib/grafana/dashboards
Bu yöntemle /var/lib/grafana/dashboards/ dizinine koyduğunuz JSON dosyaları otomatik olarak Grafana’ya yükleniyor. CI/CD pipeline’ınıza entegre etmek çok kolaylaşıyor.
Grafana Annotations: Olayları Grafiğe İşaretlemek
Deploy attınız, bir değişiklik yaptınız ya da bakım penceresi açtınız. Bu olayları Grafana grafiklerinde dikey çizgi olarak görmek analizi çok kolaylaştırıyor.
# Deploy sonrasi annotation olustur
curl -X POST
-H "Content-Type: application/json"
-u admin:admin
http://localhost:3000/api/annotations
-d "{
"dashboardId": 5,
"time": $(date +%s%3N),
"tags": ["deploy", "v2.3.1"],
"text": "Siparis servisi v2.3.1 deploy edildi"
}"
Bunu CI/CD pipeline’ınızın sonuna ekleyin. Böylece her deploy sonrasında grafiklerde otomatik işaret belirecek ve “bu spike deploy’dan mı kaynaklandı?” sorusuna anında cevap verebileceksiniz.
Alertmanager ile Akıllı Bildirim Yönetimi
Prometheus alert’larını Slack, PagerDuty ya da e-posta ile iletmek için Alertmanager konfigürasyonu:
# /etc/alertmanager/alertmanager.yml
global:
resolve_timeout: 5m
slack_api_url: 'https://hooks.slack.com/services/XXXX/YYYY/ZZZZ'
route:
group_by: ['alertname', 'takim']
group_wait: 30s
group_interval: 5m
repeat_interval: 4h
receiver: 'default'
routes:
- match:
severity: critical
takim: backend
receiver: 'backend-kritik'
group_wait: 10s
repeat_interval: 1h
- match:
severity: warning
receiver: 'slack-uyarilar'
receivers:
- name: 'default'
slack_configs:
- channel: '#ops-genel'
title: '{{ .GroupLabels.alertname }}'
text: '{{ range .Alerts }}{{ .Annotations.description }}{{ end }}'
- name: 'backend-kritik'
slack_configs:
- channel: '#backend-kritik'
title: ':fire: KRİTİK: {{ .GroupLabels.alertname }}'
text: |
*Ozet:* {{ .CommonAnnotations.summary }}
*Detay:* {{ range .Alerts }}{{ .Annotations.description }}{{ end }}
*Runbook:* {{ .CommonAnnotations.runbook_url }}
pagerduty_configs:
- routing_key: 'xxxxxxxxxxxxx'
- name: 'slack-uyarilar'
slack_configs:
- channel: '#ops-uyarilar'
title: ':warning: {{ .GroupLabels.alertname }}'
Dashboard Organizasyonu: Folder Yapısı ve Erişim Kontrolü
Büyük organizasyonlarda dashboard kaosunu önlemek kritik önem taşıyor. Grafana’nın folder yapısını ve team permission sistemini düzgün kurmak çok iş kurtarıyor.
- Altyapı Ekibi Klasörü: Sunucu metrikleri, ağ istatistikleri, disk kullanımı
- Backend Ekibi Klasörü: API performansı, sipariş metrikleri, veritabanı gecikmeleri
- İş Analitiği Klasörü: Saatlik/günlük sipariş hacimleri, ödeme yöntemi dağılımı, başarı oranları
- Operasyon Klasörü: Stok uyarıları, cron job durumları, batch işlem süreleri
Her klasör için ayrı team tanımlayın ve Edit/View izinlerini ayarlayın. Birisi dashboard’ı yanlışlıkla bozmasın diye iş analitiği dashboard’larını read-only olarak bırakabilirsiniz.
Gerçek Dünya Senaryosu: Black Friday Hazırlığı
Yılın en yoğun alışveriş döneminde ne izlemeniz gerektiğini bilmek, izleme sistemini kurmak kadar önemli. Biz bunu şöyle kurguladık:
Normal dönemde saniyede 50 sipariş işleniyordu. Black Friday’de 400-500’e çıkması bekleniyordu. Dashboard üzerinde şu paneller kritikti:
- Gerçek zamanlı sipariş/dakika sayacı (büyük sayı göstergesi, en üstte)
- Ödeme gateway başarı oranları (üç gateway için yan yana gauge paneller)
- P50/P95/P99 işlem süreleri zaman serisi grafiği
- Stok kritik ürün sayısı (saatlik değişim)
- Aktif sepet sayısı vs tamamlanan sipariş oranı
Black Friday başladığında Stripe’taki P99 sürenin normalin 3 katına çıktığını Grafana’da görmek, aynı anda destek ekibiyle Slack’te tartışmaktan çok daha hızlı aksiyon almamızı sağladı. Alertmanager 2 dakikada Slack bildirimi gönderdi, ekip hemen Stripe’ın status page’ini kontrol etti ve yük dengelemeyi ikinci gateway’e kaydırdı.
Dashboard’u Production’a Taşımak
Grafana’yı production ortamında çalıştırırken dikkat edilmesi gereken birkaç nokta var.
Varsayılan SQLite veritabanı yerine PostgreSQL kullanın. /etc/grafana/grafana.ini dosyasında:
[database]
type = postgres
host = postgres-srv:5432
name = grafana
user = grafana
password = guclu_sifre_burada
ssl_mode = require
[security]
admin_password = degistir_bunu
secret_key = rastgele_uzun_bir_anahtar
[smtp]
enabled = true
host = smtp.sirket.com:587
user = [email protected]
password = smtp_sifresi
from_address = [email protected]
from_name = Grafana Monitoring
Grafana’yı systemd servisi olarak çalıştırın ve log rotation ekleyin:
systemctl enable grafana-server
systemctl start grafana-server
# Log rotation icin /etc/logrotate.d/grafana
cat > /etc/logrotate.d/grafana << 'EOF'
/var/log/grafana/grafana.log {
daily
rotate 14
compress
delaycompress
missingok
notifempty
sharedscripts
postrotate
systemctl kill -s HUP grafana-server
endscript
}
EOF
Sonuç
Grafana ile özel dashboard kurma süreci birkaç katmandan oluşuyor ve her katmanı sağlam atmak gerekiyor. Uygulama tarafında metrik expose etmekle başlıyor, Prometheus’ta recording rules ve alert kurallarıyla devam ediyor, Grafana tarafında anlamlı görselleştirmelerle tamamlanıyor.
En önemli çıkarım şu: Teknik metrikler ile iş metrikleri aynı platformda yaşayabilir ve yaşamalı. Bir geliştiricinin CPU grafiğiyle bir ürün yöneticisinin sipariş başarı oranını aynı araçta görmesi, organizasyon içinde ortak bir dil oluşturuyor. “Sistem yavaş” yerine “ödeme işlem süresi P95’te 4 saniyeye çıktı, bu da sepet terk oranını etkileyebilir” diyebilmek çok daha kıymetli bir tartışma başlatıyor.
Dashboard’larınızı version control’de tutun, provisioning ile deploy edin ve alert’larınızı gerçek iş etkileri üzerine kurgulayın. Gece 3’te sadece CPU spike’ı için değil, sipariş başarı oranı düştüğü için uyandırılmak aslında daha anlamlı. Çünkü o alert geldiğinde zaten işin durduğunu biliyorsunuz.
