Structured Logging
Problem
Implement request logging middleware that emits structured JSON logs for every HTTP request. Each log entry must include the request method, path, status code, response time, and a correlation ID that traces a request through your system.
Background
Unstructured text logs (console.log("user logged in")) are useless at scale. You can't search them, aggregate them, or alert on them. Structured JSON logs let tools like Elasticsearch, Datadog, and CloudWatch parse, index, and query your logs automatically.
Every production system needs structured logging with correlation IDs — a unique identifier that follows a request through all services, making it possible to trace a single user action across distributed systems.
Requirements
- Every request should produce a JSON log line on stdout (one line per request)
- Each log must include:
method,path,statusCode,durationMs,requestId - The
requestIdshould be taken from thex-request-idheader if present, or generated as a UUID - The
requestIdmust be returned in the responsex-request-idheader - Log entries must include a
timestampfield in ISO 8601 format - Error responses (4xx, 5xx) should include
level: "error", success responseslevel: "info" - Implement
POST /echowhich returns the request body — this is the endpoint the harness will test
Your Server
- Your server receives
PORT(default3000) - No database or external dependencies needed
- Logs must go to stdout (console.log), one JSON object per line
API Contract
`GET /health`
- Status:
200 - Body:
{ "status": "ok" }
`POST /echo`
Returns the request body as-is.
Request:
- Body: any JSON object
Response:
- Status:
200 - Body: same JSON as request body
`GET /error`
Returns a server error (for testing error-level logging).
- Status:
500 - Body:
{ "error": "Something went wrong" }
Log Format
Each log entry should be a single JSON line on stdout:
{
class="text-pass">"timestamp": class="text-pass">"2024-01-15T10:30:00.000Z",
class="text-pass">"level": class="text-pass">"info",
class="text-pass">"method": class="text-pass">"POST",
class="text-pass">"path": class="text-pass">"/echo",
class="text-pass">"statusCode": 200,
class="text-pass">"durationMs": 3,
class="text-pass">"requestId": class="text-pass">"abc-123"
}Useful APIs
These are the key APIs you'll need. How you combine them is the challenge.
class=class="text-pass">"text-fg-subtle">// Generate a UUID (built-in, no dependencies)
const id = crypto.randomUUID()
class=class="text-pass">"text-fg-subtle">// Get the current time as ISO 8601
new Date().toISOString()
class=class="text-pass">"text-fg-subtle">// Measure elapsed time in milliseconds
const start = Date.now()
class=class="text-pass">"text-fg-subtle">// ... later ...
const durationMs = Date.now() - start
class=class="text-pass">"text-fg-subtle">// Run code after the response is sent (to capture status code)
res.on(class="text-pass">'finish', () => { console.log(res.statusCode) })
class=class="text-pass">"text-fg-subtle">// Output a single JSON line to stdout
console.log(JSON.stringify({ key: class="text-pass">'value' }))
class=class="text-pass">"text-fg-subtle">// Express middleware signature
app.use((req, res, next) => { /* before */ next() /* after fires on res events */ })Your solution will be tested against these scenarios plus a hidden set.
- 01Server emits structured JSON log lines to stdout
- 02Log entries include method, path, statusCode, durationMs, requestId, and timestamp
- 03x-request-id from request header is used as requestId and returned in response header
- 04A UUID requestId is generated when x-request-id header is not provided
Hints
Click each hint to reveal it. Take your time — try before you peek.