Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Added

- **Darling Web: a read-only browser dashboard served by the service** ([#1574]) - Darling gains an optional web UI so an operator can watch the fleet from any browser (a remote Mac included) with no WPF viewer install. A SECOND, independent Kestrel host (`DarlingWebHostService`) serves it on its own port (default **5153**), with its own kill switch, LAN-exposure block, firewall rule, and least-privilege VIEWER-role store pool - deliberately separate from the MCP host (which owns root on 5152 and gates a different blast radius, so the two get independent enable switches and tokens). It is **off by default** and toggled LIVE from the viewer's Settings via a `web_enabled`/`web_port` control-plane pair (the twin of MCP's, added by store migration **V30**); the supervisor starts/stops/rebinds the host within seconds with no service restart. Loopback is tokenless; managed-mode LAN exposure rides a `?token=` -> HMAC-signed HttpOnly SameSite=Strict session-cookie handshake behind an in-app CIDR check, fail-closed. The HTTP surface is `GET /api/read/{tool}` 1:1 with the read-only MCP tool catalog (**69 endpoints**), calling the SAME public static tool methods the MCP server exposes so there is zero SQL/projection drift, plus a pre-banded `GET /api/fleet` NOC roll-up from a new service-side `DarlingFleetReader` that runs bounded cross-server aggregates (a fixed ~9 round-trips regardless of fleet size, not an N-servers x per-metric fan-out) and a matching `get_fleet_overview` MCP tool. The per-server health banding is unified ONCE in `PerformanceMonitor.Common` (`ServerHealthClassifier` + `ServerHealthThresholds` - collection freshness, the six per-metric bands, and the fleet band/worst-first score); the WPF viewer's Overview cards now delegate to it, so the thresholds that used to live twice can no longer drift. The browser frontend is vanilla ES modules with NO framework, NO build step, and ZERO off-origin references (air-gapped - a CI scan fails the build on any CDN / font / remote include): a **Fleet Overview** (pre-banded server cards with a status dot, six metric bands, and the amber "Awaiting first collection" state rendered exactly as the API reports it; a worst-first Needs-Attention list; an all-healthy line), a per-server **drill-down** (Overview stats, Wait Stats + a trend for the heaviest wait, Active Queries, a 4-series CPU chart, Memory and File-I/O trends, and Collection Health - all charted with dependency-free inline SVG), and a fleet-wide filterable **Alert History**. All untrusted text (query text, object / wait / server names) renders through `textContent` (never `innerHTML`), and every naive-UTC timestamp is localized in the browser. Everything renders through a `renderPanel({read, params, viz, span})` seam (viz registry: table / line / stat / bandlist; pages are hardcoded descriptor arrays) so #1563 can later drive the pages from stored JSON. A follow-up design-review pass then hardened the frontend: chart series use a neutral, severity-safe categorical palette (never the ok/warn/err alert colors) on nice-rounded, percentage-clamped axes with vertical gridlines, and the CPU chart drops Idle% (now three series) so the real series are not crushed; Alert History collapses channel/sent/muted/delivery-error into one status column and truncates each detail to a one-line click-to-expand disclosure (structured findings render as labeled Story/Severity/Confidence fields); the fleet cards gain a secondary detail line per metric (SQL-vs-total CPU, threads free/max, memory + buffer-pool GB, blocking max wait, deadlock last-seen, collectors healthy/failing), a keyboard path with focus rings, and non-color severity badges; and a fleet status-bar footer, a card sort control, tabular numerals, and assorted density/typography fixes round it out (the pre-banded card DTO gains a `deadlock_last_seen` field).

- **Long-running query completion trace (opt-in, default OFF) in Lite and the Darling viewer** ([#1572]) - a new `long_query_completions` collector captures the Extended Events equivalent of the classic long-query trace (SSMS's QuickSessionStandard completion trio): `rpc_completed` + `sql_batch_completed` filtered by `duration >= threshold` (default 2,000,000 µs = 2 s, matching the Full Dashboard's SQL Trace default in `install/30_collect_trace_management.sql`), plus `attention` captured UNFILTERED so cancelled/timed-out long queries are still evidenced (the attention event's own duration is the cancellation-handling time, not the query runtime, so a duration predicate would discard exactly those rows - MS Learn-verified). Each completion carries the 9 QuickSessionStandard actions plus duration/CPU/reads/writes/row_count/`result` (Abort = the long query was killed) and the statement text. It reads its own app-managed ring-buffer XE session exactly like the blocked-process/deadlock collectors - server-scoped on on-prem/MI/RDS, database-scoped per monitored database on Azure SQL DB (#1535 pattern; `nt_username` omitted there since Azure uses Entra/SQL auth). **Erik's dedicated switch:** the collector is seeded DISABLED and opted into per fleet (a completion trace is not free on a busy server); enabling it CREATES the session on the monitored servers and disabling it DROPS the session there (the session itself is the cost - the lifecycle reconciles to the flag both ways, mirrored across both SKUs from shared session-DDL builders so the two can't drift). Both apps get a **Long Queries** tab (a grid of completed long queries + attentions, default-sorted DESCENDING by duration, aborted/attention rows tinted) with an explicit empty-state banner naming the exact switch to turn it on when the collector is disabled, plus a `get_long_query_completions` MCP read tool. Retention rides the shared 30-day collector horizon; the Darling store adds it via migration V29.

- **Darling viewer: ships as a Velopack `Setup.exe` for remote seats, like Lite and Dashboard** ([#1571]) - the standalone viewer that connects to a central Darling store from an operator's own machine now has a real install affordance: a per-user `Setup.exe` with Start Menu / desktop shortcuts, Apps & Features registration, and delta auto-updates from the releases feed, on its own `darlingviewer` Velopack channel. This required making the viewer a first-class Velopack app (it never was - it only shipped co-located inside the service zip): a `Program.Main` entry point that calls `VelopackApp.Build().Run()` before any window (wired via `<StartupObject>`, exactly as Lite/Dashboard), the `Velopack` package pinned to the suite's `1.2.0`, and Lite's "Check for Updates" affordance ported into the About dialog (Velopack self-update, falling back to opening the releases page). Nightly builds publish the `Setup.exe` UNSIGNED as a plain release asset alongside the existing zips (which are unchanged); the release pipeline is wired to publish self-contained, sign, `vpk pack`, and upload to the channel - but the signed release path is inert until the `DarlingViewer` SignPath artifact-configuration slug is created (the standing #1340 signing prerequisite, Erik's side). The co-located viewer inside `PerformanceMonitorDarling-*.zip` is untouched (zero-config parent-directory `darling.json` discovery), and the Velopack install id (`%LocalAppData%\PerformanceMonitorDarlingViewer`) does not collide with the viewer's per-user state (`%APPDATA%\PerformanceMonitorDarling`), so both can coexist for one user.
Expand Down Expand Up @@ -415,6 +417,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
[#1570]: https://github.com/erikdarlingdata/PerformanceMonitor/pull/1570
[#1572]: https://github.com/erikdarlingdata/PerformanceMonitor/pull/1572
[#1571]: https://github.com/erikdarlingdata/PerformanceMonitor/pull/1571
[#1574]: https://github.com/erikdarlingdata/PerformanceMonitor/pull/1574
[#1536]: https://github.com/erikdarlingdata/PerformanceMonitor/pull/1536
[#1534]: https://github.com/erikdarlingdata/PerformanceMonitor/pull/1534
[#1533]: https://github.com/erikdarlingdata/PerformanceMonitor/pull/1533
Expand Down
Loading
Loading