Repository navigation
Give Collection Stopped, Capture Down and Collector Cost Regression an authored self-monitor notebook (#4223) - #4437
Merged
Conversation
…n authored self-monitor notebook (#4223) - get_collection_health for every metric, plus a status-appropriate get_collection_log read: no status filter for Collection Stopped (the recent runs a stopped collection covers span every failure status), status=SESSION_MISSING for Capture Down (the only status its firing condition can ever see), and a collector-scoped log for Collector Cost Regression. - Collector Cost Regression additionally reads get_collector_cost (14-day trend) and get_collector_stall_probes for the collector named in the firing alert's own context, or a note cell when an older row carries no collector name. - AlertContext gains a structured CollectorName field (mirroring the existing WaitType field), set at the Collector Cost Regression fire site and read back by the template instead of re-deriving it from prose. - No trend panel: get_collector_cost and get_collector_stall_probes have no chart-catalog source, so this family is read cells only.
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.
Refs #4223.
Why
The alert notebook's mechanical fallback converts a metric's generic triage sections into read cells with no awareness of what actually drives the alert. The three self-monitor alerts — Collection Stopped, Capture Down, Collector Cost Regression — are about the monitoring tool's own health on one real server, and each has a specific, known-shape set of evidence a reader needs: the collection log, and for a cost regression, that one collector's own cost trend and stall history. This gives them an authored template instead of the fallback.
What changes
AlertContext.CollectorName(new field,PerformanceMonitor.Notifications/AlertContext.cs): a structured collector name, mirroring the existingWaitTypefield added for Poison Wait. Persisted as the trailing, nullable member ofAlertContextDto, withAlertContextSerializer.TryReadCollectorName(contextJson)reading it back without rehydrating the whole context. Set at the Collector Cost Regression fire site inDarlingSelfAlertEvaluator.cs(ApplyCostRegressionsAsync, ~line 1640):context: new AlertContext { CollectorName = regression.CollectorName }.FireAsync(~line 6981) passes a caller-supplied context straight through with no merge, so this is the only context data this fire site carries.AlertNotebookEndpoint.Templates.SelfMonitor.cs: one builder,BuildSelfMonitorCells, registered once ins_authoredTemplatesfor all three metric names, routing toauthored/self-monitor. Cells:HeaderCell,StatusCell,get_collection_healthfor every metric, then a per-metricget_collection_logread:statusfilter,hours=2,limit=50.ApplyCollectionStoppedAsyncfires off "no SUCCESS/SKIPPED run recently" (ReadCollectionSignalsAsync), so the recent runs it covers can beERROR,PERMISSIONS,EXTENSION_MISSING, or simply absent — no single status value covers all of those, so none is applied (documented in the file's doc comment).status=SESSION_MISSING,hours=24,limit=50. Traced the firing condition directly:ApplyCaptureDownAsync(DarlingSelfAlertEvaluator.cs~1420) only ever receives collector names fromReadMissingCaptureSessionsAsync(~6691), which runsMissingCaptureSessionsSql(~6637) — and that statement's ownWHERE x.status = 'SESSION_MISSING'clause (line ~6655) is the ONLY predicate that can put a collector into themissinglist. No other status can reach this alert's firing path, so one status value covers every case.collector_name-scopedget_collection_log, plusget_collector_cost(days_back=14) andget_collector_stall_probes(days_back=7) for the collector named in the row's persisted context (read the same wayBuildPoisonWaitCellsreadsWaitType— offrow.ContextJson, never re-derived from prose). When the context carries no collector name (a row written before this member existed), the two collector-scoped reads are replaced with a note cell, and the log read falls back to the unscoped form — never a read with an emptycollector_name.get_collector_costandget_collector_stall_probeshave noComposeSpec/chart-catalog source, so unlike every other authored family (which plots the condition it fired on) this family is read cells only.AlertNotebookAuthoredTemplateTests'AllAuthoredMetrics/AllAuthoredMetricsWithExpectedIdtheories are data-driven offs_authoredTemplatesitself, so the new row is automatically covered by every existing shared theory (routing,ValidateNotebookDefinition, budget) with no list to update.s_authoredLimitlessTrendReadsgainedget_collector_cost(declares onlydays_back/collector_name, nolimitparam at all).Test plan
New class
AlertNotebookTemplateSelfMonitorTests.cs(20 cases): routing for all three metrics toauthored/self-monitor; Collection Stopped's log cell carries nostatus; Capture Down's carriesstatus=SESSION_MISSING; Collector Cost Regression's collector-scoped reads carry the name from two different row contexts (not a literal); the no-collector-name case degrades to a note with no collector-scoped reads and no emptycollector_nameparam on any cell, for any of the three metrics; nopanel-type cell for any of the three; every param every read cell passes is declared in that read's catalog descriptor (DarlingWebEndpoints.CatalogDescriptors); anAlertContextround trip forCollectorName, plus the legacy-JSON-has-no-member case.Fire-site pin, through the product's own path (not a direct helper call): extended
CollectorCostRegression_FiresOnEntry_SuppressedWithinCooldown_ResolvesWhenGoneinDarlingSelfAlertTests.csto assert theAlertOutcomethe deliverer actually received (ApplyCostRegressionsAsync→FireAsync→RecordingDeliverer) carriesContext.CollectorName == "query_store".RED / mutation, run in-process on macOS (
Darling.Tests.dll,Microsoft.WindowsDesktop.Appstripped from the runtimeconfig):CollectorName = regression.CollectorNameassignment at the fire site (context: new AlertContext { }), rebuilt, ran the fire-site pin:Darling.Tests.DarlingSelfAlertTests.CollectorCostRegression_FiresOnEntry_SuppressedWithinCooldown_ResolvesWhenGone [FAIL]—Total: 248, Errors: 0, Failed: 1. Restored the assignment, rebuilt:Total: 248, Errors: 0, Failed: 0.AlertNotebookTemplateSelfMonitorTests(20/20),AlertNotebookAuthoredTemplateTests(152/152),AlertNotebookEndpointTests(29/29),AlertNotebookTemplateCustomRulesTests(11/11),AlertNotebookTemplateAnalysisFindingsTests(9/9),DarlingSelfAlertTests(248/248, 3 skipped — pre-existing, unrelated to this change),DocCommentHygieneTests(part of the combined 99/99 run alongside the new class).AlertNotebookAuthoredContextTests(live, own rig): not run — this PR adds no new live class and does not touch that file; its coverage is unaffected by a plain-field addition toAlertContext.origin/dev@64ea4a2a5(detached worktree, new test file copied in, no other source change): the new class doesn't compile against dev as-is, sinceAlertContext.CollectorName,AlertContextSerializer.TryReadCollectorName, and theAlertNotebookEndpoint.SelfMonitorTemplateVersionconstant don't exist there yet. Added three minimal, unwired compile shims in the scratch worktree only (never committed): aCollectorNameauto-property onAlertContext; aTryReadCollectorNamethat always returnsnull; and aSelfMonitorTemplateVersionconstant (value-1, satisfies the compiler only — routing for the three metrics isn't registered on dev, so the version-equality assertion fails at runtime, not the constant). Built clean, ranAlertNotebookTemplateSelfMonitorTests:Total: 22, Errors: 0, Failed: 21, Skipped: 0. Failing (21 of 22; the routing/build, per-metric status-filter, collector-name, empty-param, no-panel-cell, and declared-param theories all fail, plus the round trip):AuthoredTemplate_SelfMonitorMetrics_AreNotNulland_RouteToOneTemplate(all 3 metrics),BuildSelfMonitorCells_CollectionStopped_LogCellHasNoStatusFilter,BuildSelfMonitorCells_CaptureDown_LogCellFiltersSessionMissing,BuildSelfMonitorCells_CostRegression_CollectorNameComesFromRowContext(both cases),BuildSelfMonitorCells_CostRegression_NoCollectorName_UsesNoteInsteadOfScopedReads,BuildSelfMonitorCells_NeverEmitsAnEmptyCollectorNameParam(all 3 metrics),BuildSelfMonitorCells_EmitsNoPanelCell(all 3 metrics),BuildSelfMonitorCells_EveryReadCellParamIsDeclaredInItsCatalogEntry(all 3 metrics),SelfMonitorContext_SerializesAndRehydratesTheCollectorName. Sample assertion (AuthoredTemplate_SelfMonitorMetrics_AreNotNull, metric "Collection Stopped"):Assert.NotNull() Failure: Value of type 'Nullable<AuthoredTemplateEntry>' does not have a value— dev has no routing entry for these metrics, soAuthoredTemplate(...)returns null. Round-trip sample (SelfMonitorContext_SerializesAndRehydratesTheCollectorName):Assert.Equal() Failure: Strings differ \ Expected: "query_store" \ Actual: null— the null-returning shim can't round-trip a value. The one passing case out of 22,SelfMonitorContext_LegacyJsonWithNoCollectorNameMember_RehydratesNull, isn't a false green: it asserts the reader returns null for context JSON with noCollectorNamemember, and the null-returning shim satisfies that unconditionally, so it carries no signal either way. Shims removed with the scratch worktree; nothing from this step is committed.Lite (
PerformanceMonitor.Notifications/AlertContext.csis shared with Lite):Lite.Tests.dllcannot run in-process on this Mac — discovery dies onWindowsBase, per the repo's own documented limitation; build only.Lite.Tests/Lite.Tests.csprojbuilt clean (0 errors, 0 warnings) against the newCollectorNamefield. ReadLite.Tests/AnalysisNotificationTests.cs,Lite.Tests/FindingRoutingTests.cs,Lite.Tests/GenericWebhookTests.csandLite.Tests/AlertContextBuildersTests.cs, which coverAlertContextSerializer.Serialize/TryDeserializeround trips (analogous toWaitType's Darling-side pin) — none of them assert on a fixed member list, so a plain nullable field addition can't red them; they weren't changed here since they're existing, generic round-trip coverage, not a per-field census. CI's Lite job should confirm this on Windows: it runsAnalysisNotificationTests,FindingRoutingTests,GenericWebhookTestsandAlertContextBuildersTests, and none should change.CHANGELOG entry
SECTION: Added
ENTRY:
REF:
[Give Collection Stopped, Capture Down and Collector Cost Regression an authored self-monitor notebook (#4223) #4437]: Give Collection Stopped, Capture Down and Collector Cost Regression an authored self-monitor notebook (#4223) #4437