Skip to content

fix: classify cancelled requests with "cancelled" status instead of "error" in logging, telemetry, and analytics queries - #2666

Closed
Raajheer1 wants to merge 3 commits into
maximhq:devfrom
Raajheer1:fix/cancelled-request-status
Closed

Raajheer1 wants to merge 3 commits into
maximhq:devfrom
Raajheer1:fix/cancelled-request-status

Conversation

@Raajheer1

Copy link
Copy Markdown

Summary

Briefly explain the purpose of this PR and the problem it solves.

Changes

  • What was changed and why
  • Any notable design decisions or trade-offs

Type of change

  • Bug fix
  • Feature
  • Refactor
  • Documentation
  • Chore/CI

Affected areas

  • Core (Go)
  • Transports (HTTP)
  • Providers/Integrations
  • Plugins
  • UI (Next.js)
  • Docs

How to test

Describe the steps to validate this change. Include commands and expected outcomes.

# Core/Transports
go version
go test ./...

# UI
cd ui
pnpm i || npm i
pnpm test || npm test
pnpm build || npm run build

If adding new configs or environment variables, document them here.

Screenshots/Recordings

If UI changes, add before/after screenshots or short clips.

Breaking changes

  • Yes
  • No

If yes, describe impact and migration instructions.

Related issues

Link related issues and discussions. Example: Closes #123

Security considerations

Note any security implications (auth, secrets, PII, sandboxing, etc.).

Checklist

  • I read docs/contributing/README.md and followed the guidelines
  • I added/updated tests where appropriate
  • I updated documentation where needed
  • I verified builds succeed (Go and UI)
  • I verified the CI pipeline passes locally if applicable

…error" in logging, telemetry, and analytics queries
@coderabbitai

coderabbitai Bot commented Apr 13, 2026

Copy link
Copy Markdown
Contributor

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: c8297948-f790-4000-8fb3-a53323994aa8

📥 Commits

Reviewing files that changed from the base of the PR and between fe576aa and a7048d2.

📒 Files selected for processing (1)
  • core/schemas/bifrost.go

📝 Walkthrough

Summary by CodeRabbit

  • New Features

    • Added a Prometheus metric to track cancelled requests separately.
    • Logging and telemetry now record cancelled requests distinctly from errors.
  • Bug Fixes

    • Fixed misclassification of cancelled requests that were previously reported as errors.
    • Raw log aggregation now includes cancelled rows while analytic success/error aggregations continue to exclude cancelled for those metrics.
  • Documentation

    • Log status documentation updated to include "cancelled".

Walkthrough

Adds explicit detection and handling of request-cancelled errors: new BifrostError helper, logging and telemetry emit/record "cancelled" status/metric, materialized view and model docs updated to include cancelled, and analytics queries consolidated to exclude cancelled where appropriate.

Changes

Cohort / File(s) Summary
Error Classification
core/schemas/bifrost.go
Added func (e *BifrostError) IsRequestCancelled() bool to detect request-cancelled errors.
Database Materialized View
framework/logstore/matviews.go
mv_logs_hourly view now includes status = 'cancelled' in its source WHERE clause, affecting hourly aggregations.
Query Status Consolidation
framework/logstore/rdb.go
Introduced shared status slices (completedStatuses, analyticsStatuses) and replaced many inline ['success','error'] predicates with analyticsStatuses (which excludes cancelled) across multiple analytics/query builders.
Log Model Documentation
framework/logstore/tables.go
Extended Log.Status comment to document "cancelled" as a valid status value (no type/tag changes).
Logging Integration
plugins/logging/main.go
PostLLMHook now sets Status = "cancelled" when upstream error indicates request cancellation and avoids overwriting "cancelled" in passthrough status-code logic.
Telemetry / Metrics
plugins/telemetry/main.go
Added CancelledRequestsTotal *prometheus.CounterVec, registered bifrost_cancelled_requests_total, and incremented it for request-cancelled errors in PostLLMHook.

Sequence Diagram

sequenceDiagram
    participant Client
    participant LLMHandler
    participant LoggerPlugin
    participant LogStore
    participant TelemetryPlugin
    participant Prometheus

    Client->>LLMHandler: Send request (may be cancelled)
    LLMHandler->>LLMHandler: Process request / detect cancellation
    LLMHandler->>LoggerPlugin: PostLLMHook (bifrostErr)
    LoggerPlugin->>LoggerPlugin: IsRequestCancelled() / inspect Error.Type
    alt cancelled
        LoggerPlugin->>LogStore: Save log entry (status="cancelled")
        LoggerPlugin->>TelemetryPlugin: Notify cancelled
        TelemetryPlugin->>Prometheus: Increment bifrost_cancelled_requests_total
    else non-cancelled error
        LoggerPlugin->>LogStore: Save log entry (status="error"/"success")
        LoggerPlugin->>TelemetryPlugin: Notify error or success
        TelemetryPlugin->>Prometheus: Increment appropriate metric
    end
    LogStore->>LogStore: Persist / materialized views aggregate (hourly includes cancelled)
    Prometheus->>Prometheus: Record metric
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Poem

🐰 I hopped through logs and metrics bright,
Found a cancelled whisper in the night.
Counters count it, views now see,
Status set true — that's clarity!
A tiny rabbit cheers with glee.

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Description check ⚠️ Warning The PR description is entirely templated with no substantial content filled in; all sections remain as placeholders without narrative explanation of changes, rationale, or testing approach. Complete the description by filling in the Summary, Changes, Type of change checkbox, Affected areas, How to test steps, Related issues link, and other applicable sections with concrete details.
Linked Issues check ⚠️ Warning The PR objectives do not match the linked issue (#123 is about Files API support); the actual changes address cancelled request status classification, which is unrelated to the linked issue. Either link the correct issue(s) that specify cancelled request status handling requirements, or clarify the relationship to issue #123 if it is indeed correct.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The PR title clearly and specifically describes the main change: classifying cancelled requests with 'cancelled' status instead of 'error' in logging, telemetry, and analytics queries.
Out of Scope Changes check ✅ Passed All changes consistently implement cancelled request status classification across schemas, logging, telemetry, analytics, and materialized views—directly aligned with the PR title intent and no unrelated modifications detected.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@greptile-apps

greptile-apps Bot commented Apr 13, 2026

Copy link
Copy Markdown
Contributor

Confidence Score: 3/5

Not safe to merge as-is — two P1 regressions affect live analytics correctness and a filter used for cost backfill.

The core status-classification logic is correct throughout logging and telemetry, but two concrete data-correctness regressions remain: (1) the matview-based success rate calculation is now wrong on Postgres, giving different numbers than the raw-SQL path; (2) the MissingCostOnly filter is now broken for all users with cancelled requests.

framework/logstore/matviews.go (getStatsFromMatView success rate denominator) and framework/logstore/rdb.go (MissingCostOnly filter)

Important Files Changed

Filename Overview
core/schemas/bifrost.go Adds RequestCancelled constant and IsRequestCancelled() helper on *BifrostError — straightforward and correct.
framework/logstore/matviews.go Materialized view DDL correctly adds 'cancelled' to the WHERE clause, but getStatsFromMatView still uses SUM(count) (now includes cancelled) as the success rate denominator, producing a diluted rate inconsistent with the non-matview path and the stated intent of analyticsStatuses.
framework/logstore/rdb.go Introduces completedStatuses/analyticsStatuses split with clear intent, but the MissingCostOnly filter was not updated and now surfaces all cancelled requests (which always have null/zero cost).
framework/logstore/tables.go Data model and status constant definitions look correct.
plugins/logging/main.go Correctly sets status = 'cancelled' in all four logging paths and guards 'cancelled' from being overwritten by the passthrough error flip.
plugins/telemetry/main.go Correctly routes cancelled requests to CancelledRequestsTotal counter instead of ErrorRequestsTotal.

Comments Outside Diff (1)

  1. framework/logstore/matviews.go, line 241-253 (link)

    P1 getStatsFromMatView success rate diluted by cancelled requests

    The matview DDL now includes status IN ('success', 'error', 'cancelled') so COUNT(*) AS count in the materialized view includes cancelled rows. getStatsFromMatView then computes successRate = SuccessCount / TotalCount, where TotalCount = SUM(count) = success + error + cancelled. This directly contradicts the explicit design intent of analyticsStatuses (defined in rdb.go) which states "Excludes 'cancelled' so that totals equal success + error and success rate is not diluted by client cancellations."

    The non-matview GetStats path correctly restricts to analyticsStatuses before computing the rate, so the same query returns different success rates on Postgres (via matview) vs. other DBs or when matview can't be used.

    To fix, use the matview's already-present success_count and error_count as the denominator, and change the success rate to SuccessCount / AnalyticsCount. Similarly, getHistogramFromMatView uses SUM(count) AS total while the non-matview GetHistogram path filters to analyticsStatuses, causing histogram totals to be higher on Postgres than on other DBs for the same data.

Reviews (3): Last reviewed commit: "Update core/schemas/bifrost.go" | Re-trigger Greptile

Comment thread core/schemas/bifrost.go

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
framework/logstore/matviews.go (1)

34-46: ⚠️ Potential issue | 🟠 Major

Materialize cancelled_count before widening the view filter.

After this change, count includes cancelled rows, but the view still only stores success_count and error_count. Every PostgreSQL fast-path query built on mv_logs_hourly now loses the new status and can no longer reconcile the exposed breakdown with the total. Add a cancelled_count aggregate here and thread it through the consumers before expanding the source filter.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@framework/logstore/matviews.go` around lines 34 - 46, The view aggregates in
mv_logs_hourly are missing cancelled_count, causing totals to mismatch after
widening the WHERE filter; add SUM(CASE WHEN status = 'cancelled' THEN 1 ELSE 0
END) AS cancelled_count alongside success_count and error_count in the SELECT
that builds mv_logs_hourly (the SQL block in framework/logstore/matviews.go),
then update all consumers and functions that consume mv_logs_hourly (e.g., any
code reading success_count, error_count, total or performing reconciliation) to
accept and use cancelled_count so totals reconcile correctly before expanding
the source filter.
🧹 Nitpick comments (3)
core/schemas/bifrost.go (1)

898-901: Make IsRequestCancelled() nil-safe.

As written, this helper still panics on a nil *BifrostError, so the older call sites in core/bifrost.go still can't collapse to a single predicate. Adding the nil check lets this become the one canonical cancellation test.

♻️ Proposed fix
 func (e *BifrostError) IsRequestCancelled() bool {
-	return e.Error != nil && e.Error.Type != nil && *e.Error.Type == RequestCancelled
+	return e != nil && e.Error != nil && e.Error.Type != nil && *e.Error.Type == RequestCancelled
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@core/schemas/bifrost.go` around lines 898 - 901, The IsRequestCancelled
method can panic when called on a nil *BifrostError; update IsRequestCancelled
to first check the receiver for nil (e == nil) before accessing e.Error and
e.Error.Type, then return false if nil; keep the existing checks for e.Error and
e.Error.Type and the final comparison to RequestCancelled so IsRequestCancelled
becomes a nil-safe canonical cancellation predicate.
plugins/logging/main.go (1)

642-643: Use IsRequestCancelled() instead of repeating nested error-type checks.

The same cancellation predicate is duplicated in four locations. Switching to bifrostErr.IsRequestCancelled() keeps classification logic centralized and aligned with the shared schema helper.

Refactor sketch
-			if bifrostErr.Error != nil && bifrostErr.Error.Type != nil && *bifrostErr.Error.Type == schemas.RequestCancelled {
+			if bifrostErr.IsRequestCancelled() {
 				status = "cancelled"
 			}
...
-		if bifrostErr.Error != nil && bifrostErr.Error.Type != nil && *bifrostErr.Error.Type == schemas.RequestCancelled {
+		if bifrostErr.IsRequestCancelled() {
 			entry.Status = "cancelled"
 		}

Also applies to: 684-685, 730-731, 771-772

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@plugins/logging/main.go` around lines 642 - 643, Replace the repeated nested
cancellation checks (e.g., if bifrostErr.Error != nil && bifrostErr.Error.Type
!= nil && *bifrostErr.Error.Type == schemas.RequestCancelled) with the shared
predicate method bifrostErr.IsRequestCancelled(); in each block where you
currently set status = "cancelled" (the occurrences around the duplicated
checks) call bifrostErr.IsRequestCancelled() and set status = "cancelled" when
it returns true, removing the duplicated nil/type dereferencing logic so
cancellation classification is centralized.
plugins/telemetry/main.go (1)

490-494: Prefer bifrostErr.IsRequestCancelled() for cancellation classification.

Use the shared helper here as well to keep telemetry classification logic aligned with schema-level behavior and avoid duplicated nested checks.

Refactor sketch
-			if bifrostErr.Error != nil && bifrostErr.Error.Type != nil && *bifrostErr.Error.Type == schemas.RequestCancelled {
+			if bifrostErr.IsRequestCancelled() {
 				p.CancelledRequestsTotal.WithLabelValues(errorPromLabelValues...).Inc()
 			} else {
 				p.ErrorRequestsTotal.WithLabelValues(errorPromLabelValues...).Inc()
 			}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@plugins/telemetry/main.go` around lines 490 - 494, Replace the nested
nil/type checks with the shared helper by calling
bifrostErr.IsRequestCancelled() to classify cancellations; if that returns true
increment
p.CancelledRequestsTotal.WithLabelValues(errorPromLabelValues...).Inc(),
otherwise increment
p.ErrorRequestsTotal.WithLabelValues(errorPromLabelValues...).Inc(); this
removes the duplicated nested checks (the current bifrostErr.Error != nil &&
bifrostErr.Error.Type != nil && *bifrostErr.Error.Type ==
schemas.RequestCancelled) while preserving the existing label usage and else
branch behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@framework/logstore/rdb.go`:
- Around line 26-28: The shared variable completedStatuses currently includes
"cancelled" and is being reused by analytics endpoints (SearchStats,
MCPToolLogStats, HistogramBucket, MCPHistogramBucket, ModelUsageStats) which
only return success/error buckets, causing totals to mismatch; fix by
introducing a separate filter variable (e.g., completedStatusesWithCancelled)
for queries that should include cancelled and keep the existing
analytics-specific slice as []string{"success","error"} for those functions,
then update callers: have functions that need cancelled use
completedStatusesWithCancelled and leave SearchStats, MCPToolLogStats,
HistogramBucket, MCPHistogramBucket, and ModelUsageStats using the two-status
slice so count == success + error.

In `@plugins/logging/main.go`:
- Around line 730-732: The "cancelled" classification set via entry.Status =
"cancelled" when bifrostErr.Error.Type == schemas.RequestCancelled is later
overwritten by the passthrough error branch; update the passthrough
error-setting logic so it preserves an existing cancelled status: when you set
entry.Status = "error" in the streaming passthrough path (the block that
inspects passthrough/4xx/5xx), first check if entry.Status == "cancelled" (or
re-check bifrostErr.Error.Type == schemas.RequestCancelled) and skip overwriting
if so; apply the same guard to both passthrough error sites mentioned so
cancelled remains authoritative.

---

Outside diff comments:
In `@framework/logstore/matviews.go`:
- Around line 34-46: The view aggregates in mv_logs_hourly are missing
cancelled_count, causing totals to mismatch after widening the WHERE filter; add
SUM(CASE WHEN status = 'cancelled' THEN 1 ELSE 0 END) AS cancelled_count
alongside success_count and error_count in the SELECT that builds mv_logs_hourly
(the SQL block in framework/logstore/matviews.go), then update all consumers and
functions that consume mv_logs_hourly (e.g., any code reading success_count,
error_count, total or performing reconciliation) to accept and use
cancelled_count so totals reconcile correctly before expanding the source
filter.

---

Nitpick comments:
In `@core/schemas/bifrost.go`:
- Around line 898-901: The IsRequestCancelled method can panic when called on a
nil *BifrostError; update IsRequestCancelled to first check the receiver for nil
(e == nil) before accessing e.Error and e.Error.Type, then return false if nil;
keep the existing checks for e.Error and e.Error.Type and the final comparison
to RequestCancelled so IsRequestCancelled becomes a nil-safe canonical
cancellation predicate.

In `@plugins/logging/main.go`:
- Around line 642-643: Replace the repeated nested cancellation checks (e.g., if
bifrostErr.Error != nil && bifrostErr.Error.Type != nil &&
*bifrostErr.Error.Type == schemas.RequestCancelled) with the shared predicate
method bifrostErr.IsRequestCancelled(); in each block where you currently set
status = "cancelled" (the occurrences around the duplicated checks) call
bifrostErr.IsRequestCancelled() and set status = "cancelled" when it returns
true, removing the duplicated nil/type dereferencing logic so cancellation
classification is centralized.

In `@plugins/telemetry/main.go`:
- Around line 490-494: Replace the nested nil/type checks with the shared helper
by calling bifrostErr.IsRequestCancelled() to classify cancellations; if that
returns true increment
p.CancelledRequestsTotal.WithLabelValues(errorPromLabelValues...).Inc(),
otherwise increment
p.ErrorRequestsTotal.WithLabelValues(errorPromLabelValues...).Inc(); this
removes the duplicated nested checks (the current bifrostErr.Error != nil &&
bifrostErr.Error.Type != nil && *bifrostErr.Error.Type ==
schemas.RequestCancelled) while preserving the existing label usage and else
branch behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 31c14967-8b8a-4cc7-94ea-06104c776e37

📥 Commits

Reviewing files that changed from the base of the PR and between 0fc568d and 6f716a0.

📒 Files selected for processing (6)
  • core/schemas/bifrost.go
  • framework/logstore/matviews.go
  • framework/logstore/rdb.go
  • framework/logstore/tables.go
  • plugins/logging/main.go
  • plugins/telemetry/main.go

Comment thread framework/logstore/rdb.go
Comment thread plugins/logging/main.go
…elled from analytics queries, and add guard for status preservation
coderabbitai[bot]
coderabbitai Bot previously approved these changes Apr 14, 2026
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
coderabbitai[bot]
coderabbitai Bot previously approved these changes Apr 16, 2026
@CLAassistant

Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you all sign our Contributor License Agreement before we can accept your contribution.
1 out of 2 committers have signed the CLA.

✅ Raajheer1
❌ akshaydeo
You have signed the CLA already but the status is still pending? Let us recheck it.

@akshaydeo
akshaydeo changed the base branch from main to dev May 16, 2026 11:58
@akshaydeo
akshaydeo dismissed coderabbitai[bot]’s stale review May 16, 2026 11:58

The base branch was changed.

@akshaydeo
akshaydeo force-pushed the dev branch 5 times, most recently from d36cd75 to 5e4bfb7 Compare May 26, 2026 18:59
@akshaydeo
akshaydeo force-pushed the dev branch 3 times, most recently from 6711ce3 to a1beab5 Compare June 4, 2026 10:02
@akshaydeo
akshaydeo force-pushed the dev branch 2 times, most recently from e389df7 to a65fce4 Compare June 8, 2026 11:25
@akshaydeo
akshaydeo force-pushed the dev branch 4 times, most recently from fa15f50 to ca190fc Compare June 21, 2026 11:44
@akshaydeo
akshaydeo force-pushed the dev branch 2 times, most recently from ac30a53 to 7c66b20 Compare July 1, 2026 12:24
@Raajheer1 Raajheer1 closed this by deleting the head repository Jul 25, 2026
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.

Files API Support

3 participants