Skip to content

feat: implement structured JSON logging for gateway requests and payments#206

Open
aayushprsingh wants to merge 5 commits into
AnkanMisra:mainfrom
aayushprsingh:gssoc-fix-192
Open

feat: implement structured JSON logging for gateway requests and payments#206
aayushprsingh wants to merge 5 commits into
AnkanMisra:mainfrom
aayushprsingh:gssoc-fix-192

Conversation

@aayushprsingh

@aayushprsingh aayushprsingh commented Jun 7, 2026

Copy link
Copy Markdown

This PR adds structured JSON logging capability to the gateway service. When LOG_FORMAT=json is set, Gin is configured in ReleaseMode, default logger is bypassed, and JSONLoggerMiddleware is registered to write structured execution details to stdout. Verification errors and successful payments are recorded dynamically inside the Gin context. This update also adds cache status tracking and ensures sensitive data like API keys and private keys are redacted from internal error logs.

Summary by CodeRabbit

  • New Features

    • Structured JSON request logging (one-line per request) with optional plain-text mode.
    • Payment status and payer info captured on requests; cache status included in logs.
    • Redaction of sensitive keys/errors in logs and recovery output.
  • Bug Fixes

    • Prevents overwriting an existing successful payment status.
    • Suppresses plaintext log noise when JSON logging is enabled.
  • Tests

    • Added tests for JSON logging fields, redaction, and payment-status behavior.
  • Documentation

    • Updated docs for LOG_FORMAT configuration and usage.

Copilot AI review requested due to automatic review settings June 7, 2026 03:13
@vercel

vercel Bot commented Jun 7, 2026

Copy link
Copy Markdown

@aayushprsingh is attempting to deploy a commit to the ankanmisra's projects Team on Vercel.

A member of the Team first needs to authorize it.

@github-actions

github-actions Bot commented Jun 7, 2026

Copy link
Copy Markdown

Hi @aayushprsingh, thanks for opening this PR.

Every contribution helps MicroAI-Paygate grow. If you find the project useful, consider starring the repository — it helps others discover it.

Star MicroAI-Paygate on GitHub

Looking forward to reviewing this PR.

@github-actions github-actions Bot added go Pull requests that update go code type:testing Tests, coverage, fixtures, or validation-only work. labels Jun 7, 2026
@coderabbitai

coderabbitai Bot commented Jun 7, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Adds JSONLoggerMiddleware and redaction utilities, gates plaintext logs when LOG_FORMAT=json, records cache/payment fields in Gin context (payment_status, payer, cache_status), updates respondError to store sanitized internal_error, and adds tests and docs for structured logging and redaction.

Changes

JSON Structured Logging with Error Sanitization

Layer / File(s) Summary
Logging imports and jsonLogging init
gateway/middleware.go
Adds encoding/json/os, introduces cached jsonLogging and initLogFormat() to read LOG_FORMAT and control plaintext suppression.
JSON logger and recovery redaction
gateway/middleware.go
Adds JSONLogEntry, implements JSONLoggerMiddleware() that marshals request/context fields to stdout, and redactingWriter()/redactedRecoveryWriter() to scrub x402 headers from recovery dumps.
Correlation ID and plaintext log gating
gateway/middleware.go, gateway/cache.go
Gates plaintext correlation-ID and cache/receipt debug logs behind the jsonLogging flag so they are suppressed when LOG_FORMAT=json.
Error sanitization and respondError changes
gateway/errors.go
Adds regexes and sanitizeErrorString to redact 64-hex and sk-or-* patterns; respondError now sets payment_error, only marks payment_status=failed if unset, stores sanitized internal_error, and suppresses plaintext error logs in JSON mode.
Cache middleware payment context & status
gateway/cache.go
Cache-hit path now sets cache_status="hit", sets payment_status="success" and payer on hit responses, distinguishes cache_status miss vs error using redis.Nil, and conditions log emission on jsonLogging.
Gin wiring and handler payment tracking
gateway/main.go
When LOG_FORMAT=json Gin is initialized with JSONLoggerMiddleware() and redacted recovery; handleSummarize records payment_status (required/success) and payer; receipt-error logs are gated or stored as sanitized internal_error in JSON mode.
Tests and docs
gateway/main_test.go, .env.example, README.md, gateway/README.md
Adds tests capturing JSON log output and asserting redaction and payment/status semantics; documents LOG_FORMAT in examples and READMEs.

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant GinHandler
  participant JSONLoggerMiddleware
  participant GinContext
  participant Stdout
  Client->>GinHandler: HTTP request
  GinHandler->>GinContext: set context fields (correlation, payment, cache)
  GinHandler->>JSONLoggerMiddleware: on response completion
  JSONLoggerMiddleware->>GinContext: read status,path,method,latency,payment/cache/internal_error
  JSONLoggerMiddleware->>Stdout: write marshaled JSONLogEntry
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related issues

Possibly related PRs

Suggested labels

apertre3.0, level:advanced

Suggested reviewers

  • AnkanMisra

Poem

🐇 I typed a log in JSON, neat and bright,

redacted keys tucked safely out of sight.
Payments noted, cache whispers softly stored,
stdout hums one line — tidy, not a hoard.
Hop on, dear gateway, hop into the night!

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description is largely incomplete against the template: missing Summary bullet, Type Of Change checkboxes, Affected Areas checkboxes, Contributor Checklist items, Verification section with commands, and Notes For Reviewers. Fill in the missing template sections: Summary, Type Of Change (check Feature), Affected Areas (check Gateway), all Contributor Checklist items, Verification with exact test commands, and Notes For Reviewers describing any risky areas or follow-up work.
Docstring Coverage ⚠️ Warning Docstring coverage is 25.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main change—adding structured JSON logging for gateway requests and payments—matching the core objective and changes across multiple files.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

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

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

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 golangci-lint (2.12.2)

level=error msg="[linters_context] typechecking error: pattern ./...: directory prefix . does not contain main module or its selected dependencies"


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.

Copilot AI 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.

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

This PR introduces structured JSON logging for the gateway (enabled via LOG_FORMAT=json), enriches request context with log metadata (cache/payment/error fields), and adds sanitization to prevent leaking sensitive values in logs.

Changes:

  • Add JSONLoggerMiddleware emitting structured request logs and suppress plaintext logging when JSON logging is enabled
  • Add error-string sanitization and propagate error/payment metadata via gin.Context
  • Add tests covering JSON logging output and sanitization behavior

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
gateway/middleware.go Adds JSON log entry struct + JSON logging middleware; suppresses correlation plaintext logging when JSON is enabled
gateway/main.go Switches router setup based on LOG_FORMAT; sets payment-related context fields for logging; suppresses plaintext logs in JSON mode
gateway/errors.go Adds sanitization helpers; attaches failure metadata to context; avoids plaintext internal error logging in JSON mode
gateway/cache.go Records cache hit/miss in context and suppresses plaintext cache logs in JSON mode
gateway/main_test.go Adds tests that capture stdout to validate JSON log shape and sanitization

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread gateway/middleware.go
Comment on lines +354 to +355
correlationID, _ := c.Get("correlation_id")
corrStr, _ := correlationID.(string)
Comment thread gateway/middleware.go
Comment on lines +373 to +375
if data, err := json.Marshal(entry); err == nil {
fmt.Println(string(data))
}
Comment thread gateway/cache.go Outdated
Comment on lines +118 to +120
if os.Getenv("LOG_FORMAT") != "json" {
log.Printf("Cache HIT: %s", cacheKey)
}
Comment thread gateway/main_test.go
Comment on lines +622 to +624
oldStdout := os.Stdout
rPipe, wPipe, _ := os.Pipe()
os.Stdout = wPipe

@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: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@gateway/cache.go`:
- Around line 118-122: The plaintext log.Printf calls that print cache HIT/MISS
info (using cacheKey) are still executed even when LOG_FORMAT=json; update the
code paths where log.Printf is used (the cache hit/miss/error branches around
the cache handling that call log.Printf and set c.Set("cache_status", ...)) to
conditionally emit that plaintext only when os.Getenv("LOG_FORMAT") != "json"
(or replace them with the existing structured logger used elsewhere), so that
when LOG_FORMAT=json is set you suppress/plainly redact the cacheKey output and
rely on the JSON-structured logger for status; target the spots referencing
cacheKey and c.Set("cache_status", "...") and the raw log.Printf invocations for
the change.

In `@gateway/errors.go`:
- Around line 15-22: The current openRouterKeyRegex (sk-or-[a-zA-Z0-9]+) stops
at the first hyphen and can leak keys like sk-or-v1-..., so update the
openRouterKeyRegex declaration to allow the full key token (e.g., include hyphen
and dot characters such as [A-Za-z0-9_.-]+ and optionally a word-boundary) and
keep sanitizeErrorString using that regex; modify the openRouterKeyRegex symbol
so it matches complete OpenRouter keys like sk-or-v1-... to ensure full
redaction.

In `@gateway/main.go`:
- Around line 269-277: The JSON logger middleware is registered after
gin.Recovery which allows Recovery to handle panics and skip the
JSONLoggerMiddleware's post-c.Next() logging; move the JSONLoggerMiddleware()
registration to before gin.Recovery() in the gin.New() branch so
JSONLoggerMiddleware runs earlier (and still executes its post-c.Next() block
even when Recovery handles a panic); update the ordering around r = gin.New(),
r.Use(JSONLoggerMiddleware()), r.Use(gin.Recovery()), r.Use(gin.Recovery())
usage to ensure JSONLoggerMiddleware precedes gin.Recovery.
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: f8357298-eff5-47fc-a941-1099a00c883e

📥 Commits

Reviewing files that changed from the base of the PR and between 7d10ad6 and e4fe0cc.

📒 Files selected for processing (5)
  • gateway/cache.go
  • gateway/errors.go
  • gateway/main.go
  • gateway/main_test.go
  • gateway/middleware.go

Comment thread gateway/cache.go Outdated
Comment thread gateway/errors.go Outdated
Comment thread gateway/main.go
@vercel

vercel Bot commented Jun 7, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
microai-paygate Ready Ready Preview, Comment Jun 8, 2026 2:35pm

@AnkanMisra

Copy link
Copy Markdown
Owner

@codex review this pr

@AnkanMisra

Copy link
Copy Markdown
Owner

@aayushprsingh which issue are you solving please refer it in the description

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: e4fe0ccc6d

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread gateway/errors.go Outdated
)

var (
hex64Regex = regexp.MustCompile(`\b[0-9a-fA-F]{64}\b`)

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.

P1 Badge Redact 0x-prefixed Ethereum secrets

When an internal error contains the standard 0x-prefixed form of an Ethereum private key or signature, the leading x and first hex digit are both word characters, so this word-boundary regex does not match and the secret is emitted in internal_error. The repository documents private keys in this form, so make the prefix part of the redaction pattern and add a regression test using an actual 0x-prefixed value.

Useful? React with 👍 / 👎.

Comment thread gateway/main.go Outdated
Comment on lines +273 to +274
r.Use(gin.Recovery())
r.Use(JSONLoggerMiddleware())

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.

P2 Badge Keep the JSON logger outside panic recovery

When any downstream handler panics, gin.Recovery() catches the panic only after the stack has unwound through JSONLoggerMiddleware, so execution never reaches the logger's post-c.Next() code and the failed request has no structured entry. Register the JSON logger before recovery, or defer its logging logic, so recovered 500 responses remain observable.

Useful? React with 👍 / 👎.

Comment thread gateway/errors.go Outdated
Comment on lines +26 to +27
c.Set("payment_status", "failed")
c.Set("payment_error", publicMsg)

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.

P2 Badge Do not classify every application error as payment failure

When payment verification succeeds but the AI provider or receipt generation subsequently fails, handleSummarize first records payment_status=success and then respondError overwrites it with failed. This makes upstream and storage outages appear as rejected payments in the structured telemetry; only verification/payment errors should change these payment-specific fields.

Useful? React with 👍 / 👎.

Comment thread gateway/cache.go
if os.Getenv("LOG_FORMAT") != "json" {
log.Printf("Cache HIT: %s", cacheKey)
}
c.Set("cache_status", "hit")

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.

P2 Badge Record successful payments on cache hits

On a cache hit, this middleware verifies the payment and aborts before handleSummarize, but the success path only sets payment_verification and payment_context; therefore the new JSON entry reports cache_status=hit while omitting both payment_status and payer. Set those logging fields after successful cache-hit verification so payment telemetry is complete for both cached and uncached requests.

Useful? React with 👍 / 👎.

Comment thread gateway/errors.go Outdated

var (
hex64Regex = regexp.MustCompile(`\b[0-9a-fA-F]{64}\b`)
openRouterKeyRegex = regexp.MustCompile(`sk-or-[a-zA-Z0-9]+`)

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.

P1 Badge Redact the complete OpenRouter API key

For actual OpenRouter keys such as sk-or-v1-<secret>, this pattern matches only sk-or-v1 because hyphens are excluded from the character class, leaving -<secret> visible in internal_error. Extend the expression to consume the complete documented key format and test a representative sk-or-v1-... value so structured error logs do not disclose usable credential material.

Useful? React with 👍 / 👎.

Comment thread gateway/middleware.go
Comment on lines +334 to +335
PaymentStatus string `json:"payment_status,omitempty"`
PaymentError string `json:"payment_error,omitempty"`

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.

P2 Badge Record unsigned payment challenges

For the normal first request without payment headers, handleSummarize returns the 402 challenge without setting any context fields, so this newly added payment telemetry omits payment_status and payment_error for the most frequent x402 payment event. Record a distinct status such as required before returning the challenge so dashboards can distinguish unsigned payment challenges from unrelated HTTP 402 responses or requests with no payment flow.

Useful? React with 👍 / 👎.

Comment thread gateway/main.go Outdated

r := gin.Default()
var r *gin.Engine
if os.Getenv("LOG_FORMAT") == "json" {

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.

P2 Badge Document the LOG_FORMAT configuration

The new behavior is reachable only through LOG_FORMAT=json, but that variable is absent from .env.example, the root configuration table, and gateway/README.md. Operators following the repository's documented setup therefore cannot discover or reliably configure the feature; add the variable, accepted value, default behavior, and output semantics to the synchronized configuration documentation.

Useful? React with 👍 / 👎.

Comment thread gateway/main.go Outdated
Comment on lines 945 to 948
if os.Getenv("LOG_FORMAT") != "json" {
log.Printf("Failed to retrieve receipt %s: %v", id, err)
}
c.JSON(500, gin.H{"error": "Failed to retrieve receipt"})

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.

P2 Badge Preserve receipt-store errors in JSON logs

When receipt retrieval fails in JSON mode, this branch now suppresses the only log containing err and returns the response directly instead of populating internal_error, so the structured request entry contains only a generic 500 with no explanation. Use respondError or explicitly attach a sanitized internal error before returning, otherwise Redis and receipt-store outages cannot be diagnosed from gateway logs.

Useful? React with 👍 / 👎.

Comment thread gateway/cache.go Outdated
Comment on lines +188 to +192
// Cache MISS
log.Printf("Cache MISS: %s", cacheKey)
if os.Getenv("LOG_FORMAT") != "json" {
log.Printf("Cache MISS: %s", cacheKey)
}
c.Set("cache_status", "miss")

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.

P2 Badge Distinguish cache failures from cache misses

When Redis returns a connection error or a cached value is corrupt, getFromCache returns an error and this path unconditionally records cache_status=miss. That makes backend outages and invalid cache data indistinguishable from a normal absent key in the new structured telemetry; check for the Redis miss sentinel separately and record an error or bypass status for other failures.

Useful? React with 👍 / 👎.

Comment thread gateway/main.go Outdated
if os.Getenv("LOG_FORMAT") == "json" {
gin.SetMode(gin.ReleaseMode)
r = gin.New()
r.Use(gin.Recovery())

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.

P1 Badge Prevent recovery logs from exposing payment headers

When a request with X-402-Signature encounters a broken-pipe panic, Gin's default recovery path dumps the request and sanitizes only Authorization; the x402 signature, nonce, and timestamp therefore go to stderr in plaintext even in JSON mode. Configure custom recovery output that redacts these payment headers, since a signature may remain replayable until its nonce is successfully consumed.

Useful? React with 👍 / 👎.

respondError unconditionally set payment_status="failed", clobbering a
verified payment when a later receipt-generation step failed — corrupting
the very metric this feature captures. Now it only marks failed when no
prior status exists.

Redaction regexes missed real key formats: 0x-prefixed private keys (the
\b anchor never matched after "x") and versioned sk-or-v1-<secret> tokens
(charset excluded dashes). Widened both patterns and reordered so API-key
redaction runs first. Added tests covering realistic key shapes and the
post-success error path.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

@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.

🧹 Nitpick comments (1)
gateway/main_test.go (1)

621-678: 💤 Low value

Consider adding ClientIP assertion for completeness.

The test verifies most JSONLogEntry fields but omits ClientIP. Since req.RemoteAddr is explicitly set to "127.0.0.1:12345" on line 647, adding an assertion like require.Equal(t, "127.0.0.1", logEntry.ClientIP) would provide more complete coverage of the middleware's output.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@gateway/main_test.go` around lines 621 - 678, The test
TestJSONLoggerMiddleware is missing an assertion for ClientIP even though
req.RemoteAddr is set; update the test in gateway/main_test.go (inside
TestJSONLoggerMiddleware) to assert that JSONLogEntry.ClientIP equals
"127.0.0.1" after unmarshalling (use require.Equal with logEntry.ClientIP and
"127.0.0.1") so the middleware's client IP extraction is covered — place the
assertion alongside the other require.Equal checks for Status, Path, Method,
etc.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@gateway/main_test.go`:
- Around line 621-678: The test TestJSONLoggerMiddleware is missing an assertion
for ClientIP even though req.RemoteAddr is set; update the test in
gateway/main_test.go (inside TestJSONLoggerMiddleware) to assert that
JSONLogEntry.ClientIP equals "127.0.0.1" after unmarshalling (use require.Equal
with logEntry.ClientIP and "127.0.0.1") so the middleware's client IP extraction
is covered — place the assertion alongside the other require.Equal checks for
Status, Path, Method, etc.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 393415b7-467d-48bd-8590-3b05b5a8bae0

📥 Commits

Reviewing files that changed from the base of the PR and between e4fe0cc and d61a909.

📒 Files selected for processing (2)
  • gateway/errors.go
  • gateway/main_test.go
🚧 Files skipped from review as they are similar to previous changes (1)
  • gateway/errors.go

Addresses the outstanding bot review on PR AnkanMisra#206:

- Centralize the scattered LOG_FORMAT=="json" checks into a single
  package-level jsonLogging flag set once at startup (initLogFormat).
- Suppress/sanitize the remaining plaintext logs that still fired in JSON
  mode: invalid-JSON debug, cache-hit verification error, and cached
  receipt failure in cache.go.
- Register JSONLoggerMiddleware before gin.Recovery so panics still
  produce a structured entry, and route recovery through a writer that
  redacts X-402-Signature/Nonce/Timestamp (the default dump only scrubs
  Authorization; a leaked signature is replayable until its nonce burns).
- Record payment_status=success + payer on cache-hit verification so
  cached requests carry the same telemetry as handleSummarize.
- Set payment_status=required on the unsigned 402 challenge so dashboards
  separate it from unrelated 402s.
- Preserve a sanitized internal_error in handleGetReceipt under JSON mode
  so receipt-store outages stay diagnosable.
- Distinguish a genuine cache miss (redis.Nil) from a backend error so
  Redis outages aren't masked as ordinary misses.
- Document LOG_FORMAT in .env.example, README.md, and gateway/README.md.

Tests: redacting writer scrubs x402 headers, 402 sets required status,
plus the existing redaction/payment-status regression tests. Full gateway
suite green.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@github-actions github-actions Bot added documentation Improvements or additions to documentation type:docs Documentation, API docs, examples, or contributor docs. labels Jun 9, 2026

@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.

Caution

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

⚠️ Outside diff range comments (1)
gateway/cache.go (1)

200-221: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Do not count backend cache failures as cache misses.

Line [203]-Line [206] classifies Redis/backend failures as cache_status="error", but Line [220] still increments cacheMisses unconditionally. That keeps masking outages as ordinary misses in metrics.

Suggested fix
 		routePath := c.FullPath()
 		if routePath == "" {
 			routePath = "unknown"
 		}
-		cacheMisses.WithLabelValues(routePath).Inc()
+		if cacheStatus == "miss" {
+			cacheMisses.WithLabelValues(routePath).Inc()
+		}

As per coding guidelines, "Check per-IP/per-wallet bucket selection, cleanup, disabled-mode behavior, Redis URL validation, cache miss/fallback behavior, and concurrency safety in rate limiting/cache logic."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@gateway/cache.go` around lines 200 - 221, The code treats non-nil Redis
errors as cache_status="error" but still unconditionally calls
cacheMisses.WithLabelValues(routePath).Inc(); change the logic so metric
increments only for genuine misses: after computing cacheStatus (using
errors.Is(cacheErr, redis.Nil)), call
cacheMisses.WithLabelValues(routePath).Inc() only when cacheStatus == "miss"
(i.e., the branch where redis.Nil was detected), while still setting
c.Set("cache_status", cacheStatus) and preserving the existing logging of error
vs miss (see variables cacheStatus, cacheErr, cacheMisses, c.Set, routePath,
sanitizeErrorString).

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@gateway/cache.go`:
- Around line 200-221: The code treats non-nil Redis errors as
cache_status="error" but still unconditionally calls
cacheMisses.WithLabelValues(routePath).Inc(); change the logic so metric
increments only for genuine misses: after computing cacheStatus (using
errors.Is(cacheErr, redis.Nil)), call
cacheMisses.WithLabelValues(routePath).Inc() only when cacheStatus == "miss"
(i.e., the branch where redis.Nil was detected), while still setting
c.Set("cache_status", cacheStatus) and preserving the existing logging of error
vs miss (see variables cacheStatus, cacheErr, cacheMisses, c.Set, routePath,
sanitizeErrorString).

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 12de0640-5bdd-40a7-a80b-bfe8ff82b7ed

📥 Commits

Reviewing files that changed from the base of the PR and between d61a909 and 5a61328.

📒 Files selected for processing (8)
  • .env.example
  • README.md
  • gateway/README.md
  • gateway/cache.go
  • gateway/errors.go
  • gateway/main.go
  • gateway/main_test.go
  • gateway/middleware.go
✅ Files skipped from review due to trivial changes (3)
  • gateway/README.md
  • .env.example
  • README.md
🚧 Files skipped from review as they are similar to previous changes (2)
  • gateway/errors.go
  • gateway/main.go

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation go Pull requests that update go code type:docs Documentation, API docs, examples, or contributor docs. type:testing Tests, coverage, fixtures, or validation-only work.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants