Skip to content

Conversation

@nikhilsinhaparseable
Copy link
Contributor

@nikhilsinhaparseable nikhilsinhaparseable commented Nov 9, 2025

also exclude alert state from loading alerts

Summary by CodeRabbit

  • New Features

    • Filter alerts by arbitrary query parameters / custom fields with sorting and pagination.
    • Preserve and surface unknown extra fields in alert data and summaries.
  • Bug Fixes

    • Gracefully handle empty or missing created timestamps; defaults to current time and logs a warning.
    • Validate extra fields: reject more than 10 entries and disallow reserved field names.
  • Behavior Change

    • Exclude internal alert state files from alert listings.

also exclude alert state from loading alerts
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 9, 2025

Walkthrough

Adds flattened other_fields to alert request/config/response structs and propagates them through conversions; introduces a datetime deserializer that treats empty/missing created as now; enables HTTP-list filtering by arbitrary query params; and excludes alert_state_ files from alert object listings.

Changes

Cohort / File(s) Summary
Alert struct additions & deserialization
src/alerts/alert_structs.rs
Added pub other_fields: Option<serde_json::Map<String, Value>> with #[serde(flatten)] to AlertRequest, AlertConfig, AlertConfigResponse; added deserialize_datetime_with_empty_string_fallback and default_created_time; updated created serde attrs; introduced RESERVED_FIELDS; validated/propagated other_fields through conversions and responses.
Alert type updates
src/alerts/alert_types.rs
Added other_fields: Option<serde_json::Map<String, Value>> (with #[serde(flatten)]) to ThresholdAlert; updated its created serde attrs; updated From/From conversions to carry other_fields.
Alerts module surface & summary
src/alerts/mod.rs
Re-exported default_created_time and deserialize_datetime_with_empty_string_fallback; initialize other_fields during migration; include other_fields entries in AlertConfig::to_summary.
HTTP alerts filtering & pagination
src/handlers/http/alerts.rs
Added query parsing (reserved params vs dynamic), ListQueryParams, parse_list_query_params, filter_by_other_fields, sort_alerts, paginate_alerts; apply dynamic-field filtering before sort/pagination; defined RESERVED_PARAMS, MAX_LIMIT, DEFAULT_LIMIT.
Object store listing filter
src/metastore/metastores/object_store_metastore.rs
Adjusted alerts object listing to exclude filenames starting with alert_state_ in addition to .json filter.

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant HTTP as AlertsHandler
  participant Service as AlertService
  participant Store as Metastore

  Note over Client,HTTP: GET /alerts with reserved + dynamic query params
  Client->>HTTP: request (tags, offset, limit, region=us, foo=bar)
  HTTP->>Service: parse params → ListQueryParams (reserved, other_fields_filters)
  Service->>Store: list alert objects (filter ".json" AND NOT "alert_state_*")
  Store-->>Service: object list
  Service->>Service: deserialize -> AlertConfig (created uses fallback/default)
  Service->>Service: to summaries (include other_fields)
  Service->>Service: filter_by_other_fields (match all dynamic filters)
  Service->>Service: sort_alerts → paginate_alerts
  Service-->>HTTP: paginated, sorted summaries
  HTTP-->>Client: 200 OK (response)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • Inspect custom deserializer behavior and logging for empty created values.
  • Verify #[serde(flatten)] avoids key collisions and reserved-field validation in AlertRequest::into.
  • Review HTTP dynamic filtering logic for type/format matching and pagination/sorting integration.
  • Confirm object-store exclusion rule doesn't discard valid alerts.

Possibly related PRs

  • #1424: Modifies AlertConfig/AlertRequest/ThresholdAlert and metastore wiring — overlaps on struct fields and persistence handling.
  • #1408: Changes AlertRequest validation and conversions — relates to AlertRequest::into validation and other_fields.
  • #1389: Adjusts AlertConfig created/serialization behavior — relates to created deserialization/default handling.

Suggested labels

for next release

Poem

🐰
I stash stray fields in a cozy burrow,
Empty timestamps bounce to now, not sorrow,
Queries sniff out regions and clay,
Old state-files hop quietly away,
I thump my paw and ship—hip, hip, hooray!

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Description check ⚠️ Warning The PR description is incomplete and does not follow the template. It only mentions one minor change (excluding alert state) but does not describe the main objective of adding other_fields to alerts or explain the rationale. Expand the description to explain the goal of adding other_fields support, describe the changes across AlertRequest/AlertConfig/AlertConfigResponse, and address testing/documentation requirements from the template.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main changes: adding other_fields to alert request, config, and response structures.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a91a3cc and 73d88d7.

📒 Files selected for processing (5)
  • src/alerts/alert_structs.rs (7 hunks)
  • src/alerts/alert_types.rs (5 hunks)
  • src/alerts/mod.rs (2 hunks)
  • src/handlers/http/alerts.rs (3 hunks)
  • src/metastore/metastores/object_store_metastore.rs (1 hunks)
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-10-24T11:54:20.269Z
Learnt from: parmesant
Repo: parseablehq/parseable PR: 1449
File: src/metastore/metastores/object_store_metastore.rs:83-98
Timestamp: 2025-10-24T11:54:20.269Z
Learning: In the `get_overviews` method in `src/metastore/metastores/object_store_metastore.rs`, using `.ok()` to convert all storage errors to `None` when fetching overview objects is the intended behavior. This intentionally treats missing files and other errors (network, permissions, etc.) the same way.

Applied to files:

  • src/metastore/metastores/object_store_metastore.rs
📚 Learning: 2025-07-24T11:09:21.781Z
Learnt from: nikhilsinhaparseable
Repo: parseablehq/parseable PR: 1388
File: src/alerts/mod.rs:88-104
Timestamp: 2025-07-24T11:09:21.781Z
Learning: In the Parseable alert system (src/alerts/mod.rs), alert versions are server-generated and controlled via CURRENT_ALERTS_VERSION constant, not user input. The AlertVerison enum's From<&str> implementation correctly defaults unknown versions to V2 since the server only generates known versions (v1, v2). Unknown versions would only occur in exceptional cases like file corruption, making the current fallback approach appropriate.

Applied to files:

  • src/alerts/alert_types.rs
  • src/alerts/alert_structs.rs
  • src/alerts/mod.rs
🧬 Code graph analysis (3)
src/alerts/alert_types.rs (1)
src/alerts/alert_structs.rs (2)
  • default_created_time (84-86)
  • deserialize_datetime_with_empty_string_fallback (52-80)
src/alerts/alert_structs.rs (1)
src/alerts/mod.rs (1)
  • serde_json (1034-1034)
src/alerts/mod.rs (1)
src/event/mod.rs (1)
  • map (137-137)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (10)
  • GitHub Check: Build Default x86_64-pc-windows-msvc
  • GitHub Check: coverage
  • GitHub Check: Quest Smoke and Load Tests for Distributed deployments
  • GitHub Check: Quest Smoke and Load Tests for Standalone deployments
  • GitHub Check: Build Default x86_64-apple-darwin
  • GitHub Check: Build Default aarch64-apple-darwin
  • GitHub Check: Build Default aarch64-unknown-linux-gnu
  • GitHub Check: Build Default x86_64-unknown-linux-gnu
  • GitHub Check: Build Kafka aarch64-apple-darwin
  • GitHub Check: Build Kafka x86_64-unknown-linux-gnu
🔇 Additional comments (15)
src/metastore/metastores/object_store_metastore.rs (1)

183-185: LGTM! Proper separation of alert configs from alert state files.

The filter correctly excludes alert state files when retrieving alerts, ensuring only alert configuration files are loaded. This aligns with the separate get_alert_states() method for retrieving state-specific files.

src/handlers/http/alerts.rs (2)

54-56: LGTM! Clean separation of reserved and dynamic query parameters.

The reserved parameters list is well-defined, and the other_fields_filters map provides a clean way to capture arbitrary additional filters.


94-100: LGTM! Correct collection of non-reserved query parameters.

The loop properly filters out reserved parameters and collects the remaining fields for filtering alerts.

src/alerts/mod.rs (2)

137-137: LGTM! Correct initialization of other_fields during v1 migration.

Setting other_fields: None is appropriate for v1 alerts that didn't have this field, maintaining backward compatibility.


686-690: LGTM! Proper propagation of other_fields to alert summary.

The implementation correctly includes dynamic fields in the summary when present, placed after standard fields to avoid accidental overwrites.

src/alerts/alert_types.rs (4)

22-22: LGTM! Necessary imports for other_fields and datetime handling.

The imports support the new other_fields functionality and robust datetime deserialization.

Also applies to: 32-35


68-71: LGTM! Robust datetime handling for the created field.

The serde attributes provide graceful handling of legacy data with empty timestamps while maintaining backward compatibility.


76-77: LGTM! Correct implementation of other_fields with serde flatten.

The use of #[serde(flatten)] properly captures arbitrary additional fields during deserialization while maintaining the optional nature of the field.


421-421: LGTM! Bidirectional propagation of other_fields in conversions.

Both conversion implementations correctly preserve other_fields, ensuring no data loss during type transformations between AlertConfig and ThresholdAlert.

Also applies to: 445-445

src/alerts/alert_structs.rs (6)

42-86: LGTM! Excellent implementation of backward-compatible datetime handling.

The custom deserializer is well-documented and handles legacy data gracefully:

  • Supports valid timestamps, empty strings, and missing fields
  • Logs warnings for data quality issues
  • Clear migration path documentation

This is a good example of defensive programming for data migration scenarios.


303-304: LGTM! Consistent addition of other_fields to AlertRequest.

The flattened optional field allows clients to include arbitrary additional metadata in alert requests.


361-361: LGTM! Correct propagation of other_fields during request conversion.

The implementation ensures that dynamic fields from the alert request are preserved in the resulting AlertConfig.


386-394: LGTM! Consistent datetime handling and other_fields implementation in AlertConfig.

The serde attributes match those in ThresholdAlert, ensuring consistent behavior across alert types.


418-426: LGTM! Complete propagation of other_fields to API responses.

The AlertConfigResponse correctly includes the same datetime handling and other_fields as AlertConfig, ensuring API clients receive all alert metadata.


466-466: LGTM! Final link in other_fields propagation chain.

The implementation ensures that dynamic fields are preserved all the way through to API responses, completing the end-to-end data flow.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
src/alerts/alert_structs.rs (1)

42-80: Well-designed compatibility layer for legacy timestamps.

The deserializer correctly handles empty strings, missing fields, and valid timestamps. The warning logging is helpful for identifying data quality issues.

Note: If many legacy alerts contain empty created fields, the warning logs could be verbose during alert loading. Consider monitoring log volume and possibly implementing a summary message (e.g., "Found N alerts with empty created timestamps") if this becomes an issue.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 73d88d7 and 9a9f929.

📒 Files selected for processing (2)
  • src/alerts/alert_structs.rs (7 hunks)
  • src/alerts/mod.rs (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/alerts/mod.rs
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-07-24T11:09:21.781Z
Learnt from: nikhilsinhaparseable
Repo: parseablehq/parseable PR: 1388
File: src/alerts/mod.rs:88-104
Timestamp: 2025-07-24T11:09:21.781Z
Learning: In the Parseable alert system (src/alerts/mod.rs), alert versions are server-generated and controlled via CURRENT_ALERTS_VERSION constant, not user input. The AlertVerison enum's From<&str> implementation correctly defaults unknown versions to V2 since the server only generates known versions (v1, v2). Unknown versions would only occur in exceptional cases like file corruption, making the current fallback approach appropriate.

Applied to files:

  • src/alerts/alert_structs.rs
🧬 Code graph analysis (1)
src/alerts/alert_structs.rs (1)
src/alerts/mod.rs (1)
  • serde_json (1034-1034)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (10)
  • GitHub Check: Quest Smoke and Load Tests for Standalone deployments
  • GitHub Check: Quest Smoke and Load Tests for Distributed deployments
  • GitHub Check: Build Default x86_64-pc-windows-msvc
  • GitHub Check: Build Kafka x86_64-unknown-linux-gnu
  • GitHub Check: Build Default aarch64-unknown-linux-gnu
  • GitHub Check: Build Default aarch64-apple-darwin
  • GitHub Check: Build Default x86_64-unknown-linux-gnu
  • GitHub Check: Build Default x86_64-apple-darwin
  • GitHub Check: coverage
  • GitHub Check: Build Kafka aarch64-apple-darwin
🔇 Additional comments (6)
src/alerts/alert_structs.rs (6)

22-23: LGTM!

The new imports are necessary for the custom deserializer and dynamic field handling introduced in this PR.


82-86: LGTM!

Clean helper function that provides a sensible default for missing created timestamps.


361-361: LGTM!

Correctly propagates other_fields from the request to the alert configuration.


386-394: LGTM!

The combination of default and deserialize_with on the created field correctly handles missing fields, empty strings, and valid timestamps. The other_fields addition maintains consistency with AlertRequest.


418-426: LGTM!

The datetime handling and other_fields implementation are consistent with AlertConfig.


466-466: LGTM!

Correctly propagates other_fields to the response, ensuring arbitrary fields are preserved through the entire request-config-response lifecycle.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (2)
src/handlers/http/alerts.rs (2)

154-191: Consider handling invalid enum parsing more explicitly.

The sort function defaults to AlertState::NotTriggered and Severity::Low when parsing fails (lines 162, 174). While this ensures the sort never fails, it silently swallows parsing errors. If an alert summary contains malformed state/severity data, it will be sorted incorrectly without any indication.

Consider logging a warning when parsing fails, or verifying that alert summaries always contain valid enum strings.

let state_a = a
    .get("state")
    .and_then(|v| v.as_str())
    .and_then(|s| {
        s.parse::<AlertState>().ok().or_else(|| {
            tracing::warn!("Failed to parse alert state: {}", s);
            Some(AlertState::NotTriggered)
        })
    })
    .unwrap_or(AlertState::NotTriggered);

136-145: Document array/object filtering behavior for complex query parameters.

While the current implementation correctly converts arrays/objects to JSON strings for comparison (e.g., [1,2,3]), users might expect more flexible matching. For example, ?ids=[1, 2, 3] (with spaces) won't match [1,2,3] (no spaces) due to exact string comparison.

Consider adding a comment or documentation explaining that:

  • Array/object query parameters must match the exact JSON representation
  • Whitespace matters in the comparison
  • Alternatively, normalize JSON strings before comparison (e.g., by parsing and re-serializing both sides)
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9a9f929 and dbf882d.

📒 Files selected for processing (2)
  • src/alerts/alert_structs.rs (7 hunks)
  • src/handlers/http/alerts.rs (2 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-07-24T11:09:21.781Z
Learnt from: nikhilsinhaparseable
Repo: parseablehq/parseable PR: 1388
File: src/alerts/mod.rs:88-104
Timestamp: 2025-07-24T11:09:21.781Z
Learning: In the Parseable alert system (src/alerts/mod.rs), alert versions are server-generated and controlled via CURRENT_ALERTS_VERSION constant, not user input. The AlertVerison enum's From<&str> implementation correctly defaults unknown versions to V2 since the server only generates known versions (v1, v2). Unknown versions would only occur in exceptional cases like file corruption, making the current fallback approach appropriate.

Applied to files:

  • src/alerts/alert_structs.rs
🧬 Code graph analysis (2)
src/handlers/http/alerts.rs (2)
src/alerts/mod.rs (6)
  • value (415-415)
  • value (423-423)
  • value (431-431)
  • value (444-444)
  • value (455-455)
  • alerts (1329-1333)
src/utils/actix.rs (1)
  • extract_session_key_from_req (51-71)
src/alerts/alert_structs.rs (1)
src/alerts/mod.rs (1)
  • serde_json (1034-1034)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (10)
  • GitHub Check: coverage
  • GitHub Check: Quest Smoke and Load Tests for Distributed deployments
  • GitHub Check: Quest Smoke and Load Tests for Standalone deployments
  • GitHub Check: Build Default x86_64-pc-windows-msvc
  • GitHub Check: Build Kafka x86_64-unknown-linux-gnu
  • GitHub Check: Build Default aarch64-apple-darwin
  • GitHub Check: Build Default aarch64-unknown-linux-gnu
  • GitHub Check: Build Default x86_64-unknown-linux-gnu
  • GitHub Check: Build Kafka aarch64-apple-darwin
  • GitHub Check: Build Default x86_64-apple-darwin
🔇 Additional comments (8)
src/alerts/alert_structs.rs (4)

27-46: LGTM – Comprehensive reserved field protection.

The RESERVED_FIELDS constant provides effective protection against field name collisions by covering all critical alert fields. This is a solid defensive measure.


73-101: LGTM – Robust compatibility layer for legacy datetime handling.

The custom deserializer gracefully handles empty string timestamps from legacy data while logging warnings. The untagged enum approach correctly prioritizes valid datetime parsing before falling back to string handling.


329-348: LGTM – Validation effectively addresses previous security concerns.

The validation logic successfully prevents key collision by checking against RESERVED_FIELDS and enforces a reasonable 10-field limit to prevent abuse. This addresses the security concerns raised in previous reviews.

Based on learnings


427-430: Implementation verified: all three scenarios are handled correctly.

The code properly handles the interaction between default and deserialize_with:

  1. Missing fielddefault_created_time is invoked, returns Utc::now() (per serde semantics, default applies only when field absent)
  2. Empty string → custom deserializer processes it, logs warning (lines 91–93), returns Utc::now() (line 96)
  3. Valid timestamp → deserializer parses successfully (line 100)

The behavior matches the stated expectations. No issues found.

src/handlers/http/alerts.rs (4)

54-120: LGTM – Comprehensive query parameter parsing and validation.

The parsing logic correctly validates:

  • Empty tags after splitting (lines 79-83)
  • Numeric offset and limit (lines 88-91, 95-97)
  • Limit bounds (1 to 1000) (lines 100-104)

The separation of reserved vs. non-reserved parameters is clean and maintainable.


122-152: LGTM – Filtering now correctly handles non-string JSON types.

The updated filtering logic (lines 136-145) successfully addresses the previous concern about non-string values by:

  • Using .as_str() for JSON strings to avoid quote wrapping
  • Using .to_string() for numbers, booleans, arrays, and objects

This ensures query parameters like ?count=5 correctly match JSON numbers, and ?active=true matches boolean values.


193-204: LGTM – Clean pagination implementation.

The pagination logic correctly applies offset and limit after filtering and sorting, which is the correct order of operations.


206-244: LGTM – Well-structured list handler with clear flow.

The refactored handler follows a logical pipeline:

  1. Parse and validate query parameters
  2. Fetch user-specific alerts
  3. Convert to summaries
  4. Filter by other_fields
  5. Sort by priority
  6. Paginate results

The separation of concerns makes the code maintainable and testable.

@nitisht nitisht merged commit cbb8942 into parseablehq:main Nov 9, 2025
13 checks passed
@nikhilsinhaparseable nikhilsinhaparseable deleted the alert-query-param branch November 9, 2025 18:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants