from __future__ import annotations import re from urllib.parse import parse_qs, urlparse REASON_CLINIC_DATA_NOT_READY = 'clinic_data_not_ready' REASON_GRAFANA_RELATIVE_WINDOW = 'grafana_relative_time_window' REASON_PER_STORE_EVIDENCE_MISSING = 'per_store_evidence_missing' REASON_PER_HOP_EVIDENCE_MISSING = 'per_hop_evidence_missing' REASON_LOWER_LAYER_EVIDENCE_MISSING = 'lower_layer_evidence_missing' def grafana_link_has_relative_window(link: str) -> bool: parsed = urlparse(str(link or '').strip()) params = parse_qs(parsed.query) for key in ('from', 'to'): for value in params.get(key, []): normalized = str(value or '').strip().lower() if normalized.startswith('now'): return True return False def analyze_missing_evidence_reasons(context: dict, clinic_results: list[dict]) -> list[str]: reasons = [] text = '\n'.join( str(context.get(key) or '') for key in ('title', 'problem_statement', 'phenomenon', 'routing_context_text') ) lowered = text.lower() successful_clinic = [item for item in clinic_results or [] if not item.get('error')] if any((item.get('data_status') or {}) and not bool((item.get('data_status') or {}).get('ready')) for item in clinic_results or []): reasons.append(REASON_CLINIC_DATA_NOT_READY) grafana_refs = context.get('grafana_references') or [] if grafana_refs and any(grafana_link_has_relative_window(item.get('link') or '') for item in grafana_refs): reasons.append(REASON_GRAFANA_RELATIVE_WINDOW) if not successful_clinic and 'tikv' in lowered: reasons.append(REASON_PER_STORE_EVIDENCE_MISSING) if re.search( r'tikvrpc|batch receive|wait connection establish|rpc layer latency|unreachable|' r'network jitter|network latency|network interruption|network saturation|' r'带宽打满|网络抖动|网络异常|网络问题', text, re.I, ): reasons.append(REASON_PER_HOP_EVIDENCE_MISSING) if re.search( r'serverisbusy|server is busy|deadline exceeded|flow control|throttle duration|' r'discard ratio|scheduler pending write|pending compaction|l0 file|memtable|' r'snapshot|scatter|rebalance|delete-range|io jitter|disk latency|ebs|rocksdb', text, re.I, ): reasons.append(REASON_LOWER_LAYER_EVIDENCE_MISSING) deduped = [] seen = set() for reason in reasons: key = str(reason or '').strip() if not key or key in seen: continue seen.add(key) deduped.append(key) return deduped