zebra-report: deploy expanded telemetry (lp + signal firehose)

This commit is contained in:
russell@unturf.com 2026-06-04 12:39:56 -04:00
parent 6c214a19fb
commit 954b4cf8fd
No known key found for this signature in database

View file

@ -3524,15 +3524,28 @@ async function dumpTelemetry(){
if (sfuSubPC && typeof sfuSubPC.getStats === 'function'){
try {
const stats = await sfuSubPC.getStats(null);
const nowMs = Date.now();
stats.forEach(r => {
if (r.type === 'inbound-rtp' && r.kind === 'audio'){
/* lastPacketReceivedTimestamp pins the EXACT real-time
* moment audio RTP stopped — pkt-delta only shows it after
* the next tick. Express as 'ago' so a frozen flow stands
* out at a glance ('lp=0.1s' = fine, 'lp=12s' = dead). */
const lp = r.lastPacketReceivedTimestamp
? ((nowMs - r.lastPacketReceivedTimestamp) / 1000).toFixed(1) + 's'
: '?';
parts.push('aud.recv pkt=' + (r.packetsReceived|0) + ' lost=' + (r.packetsLost|0) +
' bytes=' + (r.bytesReceived|0) + ' jitter=' + (r.jitter || 0).toFixed(4) +
' level=' + (r.audioLevel || 0).toFixed(3));
' level=' + (r.audioLevel || 0).toFixed(3) +
' lp=' + lp);
}
if (r.type === 'inbound-rtp' && r.kind === 'video'){
const lp = r.lastPacketReceivedTimestamp
? ((nowMs - r.lastPacketReceivedTimestamp) / 1000).toFixed(1) + 's'
: '?';
parts.push('vid.recv pkt=' + (r.packetsReceived|0) + ' lost=' + (r.packetsLost|0) +
' frames=' + (r.framesDecoded|0));
' frames=' + (r.framesDecoded|0) +
' lp=' + lp);
}
});
} catch(e){ parts.push('stats.err=' + e.message); }
@ -3637,6 +3650,21 @@ function openSignal(){
async function handleSignal(raw){
let m; try { m = JSON.parse(raw); } catch(_){ return; }
/* Firehose every received signal event with its epoch. Lets us
* correlate phone-side regressions ('audio went silent at 16:29:07')
* against the exact server events the phone received. Skip the
* uninteresting high-rate types so the log stays readable. */
const noiseTypes = new Set(['sdp-from', 'mic-state', 'spotlight', 'state']);
if (!noiseTypes.has(m.type)){
const ep = (m.epoch != null) ? ' e=' + m.epoch : '';
const who = m.uuid ? (' u=' + String(m.uuid).slice(0,4))
: m.from ? (' from=' + String(m.from).slice(0,4))
: m.target ? (' tgt=' + String(m.target).slice(0,4))
: '';
const role = m.role ? (' role=' + m.role) : '';
const action = m.action ? (' action=' + m.action) : '';
logLine('', '« ' + m.type + ep + who + role + action);
}
switch (m.type){
case 'welcome':
{
@ -5433,8 +5461,8 @@ logLine('', 'ready — pick a handle, type a rendezvous code, enter the space');
<footer style="margin:2.2rem auto 0;font-size:0.65rem;color:#999;line-height:1.7;word-break:break-all;font-family:monospace">
<span id="pi-seal" style="color:#777;cursor:default;user-select:none" title="">page integrity</span> &nbsp;·&nbsp; built <span class="stamp-date">2026-06-04</span><br>
md5 <span class="stamp-md5">bd33f463261d6f66f7d1db7743c84b2d</span><br>
sha256 <span class="stamp-sha">bf69db896f0f32a8bc22838551c0403ead65d36e0e64abcc0f5b66d58e14f6bc</span><br>
md5 <span class="stamp-md5">c50ca959819e3472ffebe76d431f8531</span><br>
sha256 <span class="stamp-sha">3c1d1ba521f485f911bf5fd4555d72a53a737b5219d55a079ff93a502845dc12</span><br>
<span style="color:#bbb">hashes are of this page with these two fields zeroed — to verify, blank them and re-hash</span><br>
<span style="color:#bbb">one self-contained file — <strong>save a copy</strong> and verify against these hashes; point at your own servers with ?signal= and ?turncred=, or <a href="host-your-own.html" style="color:#999">host your own community</a></span>
</footer>