Fix/ppl lookback preview alert disable - #1501
Conversation
…make injection idempotent Signed-off-by: Riya Saxena <riysaxen@amazon.com>
Signed-off-by: Riya Saxena <riysaxen@amazon.com>
Signed-off-by: Riya Saxena <riysaxen@amazon.com>
…e disable action Signed-off-by: Riya Saxena <riysaxen@amazon.com>
|
The three UT runs failing:
|
lezzago
left a comment
There was a problem hiding this comment.
Code review findings
Ranked most-severe first.
1. Stale time filter left baked into query when lookback disabled (High)
public/pages/CreateMonitor/containers/CreateMonitor/utils/pplAlertingMonitorToFormik.js:40
On edit, pplQuery is hydrated with the previously injected time filter still embedded. The strip logic (stripTimeFilterFromQuery) only runs inside addTimeFilterToQuery, which pplFormikToMonitor.js:207 skips whenever lbMinutes <= 0.
Failure scenario: Edit a PPL monitor saved with lookback ON (stored query source=logs | where @timestamp > DATE_SUB(NOW(), INTERVAL 1 HOUR) | stats count()), uncheck the lookback window, and save. pplFormikToMonitor.js sees lbMinutes=0 and skips addTimeFilterToQuery, so stripTimeFilterFromQuery is never called; the persisted query still contains | where @timestamp > DATE_SUB(...). The monitor keeps filtering by the window the user just disabled, and the raw filter is shown verbatim in the query editor. Fix: strip during hydration, or strip unconditionally on save.
2. Silently swallowed error in disableSelectedMonitors (Medium)
public/pages/Dashboard/containers/DashboardClassic.js:364
The per-monitor catch block returns the error object without emitting any notification. err?.ok is undefined, so a thrown/network failure isn't counted as success and no error toast fires.
Failure scenario: disableSelectedMonitors runs; the httpClient.get or .put for a monitor throws (network error / timeout). The catch returns err, which isn't counted as success and fires no backendErrorNotification. The user selects a monitor, clicks Disable monitors, the monitor is NOT disabled, and no feedback appears — contradicting the PR's stated "failures surface per-monitor error notifications."
3. Unescaped $ in string replace injection (Low)
public/pages/CreateMonitor/containers/CreateMonitor/utils/pplAlertingHelpers.js:191
Injection uses cleanQuery.replace('|', \${timeFilterClause} |`). If timestampFieldever contains a-patterns (e.g. $&, $1) are interpreted rather than inserted literally, corrupting the injected clause. Low likelihood for typical field names, but the replacement is not escaped — a function replacer or split/join` would avoid it.
4. Redundant second queryString.parse (Low / maintainability)
public/pages/CreateMonitor/containers/CreateMonitor/utils/helpers.js:12
location.search is parsed a second time here solely to pull dataSourceId, duplicating the queryString.parse already done at line 40. Reuse the top-level parse for a single source of truth for URL params.
5. Inline duplication of Monitors.updateMonitor round-trip (Low / drift risk)
public/pages/Dashboard/containers/DashboardClassic.js:345
disableSelectedMonitors re-implements Monitors.updateMonitor's fetch-then-PUT (identical omit list, seqNo/primaryTerm/dataSourceId forwarding) inline. If the Monitors omit list changes later (e.g. a new server-managed field must be dropped), this copy will silently drift and PUT stale/invalid fields. Prefer extracting a shared disable-by-id helper rather than duplicating the body.
Generated by automated code review.
…date round-trip, surface thrown errors Signed-off-by: Riya Saxena <riysaxen@amazon.com>
All five addressed in 52c54e2: (1) |
…1505) * Accept v1-shape monitor body in PPL update guard and toV1MonitorBody The monitor details page enable/disable toggle round-trips the monitor in raw v1 shape (query nested in inputs[0].ppl_input.query, nothing at top level). toV1MonitorBody read only the top-level query and defaulted to '', so before the empty-query guard this path silently wiped the monitor's PPL query on every toggle; after the guard it was rejected outright. Fall back to inputs[0].ppl_input.query in both toV1MonitorBody and the updateMonitor guard so v1-shape bodies pass through with their query intact, while truly query-less bodies are still rejected. Signed-off-by: Riya Saxena <riysaxen@amazon.com> * Address review: drop v1/v2 language, add empty nested-query rejection tests - Rename toV1MonitorBody -> toEngineMonitorBody, flattenV1Monitor -> flattenEngineMonitor, and reword all v1/v2 comments to 'engine format' vs 'flattened format' (toepkerd) -- v2 APIs were never launched, so version language is a vestige of the removed v2 push. - Add tests asserting the guard still rejects engine-shape bodies whose nested query is empty or whose ppl_input is empty (eirsep). Signed-off-by: Riya Saxena <riysaxen@amazon.com> * Fix pre-existing main test failure: unwrap ppl_monitor in lookback-strip test buildPPLMonitorFromFormik returns the wrapped shape { ppl_monitor: {...} } (from #1500), but the lookback-strip test (from #1501) asserted query on the top-level return, which is undefined -- a semantic merge conflict between the two PRs that has kept the unit-test workflow red on main since Aug 20. Assert against ppl_monitor.query instead. Signed-off-by: Riya Saxena <riysaxen@amazon.com> * Address review: strip stale trigger metadata from engine-shape bodies, extract shared extractPplQuery helper - Unwrap ppl_trigger before stripping id/last_triggered_time/last_execution_time so the newly-accepted engine-shape bodies get the same trigger cleaning as the flattened path - Extract extractPplQuery() shared by the update guard and toEngineMonitorBody so the two can never drift apart - A whitespace-only top-level query no longer short-circuits the nested query fallback Signed-off-by: Riya Saxena <riysaxen@amazon.com> --------- Signed-off-by: Riya Saxena <riysaxen@amazon.com>
Description
Bug 1: Lookback window injects a frozen absolute time window.
addTimeFilterToQuerybuilt the lookback filter from absolute timestamps computed at save time:Since the filter is persisted into the monitor's query, every scheduled execution forever re-queries the same static window from the moment the monitor was saved — after the first interval elapses, the monitor can never match new data again.
Fix: inject a dynamic sliding window instead, evaluated by the engine at each execution:
The interval unit is derived from the configured window (MINUTE/HOUR/DAY). All call sites (save serialization plus the query/trigger previews) share the same helper, so they inherit the fix.
Bug 2: Query preview broken on monitor edit.
Two independent causes:
Stacked/stale time filters. On edit, the hydrated query already contains the previously injected lookback filter. Preview and re-save injected a second filter on top. Combined with Bug 1, the old filter's upper bound is entirely in the past, so preview on edit deterministically returned zero rows while create worked.
Fix:
addTimeFilterToQueryis now idempotent — a newstripTimeFilterFromQueryremoves any previously injected filter for the timestamp field (both the newDATE_SUBform and the legacy absoluteTIMESTAMP('...')form persisted by older saves) before injecting, so injection replaces rather than stacks. This also transparently migrates monitors saved with the old frozen filter the next time they are saved.dataSourceIddropped on edit. The edit branch ofgetInitialValuesrebuilds the formik values wholesale from the stored monitor, discarding the query-param initialization — and the stored monitor carries nodataSourceId. Preview and field-detection calls then fall back to whatever data source the page happens to have selected, which in MDS environments may not be the monitor's data source.Fix: preserve
dataSourceIdfrom the edit-page URL when hydrating a monitor for edit (both the PPL and default hydration paths).Bug 3: Monitors cannot be disabled from the Alerts page.
The Alerts page (
DashboardClassic) offered only Acknowledge / View alert details / View detector — there was no way to stop a noisy monitor without navigating to the Monitors page and finding it by name.Fix: add a Disable monitors action to the Alerts page toolbar. It collects the unique
monitor_ids behind the selected alerts (skipping chained/workflow alerts, for which the button stays disabled) and disables each via the same fetch-then-PUT round-trip the Monitors page uses — the full monitor body is fetched and written back with onlyenabled: falsechanged, so all monitor types (including PPL) are handled safely. Sequence-number concurrency params anddataSourceIdare forwarded, successes surface a toast, failures surface per-monitor error notifications, and the dashboard refreshes.Testing
public/pages/CreateMonitor/containers/CreateMonitor/utils/pplAlertingHelpers.test.js(9 tests for the time-filter helper): slidingDATE_SUBform with MINUTE/HOUR/DAY units, injection before the first pipe, preservation of complex piped queries, idempotence (re-injection replaces instead of stacking), replacement of the legacy absoluteTIMESTAMP('...')filter, and non-interference with user-written filters on other fields.| where @timestamp > DATE_SUB(NOW(), INTERVAL 1 HOUR)exactly once (network capture of the preview request), and the saved monitor persists the same form.DATE_SUBfilter on the same field is replaced, not duplicated.Related Issues
n/a — found while investigating PPL monitor reliability issues, follow-up to #1500.
Check List
--signoff.