Skip to content

feat: http status code not being correct for metrics#2516

Merged
SkArchon merged 3 commits intomainfrom
milinda/http-status-code-on-metrics
Feb 17, 2026
Merged

feat: http status code not being correct for metrics#2516
SkArchon merged 3 commits intomainfrom
milinda/http-status-code-on-metrics

Conversation

@SkArchon
Copy link
Copy Markdown
Contributor

@SkArchon SkArchon commented Feb 17, 2026

Right now if a non 200 http status code is returned from a non happy path before the final happy path, this would not be detected in metrics. As we set a static 200 http status code, this leads to cases where metrics report 200 http status codes but the status code returned to the user is 401 or such. This PR ensures that all paths will record the correct http status code for metrics.

Note: The wrapped writer roughly adds 70~100 nanoseconds.

Summary by CodeRabbit

  • Tests

    • Added test scenarios to confirm authentication failures are recorded with the correct HTTP status in metrics; also added test utilities to help assert metric attributes.
  • Bug Fixes

    • Improved metric capture so HTTP status codes and payload information are recorded correctly for authentication failures and early-exit paths.

Checklist

  • I have discussed my proposed changes in an issue and have received approval to proceed.
  • I have followed the coding standards of the project.
  • Tests or benchmarks have been added or updated.
  • Documentation has been updated on https://github.com/wundergraph/cosmo-docs.
  • I have read the Contributors Guide.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Feb 17, 2026

Walkthrough

Adds tests asserting authentication-failure HTTP status is recorded in metrics, introduces helper functions for metric-data checks, and refactors GraphQL prehandler to wrap the ResponseWriter early to capture status and bytes for all code paths.

Changes

Cohort / File(s) Summary
Prometheus tests
router-tests/prometheus_test.go
Adds subtest(s) asserting that an unauthenticated request produces a 401 entry in router_http_requests_total. The new test appears duplicated within the file.
Telemetry tests
router-tests/telemetry/telemetry_test.go
Adds scenario(s) asserting unauthenticated requests result in metrics with http.status_code=401 for router.http.requests and router.http.request.duration_milliseconds. The scenario is duplicated within the file.
Metric test utilities
router-tests/utils.go
Adds exported generics: `HasDataPointWithAttribute[N int64
Response writer wrapping
router/core/graphql_prehandler.go
Wraps http.ResponseWriter early with middleware.NewWrapResponseWriter (ww) and updates subsequent error, auth, and metrics code paths to use ww so recorded status and written bytes reflect actual responses.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: fixing HTTP status codes being incorrectly reported in metrics, which is the core issue addressed across all modified files.

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

✨ Finishing touches
  • 📝 Generate docstrings

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

@github-actions
Copy link
Copy Markdown

github-actions bot commented Feb 17, 2026

Router image scan passed

✅ No security vulnerabilities found in image:

ghcr.io/wundergraph/cosmo/router:sha-11336464bf83b14a3b22061b04669b6f631bf178

Copy link
Copy Markdown
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)
router-tests/prometheus_test.go (1)

4261-4264: Set Content-Type to keep the auth failure deterministic.
With a nil header, a future change in request parsing order could yield a 400 instead of 401 and break the intent of this test.

✅ Proposed tweak
- res, err := xEnv.MakeRequest(http.MethodPost, "/graphql", nil,
+ header := http.Header{"Content-Type": []string{"application/json"}}
+ res, err := xEnv.MakeRequest(http.MethodPost, "/graphql", header,
     strings.NewReader(`{"query":"{ employees { id } }"}`))
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@router-tests/prometheus_test.go` around lines 4261 - 4264, The test currently
calls xEnv.MakeRequest(http.MethodPost, "/graphql", nil, ...) with a nil header
which can make auth failure nondeterministic; update the call in the test to
pass an explicit headers map containing "Content-Type":"application/json" so the
request parsing always treats the body as JSON and the unauthenticated request
deterministically yields 401 (locate the xEnv.MakeRequest invocation in the test
and replace the nil header argument with the headers map).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@router-tests/telemetry/telemetry_test.go`:
- Around line 7880-7898: The test currently assumes datapoints are in a stable
order by accessing DataPoints[0] for requestsMetric and durationMetric; change
the assertions to scan the DataPoints slice for the point whose Attributes
contains statusCodeKey == http.StatusUnauthorized instead of using
DataPoints[0]. Specifically, after calling metricReader.Collect and locating the
scope via integration.GetMetricScopeByName and the metrics via
integration.GetMetricByName (router.http.requests and
router.http.request.duration_milliseconds), iterate over
requestsMetric.Data.(metricdata.Sum[int64]).DataPoints and
durationMetric.Data.(metricdata.Histogram[float64]).DataPoints, find the
datapoint whose Attributes.Value(statusCodeKey).AsInt64() ==
int64(http.StatusUnauthorized), and assert on that point (fail the test if no
matching datapoint is found).

---

Nitpick comments:
In `@router-tests/prometheus_test.go`:
- Around line 4261-4264: The test currently calls
xEnv.MakeRequest(http.MethodPost, "/graphql", nil, ...) with a nil header which
can make auth failure nondeterministic; update the call in the test to pass an
explicit headers map containing "Content-Type":"application/json" so the request
parsing always treats the body as JSON and the unauthenticated request
deterministically yields 401 (locate the xEnv.MakeRequest invocation in the test
and replace the nil header argument with the headers map).

@codecov
Copy link
Copy Markdown

codecov bot commented Feb 17, 2026

Codecov Report

❌ Patch coverage is 90.90909% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 62.18%. Comparing base (360bee4) to head (9eff981).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
router/core/graphql_prehandler.go 90.90% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #2516      +/-   ##
==========================================
+ Coverage   61.79%   62.18%   +0.38%     
==========================================
  Files         231      231              
  Lines       24143    24141       -2     
==========================================
+ Hits        14919    15011      +92     
+ Misses       7980     7865     -115     
- Partials     1244     1265      +21     
Files with missing lines Coverage Δ
router/core/graphql_prehandler.go 83.76% <90.90%> (+0.53%) ⬆️

... and 23 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copy link
Copy Markdown
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

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@router-tests/telemetry/telemetry_test.go`:
- Around line 7884-7885: The test currently blindly dereferences the result of
integration.GetMetricScopeByName (assigned to scopeMetric) which can be nil;
change the code to capture the pointer (e.g., scopeMetricPtr :=
integration.GetMetricScopeByName(rm.ScopeMetrics, "cosmo.router")), check if
scopeMetricPtr == nil and fail the test with a clear message (t.Fatalf or
require.NotNil) before using it, then use *scopeMetricPtr (or keep pointer
usage) for the rest of the assertions to avoid a panic and produce a helpful
test failure.

@SkArchon SkArchon merged commit 0c98cd0 into main Feb 17, 2026
41 of 42 checks passed
@SkArchon SkArchon deleted the milinda/http-status-code-on-metrics branch February 17, 2026 17:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants