Skip to content

Commit e528bd0

Browse files
Merge pull request #711 from codenerde/task/webhooks-logs-v7
feat: structured logs /api/webhooks with correlation IDs
2 parents 8e7c620 + 74fece1 commit e528bd0

3 files changed

Lines changed: 460 additions & 0 deletions

File tree

src/middleware/accessLog.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,8 @@ export function accessLog(req: Request, res: Response, next: NextFunction): void
129129
logName = "markets_access_log";
130130
} else if (req.originalUrl.startsWith("/api/feature-flags")) {
131131
logName = "feature_flags_access_log";
132+
} else if (req.originalUrl.startsWith("/api/webhooks")) {
133+
logName = "webhooks_access_log";
132134
}
133135

134136
const durationMs = Date.now() - startMs;

src/routes/webhooks.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,11 @@
1010
* Rate-limit keying is based on the authenticated stellar address populated by
1111
* `requireAuth`, so quota is tracked independently per user, not per IP.
1212
*
13+
* All routes are wrapped by `accessLog` which:
14+
* - Resolves a correlation ID via the priority chain (header → req.id → UUID)
15+
* - Echoes it back in the `X-Correlation-Id` response header
16+
* - Emits a structured `webhooks_access_log` entry on every response finish.
17+
*
1318
* Endpoints:
1419
* GET / — list webhook subscriptions
1520
* POST / — create a new webhook subscription
@@ -24,6 +29,7 @@
2429
import { Router } from "express";
2530
import { logger } from "../config/logger";
2631
import { getRequestId } from "../lib/requestContext";
32+
import { accessLog } from "../middleware/accessLog";
2733
import { webhookCors } from "../middleware/cors";
2834
import { requireAdmin } from "../middleware/requireAdmin";
2935
import { webhooksRateLimiter } from "../middleware/rateLimit";
@@ -38,6 +44,11 @@ import { webhooksRateLimiter } from "../middleware/rateLimit";
3844

3945
export const webhooksRouter = Router();
4046

47+
// Structured access log — resolves correlation ID, echoes it back, and
48+
// emits a webhooks_access_log entry on every response finish.
49+
// Mounted first so the correlation ID is available to all downstream handlers.
50+
webhooksRouter.use(accessLog);
51+
4152
// Enforce CORS allowlist before admin auth so unapproved origins are
4253
// rejected early without leaking auth challenge details.
4354
webhooksRouter.use(webhookCors());

0 commit comments

Comments
 (0)