Skip to content

Conversation

@gocanto
Copy link
Collaborator

@gocanto gocanto commented Sep 25, 2025

Summary

  • configure the Sentry client with environment metadata, tracing, and delivery behaviour
  • wrap the HTTP server with the Sentry middleware and capture API errors with request context
  • align kernel tests with the enriched environment requirements and router setup

Testing

  • go test ./...

https://chatgpt.com/codex/tasks/task_e_68d4e11962788333946c514b477f7ef3

Summary by CodeRabbit

  • New Features

    • Environment-aware Sentry across tools with tracing, enriched context, startup capture/flush, and API error reporting.
    • Panic recovery reporting to Sentry and improved startup error capture.
    • Conditional non-production CORS with expanded allowed origins and added X-API-Intended-Origin header.
    • Website routes now wired during bootstrap.
  • Refactor

    • Composed HTTP handler flow to enable middleware stacking (CORS then Sentry).
  • Tests

    • Expanded test env vars and added recovery and router wiring tests.

@coderabbitai
Copy link

coderabbitai bot commented Sep 25, 2025

Caution

Review failed

The pull request is closed.

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

Walkthrough

Reworks startup and HTTP wiring to compose a final handler with environment-aware CORS and optional Sentry wrapping, expands Sentry initialization/options and exposure on App, adds Sentry-backed API error capture, and wires recover/flush into CLI and seeder startups and tests.

Changes

Cohort / File(s) Summary
HTTP composition & startup
main.go
Builds a mutable handler from GetMux(); returns NotFound when mux is nil; conditionally wraps with CORS in non-production and with Sentry handler when available; captures startup errors via Sentry hub before logging/panicking.
Sentry factory & App helpers
metal/kernel/factory.go, metal/kernel/helpers.go
Expands MakeSentry options (AttachStacktrace, EnableTracing, TracesSampleRate, Environment, Release, Timeout, WaitForDelivery); exposes App.GetSentry() and adds RecoverWithSentry and App.Recover() helpers; portal.Sentry literal now includes Env.
API error capture
pkg/http/handler.go
Adds captureApiError path invoked from MakeApiHandler to record API errors to Sentry (level by status, tags: http.method/status/route, includes request and optional data), using hub from request context or current hub.
Startup lifecycle (CLI & seeder)
metal/cli/main.go, database/seeder/main.go
Introduces package-level sentryHub, initializes via kernel.MakeSentry(env), defers sentry.Flush(2 * time.Second) and kernel.RecoverWithSentry(sentryHub) in main.
Tests & router wiring
metal/kernel/kernel_test.go, .../router/...
Adds env vars to test setup (ENV_APP_URL, ENV_PUBLIC_ALLOWED_IP, ENV_SPA_DIR); adds WebsiteRoutes to Router wiring via router.NewWebsiteRoutes(env); adds test asserting App.Recover re-panics.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor Client
  participant Server
  participant Mux as Mux/Router
  participant CORS as CORS Wrapper (non-prod)
  participant SentryH as Sentry Handler (optional)

  Client->>Server: HTTP Request
  Server->>Mux: GetMux()
  alt mux is nil
    Server-->>Client: NotFound / no handler
  else mux present
    alt non-production
      Server->>CORS: wrap(mux)
      CORS->>SentryH: pass-through (if configured)
      SentryH->>Mux: ServeHTTP
    else production
      Server->>SentryH: wrap(mux) (if configured)
      SentryH->>Mux: ServeHTTP
    end
    Mux-->>Client: HTTP Response
  end
Loading
sequenceDiagram
  autonumber
  actor Client
  participant API as API Handler
  participant Sentry as Sentry Hub/Scope

  Client->>API: Request
  API->>API: process request
  alt Error occurs
    API->>Sentry: captureApiError(method, route, status, err)
    Note right of Sentry: tags: http.method, http.status_code, http.route<br/>level: warning (<500) / error (>=500)
    API-->>Client: JSON error response
  else Success
    API-->>Client: JSON success response
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~40 minutes

Possibly related PRs

Poem

Hop-hop, I stitched the startup tight,
Sentry listens through the night.
CORS for dev, localhost in play,
Errors tagged before they stray.
Flush and recover — carrot-cheerful light. 🥕

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ 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 clearly and concisely describes the main focus of the changeset, which is adding Sentry integration into the HTTP request handling pipeline, and it aligns with the modifications to middleware and error capture flow without extraneous detail.

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between fe7e9a1 and 4ff845e.

📒 Files selected for processing (4)
  • database/seeder/main.go (3 hunks)
  • main.go (2 hunks)
  • metal/kernel/factory.go (2 hunks)
  • metal/kernel/helpers.go (3 hunks)

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.

@gocanto gocanto marked this pull request as draft September 25, 2025 06:41
@gemini-code-assist
Copy link

Summary of Changes

Hello @gocanto, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request introduces comprehensive Sentry integration into the application's HTTP request handling. The primary goal is to enhance error monitoring by automatically capturing API errors, providing detailed context, and enabling distributed tracing. This ensures that issues are more easily identified and debugged across different environments.

Highlights

  • Sentry Client Configuration: The Sentry client is now configured with detailed environment metadata, tracing capabilities, and delivery behavior tailored to production and local environments.
  • HTTP Middleware Integration: The HTTP server handler is wrapped with Sentry middleware to automatically capture and report API errors, enriching them with request context.
  • Test Environment Updates: Kernel tests have been updated to include new environment variables and router setup, ensuring compatibility with the Sentry integration.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request effectively integrates Sentry for error tracking in the HTTP handling layer. The Sentry client is well-configured with environment metadata and tracing options, and the middleware is correctly applied to the server handler. The new captureApiError function is a great addition for sending detailed error reports to Sentry. I've found a critical issue that will prevent compilation, and have also included a couple of suggestions to further improve the Sentry integration for more effective error tracking and to enhance code clarity.

Copy link

@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 7e727dc and fef8fda.

📒 Files selected for processing (5)
  • main.go (1 hunks)
  • metal/kernel/factory.go (2 hunks)
  • metal/kernel/helpers.go (2 hunks)
  • metal/kernel/kernel_test.go (3 hunks)
  • pkg/http/handler.go (2 hunks)
🧰 Additional context used
🧬 Code graph analysis (5)
metal/kernel/kernel_test.go (3)
metal/router/static.go (2)
  • WebsiteRoutes (14-20)
  • NewWebsiteRoutes (22-30)
metal/router/router.go (1)
  • WebsiteRoutes (16-23)
metal/kernel/app.go (2)
  • router (17-24)
  • a (81-100)
pkg/http/handler.go (2)
pkg/http/schema.go (2)
  • ApiHandler (25-25)
  • ApiError (11-15)
pkg/http/handler_test.go (1)
  • TestMakeApiHandler (10-35)
metal/kernel/factory.go (3)
pkg/portal/sentry.go (1)
  • Sentry (8-12)
metal/env/env.go (1)
  • Environment (9-17)
metal/env/sentry.go (1)
  • DSN (3-6)
main.go (1)
pkg/portal/sentry.go (1)
  • Handler (8-12)
metal/kernel/helpers.go (3)
metal/kernel/app.go (3)
  • App (17-24)
  • a (81-100)
  • MakeApp (26-42)
pkg/portal/sentry.go (1)
  • Sentry (8-12)
metal/env/env.go (1)
  • App (9-17)
🔇 Additional comments (4)
metal/kernel/helpers.go (1)

48-50: Sentry accessor rounds out the kernel API

The accessor cleanly exposes the Sentry handle so upstream wiring can stay decoupled. Looks good to me.

metal/kernel/factory.go (1)

16-47: Environment-aware Sentry setup looks solid

App metadata, tracing, and delivery knobs are all wired in coherently. Nicely done.

pkg/http/handler.go (1)

35-68: Great addition for scoped Sentry capture

The scoped capture covers the critical HTTP context and gracefully falls back to the global hub. This will make diagnosing API errors much easier.

metal/kernel/kernel_test.go (1)

77-176: Tests now mirror the richer environment

Thanks for keeping the fixtures in sync with the new env requirements and router wiring. The additional coverage is appreciated.

@gocanto gocanto added testing and removed codex labels Sep 25, 2025
@gocanto gocanto marked this pull request as ready for review September 25, 2025 07:34
Copy link

@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 (6)
metal/kernel/factory.go (3)

21-21: Avoid forcing an unversioned Release; rely on SENTRY_RELEASE or include a version

Hardcoding Release: env.App.Name degrades grouping. Either remove it (let SENTRY_RELEASE env var drive it) or include a proper version (e.g., app@1.2.3 or git SHA).

Apply this diff to remove the forced release so Sentry can use SENTRY_RELEASE:

-        Release:          env.App.Name,

23-24: Make trace sampling configurable; 100% in production is costly

EnableTracing: true with TracesSampleRate: 1.0 will sample every request. Consider making the sample rate env‑configurable and defaulting lower in prod.


17-25: Add a BeforeSend scrubber to redact sensitive headers

You call scope.SetRequest(r) in request handlers; proactively redact Authorization and Cookie to reduce PII risk.

 func MakeSentry(env *env.Environment) *portal.Sentry {
     cOptions := sentry.ClientOptions{
         Dsn:              env.Sentry.DSN,
         Debug:            env.App.IsLocal(),
         Environment:      env.App.Type,
-        Release:          env.App.Name,
         AttachStacktrace: true,
         EnableTracing:    true,
         TracesSampleRate: 1.0,
+        BeforeSend: func(event *sentry.Event, hint *sentry.EventHint) *sentry.Event {
+            if event.Request != nil && event.Request.Headers != nil {
+                if _, ok := event.Request.Headers["Authorization"]; ok {
+                    event.Request.Headers["Authorization"] = "[Filtered]"
+                }
+                if _, ok := event.Request.Headers["Cookie"]; ok {
+                    event.Request.Headers["Cookie"] = "[Filtered]"
+                }
+            }
+            return event
+        },
     }
pkg/http/handler.go (2)

35-69: Prefer not capturing 4xx by default to reduce noise

Most teams don’t send 4xx to Sentry. Consider skipping capture for Status < 500.

 func captureApiError(r *baseHttp.Request, apiErr *ApiError) {
     if apiErr == nil {
         return
     }
 
-    level := sentry.LevelWarning
-    if apiErr.Status >= baseHttp.StatusInternalServerError {
-        level = sentry.LevelError
-    }
+    if apiErr.Status < baseHttp.StatusInternalServerError {
+        return
+    }
+    level := sentry.LevelError

12-31: Expose Sentry event ID to clients for support correlation

Return the event ID from captureApiError and set X-Sentry-Event-Id in the response.

 func MakeApiHandler(fn ApiHandler) baseHttp.HandlerFunc {
     return func(w baseHttp.ResponseWriter, r *baseHttp.Request) {
         if err := fn(w, r); err != nil {
             slog.Error("API Error", "message", err.Message, "status", err.Status)
 
-            captureApiError(r, err)
+            if eid := captureApiError(r, err); eid != "" {
+                w.Header().Set("X-Sentry-Event-Id", eid)
+            }
 
             w.Header().Set("Content-Type", "application/json")
             w.WriteHeader(err.Status)
-func captureApiError(r *baseHttp.Request, apiErr *ApiError) {
+func captureApiError(r *baseHttp.Request, apiErr *ApiError) string {
     if apiErr == nil {
-        return
+        return ""
     }
 
     level := sentry.LevelWarning
     if apiErr.Status >= baseHttp.StatusInternalServerError {
         level = sentry.LevelError
     }
 
+    var eventID sentry.EventID
     notify := func(hub *sentry.Hub) {
         hub.WithScope(func(scope *sentry.Scope) {
             scope.SetLevel(level)
             scope.SetTag("http.method", r.Method)
             scope.SetTag("http.status_code", strconv.Itoa(apiErr.Status))
             scope.SetTag("http.route", r.URL.Path)
             scope.SetRequest(r)
             scope.SetExtra("api_error_status_text", baseHttp.StatusText(apiErr.Status))
 
             if apiErr.Data != nil {
                 scope.SetExtra("api_error_data", apiErr.Data)
             }
 
-            hub.CaptureException(apiErr)
+            eventID = hub.CaptureException(apiErr)
         })
     }
 
     if hub := sentry.GetHubFromContext(r.Context()); hub != nil {
         notify(hub)
-        return
+        return string(eventID)
     }
 
     notify(sentry.CurrentHub())
+    return string(eventID)
 }

Also applies to: 35-69

main.go (1)

90-92: Avoid shadowing the sentry package name

sentby := app.GetSentry() (or sentryHub) reads clearer and prevents accidental package shadowing if used later.

-    if sentry := app.GetSentry(); sentry != nil && sentry.Handler != nil {
-        handler = sentry.Handler.Handle(handler)
+    if sh := app.GetSentry(); sh != nil && sh.Handler != nil {
+        handler = sh.Handler.Handle(handler)
     }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between fef8fda and fe7e9a1.

📒 Files selected for processing (7)
  • database/seeder/main.go (3 hunks)
  • main.go (2 hunks)
  • metal/cli/main.go (2 hunks)
  • metal/kernel/factory.go (2 hunks)
  • metal/kernel/helpers.go (3 hunks)
  • metal/kernel/kernel_test.go (4 hunks)
  • pkg/http/handler.go (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • metal/kernel/helpers.go
  • metal/kernel/kernel_test.go
🧰 Additional context used
🧬 Code graph analysis (5)
metal/cli/main.go (4)
pkg/portal/sentry.go (1)
  • Sentry (8-12)
metal/kernel/factory.go (1)
  • MakeSentry (16-44)
metal/kernel/helpers.go (1)
  • RecoverWithSentry (41-43)
metal/env/sentry.go (1)
  • DSN (3-6)
pkg/http/handler.go (1)
pkg/http/schema.go (3)
  • ApiHandler (25-25)
  • ApiError (11-15)
  • e (17-23)
main.go (1)
pkg/portal/sentry.go (1)
  • Handler (8-12)
database/seeder/main.go (4)
pkg/portal/sentry.go (1)
  • Sentry (8-12)
metal/kernel/factory.go (1)
  • MakeSentry (16-44)
metal/kernel/helpers.go (1)
  • RecoverWithSentry (41-43)
metal/env/sentry.go (1)
  • DSN (3-6)
metal/kernel/factory.go (4)
pkg/portal/sentry.go (1)
  • Sentry (8-12)
metal/kernel/app.go (1)
  • App (17-24)
metal/env/env.go (1)
  • Environment (9-17)
metal/env/sentry.go (1)
  • DSN (3-6)
🔇 Additional comments (6)
metal/cli/main.go (1)

28-29: Sentry lifecycle wiring looks correct; confirm recover helper is nil‑safe

Init + defer patterns are fine. Please confirm kernel.RecoverWithSentry tolerates a nil hub and doesn’t call os.Exit, so sentry.Flush can run.

Also applies to: 34-36

database/seeder/main.go (1)

23-24: Seeder Sentry integration LGTM; confirm recover helper behavior

Initialization and defers look good. Please verify kernel.RecoverWithSentry handles nil hubs and doesn’t bypass other defers (e.g., via os.Exit).

Also applies to: 32-36

metal/kernel/factory.go (1)

31-35: HTTP integration options look good

Repanic, WaitForDelivery in prod, and Timeout are sane defaults.

pkg/http/handler.go (1)

12-19: Good addition: capture API errors before responding

Capturing via Sentry prior to encoding the response is the right spot.

main.go (2)

31-35: Server panic recovery + flush ordering LGTM

Startup defers cover panic recovery and flushing. Good.


61-61: Fix CORS origin: add scheme to match browser Origin header

Passing host:port won’t match Origin: http://host:port. Prepend the scheme.

-        localhost := app.GetEnv().Network.GetHostURL()
+        localhost := fmt.Sprintf("http://%s", app.GetEnv().Network.GetHostURL())
 
         c := cors.New(cors.Options{
-            AllowedOrigins:   []string{localhost, "http://localhost:5173"},
+            AllowedOrigins:   []string{localhost, "http://localhost:5173"},

Also applies to: 79-81

@gocanto gocanto marked this pull request as draft September 25, 2025 07:44
@gocanto gocanto removed the testing label Sep 25, 2025
@gocanto gocanto marked this pull request as ready for review September 25, 2025 07:56
@gocanto gocanto merged commit a01da5b into main Sep 25, 2025
2 of 3 checks passed
@gocanto gocanto deleted the codex/fix-sentry-integration branch September 25, 2025 07:56
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