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

    • Added structured one-line-per-request JSON logging (toggleable via LOG_FORMAT) with request metadata and correlation/payment fields.
    • Captures payment_status and payer address during payment processing; includes cache hit/miss status in logs.
    • Redacts sensitive payment header values and sanitizes sensitive error content in logs and recovery output.
  • Bug Fixes

    • Prevents overwriting an existing successful payment status; correctly sets payment_status=required when payment headers are missing.
    • Improves cache logging semantics by distinguishing missing keys vs cache/backend errors.
  • Tests

    • Added coverage for JSON log formatting, sanitization/redaction, payment-status transitions, and 402 handling.
  • Documentation

    • Updated gateway and root READMEs plus .env.example to document LOG_FORMAT.

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

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 0385606c-3803-4468-be57-aa8120782840

📥 Commits

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

📒 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 (2)
  • gateway/README.md
  • .env.example
🚧 Files skipped from review as they are similar to previous changes (5)
  • gateway/errors.go
  • gateway/middleware.go
  • gateway/main_test.go
  • gateway/main.go
  • gateway/cache.go

📝 Walkthrough

Walkthrough

Adds JSON logging mode, redaction for sensitive errors and recovery dumps, payment/cache status propagation in gateway context, and tests/docs for structured logging and LOG_FORMAT configuration.

Changes

JSON Structured Logging with Error Sanitization

Layer / File(s) Summary
Logging runtime, structured logger, and Gin wiring
gateway/middleware.go, gateway/main.go
Adds LOG_FORMAT-driven JSON logging initialization, structured request log emission, correlation-ID plaintext log gating, x402 recovery header redaction, and Gin setup that switches between JSON and default middleware stacks.
Sanitization patterns and respondError behavior
gateway/errors.go
Adds redaction regexes and sanitizeErrorString, and updates respondError to preserve existing payment status, store sanitized internal errors, and suppress plaintext error logs in JSON mode.
Handler and cache telemetry/status propagation
gateway/cache.go, gateway/main.go
Sets payment_status, payer, and cache_status in request context, distinguishes cache miss versus cache backend error, and gates cache/receipt/summarize debug logs on JSON mode.
Behavior validation tests and LOG_FORMAT docs
gateway/main_test.go, .env.example, README.md, gateway/README.md
Adds tests for JSON logging, redaction, payment status, and recovery scrubbing, and documents LOG_FORMAT in the gateway and top-level docs.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant GinEngine
  participant Middleware
  participant GinContext
  participant Stdout
  Client->>GinEngine: HTTP request
  GinEngine->>Middleware: run request/response logging
  Middleware->>GinContext: read correlation_id, payment, cache, internal_error
  Middleware->>Stdout: write JSON log line
Loading

Possibly related issues

Possibly related PRs

Suggested labels: enhancement, type:security, level:advanced

Suggested reviewers: AnkanMisra

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description is too brief and misses the required template sections like Summary, Type Of Change, Verification, and Notes. Fill in the repository template sections, especially Summary, Type Of Change, Affected Areas, Contributor Checklist, Verification, and Notes For Reviewers.
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 is clear, concise, and matches the main change: structured JSON logging for gateway requests and payments.
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.
✨ 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.

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 👍 / 👎.

@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

AnkanMisra added a commit to aayushprsingh/MicroAI-Paygate that referenced this pull request Jun 9, 2026
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

aayushprsingh and others added 5 commits July 2, 2026 22:39
Signed-off-by: aayushprsingh <aayushprsingh@users.noreply.github.com>
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>
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>
@AnkanMisra

Copy link
Copy Markdown
Owner

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown
Contributor

Codex Review: Didn't find any major issues. You're on a roll.

Reviewed commit: 1142d223c3

ℹ️ 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".

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