fix entriy view UI
This commit is contained in:
@@ -561,7 +561,7 @@ async function refresh() {
|
||||
`MCP coverage: ${esc(displayedCoverage)}${mcp.partial_streams ? ` (${esc(mcp.partial_streams)} partial)` : ''}${mcp.truncated_streams ? ` (${esc(mcp.truncated_streams)} truncated)` : ''}${mcp.sample_limited_streams ? ` (${esc(mcp.sample_limited_streams)} sample capped)` : ''}`,
|
||||
configuration.log_source === 'graylog_mcp' && mcp.status === 'no_streams_enabled' ? `<span class="sev-high">No Graylog streams are enabled. Open Settings, Load streams, tick streams, then click Save streams.</span>` : '',
|
||||
configuration.log_source === 'graylog_mcp' && mcp.status !== 'refreshing' && enabledStreams.length > 0 && displayedRawEvents === 0 ? `<span class="sev-high">No raw events fetched from enabled streams. Check poll window, Graylog query, stream permissions, and Diagnostics -> Stream Coverage.</span>` : '',
|
||||
enabledWithNoRawEvents.length ? `<span class="sev-high">${esc(enabledWithNoRawEvents.length)} enabled stream(s) returned zero raw events in ${esc(zeroRawWindow)}.</span>` : '',
|
||||
enabledWithNoRawEvents.length && mcp.status !== 'refreshing' ? `<span class="sev-high">${esc(enabledWithNoRawEvents.length)} enabled stream(s) returned zero raw events in ${esc(zeroRawWindow)}.</span>` : '',
|
||||
mcp.coverage_warning ? `<span class="sev-high">${esc(mcp.coverage_warning)}</span>` : '',
|
||||
advisor.status === 'error' ? `<span class="sev-high">Profile advisor error: ${esc(advisor.error || 'unknown error')}</span>` : ''
|
||||
].filter(Boolean).join('<br>');
|
||||
|
||||
@@ -480,7 +480,7 @@ def write_status(status: dict[str, object], output: str) -> None:
|
||||
tmp_path.replace(output_path)
|
||||
|
||||
|
||||
def write_refreshing_status(output: str) -> None:
|
||||
def write_refreshing_status(output: str, *, cache_path: str | None = None) -> None:
|
||||
output_path = Path(output)
|
||||
try:
|
||||
current = json.loads(output_path.read_text(encoding="utf-8")) if output_path.exists() else {}
|
||||
@@ -488,6 +488,12 @@ def write_refreshing_status(output: str) -> None:
|
||||
current = {}
|
||||
if not isinstance(current, dict):
|
||||
current = {}
|
||||
used_cache = False
|
||||
if cache_path:
|
||||
cached = StatusSnapshotStore(cache_path).load("last_good")
|
||||
if cached:
|
||||
current = cached
|
||||
used_cache = True
|
||||
previous_mcp = current.get("capabilities", {}).get("graylog_mcp", {}) if isinstance(current.get("capabilities"), dict) else {}
|
||||
current.setdefault("status_schema", 2)
|
||||
current["generated_at"] = int(time.time())
|
||||
@@ -495,17 +501,27 @@ def write_refreshing_status(output: str) -> None:
|
||||
current["stale_reason"] = ""
|
||||
capabilities = current.setdefault("capabilities", {})
|
||||
if isinstance(capabilities, dict):
|
||||
previous_events = previous_mcp.get("events_fetched", 0) if isinstance(previous_mcp, dict) else 0
|
||||
previous_raw_events = previous_mcp.get("raw_events_fetched", 0) if isinstance(previous_mcp, dict) else 0
|
||||
previous_aggregate_events = previous_mcp.get("aggregate_events", 0) if isinstance(previous_mcp, dict) else 0
|
||||
previous_fetch_mode = previous_mcp.get("fetch_mode", "") if isinstance(previous_mcp, dict) else ""
|
||||
previous_coverage_status = previous_mcp.get("coverage_status", "") if isinstance(previous_mcp, dict) else ""
|
||||
capabilities["graylog_mcp"] = {
|
||||
"status": "refreshing",
|
||||
"previous_status": previous_mcp.get("status", "") if isinstance(previous_mcp, dict) else "",
|
||||
"previous_error": previous_mcp.get("error", "") if isinstance(previous_mcp, dict) else "",
|
||||
"previous_events_fetched": previous_mcp.get("events_fetched", 0) if isinstance(previous_mcp, dict) else 0,
|
||||
"previous_raw_events_fetched": previous_mcp.get("raw_events_fetched", 0) if isinstance(previous_mcp, dict) else 0,
|
||||
"previous_aggregate_events": previous_mcp.get("aggregate_events", 0) if isinstance(previous_mcp, dict) else 0,
|
||||
"previous_fetch_mode": previous_mcp.get("fetch_mode", "") if isinstance(previous_mcp, dict) else "",
|
||||
"previous_coverage_status": previous_mcp.get("coverage_status", "") if isinstance(previous_mcp, dict) else "",
|
||||
"previous_events_fetched": previous_events,
|
||||
"previous_raw_events_fetched": previous_raw_events,
|
||||
"previous_aggregate_events": previous_aggregate_events,
|
||||
"previous_fetch_mode": previous_fetch_mode,
|
||||
"previous_coverage_status": previous_coverage_status,
|
||||
"events_fetched": previous_events,
|
||||
"raw_events_fetched": previous_raw_events,
|
||||
"aggregate_events": previous_aggregate_events,
|
||||
"fetch_mode": previous_fetch_mode,
|
||||
"coverage_status": previous_coverage_status or "refreshing",
|
||||
}
|
||||
current["status_cache"] = {"served_from_cache": False, "reason": "refreshing"}
|
||||
current["status_cache"] = {"served_from_cache": used_cache, "reason": "refreshing"}
|
||||
write_status(current, output)
|
||||
|
||||
|
||||
@@ -534,7 +550,7 @@ def monitor_loop(
|
||||
effective_llm = bool(runtime.get("llm_enabled")) if runtime else llm
|
||||
effective_model = str(runtime.get("llm_model") or llm_model or "")
|
||||
if runtime.get("log_source") == "graylog_mcp":
|
||||
write_refreshing_status(output)
|
||||
write_refreshing_status(output, cache_path=status_cache_path)
|
||||
status = build_status(
|
||||
log_path, policy_path=policy_path, anomaly_limit=anomaly_limit,
|
||||
baseline_path=baseline_path, config_path=config_path, history_path=history_path,
|
||||
|
||||
@@ -68,6 +68,35 @@ class MonitorTests(unittest.TestCase):
|
||||
self.assertEqual(status["capabilities"]["graylog_mcp"]["previous_fetch_mode"], "aggregate")
|
||||
self.assertFalse(status["status_cache"]["served_from_cache"])
|
||||
|
||||
def test_write_refreshing_status_uses_last_good_cache(self):
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
output = Path(tmp) / "status.json"
|
||||
cache_path = str(Path(tmp) / "status-cache.sqlite3")
|
||||
output.write_text(
|
||||
json.dumps({"capabilities": {"graylog_mcp": {"status": "refreshing", "events_fetched": 0, "aggregate_events": 0}}}),
|
||||
encoding="utf-8",
|
||||
)
|
||||
StatusSnapshotStore(cache_path).save(
|
||||
"last_good",
|
||||
{
|
||||
"summary": {"total": 1234},
|
||||
"capabilities": {"graylog_mcp": {"status": "connected", "events_fetched": 99, "raw_events_fetched": 88, "aggregate_events": 1234, "fetch_mode": "aggregate", "coverage_status": "complete_window"}},
|
||||
"cross_source_correlations": [{"entity": "10.0.0.1", "entity_label": "host01 (10.0.0.1)"}],
|
||||
},
|
||||
)
|
||||
|
||||
write_refreshing_status(str(output), cache_path=cache_path)
|
||||
|
||||
status = json.loads(output.read_text(encoding="utf-8"))
|
||||
mcp = status["capabilities"]["graylog_mcp"]
|
||||
self.assertEqual(status["summary"]["total"], 1234)
|
||||
self.assertEqual(mcp["status"], "refreshing")
|
||||
self.assertEqual(mcp["events_fetched"], 99)
|
||||
self.assertEqual(mcp["raw_events_fetched"], 88)
|
||||
self.assertEqual(mcp["aggregate_events"], 1234)
|
||||
self.assertEqual(mcp["previous_status"], "connected")
|
||||
self.assertTrue(status["status_cache"]["served_from_cache"])
|
||||
|
||||
def test_profile_readiness_includes_stream_and_profile_names(self):
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
config_path = Path(tmp) / "config.json"
|
||||
|
||||
Reference in New Issue
Block a user