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

7.6 KiB
Raw Blame History

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

# Template'i kopyala
cp .env.template .env

# Gerçek değerleri düzenle
nano .env

2. Örnek Yapılandırmalar

Development (Local)

# .env dosyası
PUBLIC_URL=http://localhost:8000
MANAGEMENT_BASE_URL=http://localhost:8000
DEBUG=True
LOG_LEVEL=DEBUG

Staging

# .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)

# 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ü

# .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:

# 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:

# 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ığı:

// 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:

# 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:

# 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

# 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

# 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)

# 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:

# 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:

# 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)

    # K8s Secret
    apiVersion: v1
    kind: Secret
    metadata:
      name: backend-secret
    data:
      SECRET_KEY: <base64-encoded>
    

YAPILMAMASI GEREKENLER

  1. .env dosyasını commit etmeyin

    # Yanlış!
    git add .env
    
    # Doğru!
    git add .env.template
    
  2. Production secret'larını template'e koymayın

    # .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

    # 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