Skip to content

feat(diag): browser-based diagnostics viewer over OSC - #1807

Draft
dedicatedbroadcastsolutions wants to merge 10 commits into
CasparCG:masterfrom
dedicatedbroadcastsolutions:feat-diag-http-server
Draft

dedicatedbroadcastsolutions wants to merge 10 commits into
CasparCG:masterfrom
dedicatedbroadcastsolutions:feat-diag-http-server

Conversation

@dedicatedbroadcastsolutions

@dedicatedbroadcastsolutions dedicatedbroadcastsolutions commented Sep 21, 2026 •

Copy link
Copy Markdown
Contributor

Prototype of a lightweight alternative to the SFML DIAG window: a small opt-in HTTP+SSE server that mirrors every caspar::diagnostics::graph's text/values/colors/tags into JSON, with no rendering cost on the server.

  • GET / - a small <canvas>-based viewer (all rendering client-side)
  • GET /snapshot - one-shot JSON for simple polling clients
  • GET /events - Server-Sent Events stream for clients that want to subscribe and do their own rendering/processing
  • Enabled by default at configuration.diag.default-port (4000), matching how OSC's client is always active; 0 disables it
  • Tracks graphs by a stable id (not registry position), shows channel/layer context, renders per-tag severity, and boosts the visibility of dropped/late-frame style series over their (often very dark) SFML colors

Closes #899, #1310 (replaces the SFML DIAG window entirely, so it no longer competes for GPU/desktop resources). Related to #1361 (network-exposed graph stats — done over HTTP/SSE here rather than OSC), #1544 (per-port device labeling — not yet implemented, still channel/layer only), #1139 / #1654 (broader websocket control/monitoring proposals — this is a lighter-weight alternative for the monitoring half), #914 (motivation: avoiding desktop-GUI overhead on the server).

Status: draft. Core/protocol and the full executable build cleanly (confirmed both isolated and end-to-end), but I have not yet run this against a live playout server or exercised it under real load - want to validate the viewer/SSE behavior for real before marking ready for review.

Edit: This has been updated to be OSC instead of HTTP/SSE

Prototype replacement path for the SFML DIAG window (see issue CasparCG#899),
built to be lightweight and usable both as a standalone browser page and
as a feed other clients can subscribe to and render/process themselves:

- core/diagnostics/web_graph: a graph_sink that mirrors every graph's
  text/values/colors/tags into an in-memory snapshot. Registered
  alongside (not instead of) the existing osd sink, so it costs nothing
  beyond what set_value() already costs regardless of DIAG - no
  rendering happens here at all.
- protocol/util/diag_http_server: a minimal GET-only HTTP/1.1 responder
  over raw asio (no boost::beast, no new dependency):
    GET /         -> static HTML/JS viewer, all rendering is client-side
                     canvas, connects to /events
    GET /snapshot -> one JSON snapshot, for simple polling clients
    GET /events   -> Server-Sent Events stream of JSON snapshots, for
                     clients that want to subscribe and do their own
                     rendering/processing
- Disabled by default; opt in via configuration.diag.http-port in
  casparcg.config. No auth - trusted monitoring network only, same as
  OSC/AMCP.

core and protocol build clean. Full executable build (all modules) still
in progress in a slow single-core environment as of this commit; will
confirm server.cpp integration compiles once that finishes.
Rename configuration.diag.http-port to configuration.diag.default-port and
default it to 4000 (instead of 0/disabled), matching how OSC's client is
always active by default (configuration.osc.default-port). 0 still disables
it for anyone who wants it off.
… severity

Match osd_graph feature-for-feature so the web viewer is a complete
replacement:
- capture call_context (channel/layer) at sink creation and show it per graph,
  like the corner label in the SFML window
- assign each sink a stable id instead of keying the client-side viewer by
  registry position, so graphs cannot get relabeled or merged as others are
  created/destroyed
- remove a graph from the page once its id stops appearing in a snapshot,
  matching the SFML window dropping a destroyed graph's weak_ptr
- store set_tag() severity per named series (as osd_graph does) instead of a
  flat, never-cleared list of tag names, clearing pending tags once emitted
  so the web page only shows tags that fired since the previous snapshot, and
  render them as small severity-colored badges
- fix auto_reset() to decay values back to 0, matching osd_graph, rather than
  clearing tags
…eries

Default (unset) line color now matches osd_graph's white default instead of
an arbitrary green, and explicit graph_->set_color() values already decoded
with the same bit layout as get_sfml_color so they render identically.

dropped-frame, late-frame, flushed-frame, underflow, drop-out,
audio-clipping and audio-buffer-overflow are often configured with dark,
muted tones in the SFML modules (meant to sit quietly alongside busier
lines there). On the web viewer these are normalized to a vivid version of
the same hue and drawn with a thicker, glowing stroke so problems are
obvious at a glance.
Same C++20 modernization as CasparCG#1805 - drops the fixed-size stack buffer and
<cstdio> include in favor of std::format.
@dimitry-ishenko

Copy link
Copy Markdown
Contributor

As much as I love the idea of ditching the DIAG window, I don't think bolting a web server onto CasparCG Server is the right direction.

I like the idea of spitting out diagnostics through OSC via an opt-in option. That way, people can use their preferred GUIs to show that data in their preferred way. And those who don't use it won't be bothered by it.

I go by the motto "the best code is no code at all", so the more "features" we can strip out of the core Server code, the better. IMHO, of course.

@dedicatedbroadcastsolutions

dedicatedbroadcastsolutions commented Sep 22, 2026 •

Copy link
Copy Markdown
Contributor Author

Ok, I can shift it towards that direction if we want to do it via OSC. Using a browser with SSE shifts the render off with minimal overhead of serving a basic web page.

Since X11 is going away, I am not sure we can call diag replaced without having a UI for it shipped with the server, but I can make a simple UI that is a separate light weight web server executable that can provide that functionality for those who need it while keeping with your motto for the server core.

@martastain

Copy link
Copy Markdown

I like the idea of spitting out diagnostics through OSC via an opt-in option. That way, people can use their preferred GUIs to > show that data in their preferred way. And those who don't use it won't be bothered by it.

Sending diag info over OSC would be great!

@Julusian

Julusian commented Oct 7, 2026

Copy link
Copy Markdown
Member

I think that keeping this to OSC would be best. I had this in mind when doing 8f05ef7, my intention was that using that subscribe could accept an argument to say to include the detailed diag stuff too in some way (unsure how granular that should be)

I can think of 3 different ways I would like to use this data, depending on setup/environment:

  • An app which converts it to prometheus/influx or something suitable for analysing in grafana after an issue occurs, or for setting alerts.
  • A web app, for simple realtime monitoring of a server
  • Maybe a desktop app, but perhaps that could be good enough with the web app version.

So ideally there could be a separate repo(s) in the casparcg github org for these tools. I dont have a particular preference on language for any of this, or whether its one repo with different tools or multiple repos.
One thing to think about early though is that if a desktop and web app are wanted for realtime viewing, being able to share code between them will make that much easier.

@dedicatedbroadcastsolutions

This comment has been minimized.

@dedicatedbroadcastsolutions

dedicatedbroadcastsolutions commented Oct 7, 2026 •

Copy link
Copy Markdown
Contributor Author

I have a typescript/electron front end that can be the web and desktop UI for this. I'll update this pr accordingly soon.

Per PR feedback (dimitry-ishenko, Julusian), drop the bolted-on HTTP
server and canvas viewer entirely in favor of broadcasting
caspar::diagnostics::graph telemetry over the existing OSC transport,
so people can use their preferred GUI/tooling instead of a
server-shipped one:

- core/diagnostics/web_graph -> osc_graph: the graph_sink mirror now
  builds a core::monitor::state snapshot (diag/<id>/channel, .../layer,
  .../text, .../value/<name>, .../color/<name>, .../tag/<name>) instead
  of a JSON string, so it can be sent down the same path as channel
  state.
- protocol/osc/client: takes an optional diagnostics_provider callback
  and lets a subscription opt into diagnostics telemetry
  per-endpoint. Diagnostics are polled and broadcast on their own
  ~40ms cadence (they aren't tied to any channel's tick) but only
  while at least one endpoint has actually asked for them, so there's
  no cost at all otherwise.
- protocol/amcp: `OSC SUBSCRIBE <port> DIAG` opts an AMCP client's
  existing OSC subscription into diagnostics; configuration.osc
  predefined-clients gained a matching <diagnostics> flag for static
  subscribers.
- Removed protocol/util/diag_http_server and the configuration.diag
  section entirely - no more embedded web server/viewer in the core
  server.

A separate TypeScript/Electron app (web + desktop) is where the actual
viewer UI will live, consuming this OSC data directly.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@dedicatedbroadcastsolutions

Copy link
Copy Markdown
Contributor Author

Pushed an update that drops the embedded HTTP+SSE server/viewer entirely per the discussion above, in favor of broadcasting caspar::diagnostics::graph telemetry over the existing OSC transport:

  • core/diagnostics/web_graph → osc_graph: the sink now mirrors each graph into core::monitor::state (diag/<id>/channel, .../layer, .../text, .../value/<name>, .../color/<name>, .../tag/<name>) instead of a JSON blob.
  • protocol/osc/client broadcasts this on its own ~40ms cadence, but only to endpoints that have opted in, and only while at least one has - so it costs nothing for anyone not using it.
  • Opt-in is per-subscriber: OSC SUBSCRIBE <port> DIAG for AMCP clients, or a <diagnostics>true</diagnostics> flag on a configuration.osc.predefined-clients entry for static subscribers.
  • Removed protocol/util/diag_http_server and the configuration.diag section entirely - no more web server/viewer bundled with the core server.

Core, protocol, and the full executable all build cleanly with this change.

The TypeScript/Electron app I mentioned will consume this OSC data directly and is where the actual viewer UI (web + desktop) will live, as a separate project outside this repo.

@dedicatedbroadcastsolutions dedicatedbroadcastsolutions changed the title feat(diag): browser-based diagnostics viewer over HTTP/SSE feat(diag): browser-based diagnostics viewer over OSC Oct 14, 2026
@coderabbitai

coderabbitai Bot commented Oct 15, 2026

Copy link
Copy Markdown

Important

Draft PR not reviewed

Draft PRs are not automatically reviewed by default.

  • Trigger a manual review

To automatically review draft PRs, update your CodeRabbit configuration:

reviews:
  auto_review:
    drafts: true
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Comment @coderabbitai help to get the list of available commands.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Replace DIAG window with external app

4 participants