Files
haproxy-openmanager/CONFIG.md
T
mustafa.ulukaya ef26860df9 feat(logging): unified request/response log with configurable retention (v1.11.0)
Until now the only record of what happened was `user_activity_logs`, which
stores non-GET 2xx operations with no bodies. When something failed you could
see that a counter went up, never what was sent or what came back.

This adds one queryable timeline covering both directions:

- inbound: every API call, including GETs and including 4xx/5xx, with the
  user, client IP, status, duration and — redacted, size-capped — the request
  and response bodies.
- outbound: every HTTP call the backend makes, tagged with who it went to
  (ACME/Let's Encrypt, Cloudflare, GoDaddy, HAProxy stats, agents, the ACME
  diagnostics probe).

Outbound rows inherit the inbound request's id, so one operator action and the
CA/DNS calls it triggered read as a single trace: opening a failed "Request
Certificate" shows the exact POST /acme/new-order and the CA's 429 underneath.

Implementation notes:

- Capture is a pure-ASGI middleware that TEES the request and response streams
  rather than draining them. `await request.body()` inside a BaseHTTPMiddleware
  would consume the receive channel and break the raw-body agent heartbeat
  handler. Registered last so it is outermost: it then sees the final
  client-visible response and seeds correlation_id_context before the error
  handler reads it.
- Rows are written by a batching background writer with a bounded queue, so the
  request path never awaits the database and a saturated logger drops rows
  visibly (surfaced on the page) instead of blocking. Redaction runs on the
  writer, off the request coroutine.
- Secrets never land: headers are an allowlist with Authorization/Cookie kept
  only as a presence marker; body keys and value shapes are redacted
  (passwords, tokens, api_token, API keys, private-key PEMs, JWTs); the ACME
  JWS request body is never stored, because a stored protected+signature pair
  is a replayable credential — a summary is logged instead; DNS-provider errors
  record only the exception type; the ACME HTTP-01 challenge endpoint is
  excluded so key_authorization is never captured.
- Retention is operator-configurable in Settings -> Request Log: separate day
  counts for successful and failed rows (7 / 30) plus a hard row cap (500k),
  whichever is reached first. Pruned in batches under a Postgres advisory lock,
  with the day counts bound as parameters, never interpolated.
- New permissions requestlog.read / requestlog.manage. super_admin and
  security_admin get both, operator gets read, viewer gets neither.

Schema: one new table (request_logs) plus its settings seed, SCHEMA_VERSION
10 -> 11, auto-migrated. No existing table altered, no agent or rendered-config
change. Kill switches: REQUEST_LOG_ENABLED=false (middleware never registered)
or the `enabled` toggle in Settings.

Tests: 245 new (7 backend files + 1 frontend), full suite 1655 backend +
17 frontend passing.
2026-08-11 02:36:03 +03:00

324 lines
7.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Configuration Guide - HAProxy OpenManager
## 📋 Yapılandırma Dosyaları
### Dosya Yapısı
```
haproxy-openmanager/
├── .env.template # ✅ Template (GIT'e commit edilir)
├── .env # ❌ Gerçek config (GIT'e commit EDİLMEZ)
├── .gitignore # .env dosyalarını korur
└── CONFIG.md # Bu dosya
```
## 🎯 Quick Start
### 1. Template'den Config Oluşturma
```bash
# Template'i kopyala
cp .env.template .env
# Gerçek değerleri düzenle
nano .env
```
### 2. Örnek Yapılandırmalar
#### Development (Local)
```bash
# .env dosyası
PUBLIC_URL=http://localhost:8000
MANAGEMENT_BASE_URL=http://localhost:8000
DEBUG=True
LOG_LEVEL=DEBUG
```
#### Staging
```bash
# .env dosyası veya K8s ConfigMap
PUBLIC_URL=https://haproxy-staging.example.com
MANAGEMENT_BASE_URL=https://haproxy-staging.example.com
DEBUG=False
LOG_LEVEL=INFO
```
#### Production (OpenShift)
```bash
# K8s ConfigMap: k8s/manifests/07-configmaps.yaml
data:
PUBLIC_URL: 'https://haproxy-manager.example.com'
MANAGEMENT_BASE_URL: 'https://haproxy-manager.example.com'
DEBUG: 'False'
LOG_LEVEL: 'INFO'
```
## 🔐 Güvenlik
### Hassas Bilgiler
`.env` dosyası hassas bilgiler içerir:
- ❌ Database şifreleri
- ❌ Secret key'ler
- ❌ API token'ları
**Bu yüzden**:
-`.env``.gitignore`'da (commit edilmez)
-`.env.template` → Git'e commit edilir (örnek değerler)
- ✅ Production'da: Kubernetes Secrets kullan
### .gitignore Kontrolü
```bash
# .env dosyalarının ignore edildiğini kontrol et
grep "^\.env" .gitignore
# Çıktı olmalı:
# .env
# .env.local
# .env.development.local
# .env.test.local
# .env.production.local
```
## 📚 Environment Variable Detayları
### PUBLIC_URL
**Ne İşe Yarar**: Agent kurulum script'lerinde kullanılır
**Örnekler**:
```bash
# Development
PUBLIC_URL=http://localhost:8000
# Production
PUBLIC_URL=https://haproxy-manager.example.com
# OpenShift
PUBLIC_URL=https://haproxy-manager.example.com
```
**Nasıl Kullanılır**:
1. Agent Management sayfasından "Generate Install Script"
2. Script içinde `{{MANAGEMENT_URL}}` bu değerle değiştirilir
3. Agent bu URL'ye bağlanarak backend'i dinler
### REACT_APP_API_URL
**Ne İşe Yarar**: Frontend'in backend'e bağlanacağı URL
**Özel Durum**:
```bash
# Boş bırakılırsa → Auto-detect (production için önerilen)
REACT_APP_API_URL=
# Development için explicit
REACT_APP_API_URL=http://localhost:8000
```
**Auto-detect Mantığı**:
```javascript
// frontend/src/utils/api.js
if (process.env.REACT_APP_API_URL) {
return process.env.REACT_APP_API_URL;
}
// Production'da same-origin kullan
if (window.location) {
return `${window.location.protocol}//${window.location.hostname}`;
}
```
### REQUEST_LOG_ENABLED (v1.11.0)
**Ne İşe Yarar**: Request/Response Log özelliğinin sert (hard) kill-switch'i. `false` yapıldığında
loglama middleware'i ASGI zincirine **hiç eklenmez**, yazıcı ve retention görevleri başlatılmaz —
yani sıfır ek yük, ayar okuması bile yapılmaz. Değişiklik için restart gerekir.
**Örnekler**:
```bash
# Varsayılan: açık
REQUEST_LOG_ENABLED=true
# Tamamen kapat (ör. çok yüksek trafikli kurulum, veya regülasyon gereği)
REQUEST_LOG_ENABLED=false
```
**Nasıl Kullanılır**:
1. Restart gerektirmeden kapatmak isterseniz bunun yerine **Settings → Request Log → Enable request
log** anahtarını kullanın; o anında etkili olur.
2. Retention süreleri, gövde (body) yakalama, örnekleme oranı ve hariç tutulan path'ler bu env
değişkeniyle değil, veritabanındaki `requestlog.*` ayarlarıyla yönetilir — arayüzden düzenlenir.
3. Disk büyümesi asıl operasyonel konudur: sırasıyla `sample_rate`'i düşürün, `capture_get`'i
kapatın, `capture_bodies`'i kapatın, sonra `success_retention_days`'i kısaltın.
### REQUEST_LOG_QUEUE_MAX / REQUEST_LOG_BATCH_SIZE / REQUEST_LOG_FLUSH_MS (v1.11.0)
**Ne İşe Yarar**: Log satırlarını yazan arka plan görevinin ayarları. Satırlar sınırlı bir kuyruğa
konur ve toplu (batch) INSERT ile yazılır; böylece istek yolu asla veritabanını beklemez.
**Örnekler**:
```bash
# Worker başına kuyruk derinliği. Dolduğunda satırlar DÜŞÜRÜLÜR (sayılır ve
# Request Log sayfasında gösterilir), istek bloklanmaz.
REQUEST_LOG_QUEUE_MAX=2000
# Tek INSERT'te kaç satır yazılacağı (havuzdan istek başına değil, batch başına
# bir bağlantı alınır)
REQUEST_LOG_BATCH_SIZE=100
# Yarım dolu bir batch'in en fazla ne kadar bekletileceği (ms)
REQUEST_LOG_FLUSH_MS=500
```
**Nasıl Kullanılır**:
1. Request Log sayfasında "rows dropped" uyarısı görüyorsanız önce `REQUEST_LOG_QUEUE_MAX`'ı
artırın; sorun devam ederse `sample_rate`'i düşürün.
2. Bu üç değer worker başınadır — `UVICORN_WORKERS` arttıkça toplam bellek de o oranda artar.
## 🚀 Deployment Senaryoları
### Docker Compose
```bash
# 1. .env dosyası oluştur
cp .env.template .env
# 2. Değerleri düzenle
nano .env
# 3. Başlat
docker-compose up -d
# 4. Kontrol et
docker-compose logs backend | grep "PUBLIC_URL"
```
### Kubernetes/OpenShift
```bash
# 1. ConfigMap'i düzenle
vim k8s/manifests/07-configmaps.yaml
# 2. Apply
kubectl apply -f k8s/manifests/
# 3. Kontrol et
kubectl get configmap backend-config -n haproxy-manager -o yaml
```
### Manuel (Development)
```bash
# 1. Backend
cd backend
cp ../.env.template .env
export $(cat .env | xargs)
uvicorn main:app --reload
# 2. Frontend (başka terminal)
cd frontend
export REACT_APP_API_URL=http://localhost:8000
npm start
```
## 🔧 Troubleshooting
### Agent Script'inde Yanlış URL
**Sorun**: Agent script hala eski URL içeriyor
**Çözüm**:
```bash
# 1. Backend'deki değeri kontrol et
docker exec haproxy-openmanager-backend env | grep PUBLIC_URL
# 2. Container'ı yeniden başlat
docker-compose restart backend
# 3. Yeni script oluştur
# UI'dan tekrar "Generate Install Script"
```
### Frontend Backend'e Bağlanamıyor
**Sorun**: CORS hatası veya connection refused
**Çözüm**:
```bash
# 1. Frontend config'i kontrol et
docker exec haproxy-openmanager-frontend env | grep REACT_APP_API_URL
# 2. Browser console'da kontrol et
# [API Config] Base URL: http://localhost:8000
# 3. Network sekmesinde request URL'i kontrol et
```
## 📖 En İyi Pratikler
### ✅ YAPILMASI GEREKENLER
1. **Her ortam için ayrı değerler**
```
Dev: PUBLIC_URL=http://localhost:8000
Staging: PUBLIC_URL=https://staging.example.com
Prod: PUBLIC_URL=https://prod.example.com
```
2. **Template'i güncelle**
- Yeni variable eklendiğinde `.env.template`'e ekle
- Dokümantasyon ile birlikte
3. **Secrets kullan (Production)**
```yaml
# K8s Secret
apiVersion: v1
kind: Secret
metadata:
name: backend-secret
data:
SECRET_KEY: <base64-encoded>
```
### ❌ YAPILMAMASI GEREKENLER
1. **`.env` dosyasını commit etmeyin**
```bash
# Yanlış!
git add .env
# Doğru!
git add .env.template
```
2. **Production secret'larını template'e koymayın**
```bash
# .env.template içinde YANLIŞLAR:
SECRET_KEY=actual-production-secret-12345 ❌
DATABASE_URL=postgresql://admin:realpass@prod-db ❌
# Doğru:
SECRET_KEY=your-secret-key-change-this-in-production ✅
DATABASE_URL=postgresql://user:pass@host:5432/db ✅
```
3. **Hardcoded URL kullanmayın**
```python
# Yanlış!
MANAGEMENT_URL = "https://my-server.com" ❌
# Doğru!
MANAGEMENT_URL = os.getenv("PUBLIC_URL") ✅
```
## 🆘 Yardım
Sorularınız için:
- 📘 Bu dosya: `CONFIG.md`
- 📗 Ana dokümantasyon: `README.md`
- 📙 Template: `.env.template`