Przeglądaj źródła

Surface control audit telemetry

tags/v0.9.0
Jan 1 miesiąc temu
rodzic
commit
06056c08c8
2 zmienionych plików z 56 dodań i 0 usunięć
  1. +8
    -0
      docs/API.md
  2. +48
    -0
      internal/control/ui.html

+ 8
- 0
docs/API.md Wyświetl plik

@@ -15,6 +15,8 @@ Health check.
{"ok": true}
```
`controlAudit` mirrors the control plane's HTTP reject counters (405/415/413/400) so runtime telemetry can spot abusive clients and the UI can keep ops aware of guardrail hits.
`engine.state` spiegelt jetzt die Runtime-State-Maschine wider (idle, arming, prebuffering, running, degraded, muted, faulted, stopping) und bietet eine erste beobachtbare Basis für Fault-Transitions.
@@ -98,6 +100,12 @@ Live engine and driver telemetry. Only populated when TX is active.
"underrunStreak": 0,
"maxUnderrunStreak": 0,
"effectiveSampleRateHz": 2280000
},
"controlAudit": {
"methodNotAllowed": 0,
"unsupportedMediaType": 0,
"bodyTooLarge": 0,
"unexpectedBody": 0
}
}
```


+ 48
- 0
internal/control/ui.html Wyświetl plik

@@ -1193,6 +1193,19 @@ input.input-error {
</div>
</div>


<div class="sidebar-section">
<div class="sidebar-title">Control Audit</div>
<div class="section-note">Counts of 4xx rejects recorded by the control plane APIs.</div>
<div class="kv">
<div class="k">Rejects total</div><div class="v" id="audit-total">--</div>
<div class="k">405 Method Not Allowed</div><div class="v" id="audit-methodNotAllowed">--</div>
<div class="k">415 Unsupported Media Type</div><div class="v" id="audit-unsupportedMediaType">--</div>
<div class="k">413 Request Too Large</div><div class="v" id="audit-bodyTooLarge">--</div>
<div class="k">400 Unexpected Body</div><div class="v" id="audit-unexpectedBody">--</div>
</div>
</div>

<div class="card panel" data-panel-key="shortcuts">
<div class="panel-head" data-panel>
<h2>Shortcuts</h2>
@@ -1974,6 +1987,7 @@ function render() {
updateText('info-live', engine.state ? `${String(engine.state).toUpperCase()} / ${state.server.runtimeOk ? 'runtime ok' : 'runtime pending'}` : (state.server.configOk ? 'config only' : '--'));

updateHealth(engine, driver, audioStream);
updateControlAudit(runtime.controlAudit);
updateFaultHistory(engine);
updateTransitionHistory();
updateResetHint(engine);
@@ -2248,6 +2262,40 @@ function updateHealth(engine, driver, audioStream) {
}



function updateControlAudit(audit) {
const entries = [
{ key: 'methodNotAllowed', id: 'audit-methodNotAllowed' },
{ key: 'unsupportedMediaType', id: 'audit-unsupportedMediaType' },
{ key: 'bodyTooLarge', id: 'audit-bodyTooLarge' },
{ key: 'unexpectedBody', id: 'audit-unexpectedBody' },
];
let total = 0;
let hasData = false;
entries.forEach(({ key, id }) => {
const raw = audit && typeof audit[key] !== 'undefined' ? Number(audit[key]) : NaN;
const value = Number.isFinite(raw) ? raw : null;
if (value != null) {
hasData = true;
total += value;
}
setAuditValue(id, value);
});
setAuditValue('audit-total', hasData ? total : null);
}

function setAuditValue(id, count) {
const el = $(id);
if (!el) return;
if (count == null) {
el.textContent = '--';
el.className = 'val';
return;
}
el.textContent = String(count);
el.className = 'val ' + (count > 0 ? 'warn' : 'good');
}

function updateFaultHistory(engine) {
const container = $('fault-history');
if (!container) return;


Ładowanie…
Anuluj
Zapisz