refactoring(Gateway)
TODO-Roadmap.md Micrometer Metrics Integration for Observability in Gateway
This commit is contained in:
@@ -16,8 +16,9 @@ Das Gateway ist als eigenständiger Spring Boot Service implementiert und nutzt
|
||||
- **Spring WebFlux** - Reaktive Web-Programmierung mit Netty
|
||||
- **Resilience4j** - Circuit Breaker Pattern Implementation
|
||||
- **Consul** - Service Discovery und Health Checks
|
||||
- **Micrometer + Prometheus** - Metriken und Monitoring
|
||||
- **Micrometer + Prometheus** - Umfassende Metriken und Monitoring
|
||||
- **JWT** - Token-basierte Authentifizierung
|
||||
- **Reactive Streams** - Non-blocking I/O für optimale Performance
|
||||
|
||||
## Hauptverantwortlichkeiten
|
||||
|
||||
@@ -57,14 +58,43 @@ Das Gateway handhabt alle Cross-Cutting Concerns (übergreifende Belange), die f
|
||||
- **Graceful Degradation**: Systembetrieb auch bei partiellen Service-Ausfällen
|
||||
|
||||
### 5. Monitoring und Observability
|
||||
- **Health Indicator**: Umfassende Überwachung aller Downstream Services
|
||||
Das Gateway implementiert umfassende Observability durch eine vollständig integrierte Micrometer-basierte Metriken-Architektur.
|
||||
|
||||
#### Automatische Metriken-Erfassung (GatewayMetricsConfig)
|
||||
- **Request Duration Tracking**: Automatische Messung aller Request-Response Zyklen
|
||||
- Metric: `gateway_request_duration` (Timer)
|
||||
- Tags: method, path, status, status_series
|
||||
- Percentile-basierte Auswertung (P50, P90, P95, P99)
|
||||
- **Error Rate Monitoring**: Detailliertes Error-Tracking für 4xx/5xx Responses
|
||||
- Metric: `gateway_errors_total` (Counter)
|
||||
- Tags: method, path, status, status_series, error_type
|
||||
- Unterscheidung zwischen client_error und server_error
|
||||
- **Request Volume Tracking**: Vollständige Request-Volumen Überwachung
|
||||
- Metric: `gateway_requests_total` (Counter)
|
||||
- Tags: method, path für detaillierte Analyse
|
||||
- **Circuit Breaker Events**: Monitoring von Resilience-Pattern Events
|
||||
- Metric: `gateway_circuit_breaker_events_total` (Counter)
|
||||
- Integration mit Resilience4j Circuit Breaker Status
|
||||
|
||||
#### Intelligente Pfad-Normalisierung
|
||||
- **Kardinalitäts-Kontrolle**: Automatische Normalisierung von dynamischen Pfaden
|
||||
- `/api/horses/123` → `/api/horses/{id}`
|
||||
- UUID-Pattern → `/{uuid}`
|
||||
- Sehr lange Pfade werden gekürzt (100+ Zeichen)
|
||||
|
||||
#### Health Monitoring Integration
|
||||
- **Downstream Service Health**: Umfassende Überwachung aller Backend Services
|
||||
- Kritische Services: Members, Horses, Events, Masterdata, Auth
|
||||
- Optionale Services: Ping Service
|
||||
- Circuit Breaker Status Integration
|
||||
- **Distributed Tracing**: Korrelations-ID basiertes Request-Tracking
|
||||
- **Prometheus Metriken**: Detaillierte Performance- und Business-Metriken
|
||||
- **Strukturierte Logs**: JSON-Format für maschinelle Auswertung
|
||||
|
||||
#### Prometheus Export
|
||||
- **Automatischer Export**: Alle Metriken werden automatisch an Prometheus exportiert
|
||||
- **Common Tags**: Alle Metriken erhalten automatisch Service- und Component-Tags
|
||||
- **Filter-Optimierung**: Rauschen-reduzierende Metrik-Filter für interne Spring/Netty Metriken
|
||||
|
||||
### 6. CORS-Management
|
||||
- **Produktionstaugliche CORS-Konfiguration**:
|
||||
- Erlaubte Origins: `https://*.meldestelle.at`, `http://localhost:*`
|
||||
@@ -98,6 +128,14 @@ Das Gateway handhabt alle Cross-Cutting Concerns (übergreifende Belange), die f
|
||||
✅ **OCI Compliance**: Vollständige Container-Metadaten
|
||||
✅ **Production-Ready**: Optimierte JVM-Settings für Container-Umgebung
|
||||
|
||||
### Metriken-Integration (GatewayMetricsConfig.kt)
|
||||
✅ **Comprehensive Micrometer Integration**: Vollständige Metriken-Erfassung mit automatischem Prometheus Export
|
||||
✅ **Request/Response Time Tracking**: Detaillierte Performance-Metriken mit Percentile-Auswertung
|
||||
✅ **Error Rate Monitoring**: Intelligente Fehler-Klassifikation und -Tracking
|
||||
✅ **Path Normalization**: Kardinalitäts-kontrolle für dynamische API-Pfade
|
||||
✅ **Circuit Breaker Metrics**: Integration mit Resilience4j Event-Tracking
|
||||
✅ **Custom Business Metrics**: Erweiterbare Metrik-Architektur für fachliche KPIs
|
||||
|
||||
### Dokumentation
|
||||
✅ **OpenAPI 3.0.3 Spezifikation**: Vollständige API-Dokumentation mit Members Service
|
||||
✅ **Interactive Swagger UI**: Modern dokumentierte API-Endpunkte
|
||||
@@ -150,11 +188,37 @@ Ein typischer Anfrage-Flow:
|
||||
- `/actuator/circuitbreakers` - Circuit Breaker Status
|
||||
|
||||
### Key Performance Indicators (KPIs)
|
||||
- **Request Throughput**: Anfragen pro Sekunde
|
||||
- **Response Times**: P50, P90, P95, P99 Percentile
|
||||
- **Error Rates**: 4xx/5xx Response Codes
|
||||
- **Circuit Breaker States**: Open/Half-Open/Closed Status
|
||||
- **Service Availability**: Upstream Service Health
|
||||
|
||||
#### Automatisch erfasste Metriken
|
||||
- **Request Throughput**: `gateway_requests_total` - Anfragen pro Sekunde nach Method/Path
|
||||
- **Response Times**: `gateway_request_duration` - P50, P90, P95, P99 Percentile nach Status
|
||||
- **Error Rates**: `gateway_errors_total` - 4xx/5xx Response Codes mit Error-Type Klassifikation
|
||||
- **Circuit Breaker Events**: `gateway_circuit_breaker_events_total` - Resilience Pattern Aktivierungen
|
||||
- **Service Availability**: Upstream Service Health via Health Indicators
|
||||
|
||||
#### Verfügbare Metric Tags für detaillierte Analyse
|
||||
- **method**: HTTP-Method (GET, POST, PUT, DELETE, etc.)
|
||||
- **path**: Normalisierter API-Pfad (z.B. `/api/horses/{id}`)
|
||||
- **status**: HTTP-Status-Code (200, 404, 500, etc.)
|
||||
- **status_series**: Status-Gruppe (2xx, 3xx, 4xx, 5xx)
|
||||
- **error_type**: Fehler-Klassifikation (client_error, server_error)
|
||||
- **service**: Automatisches "gateway" Tag
|
||||
- **component**: Automatisches "infrastructure" Tag
|
||||
|
||||
#### Prometheus Query Beispiele
|
||||
```promql
|
||||
# Request Rate pro Endpunkt
|
||||
rate(gateway_requests_total[5m])
|
||||
|
||||
# 95. Percentile Response Time
|
||||
histogram_quantile(0.95, rate(gateway_request_duration_bucket[5m]))
|
||||
|
||||
# Error Rate nach Service
|
||||
rate(gateway_errors_total[5m]) / rate(gateway_requests_total[5m])
|
||||
|
||||
# Circuit Breaker Aktivierungen
|
||||
increase(gateway_circuit_breaker_events_total[1h])
|
||||
```
|
||||
|
||||
## Security Features
|
||||
|
||||
@@ -272,6 +336,13 @@ spec:
|
||||
- JVM Heap Usage monitoring
|
||||
- Request Rate Limiting überprüfen
|
||||
|
||||
**Metriken und Monitoring Issues**
|
||||
- Prometheus Scraping Endpunkt prüfen: `/actuator/prometheus`
|
||||
- Metrics Registry Status überprüfen: `/actuator/metrics`
|
||||
- GatewayMetricsWebFilter Aktivierung validieren
|
||||
- Metric Tags auf Kardinalitäts-Explosion prüfen
|
||||
- Path Normalization bei unerwarteten Metric-Namen
|
||||
|
||||
### Logging und Debugging
|
||||
```bash
|
||||
# Logs mit Korrelations-IDs
|
||||
@@ -313,10 +384,10 @@ curl http://localhost:8080/actuator/health
|
||||
|
||||
**Letzte Aktualisierung**: 14. August 2025
|
||||
|
||||
**Version**: 1.0.0
|
||||
**Version**: 1.1.0
|
||||
|
||||
**Maintainer**: Meldestelle Development Team
|
||||
|
||||
---
|
||||
|
||||
Diese Dokumentation wurde durch die Konsolidierung von OPTIMIZATION_SUMMARY.md und der ursprünglichen README-INFRA-GATEWAY.md erstellt und um alle implementierten Optimierungen erweitert.
|
||||
Diese Dokumentation wurde umfassend aktualisiert und um die neue Micrometer Metrics Integration (GatewayMetricsConfig.kt) erweitert. Sie dokumentiert alle implementierten Optimierungen einschließlich der vollständigen Observability-Architektur mit automatischer Request/Response Zeit Messung, Error Rate Tracking und Custom Business Metrics.
|
||||
|
||||
+186
@@ -0,0 +1,186 @@
|
||||
package at.mocode.infrastructure.gateway.metrics
|
||||
|
||||
import io.micrometer.core.instrument.Counter
|
||||
import io.micrometer.core.instrument.MeterRegistry
|
||||
import io.micrometer.core.instrument.Timer
|
||||
import io.micrometer.core.instrument.config.MeterFilter
|
||||
import org.springframework.boot.actuate.autoconfigure.metrics.MeterRegistryCustomizer
|
||||
import org.springframework.context.annotation.Bean
|
||||
import org.springframework.context.annotation.Configuration
|
||||
import org.springframework.web.server.ServerWebExchange
|
||||
import org.springframework.web.server.WebFilter
|
||||
import org.springframework.web.server.WebFilterChain
|
||||
import reactor.core.publisher.Mono
|
||||
import java.time.Duration
|
||||
|
||||
/**
|
||||
* Konfiguration für Gateway-spezifische Metriken mit Micrometer.
|
||||
*
|
||||
* Diese Konfiguration stellt folgende Metriken bereit:
|
||||
* - Request/Response Zeit Metriken (Timer)
|
||||
* - Fehlerrate Tracking (Counter)
|
||||
* - Custom Business Metrics
|
||||
*
|
||||
* Alle Metriken werden automatisch an Prometheus exportiert durch die
|
||||
* bestehende monitoring-client Integration.
|
||||
*/
|
||||
@Configuration
|
||||
class GatewayMetricsConfig {
|
||||
|
||||
companion object {
|
||||
// Metric Namen als Konstanten für bessere Wartbarkeit
|
||||
const val GATEWAY_REQUEST_TIMER = "gateway_request_duration"
|
||||
const val GATEWAY_ERROR_COUNTER = "gateway_errors_total"
|
||||
const val GATEWAY_REQUESTS_COUNTER = "gateway_requests_total"
|
||||
const val GATEWAY_CIRCUIT_BREAKER_COUNTER = "gateway_circuit_breaker_events_total"
|
||||
const val GATEWAY_DOWNSTREAM_HEALTH_GAUGE = "gateway_downstream_health_status"
|
||||
}
|
||||
|
||||
/**
|
||||
* Konfiguriert globale Meter-Registry Einstellungen für das Gateway.
|
||||
*/
|
||||
@Bean
|
||||
fun gatewayMeterRegistryCustomizer(): MeterRegistryCustomizer<MeterRegistry> {
|
||||
return MeterRegistryCustomizer { registry ->
|
||||
// Gemeinsame Tags für alle Gateway-Metriken
|
||||
registry.config()
|
||||
.commonTags("service", "gateway", "component", "infrastructure")
|
||||
// Filterung von zu detaillierten Metriken
|
||||
.meterFilter(MeterFilter.deny { id ->
|
||||
val name = id.name
|
||||
// Ausschluss von internen Spring/Netty Metriken, die zu viel Rauschen erzeugen
|
||||
name.startsWith("reactor.netty.connection.provider") ||
|
||||
name.startsWith("reactor.netty.bytebuf.allocator") ||
|
||||
name.startsWith("jvm.gc.overhead")
|
||||
})
|
||||
// Histogram-Buckets für Request Duration optimieren
|
||||
.meterFilter(MeterFilter.accept())
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* WebFilter für automatische Request/Response Zeit und Error Rate Tracking.
|
||||
*
|
||||
* Dieser Filter misst:
|
||||
* - Gesamte Request-Verarbeitungszeit
|
||||
* - Anzahl der Requests nach Status-Code kategorisiert
|
||||
* - Error-Rate basierend auf HTTP Status Codes
|
||||
*/
|
||||
@Bean
|
||||
fun gatewayMetricsWebFilter(meterRegistry: MeterRegistry): WebFilter {
|
||||
return GatewayMetricsWebFilter(meterRegistry)
|
||||
}
|
||||
|
||||
/**
|
||||
* Bean für Request Duration Timer - ermöglicht manuelle Messungen.
|
||||
*/
|
||||
@Bean
|
||||
fun requestTimer(meterRegistry: MeterRegistry): Timer {
|
||||
return Timer.builder(GATEWAY_REQUEST_TIMER)
|
||||
.description("Gateway request processing time")
|
||||
.tag("type", "http")
|
||||
.register(meterRegistry)
|
||||
}
|
||||
|
||||
/**
|
||||
* Bean für Error Counter - ermöglicht manuelles Error Tracking.
|
||||
*/
|
||||
@Bean
|
||||
fun errorCounter(meterRegistry: MeterRegistry): Counter {
|
||||
return Counter.builder(GATEWAY_ERROR_COUNTER)
|
||||
.description("Total number of gateway errors")
|
||||
.register(meterRegistry)
|
||||
}
|
||||
|
||||
/**
|
||||
* Bean für Request Counter - ermöglicht Request-Volumen Tracking.
|
||||
*/
|
||||
@Bean
|
||||
fun requestCounter(meterRegistry: MeterRegistry): Counter {
|
||||
return Counter.builder(GATEWAY_REQUESTS_COUNTER)
|
||||
.description("Total number of gateway requests")
|
||||
.register(meterRegistry)
|
||||
}
|
||||
|
||||
/**
|
||||
* Bean für Circuit Breaker Events Counter.
|
||||
*/
|
||||
@Bean
|
||||
fun circuitBreakerCounter(meterRegistry: MeterRegistry): Counter {
|
||||
return Counter.builder(GATEWAY_CIRCUIT_BREAKER_COUNTER)
|
||||
.description("Circuit breaker events in gateway")
|
||||
.register(meterRegistry)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* WebFilter Implementation für automatische Metrics-Erfassung.
|
||||
*/
|
||||
class GatewayMetricsWebFilter(private val meterRegistry: MeterRegistry) : WebFilter {
|
||||
|
||||
override fun filter(exchange: ServerWebExchange, chain: WebFilterChain): Mono<Void> {
|
||||
val startTime = System.nanoTime()
|
||||
val request = exchange.request
|
||||
val path = request.path.value()
|
||||
val method = request.method.toString()
|
||||
|
||||
// Request Counter incrementer
|
||||
Counter.builder(GatewayMetricsConfig.GATEWAY_REQUESTS_COUNTER)
|
||||
.tag("method", method)
|
||||
.tag("path", normalizePath(path))
|
||||
.description("Total gateway requests")
|
||||
.register(meterRegistry)
|
||||
.increment()
|
||||
|
||||
return chain.filter(exchange)
|
||||
.doFinally { _ ->
|
||||
val duration = Duration.ofNanos(System.nanoTime() - startTime)
|
||||
val response = exchange.response
|
||||
val statusCode = response.statusCode?.value()?.toString() ?: "unknown"
|
||||
val statusSeries = when {
|
||||
statusCode.startsWith("2") -> "2xx"
|
||||
statusCode.startsWith("3") -> "3xx"
|
||||
statusCode.startsWith("4") -> "4xx"
|
||||
statusCode.startsWith("5") -> "5xx"
|
||||
else -> "unknown"
|
||||
}
|
||||
|
||||
// Request Duration Timer
|
||||
Timer.builder(GatewayMetricsConfig.GATEWAY_REQUEST_TIMER)
|
||||
.tag("method", method)
|
||||
.tag("path", normalizePath(path))
|
||||
.tag("status", statusCode)
|
||||
.tag("status_series", statusSeries)
|
||||
.description("Gateway request processing time")
|
||||
.register(meterRegistry)
|
||||
.record(duration)
|
||||
|
||||
// Error Counter für 4xx und 5xx Responses
|
||||
if (statusCode.startsWith("4") || statusCode.startsWith("5")) {
|
||||
Counter.builder(GatewayMetricsConfig.GATEWAY_ERROR_COUNTER)
|
||||
.tag("method", method)
|
||||
.tag("path", normalizePath(path))
|
||||
.tag("status", statusCode)
|
||||
.tag("status_series", statusSeries)
|
||||
.tag("error_type", if (statusCode.startsWith("4")) "client_error" else "server_error")
|
||||
.description("Gateway error count")
|
||||
.register(meterRegistry)
|
||||
.increment()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalisiert Pfade für Metriken, um Kardinalität-Explosion zu vermeiden.
|
||||
* Beispiel: /api/horses/123 → /api/horses/{id}
|
||||
*/
|
||||
private fun normalizePath(path: String): String {
|
||||
return path
|
||||
// UUID pattern ersetzen
|
||||
.replace(Regex("/[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}"), "/{uuid}")
|
||||
// Numerische IDs ersetzen
|
||||
.replace(Regex("/\\d+"), "/{id}")
|
||||
// Sehr lange Pfade kürzen
|
||||
.let { if (it.length > 100) "${it.substring(0, 97)}..." else it }
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user