@@ -110,11 +110,14 @@ public Map<String, Object> getFullSidecarDetails() {
110110 // Sektion B: Gesundheit & Fehler
111111 Map <String , Object > health = new HashMap <>();
112112 String rawStats = restTemplate .getForObject (
113- envoyAdminUrl + "/stats?filter=.*(errors|5xx|timeout|retry|fail|reset|refused|overflow|pending|cx_none).* " ,
113+ envoyAdminUrl + "/stats" ,
114114 String .class );
115- Map <String , String > activeErrors = parseStats (rawStats , true );
115+ Map <String , String > activeErrors = parseStats (rawStats , false );
116+ // xds-grpc ist interne Istio Control-Plane – kein App-Traffic, rausfiltern
117+ activeErrors .entrySet ().removeIf (e -> e .getKey ().startsWith ("cluster.xds-grpc" ));
116118 health .put ("activeErrorMetrics" , activeErrors );
117119 health .put ("errorCount" , activeErrors .size ());
120+ health .put ("diagnoses" , diagnoseMetrics (activeErrors ));
118121 report .put ("healthDiagnostics" , health );
119122
120123 report .put ("timestamp" , new Date ());
@@ -185,6 +188,57 @@ public List<Object> getIstioResources(String namespace, String type) {
185188 return Collections .emptyList ();
186189 }
187190
191+ private List <Map <String , Object >> diagnoseMetrics (Map <String , String > metrics ) {
192+ record Rule (String pattern , String severity , String title , String description , String recommendation ) {}
193+
194+ List <Rule > rules = List .of (
195+ new Rule ("upstream_rq_pending_overflow" , "KRITISCH" , "Circuit Breaker / Pool-Overflow" ,
196+ "Der Connection Pool ist voll oder ein Circuit Breaker ist offen." ,
197+ "DestinationRule.trafficPolicy.connectionPool und outlierDetection prüfen." ),
198+ new Rule ("upstream_cx_none_healthy" , "KRITISCH" , "Keine gesunden Endpoints" ,
199+ "Alle Upstream-Endpoints sind nicht erreichbar." ,
200+ "Pod-Status und Readiness-Probes prüfen. Envoy-Cluster-Health in Tab A ansehen." ),
201+ new Rule ("upstream_cx_connect_fail" , "KRITISCH" , "Verbindung abgelehnt (Connection refused)" ,
202+ "Envoy kann keine TCP-Verbindung zum Upstream aufbauen." ,
203+ "Prüfen: Pod läuft? Richtiger Port? NetworkPolicy blockiert? Service-Selector korrekt?" ),
204+ new Rule ("upstream_rq_timeout" , "WARNUNG" , "Request Timeouts" ,
205+ "Requests zum Upstream überschreiten das Timeout." ,
206+ "NetworkPolicy auf blockierte Ports prüfen. DestinationRule Timeout-Werte anpassen." ),
207+ new Rule ("upstream_cx_connect_timeout" , "WARNUNG" , "Connection Timeout" ,
208+ "Verbindungsaufbau zum Upstream schlägt fehl." ,
209+ "Pod läuft möglicherweise nicht oder Port ist falsch. NetworkPolicy prüfen." ),
210+ new Rule ("upstream_rq_5xx" , "WARNUNG" , "5xx Fehler vom Upstream" ,
211+ "Der Upstream-Service gibt 5xx-Statuscodes zurück." ,
212+ "Upstream-Logs prüfen. VirtualService-Routing und DestinationRule-Gewichtungen validieren." ),
213+ new Rule ("upstream_rq_retry_limit_exceeded" , "INFO" , "Retry-Limit überschritten" ,
214+ "Requests wurden mehrfach wiederholt und das Limit wurde erreicht." ,
215+ "VirtualService retryPolicy anpassen oder Upstream-Stabilität verbessern." ),
216+ new Rule ("upstream_cx_destroy_remote_with_active_rq" , "INFO" , "Verbindung mit aktiven Requests abgebrochen" ,
217+ "Die Remote-Seite hat die Verbindung während aktiver Requests getrennt." ,
218+ "Upstream Keep-Alive Konfiguration und Istio idle_timeout prüfen." )
219+ );
220+
221+ List <Map <String , Object >> diagnoses = new ArrayList <>();
222+ for (Rule rule : rules ) {
223+ List <String > matchingKeys = metrics .entrySet ().stream ()
224+ .filter (e -> e .getKey ().contains (rule .pattern ()))
225+ .map (Map .Entry ::getKey )
226+ .sorted ()
227+ .collect (java .util .stream .Collectors .toList ());
228+
229+ if (!matchingKeys .isEmpty ()) {
230+ Map <String , Object > diagnosis = new LinkedHashMap <>();
231+ diagnosis .put ("severity" , rule .severity ());
232+ diagnosis .put ("title" , rule .title ());
233+ diagnosis .put ("description" , rule .description ());
234+ diagnosis .put ("recommendation" , rule .recommendation ());
235+ diagnosis .put ("affectedMetrics" , matchingKeys );
236+ diagnoses .add (diagnosis );
237+ }
238+ }
239+ return diagnoses ;
240+ }
241+
188242 private String summarizeClusters (String rawClusters ) {
189243 if (rawClusters == null || rawClusters .isBlank ())
190244 return "Keine Upstream-Daten" ;
0 commit comments