Skip to content

Feature: Structured Request ID Propagation Across Logs and Error Responses #13

Description

@merlik787-droi

Labels / Complexity: enhancement · High — 800

Context

The service logs per request but never correlates them. src/app.ts mounts morgan('dev') for access logs, src/config/logger.ts emits Winston logs with a simple() format, and src/middleware/error.middleware.ts logs errors and returns an envelope — but none of these attach a shared request identifier. When a request fans out across a controller, the rewards/Stellar service, and the error handler, there is no way to group its log lines.

The roadmap already commits to this work:

// docs/ROADMAP.md — "Next"
- Add structured request IDs and propagate them across logs and HTTP responses.

A naive hardcoded console.log of a counter would not survive a multi-replica deployment and would not be retrievable by the client, which is the whole point of a request ID.

Goal

Assign every incoming request a unique, propagated identifier, include it in all log lines produced while handling that request, and return it to the client in every response (and in the error envelope) so an operator can trace a single request end to end from the access log through service logs to the HTTP response.

Scope

1. Request ID assignment middleware

Add middleware early in src/app.ts (before morgan and routes) that reads an inbound X-Request-Id (validating it, and rejecting or sanitizing values over a bounded length) or generates one, then stores it on the request. Decide the format (UUID v4 vs. a short nonce) and whether a client-supplied value is trusted or always overwritten.

2. Log correlation

Propagate the request ID into the Winston logger and morgan so every line includes it. Extend src/config/logger.ts (currently format.simple()) with the request ID as structured metadata, and configure morgan in src/app.ts to emit the token. Decide whether the logger reads the ID from an async-local storage context or from an explicit argument passed down the call chain.

3. Response and error propagation

Return the ID on every response — a X-Request-Id header and/or a requestId field — and add it to the errorHandler envelope in src/middleware/error.middleware.ts (both the success-adjacent and error shapes). Ensure asyncHandler and notFoundHandler also preserve it.

4. Tests and documentation

Cover the middleware (generates a valid ID, honors/overwrites an inbound one, rejects an oversized value) and the error handler (ID present on error responses). Document the header in docs/API.md and docs/OPERATIONS.md.

Downstream impact

Adding a response header and an error-envelope field is backward-compatible for clients that ignore unknown fields. Kqirox/Orivex-Frontend is unaffected (it makes no live requests yet). No bindings are regenerated.

Acceptance criteria

Middleware

  • Every response carries an X-Request-Id (or equivalent) whose value is a valid, bounded identifier.
  • A client-supplied X-Request-Id is either honored (after validation) or safely overwritten, per the documented decision, and oversized or malformed values never crash the handler.

Logging

  • Request-scoped log lines from morgan, Winston, and error.middleware.ts include the same request ID for a single request.

Error responses

  • The errorHandler envelope includes the request ID alongside error.message and error.code.

Tests

  • Unit tests assert ID generation, inbound handling, and presence on both success and error responses.

Documentation

  • docs/API.md and docs/OPERATIONS.md document the X-Request-Id header and how to query logs by it.

Out of scope

Do not implement OpenTelemetry tracing in this issue (that is a separate roadmap item); request IDs are plain correlation, not spans.

Getting started

Files in scope: src/app.ts, src/config/logger.ts, src/middleware/error.middleware.ts, src/utils/logger.ts, docs/API.md, docs/OPERATIONS.md.

Commands: pnpm lint, pnpm build, pnpm test:ci.

Good first files to read: src/app.ts, src/config/logger.ts, src/middleware/error.middleware.ts.

Metadata

Metadata

Labels

GrantFox OSSIssue tracked in GrantFox OSSMaybe RewardedIssue may be eligible for a GrantFox rewardThird CampaignCampaign: Third CampaignenhancementNew feature or request

Type

No type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions