diff --git a/CHANGELOG.md b/CHANGELOG.md index d51767d27..77ec0c854 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,6 +32,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed +- **Full Dashboard (deprecated): `report.daily_summary_v2` no longer garbles `worst_query_hash`** ([#1667]) - the view boxed the raw `binary(8)` `query_hash` straight into its `sql_variant` pivot column, so anything that stringified that value reinterpreted the 8 bytes as UTF-16 and printed mojibake (`稟렿坧譈`) instead of a hash. It is the only non-scalar payload among the view's 25 pivoted metrics - every other row boxes a number or a string and round-trips cleanly. Now hex-encoded before boxing (`CONVERT(nvarchar(20), ..., 1)`), yielding `0x1F7A7FB76757088B`. Community fix by @argpna ([#1666]), verified live against SQL Server 2022. **Note for anyone querying this view directly:** the `sql_variant`'s base type for that one row changes from `binary(8)` to `nvarchar(20)`, so a caller doing `CONVERT(varbinary(8), metric_value)` needs updating - though in practice the old value was unusable, which is the bug. - **Darling Web: composed custom-view panels no longer route onto rollups the store doesn't have** ([#1675]) - the composer's arm of the #1664 availability guard, and its pre-existing sibling: `ComposeSourceRouter` picked `query_stats_hourly` / `procedure_stats_hourly` / `query_store_stats_hourly` (or the `_daily` tiers) purely by window age and dimension coverage, never checking the rollup **exists in the store**. The continuous aggregates are runtime TimescaleDB setup, so on a bring-your-own **plain PostgreSQL** store any composed panel with a window past ~3 days compiled SQL against a missing relation and failed at run time with `42P01` - and a TimescaleDB store whose failure-isolated ensure sweep only built some aggregates routed onto the missing ones the same way. The #1664 probe now covers all three composer catalog tables' rollup pairs (per-table flags, since a partial build can lose one table's pair and not another's), the compile-and-run endpoint probes it lazily with the viewer's exact caching rule (permanent once fully built, 5-minute re-probe while partial, raw on a failed probe), and the route degrades through the SAME shared `RetentionTierRouter` ladder the built-in tabs use (daily missing -> hourly capped, hourly missing -> raw) so the two readers can never drift. On plain PG the raw fallback is complete, not degraded - nothing ever drops raw there - so it stays silent; on a **retention-active** store, a route that lands on a tier whose retention cannot reach the window's start (a forced raw fallback truncates at ~4 days, a daily-less hourly route at ~21) now returns a `notice` alongside the rows - "partial window, and says so," the same treatment the expensive-queries panel got in #1664 - rendered above the chart on every web surface and riding along verbatim through the MCP `run_custom_view_panel` tool. Pinned by router availability tests (per-table degrade), a compile-level raw-route test, notice-boundary tests, an 8-view probe/`Has()` drift guard, and a gated-live end-to-end that runs a 10-day window through the real runner against plain PostgreSQL - the exact 42P01 repro, now green. - **Full Dashboard (deprecated): the Trace Flag Changes grid and the `get_trace_flag_changes` MCP tool throw `InvalidCastException` now that the view returns rows** ([#1668]) - `report.trace_flag_changes` projects `previous_status`/`new_status` as BIT, and the Dashboard reader called `SqlDataReader.GetString` on them, which performs no conversion. Before #1635 the view itself failed (Msg 245) before the reader ever ran; fixing the view exposed the cast. Fixed in the READER (GetBoolean + ON/OFF/empty formatting, matching the shared `ConfigChangeDiff.StatusText` wording) - the view's column shape is a public contract that external consumers (e.g. a Grafana companion) already query directly, so converting to text in SQL would have fixed the Dashboard by breaking them. Deprecated surface, bug-fix-only lane. - **Darling: managed PostgreSQL's `pg.log` finally rotates** ([#1670]) - closes the deliberately-left gap 1 of #1652 (#1654 fixed gaps 2-3). The server log was a single pg_ctl `-l` file with no rotation of any kind, growing unbounded across restarts on the data volume. The v6 conf block hands steady-state logging to PostgreSQL's own logging collector as a SELF-CAPPING weekday ring (`postgresql-%a.log`, rotate 1d, truncate-on-rotation - seven files, one week, zero sweep code; size rotation deliberately 0 because size rolls append rather than truncate). `pg.log` keeps exactly its diagnostic job - pg_ctl chatter plus anything the server says BEFORE the collector starts, which is precisely the startup-failure window - and now gains a few lines per restart instead of the whole log; an oversized pre-rotation `pg.log` is rolled to `pg.log.old` once (two files, bounded forever). The failure-diagnostics tail follows the log wherever Postgres last wrote it (newest of pg.log and the ring). Existing clusters heal on their next service-owned start, same as the v2-v5 blocks, and since the append runs before pg_ctl start the restart-only `logging_collector` applies immediately. Live-validated by the gated bring-up E2E: a real server boots with the block and the ring file appears. @@ -1628,3 +1629,5 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 [#1650]: https://github.com/erikdarlingdata/PerformanceMonitor/issues/1650 [#1591]: https://github.com/erikdarlingdata/PerformanceMonitor/issues/1591 [#1661]: https://github.com/erikdarlingdata/PerformanceMonitor/issues/1661 +[#1667]: https://github.com/erikdarlingdata/PerformanceMonitor/pull/1667 +[#1666]: https://github.com/erikdarlingdata/PerformanceMonitor/issues/1666