Merged
Conversation
Materialize the ring buffer XML into a table variable before shredding with CROSS APPLY .nodes(). The inline subquery pattern forced SQL Server to repeatedly parse the full 4MB+ XML blob, causing 2+ minute execution times and 30-second CommandTimeout failures during sustained load. Applied to all 4 XE ring buffer queries: - Deadlock collection (on-prem + Azure SQL DB) - Blocked process report collection (on-prem + Azure SQL DB) Performance: ~2:44 → ~0.46s (~350x improvement). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…-timeout Fix XE ring buffer query timeouts on large buffers
Surface the existing GetCollectionHealthAsync() data in a new tab showing per-collector status, run counts, failure rates, avg duration, timestamps, and last error message. Includes column-level filtering. The backend data (collection_log table, health computation) already existed but was never displayed in the UI — only accessible via status bar tooltip or MCP tool. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…th-view Add Collection Health tab to Lite UI
Expand the Collection Health tab into three sub-tabs: - Health Summary: existing per-collector status grid (from #39) - Collection Log: recent collection_log entries showing per-run timing (total, SQL, DuckDB split), rows collected, status, and errors - Duration Trends: ScottPlot chart showing collector duration over time Also adds: - GetRecentCollectionLogAsync() query and CollectionLogRow model - "Open Log File" button to open today's log in default editor - Column-level filtering on the collection log grid Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…nostics Add collector performance diagnostics to Lite UI
…column - SafeToDecimal() guards against Infinity/NaN from SQL Server float columns that crash Convert.ToDecimal() (e.g. query_cost in dm_exec_query_memory_grants) - Add Last Error At timestamp column to Health Summary grid so users can tell when an error occurred, not just what it was - Add last_error_time to GetCollectionHealthAsync() query Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…erflow Fix query_cost overflow and add Last Error At column
Replace hardcoded US-style date formats (MM/dd, MMM d, h:mm tt) with the "g" general format specifier which respects the user's system locale. Dashboard: - ServerConnectionStatus: "Checked" and "Online since" timestamps - ManageServersWindow: Last Connected column - CollectorScheduleWindow: Last Run and Next Run columns Lite: - ServerConnectionStatus: same "Checked" and "Online since" timestamps - CollectorHealthRow/CollectionLogRow: all formatted timestamp properties Does not change the time range picker (AM/PM hour list) — that needs a separate design discussion. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Change hour picker from "12 AM", "1 AM", ... "11 PM" to "00:00", "01:00", ... "23:00". Consistent with chart axis labels, SQL Server log conventions, and international users. Parse logic is index-based (SelectedIndex 0-23) so no functional change. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…atetime Use locale-aware date/time formatting throughout UI
The custom date range was already in server time (from LocalToServerTime), but the chart axis limit code added UtcOffsetMinutes again, shifting the X-axis by the server's UTC offset. With UTC-8 this caused an 8-hour shift (e.g. picking 8 AM-12 PM showed 12 AM-4 AM on the axis). Fixed in all 4 chart methods: blocking trend, deadlock trend, wait stats, and perfmon. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…-fix Fix chart X-axis timezone double-conversion
AlertStateService rewritten with JSON persistence (alert_state.json) for silenced servers and acknowledged alerts. Acknowledgement now uses timestamps instead of count comparison — switching time ranges no longer re-triggers dismissed alerts. Only genuinely new events (collected after the ack time) clear the acknowledgement. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Persist dismissed alerts across restarts (#44)
Wait stats chart now has a Metric dropdown to switch between: - Wait Time (ms/sec): existing per-second rate (default) - Avg Wait Time (ms/wait): delta_wait_time_ms / delta_waiting_tasks Shows which waits are individually painful vs just high volume. Both Dashboard and Lite get the toggle, hover tooltip unit updates to match, and Lite summary grid gains AvgWaitMsPerTask property. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add avg ms per wait chart toggle (#22)
#53) Dashboard: SettingsWindow was creating its own UserPreferencesService instance, so preference changes weren't visible to MainWindow's instance (stale in-memory cache). Now shares the same instance via constructor injection. Lite: SystemTrayService always hid window on minimize with no preference check. Added App.MinimizeToTray property, wired to settings.json (key already existed but was unused), added checkbox to Settings UI. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Fix minimize-to-tray setting ignored in both apps (#53)
…ide (#52, #56-59) New alert types for both Dashboard and Lite: Long-Running Queries, Poison Waits, TempDB Space, Long-Running Jobs — each with configurable thresholds in Settings, email notifications, tray toasts, and auto-clear when conditions resolve. Alerts History view aggregates all alerts across servers in a timeline with severity-colored rows, time range and server filters, column-level filtering, copy/export context menu, and dismiss/hide functionality. Dashboard persists alert history to JSON on exit and reloads on startup. Alerts are hidden (not deleted) when dismissed, surviving across sessions. Lite stores alerts in DuckDB with a dismissed column (schema v9 migration). Both apps auto-refresh the alerts view when visible and support multi-select dismiss and bulk dismiss-all with confirmation. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Deadlock and blocked process XML processors now check whether sp_BlitzLock / sp_HumanEventsBlockViewer actually produced parsed results. If 0 results are returned, rows stay unprocessed for automatic retry on the next run instead of being silently marked done. Logs NO_RESULTS status with descriptive error message. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ke sure something works, and then you get so excited about it working that you just sit there marveling at it working and then forget to put it back? It me. Fix Lite deadlock and blocked process collectors inserting duplicate rows (#61). Both collectors query the XE ring buffer every minute but the buffer holds ~10 minutes of events, so each event was inserted ~10 times. Now each collector queries MAX(timestamp) from DuckDB before collection and passes it as a SQL Server parameter to filter out already-collected events. Falls back to a 10-minute window on first run. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…cate-events Fix Lite duplicate deadlock and blocked process events (#61)
Some organizations require a vendor relationship or invoice before deploying open-source software. Added Supported ($500/yr) and Priority ($2,500/yr) tiers with links to the blog post and purchase page. No features are gated — the commercial tiers provide support, compatibility guarantees, and compliance paperwork. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…-support Add commercial support tiers to README
Dashboard: Sub-tab badges (Locking, Memory, Resource Metrics) now update when alerts fire from the independent alert engine. Previously only the server-level Overview badge updated. Also fix deadlock badge race condition where EvaluateAlertConditionsAsync consumed the previous deadlock count before the badge delta calculation could use it. Lite: Fix DuckDB v9 migration silently failing — ALTER TABLE ADD COLUMN does not support NOT NULL constraint in DuckDB. Changed to nullable with DEFAULT. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ixes Fix Dashboard sub-tab badges and DuckDB dismissed column migration
Wire ChartHoverHelper to every remaining chart in the Dashboard that was missing mouse-over tooltips showing series name, value, and timestamp: - MemoryContent: 5 charts (overview, grants, clerks, plan cache, pressure) - QueryPerformanceContent: 4 charts (query/proc/QS durations, exec counts) - SystemEventsContent: 19 charts (corruption, contention, errors, IO, scheduler, memory conditions, CPU tasks, memory broker, node OOM) - ResourceMetricsContent: 6 charts (CPU utilization, TempDB stats/latency, server trends CPU/TempDB/memory/perfmon) - ServerTab: 9 charts (4 resource overview + 5 locking trends) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ooltips Add hover tooltips to all Dashboard charts
…B schema tests - ci.yml: Build all 5 projects + run Lite.Tests on PR/push to dev - sql-validation.yml: Install all SQL scripts on 2017/2019/2022/2025 matrix, validate 93 objects exist - ci_validate_installation.sql: OBJECT_ID checks for all schemas, tables, procedures, views - Lite.Tests: 6 xUnit tests for DuckDB schema init, version, idempotency, indexes All tests verified locally against sql2022 and DuckDB. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When disabled, clicking a server card in Overview creates the tab without switching away from the current view. Existing-tab clicks always focus regardless of setting. Default is true (current behavior). Closes #71 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Four fixes for the deadlock chart pipeline: - Dashboard charts: plot raw per-interval columns instead of delta columns (blocking_event_count, deadlock_count, etc.) since delta framework incorrectly computed current-previous=0 for per-interval values - XAML: remove "(Delta)" from all four Locking > Trends chart titles - Analyzer: filter collect.deadlocks on collection_time instead of event_date so late-arriving XE deadlock events are not missed - Process XML: add +1 second buffer to @end_date so sp_BlitzLock's strict less-than filter works when processing a single deadlock event Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Fix deadlock charts not populating data
…ipping Fix text clipping in DataGrid rows
…-tab-setting Add setting to control server tab auto-focus
…n Lite Wire up ChartHoverHelper for the three Lite charts that were missing tooltip support. Wait Stats, Perfmon, TempDB File I/O, and File I/O charts already had this; CPU, Memory, and TempDB (by type) did not. Closes #81 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…oltips Fix missing chart tooltips for CPU, Memory, TempDB in Lite
The dashboard doesn't display blocking/deadlock or wait stats data from sp_HealthParser. Passing @skip_locks = 1 and @skip_waits = 1 (defaulted on) reduces collection time from 43s to 1.6s (27x improvement). Requires sp_HealthParser 3.3+ (DarlingData PR #666/#667). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…e schedule (#86) - Blocked process and deadlock XML collectors now chain-trigger their parsers and analyzer immediately when rows are found, eliminating up to 15 min pipeline latency - Materialize XE ring buffer XML into table variable before shredding, avoiding repeated XML document validation (35s → 300ms under load) - Master collector passes @minutes_back = frequency * 2 instead of defaulting to 15 min lookback every cycle - Bump 18 cheap collectors to 1-min frequency, 4 medium to 2-min Tested on sql2022 under TPC-C workload: 79 deadlock events collected in 297ms (was 35s), chain triggers fire correctly, zero CHAIN_ERRORs. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Pass @skip_locks and @skip_waits to health collector wrapper
…re-firing AddWithValue infers types incorrectly — for DateTime it sends legacy datetime (3.33ms precision) instead of datetime2, causing the deadlock dedup cutoff to round and re-collect the same event every cycle. Replaced all 28 usages across 7 files with explicitly typed SqlParameter. Fixed alert re-firing: ServerTab used CollectionTime (always new) instead of DeadlockTime/EventTime for ack comparison. Overview deadlock count query also filtered by collection_time instead of deadlock_time, inflating counts with duplicate rows and triggering spurious popup alerts. Tested: zero AddWithValue remaining, all 3 projects build clean, dedup confirmed working under HammerDB load (97 new deadlocks collected, zero duplicates). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
… status (#85, #91, #93) #85: Blocking/deadlock trend charts now show a visible flat line at zero instead of empty space. Added negative Y-axis margin so zero-value data renders above the axis border. Reduced fallback Y range from +100 to +1. #91: Added server_name column to collection_log DuckDB table (schema v10) so log entries identify which server produced them without a lookup join. #93: Sidebar status dots now reflect actual connection check results (IsOnline) instead of the IsEnabled user config toggle. Added IsOnline property to ServerConnection model, synced from connection status in RefreshServerList and CheckConnectionsAndNotify. Fixed first-check refresh so dots update as soon as initial connection checks complete. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…n-triggers Chain-trigger parsers, optimize XML collection, tune schedule
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Update schema version assertion to v10 in tests
…ded value Made CurrentSchemaVersion internal and added InternalsVisibleTo so the test project references the constant directly. Schema bumps no longer require updating tests. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ynamic Use DuckDbInitializer.CurrentSchemaVersion in tests instead of hardcoded value
CLI: --reset-schedule flag prepends TRUNCATE to 04_create_schedule_table.sql GUI: "Reset collection schedule to recommended defaults" checkbox Both pass resetSchedule to installer logic which truncates config.collection_schedule before the WHERE NOT EXISTS inserts re-populate with current defaults. Tested on sql2022 with update install — schedule reset to 33 collectors with current recommended frequencies. Closes #92 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add --reset-schedule flag for CLI and GUI installers
RunDueCollectorsAsync now checks IsOnline status before queuing collectors for each server. Servers marked offline by the connection check are skipped entirely, eliminating wasted timeout cycles. Connection timeout reduced from 15s to 5s to match the connection check timeout. Tested under 30-min HammerDB TPC-C load: 437 Lite collections at 100% success rate, avg 176ms. Zero offline server attempts. Closes #90 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ervers Skip offline servers during Lite collection
PRs to dev now get the same build validation as PRs to main, so package updates and other changes can be verified before merge. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add dev branch to CI build trigger
Issue #101 update NuGet packages to latest stable version
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Bump version to 1.2.0
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Release v1.2.0 — one week birthday!
New Features
Bug Fixes
Infrastructure
Test plan