feat(utils): add request context hash helper for trace correlation#237
Conversation
…ccesslayerorg#209) Adds computeRequestContextHash() that hashes method, path, and content-type into a stable 12-char hex digest for log correlation, applied in requestLoggerMiddleware as contextHash field. Closes accesslayerorg#209
|
@Spagero763 Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits. You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀 |
There was a problem hiding this comment.
Pull request overview
Adds a deterministic, non-sensitive request “context hash” for correlating log lines across the same endpoint/method, and wires it into request logging.
Changes:
- Introduces
computeRequestContextHash(req)utility that hashes method + path (no query) + normalizedcontent-type. - Adds
contextHashtorequestLoggerMiddlewarelog payloads. - Adds Jest tests covering determinism and normalization behavior.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| src/utils/request-context-hash.utils.ts | New helper that computes a short SHA-256-derived context hash from safe request fields |
| src/middlewares/request-logger.middleware.ts | Adds contextHash to request logs for correlation |
| src/utils/test/request-context-hash.utils.test.ts | New Jest suite validating hashing behavior and normalization |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| */ | ||
| export function computeRequestContextHash(req: Request): string { | ||
| const path = (req.path || '/').split('?')[0]; | ||
| const contentType = (req.headers['content-type'] ?? '').split(';')[0].trim(); |
There was a problem hiding this comment.
req.headers['content-type'] is typed as string | string[] | undefined (IncomingHttpHeaders). Calling .split() on it will either fail TypeScript compilation or throw at runtime if multiple content-type headers are present. Normalize to a single string first (e.g., Array.isArray(v) ? v[0] : v ?? '') before splitting/trim.
| const contentType = (req.headers['content-type'] ?? '').split(';')[0].trim(); | |
| const rawContentType = req.headers['content-type']; | |
| const normalizedContentType = Array.isArray(rawContentType) | |
| ? (rawContentType[0] ?? '') | |
| : (rawContentType ?? ''); | |
| const contentType = normalizedContentType.split(';')[0].trim(); |
| function makeReq(overrides: Partial<{ method: string; path: string; headers: Record<string, string> }>): Request { | ||
| return { | ||
| method: 'GET', | ||
| path: '/', | ||
| headers: {}, | ||
| ...overrides, | ||
| } as unknown as Request; |
There was a problem hiding this comment.
The helper should handle content-type being a string[] (possible when duplicate headers are present), but the tests only cover the string case and the makeReq helper currently types headers as Record<string, string>, which makes it hard to add this coverage. Consider widening the header type (e.g., Record<string, string | string[]>) and adding a test asserting ['application/json; charset=utf-8'] behaves the same as 'application/json; charset=utf-8'.
Summary
computeRequestContextHash(req)insrc/utils/request-context-hash.utils.tsthat produces a stable 12-character hex digest from safe (non-sensitive) request fields: HTTP method, URL path (query string stripped), andcontent-typeheader (charset suffix stripped)requestLoggerMiddlewareas acontextHashfield on every log entry so log lines from the same endpoint/method share a stable tag for trace correlationsrc/utils/test/request-context-hash.utils.test.ts) covering determinism, field sensitivity, query-string isolation, sensitive-header exclusion, and edge casesWhat is NOT included
Authorization, Cookie, body, query string, and any other sensitive fields are deliberately excluded from the hash computation to avoid leaking user-supplied values into log aggregation.
Test plan
computeRequestContextHashreturns 12-char lowercase hexAuthorizationandCookieheaders do not affect the hashcontent-type; charset=utf-8treated same ascontent-type/Closes #209