django-server-orchestrator 1.0.0
Django Prometheus monitoring package for multi-project server orchestration. Compatible with Django 4.2+.
License: MIT
Requires Python: >=3.9
Keywords: django, prometheus, monitoring, metrics, orchestrator, observability

# Django Server Orchestrator

[![Django 4.2+](https://img.shields.io/badge/Django-4.2%2B-green.svg)](https://djangoproject.com)
[![Python 3.9+](https://img.shields.io/badge/Python-3.9%2B-blue.svg)](https://python.org)
[![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](LICENSE)

Django 4.2+ ile uyumlu, **çoklu proje destekli** Prometheus monitoring paketi.

Aynı Redis sunucusunu paylaşan birden fazla Django projesini güvenle izlemenizi sağlar. Her projeye özel Redis key prefix'i ile verilerin karışması önlenir.

---

## İçindekiler

- [Özellikler](#özellikler)
- [Gereksinimler](#gereksinimler)
- [Kurulum](#kurulum)
- [Kullanım](#kullanım)
  - [Metrikleri Görüntüleme](#metrikleri-görüntüleme)
  - [Metrikleri Temizleme (Wipe)](#metrikleri-temizleme-wipe)
- [Toplanan Metrikler](#toplanan-metrikler)
  - [HTTP Metrikleri (Otomatik)](#http-metrikleri-otomatik)
  - [SQL Metrikleri (Otomatik)](#sql-metrikleri-otomatik)
  - [Sistem Metrikleri](#sistem-metrikleri)
- [Konfigürasyon](#konfigürasyon)
  - [Tüm Ayarlar](#tüm-ayarlar)
  - [Prefix (Redis Key İzolasyonu)](#prefix-redis-key-izolasyonu)
  - [Middleware Ayarları](#middleware-ayarları)
  - [SQL Metrikleri Ayarları](#sql-metrikleri-ayarları)
  - [Histogram Bucket'ları](#histogram-bucketları)
  - [Sistem Metrikleri Açma/Kapama](#sistem-metrikleri-açmakapama)
- [Çoklu Proje Yapılandırması](#çoklu-proje-yapılandırması)
- [Prometheus & Grafana Entegrasyonu](#prometheus--grafana-entegrasyonu)
- [Route Koruma (Güvenlik)](#route-koruma-güvenlik)
- [Laravel Paketi ile Uyumluluk](#laravel-paketi-ile-uyumluluk)
- [Sorun Giderme (SSS)](#sorun-giderme-sss)
- [Lisans](#lisans)

---

## Özellikler

| Özellik | Açıklama |
|---------|----------|
| 🔑 **Redis Key İzolasyonu** | Her proje için benzersiz prefix (`prometheus:{prefix}:*`) |
| 📊 **Otomatik HTTP Metrikleri** | Request duration histogram, toplam istek sayacı, hata sayacı |
| 🗄️ **Otomatik SQL Metrikleri** | Sorgu süresi histogram, operation/table/query label'ları |
| 🖥️ **Sistem Metrikleri** | Python info, memory, uptime, DB connections, health |
| 🐘 **MySQL + PostgreSQL Desteği** | DB bağlantı metrikleri her iki veritabanı için |
| ⚡ **Sıfır Konfigürasyon** | Kurup çalıştırın, ihtiyaç olursa her şey özelleştirilebilir |
| 🚫 **Wildcard Path Ignore** | Admin, static, media gibi yolları izlemekten hariç tutun |
| 🪟 **Platform Bağımsız** | Linux, macOS ve Windows'ta çalışır |

---

## Gereksinimler

| Paket | Versiyon |
|-------|----------|
| Python | >=3.9 |
| Django | >=4.2 |
| redis | >=4.0 |
| prometheus-client | >=0.20 |
| Redis sunucusu | Çalışır durumda olmalı |

> **Not:** `redis` ve `prometheus-client` otomatik olarak yüklenir.

---

## Kurulum

### Adım 1 — Paketi Yükleyin

```bash
pip install django-server-orchestrator
```

### Adım 2 — Django Ayarlarını Yapın

`settings.py` dosyanıza ekleyin:

```python
# INSTALLED_APPS
INSTALLED_APPS = [
    # ... diğer uygulamalar
    "server_orchestrator",
]

# MIDDLEWARE — listeye ekleyin (sıralama önemli değil)
MIDDLEWARE = [
    "server_orchestrator.middleware.PrometheusMiddleware",
    # ... diğer middleware'ler
    "django.middleware.common.CommonMiddleware",
    # ...
]

# SERVER_ORCHESTRATOR konfigürasyonu
SERVER_ORCHESTRATOR = {
    "PREFIX": "projenizin_adi",  # ZORUNLU: Her projeye özel
}
```

### Adım 3 — URL'leri Ekleyin

`urls.py` dosyanıza ekleyin:

```python
from django.urls import include, path

urlpatterns = [
    # ... diğer URL'ler
    path("", include("server_orchestrator.urls")),
]
```

Bu varsayılan olarak şu endpoint'leri oluşturur:
- `GET /api/metrics` — Prometheus metrikleri
- `POST /api/wipe-metrics` — Tüm metrikleri sıfırla

### Adım 4 — Doğrulama

```bash
# Sunucuyu başlat
python manage.py runserver

# Metrikleri kontrol et
curl http://localhost:8000/api/metrics
```

**Bu kadar!** 🎉 Artık `/api/metrics` adresinden metriklere erişebilirsiniz.

---

## Kullanım

### Metrikleri Görüntüleme

```bash
# curl ile
curl http://localhost:8000/api/metrics

# PowerShell ile
Invoke-RestMethod -Uri http://localhost:8000/api/metrics

# Tarayıcıdan
# http://localhost:8000/api/metrics
```

### Metrikleri Temizleme (Wipe)

Tüm Redis'teki metrik verilerini sıfırlar. Test/geliştirme ortamında kullanışlıdır.

```bash
curl -X POST http://localhost:8000/api/wipe-metrics
```

Yanıt:

```json
{
    "success": true,
    "message": "All metrics have been wiped.",
    "deleted_keys": 11
}
```

---

## Toplanan Metrikler

### HTTP Metrikleri (Otomatik)

Middleware tarafından her isteğinde otomatik olarak kaydedilir.

| Metrik | Tip | Açıklama |
|--------|-----|----------|
| `http_request_duration_seconds` | Histogram | İstek süresi (saniye) |
| `http_requests_total` | Counter | Toplam istek sayısı |
| `http_errors_total` | Counter | Toplam hata sayısı (4xx + 5xx) |

**Label'lar:**

| Label | Açıklama | Örnek |
|-------|----------|-------|
| `code` | HTTP durum kodu | `200`, `404`, `500` |
| `method` | HTTP metodu | `GET`, `POST`, `PUT` |
| `view_name` | Django view / URL adı | `user-list`, `LoginView` |
| `endpoint` | Normalize edilmiş URI | `/api/users/{pk}` |

> **Not:** Endpoint'lerdeki UUID ve sayısal ID'ler otomatik olarak `{uuid}` ve `{id}` ile değiştirilir. Django URL converter'ları (`<int:pk>`) da `{pk}` olarak normalize edilir.

#### Örnek Çıktı

```
# HELP http_request_duration_seconds The duration of HTTP requests processed by a Django application.
# TYPE http_request_duration_seconds histogram
http_request_duration_seconds_bucket{code="200",method="GET",view_name="user-list",endpoint="/api/users/",le="0.005"} 12
http_request_duration_seconds_bucket{code="200",method="GET",view_name="user-list",endpoint="/api/users/",le="+Inf"} 50
http_request_duration_seconds_sum{code="200",method="GET",view_name="user-list",endpoint="/api/users/"} 1.234
http_request_duration_seconds_count{code="200",method="GET",view_name="user-list",endpoint="/api/users/"} 50

# HELP http_requests_total Total number of HTTP requests.
# TYPE http_requests_total counter
http_requests_total{code="200",method="GET",view_name="user-list",endpoint="/api/users/"} 50
```

### SQL Metrikleri (Otomatik)

Django'nun `execute_wrapper()` mekanizması ile tüm SQL sorguları otomatik izlenir.

| Metrik | Tip | Açıklama |
|--------|-----|----------|
| `sql_query_duration_seconds` | Histogram | SQL sorgu süresi (saniye) |

**Label'lar:**

| Label | Açıklama | Örnek |
|-------|----------|-------|
| `operation` | SQL işlem türü | `SELECT`, `INSERT`, `UPDATE` |
| `table` | Hedef tablo adı | `users`, `orders` |
| `query` | Kısaltılmış SQL (opsiyonel) | `SELECT * FROM users WHERE...` |
| `query_hash` | SQL'in MD5 hash'i | `a1b2c3d4e5f6...` |

> **Not:** `query` label'ı `SQL_INCLUDE_QUERY_LABEL` ayarı ile kapatılabilir. Django framework sorguları (`SAVEPOINT`, `django_migrations` vb.) otomatik yok sayılır.

### Sistem Metrikleri

`GET /metrics` çağrıldığında anlık olarak hesaplanır.

| Metrik | Tip | Açıklama |
|--------|-----|----------|
| `python_info` | Gauge | Python versiyonu (label: `version`) |
| `process_uptime_seconds` | Gauge | İşlem çalışma süresi |
| `process_memory_rss_bytes` | Gauge | RSS bellek kullanımı |
| `db_connections_active` | Gauge | Aktif DB bağlantı sayısı |
| `db_connections_max` | Gauge | Maksimum bağlantı limiti |
| `app_health_status` | Gauge | Uygulama sağlığı (1=UP, 0=DOWN) |

> **Not:** `app_health_status` veritabanı bağlantısını kontrol eder. DB çalışmıyorsa `0` döner. Bağlantı testi için `socket.create_connection()` ile 2 saniyelik TCP timeout kullanılır.

---

## Konfigürasyon

Tüm ayarlar `settings.py` içindeki `SERVER_ORCHESTRATOR` dict'inden yapılır:

```python
SERVER_ORCHESTRATOR = {
    # Genel
    "ENABLED": True,
    "PREFIX": "myproject",
    "REDIS_URL": "redis://127.0.0.1:6379/0",

    # Route / URL
    "ROUTES_ENABLED": True,
    "ROUTE_PREFIX": "api",

    # Middleware
    "MIDDLEWARE_ENABLED": True,
    "IGNORE_PATHS": [
        "/api/metrics",
        "/metrics",
        "/api/wipe-metrics",
        "/wipe-metrics",
        "/admin/",
        "/static/",
        "/media/",
    ],

    # HTTP Histogram
    "HTTP_HISTOGRAM_BUCKETS": (0.001, 0.005, 0.01, 0.05, 0.1, 0.5, 1, 5),

    # SQL Metrikleri
    "SQL_METRICS_ENABLED": True,
    "SQL_INCLUDE_QUERY_LABEL": True,
    "SQL_QUERY_MAX_LENGTH": 200,
    "SQL_HISTOGRAM_BUCKETS": (0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1, 2.5, 5, 10),
    "SQL_IGNORE_PATTERNS": [
        r"^SHOW\s",
        r"^SET\s",
        r"information_schema",
        r"^SAVEPOINT\s",
        r"^RELEASE\s",
        r"django_migrations",
        r"django_content_type",
    ],

    # Sistem Metrikleri
    "SYSTEM_METRICS": {
        "python_info": True,
        "memory": True,
        "uptime": True,
        "database": True,
        "health": True,
    },
}
```

### Tüm Ayarlar

| Ayar | Env Variable | Default | Açıklama |
|------|-------------|---------|----------|
| `ENABLED` | — | `True` | Paketi aktif/pasif yap |
| `PREFIX` | `ORCHESTRATOR_PREFIX` | `"django"` | Redis key prefix'i |
| `REDIS_URL` | `ORCHESTRATOR_REDIS_URL` | `redis://127.0.0.1:6379/0` | Redis bağlantı URL'i |
| `ROUTES_ENABLED` | — | `True` | Metrics route'larını aktif et |
| `ROUTE_PREFIX` | `ORCHESTRATOR_ROUTE_PREFIX` | `"api"` | Route URL prefix'i |
| `MIDDLEWARE_ENABLED` | — | `True` | HTTP middleware'i aktif |
| `IGNORE_PATHS` | — | `[...]` | İzlenmeyen path'ler |
| `HTTP_HISTOGRAM_BUCKETS` | — | `(0.001...5)` | HTTP histogram sınırları |
| `SQL_METRICS_ENABLED` | `ORCHESTRATOR_SQL_METRICS` | `True` | SQL metrikleri aktif |
| `SQL_INCLUDE_QUERY_LABEL` | `ORCHESTRATOR_SQL_QUERY_LABEL` | `True` | SQL sorgusunu label olarak ekle |
| `SQL_QUERY_MAX_LENGTH` | — | `200` | SQL label maks uzunluk |
| `SQL_HISTOGRAM_BUCKETS` | — | `(0.005...10)` | SQL histogram sınırları |
| `SQL_IGNORE_PATTERNS` | — | `[...]` | Yok sayılacak SQL desenleri |
| `SYSTEM_METRICS` | — | `{...}` | Sistem metrikleri aç/kapat |

### Prefix (Redis Key İzolasyonu)

Her projeye benzersiz bir prefix verin. Redis'teki key formatı:

```
prometheus:{PREFIX}:{type}:{metric_name}
```

Örnek (`PREFIX=ikbackend`):

```
prometheus:ikbackend:gauges:python_info
prometheus:ikbackend:counters:http_requests_total
prometheus:ikbackend:histograms:http_request_duration_seconds
prometheus:ikbackend:histograms:sql_query_duration_seconds
```

### Middleware Ayarları

```python
SERVER_ORCHESTRATOR = {
    # Middleware'i tamamen devre dışı bırak (HTTP metrikleri toplanmaz)
    "MIDDLEWARE_ENABLED": True,

    # Bu path'lerden gelen istekler izlenmez (wildcard desteği)
    "IGNORE_PATHS": [
        "/api/metrics",
        "/admin/",
        "/static/",
        "/health/*",       # Wildcard desteği
    ],
}
```

### SQL Metrikleri Ayarları

```python
SERVER_ORCHESTRATOR = {
    # SQL metrik toplamayı tamamen kapat
    "SQL_METRICS_ENABLED": True,

    # SQL metnini label olarak dahil et (cardinality artırır!)
    "SQL_INCLUDE_QUERY_LABEL": True,

    # SQL label maks karakter uzunluğu
    "SQL_QUERY_MAX_LENGTH": 200,

    # Yok sayılacak SQL desenleri (regex)
    # Django framework sorguları varsayılan olarak yok sayılır
    "SQL_IGNORE_PATTERNS": [
        r"^SAVEPOINT\s",
        r"^RELEASE\s",
        r"django_migrations",
    ],
}
```

### Histogram Bucket'ları

```python
SERVER_ORCHESTRATOR = {
    # HTTP istekleri için (saniye)
    "HTTP_HISTOGRAM_BUCKETS": (
        0.001, 0.005, 0.01, 0.05, 0.1, 0.5, 1, 5
    ),

    # SQL sorguları için (saniye)
    "SQL_HISTOGRAM_BUCKETS": (
        0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1, 2.5, 5, 10
    ),
}
```

### Sistem Metrikleri Açma/Kapama

```python
SERVER_ORCHESTRATOR = {
    "SYSTEM_METRICS": {
        "python_info": True,    # Python versiyon bilgisi
        "memory": True,         # Bellek kullanımı (RSS)
        "uptime": True,         # İşlem çalışma süresi
        "database": True,       # DB bağlantı metrikleri
        "health": True,         # Uygulama sağlık durumu
    },
}
```

---

## Çoklu Proje Yapılandırması

### Senaryo: 3 Django Projesi, 1 Redis Sunucusu

```python
# Proje 1 — IK Backend (settings.py)
SERVER_ORCHESTRATOR = {"PREFIX": "ikbackend"}

# Proje 2 — HR Portal (settings.py)
SERVER_ORCHESTRATOR = {"PREFIX": "hrportal"}

# Proje 3 — CRM (settings.py)
SERVER_ORCHESTRATOR = {"PREFIX": "crm"}
```

Redis'teki key yapısı:

```
prometheus:ikbackend:gauges:python_info
prometheus:ikbackend:counters:http_requests_total

prometheus:hrportal:gauges:python_info
prometheus:hrportal:counters:http_requests_total

prometheus:crm:gauges:python_info
prometheus:crm:counters:http_requests_total
```

### Karma Proje: Django + Laravel Aynı Redis

Bu paket, [Laravel Server Orchestrator](https://github.com/fogeto/laravel-server-orchestrator) ile aynı Redis key yapısını kullanır. Aynı Redis'te her iki framework'ün projeleri çalışabilir:

```python
# Django projeniz
SERVER_ORCHESTRATOR = {"PREFIX": "crm_django"}
```

```env
# Laravel projeniz (.env)
ORCHESTRATOR_PREFIX=crm_laravel
```

Her iki proje farklı prefix kullandığı sürece çakışma olmaz.

---

## Prometheus & Grafana Entegrasyonu

### Prometheus Scrape Config

```yaml
# prometheus.yml
scrape_configs:
  - job_name: 'ikbackend-django'
    metrics_path: '/api/metrics'
    scrape_interval: 15s
    static_configs:
      - targets: ['192.168.1.100:8000']
        labels:
          project: 'ikbackend'
          environment: 'production'
```

### Grafana PromQL Örnekleri

```promql
# İstek oranı (req/s)
rate(http_requests_total{job="ikbackend-django"}[5m])

# Ortalama yanıt süresi
rate(http_request_duration_seconds_sum[5m]) / rate(http_request_duration_seconds_count[5m])

# P95 latency
histogram_quantile(0.95, rate(http_request_duration_seconds_bucket[5m]))

# P99 latency
histogram_quantile(0.99, rate(http_request_duration_seconds_bucket[5m]))

# Hata oranı (%)
rate(http_errors_total[5m]) / rate(http_requests_total[5m]) * 100

# En yavaş SQL sorguları
topk(5, rate(sql_query_duration_seconds_sum[5m]) / rate(sql_query_duration_seconds_count[5m]))

# DB bağlantı kullanım oranı
db_connections_active / db_connections_max * 100

# Bellek kullanımı (MB)
process_memory_rss_bytes / 1024 / 1024

# Sağlık durumu (5 dakika DOWN ise uyar)
app_health_status == 0
```

---

## Route Koruma (Güvenlik)

Metrics endpoint'lerini korumak için Django middleware veya decorator kullanabilirsiniz:

### IP Whitelist Middleware

```python
# myapp/middleware.py
from django.http import HttpResponseForbidden

ALLOWED_IPS = ["127.0.0.1", "10.0.0.0/8", "192.168.1.0/24"]

class MetricsIPWhitelistMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        if request.path.startswith("/api/metrics"):
            ip = request.META.get("REMOTE_ADDR", "")
            if ip not in ALLOWED_IPS:
                return HttpResponseForbidden("Forbidden")
        return self.get_response(request)
```

### Django REST Framework Token Auth

```python
# urls.py
from rest_framework.decorators import api_view, permission_classes
from rest_framework.permissions import IsAuthenticated

# Kendi korumalı metrics view'ınız
@api_view(["GET"])
@permission_classes([IsAuthenticated])
def protected_metrics(request):
    from server_orchestrator.views import metrics_view
    return metrics_view(request)
```

---

## Laravel Paketi ile Uyumluluk

Bu paket, [fogeto/laravel-server-orchestrator](https://github.com/fogeto/laravel-server-orchestrator) paketinin Django karşılığıdır.

| Özellik | Laravel Paketi | Django Paketi |
|---------|---------------|---------------|
| Redis key yapısı | ✅ Aynı | ✅ Aynı |
| Base64 label encoding | ✅ Aynı | ✅ Aynı |
| HTTP metrik adları | ✅ Aynı | ✅ Aynı |
| SQL metrikleri | ✅ Var | ✅ Var |
| Histogram bucket format | ✅ Aynı | ✅ Aynı |
| Lua wipe script | ✅ Aynı | ✅ Aynı |
| Prometheus text format | ✅ Aynı | ✅ Aynı |
| Dile özgü metrikler | `php_info`, `opcache` | `python_info` |
| HTTP label'lar | `controller`, `action` | `view_name` |

---

## Sorun Giderme (SSS)

### Redis Bağlantı Hatası

```
WARNING Redis adapter başlatılamadı
```

**Çözüm:**
1. Redis sunucusunun çalıştığından emin olun: `redis-cli ping`
2. `REDIS_URL` ayarını kontrol edin:
```python
SERVER_ORCHESTRATOR = {
    "REDIS_URL": "redis://127.0.0.1:6379/0",
}
```
3. Farklı Redis DB kullanıyorsanız URL'deki `/0` kısmını değiştirin

### `/api/metrics` 404 Döndürüyor

1. `urls.py`'ye `include("server_orchestrator.urls")` eklediğinizden emin olun
2. `INSTALLED_APPS`'ta `"server_orchestrator"` olduğunu kontrol edin
3. `ROUTES_ENABLED` ayarının `True` (varsayılan) olduğunu kontrol edin

### SQL Metrikleri Görünmüyor

1. `SQL_METRICS_ENABLED` ayarını kontrol edin (varsayılan: `True`)
2. SQL sorgularınız `SQL_IGNORE_PATTERNS`'da yok sayılıyor olabilir
3. Django'nun varsayılan sorguları (`SAVEPOINT`, `django_migrations`) otomatik yok sayılır

### Bellek Metrikleri Görünmüyor

- Windows'ta `ctypes.windll.psapi` gereklidir (standart Python ile gelir)
- Docker/Alpine'da `/proc/self/status` kullanılır
- Hiçbir yöntem başarısız olursa metrik sessizce atlanır

### `app_health_status` Her Zaman 0

1. Django `DATABASES` ayarını kontrol edin
2. DB sunucusunun çalıştığından emin olun
3. DB host:port'una ağ erişimi olduğunu kontrol edin (2s TCP timeout)

---

## Lisans

MIT © [FOGETO - Mustafa Oğuz BARAN](mailto:mustafaoguzbaran@fogeto.com)