← All docs
Ideas

Logging and diagnostics

> Both tracks. The DMX feature lands on top of XOSC's existing logging infrastructure — don't invent a parallel one.

Logger

XOSC has one logger: electron/logger.ts (main) + useStore.pushLog (renderer). Levels: info, warn, error, debug. Sources: "input", "osc", "serial", "system".

Add "dmx" as a source. Update:

  • electron/shared/types.tsLogEntry["source"] adds "dmx".
  • src/types/api.ts — same.
  • electron/logger.ts — make sure the formatter handles it (it should already; just verify).
  • src/features/debug/DebugPanel.tsx — the source filter dropdown adds a "dmx" chip.

What to log

| Event | Level | Example message |
|---|---|---|
| Transmitter open | info | DMX open art-net://192.168.1.50:6454 universe=u1 (univ#1) |
| Transmitter close | info | DMX close art-net://... |
| Transmitter error | error | DMX art-net://... send failed: EHOSTUNREACH (rate-limited) |
| Frame drops > 30% | warn | DMX universe u1 dropping frames (45% over last 5s) |
| Sequence start | info | Pad start "Warm Wash" (slot=ambient priority=12) |
| Sequence stop | info | Pad stop "Warm Wash" (layer-id=...) reason=user |
| Blackout | warn | BLACKOUT (was 3 layers) |
| Tap tempo | debug | Tap clock "main" bpm=128.4 |
| Mixer slot conflict | debug | Slot "ambient" silenced layer-id=... (priority=5 < 12) |

Rate-limit error spam: at most one error log per (source, message) per 200 ms (TagTable's pattern in osc.js:240+).

Sink-rate gauge

DmxOutNode renders the existing <SinkRateGauge nodeId={node.id} />. It already shows events/s in amber > 60 / red > 200 — useful when a continuous source is flooding a DMX channel. No changes needed.

Cycle detector

src/store/cycleDetect.ts walks edges + virtual ones (Resolume parameter equality). Adding DMX:

  • A dmx-out writing universe U channel C is virtually fed by any dmx-in reading universe U channel C on the same (bindHost, port). Implement as the existing Resolume-virtual-edge pattern: enumerate dmx-out / dmx-in pairs and synthesise a virtual edge for cycle detection.
Without this, a graph that wires dmx-in:c1 → transform → dmx-out:c1 would loop silently. The existing depth cap in the router still terminates it; the cycle warning UI just makes the loop visible.

Test coverage

  • One Vitest test per transmitter that builds packets and snapshots the bytes (TagTable doesn't ship tests; we write minimal ones since DMX wire format is fragile).
  • One Vitest test for composeFrame covering: graph-only, pad-only, both, slot exclusivity, mix modes.
  • One Vitest test for applyFixture covering all 8 built-in profiles.
These belong in src/features/dmx/__tests__/ and electron/dmx/__tests__/.

What's measured for the diagnostics row

The DMX settings panel surfaces a per-transmitter diagnostics row:

  • kind • config (e.g. Art-Net • 192.168.1.50:6454 universe 1)
  • FPS (computed from framesSent / uptime_s)
  • Drop rate %
  • Health badge (good / warning / critical)
  • Last-frame age (now - lastFrameTime)
  • Connection status

Theme-driven colors: var(--ok), var(--warn), var(--err) for the health badge.