Skip to content

feat: track card-info lookup failures with Prometheus metrics and structured logs - #408

Open
GauravRawat369 wants to merge 9 commits into
mainfrom
add_cards_info_to_clickhouse
Open

feat: track card-info lookup failures with Prometheus metrics and structured logs#408
GauravRawat369 wants to merge 9 commits into
mainfrom
add_cards_info_to_clickhouse

Conversation

@GauravRawat369

@GauravRawat369 GauravRawat369 commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

What

Tracks every failed outbound card-info (BIN metadata) lookup in get_card_info_by_bin with Prometheus metrics (scraped by VictoriaMetrics from the existing /metrics endpoint) plus an information-loaded structured WARN log per failure. Successful (2xx) lookups intentionally emit nothing.

Why

get_card_info_by_bin failures were only visible as bare WARN log lines. A degraded cards API (elevated 4xx/5xx, timeouts, throttling) silently disabled BIN enrichment with no way to chart or alert on it.

How

Metrics (bounded-cardinality labels only):

  • card_info_lookup_failures_total{error_code, upstream_code} — counter. error_code is the HTTP status ("400", "503", …) or TIMEOUT / REQUEST_ERROR / PARSE_ERROR; upstream_code is the cards API's own error code parsed from its error body (e.g. IR_31 "IIN does not exist", IR_01 "invalid API key"), empty when absent.
  • card_info_lookup_failure_latency_seconds{error_code} — histogram (timeouts land at the configured timeout_ms cap).
Failure mode error_code
Non-2xx response HTTP status ("400", "503", …)
Client-side timeout (card_info_service.timeout_ms) TIMEOUT
Transport/connect error REQUEST_ERROR
2xx body that fails to deserialize PARSE_ERROR

Logs carry the unbounded forensics that don't belong in metric labels: BIN-free endpoint, latency, upstream code, a 2KB response-body snippet (read chunk-by-chunk and capped, so large upstream error pages are never fully buffered), and an allowlist of useful response headers — x-request-id (correlation with Hyperswitch logs), retry-after (throttling), x-envoy-upstream-service-time (origin vs. proxy latency), plus content-type, content-length, server, via, date, cf-ray.

Sensitive-data hygiene: the BIN never appears in the endpoint field or metric labels, reqwest error messages are stripped of URLs via without_url(), and the binEnrichmentFromCardInfo debug log in flow_new.rs logs only whether the Secret-typed cardSwitchProvider was set, never its value.

No new infrastructure: the app already serves Prometheus text format on the metrics port; VictoriaMetrics/vmagent just scrapes it.

Grafana

Failure rate by error code (VictoriaMetrics datasource):

sum by (error_code) (rate(card_info_lookup_failures_total[5m]))

Alert condition (any failures in the last 5 minutes above threshold):

sum(increase(card_info_lookup_failures_total[5m])) > 10

Latency p99 of failed calls:

histogram_quantile(0.99, sum by (le) (rate(card_info_lookup_failure_latency_seconds_bucket[5m])))

Drill-down: the WARN log line (tag: "cardInfoApi") with x-request-id, headers, and the upstream error body.

Verification

Verified end-to-end locally: POST /decide-gateway with a failing lookup produced card_info_lookup_failures_total{error_code="401",upstream_code="IR_01"} 2 and populated latency-histogram buckets on :9094/metrics, and the WARN log carried the endpoint, latency, x-request-id, full header set, and upstream error body. cargo build clean; all 64 analytics unit tests pass.

🤖 Generated with Claude Code

@GauravRawat369 GauravRawat369 self-assigned this Sep 3, 2026
Copilot AI lite review requested due to automatic review settings September 3, 2026 07:19

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.

🟡 Changes recommended

The new instrumentation currently risks persisting/logging sensitive data (Secret-typed fields and full URLs/BINs) and can read large non-2xx response bodies fully into memory before truncation.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

This PR adds failure instrumentation around the outbound card-info (BIN metadata) lookup, emitting analytics events that can be monitored in ClickHouse/Grafana, and slightly expands BIN enrichment debug logging in the decide-gateway flow.

Changes:

  • Capture and record card-info lookup failures (timeouts, transport errors, non-2xx responses, parse errors) as domain analytics events, including latency and selected response metadata.
  • Introduce a dedicated analytics FlowType (card_info_lookup_error) and event_stage (card_info_lookup) for alerting/query consistency.
  • Expand BIN enrichment debug logging to include cardSwitchProvider.
File summaries
File Description
src/types/card/card_info_api.rs Adds failure handling that records analytics events, including latency and selected response headers/body on non-2xx.
src/decider/gatewaydecider/flow_new.rs Extends BIN enrichment debug log to include cardSwitchProvider.
src/analytics/service.rs Adds a convenience emitter for card-info lookup failure events with a fixed route/flow context.
src/analytics/models.rs Adds CARD_INFO_LOOKUP_STAGE constant used to tag these failure events.
src/analytics/flow.rs Adds FlowType::CardInfoLookupError and its string mapping.
src/analytics/events.rs Adds a new card_info_lookup_failure event constructor that sets stage/status/error fields.
Review details
  • Files reviewed: 6/6 changed files
  • Comments generated: 3
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread src/decider/gatewaydecider/flow_new.rs Outdated
Comment thread src/types/card/card_info_api.rs Outdated
Comment thread src/types/card/card_info_api.rs Outdated
Gaurav Rawat and others added 2 commits September 3, 2026 13:03
- don't log the Secret-typed cardSwitchProvider value; log only whether it was set
- drop the BIN from the analytics details payload (BIN-free endpoint instead of the
  full URL, no duplicate bin key — card_is_in already carries it) and strip URLs
  from reqwest error messages via without_url()
- read the non-2xx response body chunk-by-chunk capped at 2KB instead of buffering
  the whole body

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ead of ClickHouse

Replace the ClickHouse domain-event emission with two Prometheus metrics that
VictoriaMetrics scrapes from /metrics:

- card_info_lookup_failures_total{error_code, upstream_code} — error_code is the
  HTTP status or TIMEOUT/REQUEST_ERROR/PARSE_ERROR; upstream_code is the cards
  API's own error code from the error body (e.g. IR_31), both bounded-cardinality
- card_info_lookup_failure_latency_seconds{error_code} histogram

The unbounded forensics (x-request-id, response headers, 2KB body snippet,
endpoint, latency) move onto the structured WARN log line. Removes the
CardInfoLookupError flow type and its analytics plumbing.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@GauravRawat369 GauravRawat369 changed the title feat: add card info lookup failure handling and analytics tracking feat: track card-info lookup failures with Prometheus metrics and structured logs Sep 3, 2026
Gaurav Rawat and others added 4 commits September 3, 2026 15:50
…rics

card_info_lookup_failures_total gains an error_message label: the upstream error
body's message for non-2xx, the reqwest description for transport/parse failures.
Messages are sanitized to stay bounded-cardinality (serde's ' at line N column M'
suffix stripped, 120-char cap); the unmodified message stays on the WARN log.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…quest id

Remove the Instant/latency capture (latency is no longer used anywhere since the
histogram was dropped) and replace the response-header allowlist with just the
upstream x-request-id. The decision engine's own request id is already recorded
on the request tracing span, so the WARN line carries both ids for correlation.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
jagan-jaya
jagan-jaya previously approved these changes Sep 4, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants