Structured Logging in Node.js: Trace a Failed Course Request
Practical Web Development — Lesson 9 of 10 · Advanced
“The API failed” is difficult to investigate without a link between a user's error and a server event. A request identifier gives you that link. Structured logs make fields such as route, status and duration easier to search than an inconsistent paragraph of text. This example creates a small local server using only built-in Node modules.
Log the completed response
Save as server.mjs, run node server.mjs and open http://localhost:3000/api/courses. The server binds to the local machine for this learning exercise.
import { createServer } from 'node:http';
import { randomUUID } from 'node:crypto';
import { performance } from 'node:perf_hooks';
createServer((req, res) => {
const id = randomUUID();
const started = performance.now();
const path = new URL(req.url, 'http://localhost').pathname;
const route = path === '/api/courses' ? '/api/courses' : 'unmatched';
res.setHeader('X-Request-ID', id);
res.on('finish', () => {
console.log(JSON.stringify({
event: 'http_response', requestId: id, route,
method: req.method, status: res.statusCode,
durationMs: Math.round(performance.now() - started)
}));
});
res.setHeader('Content-Type', 'application/json');
if (req.method === 'GET' && route === '/api/courses') {
res.end(JSON.stringify([{ id: 'html', title: 'HTML fundamentals' }]));
} else {
res.statusCode = 404;
res.end(JSON.stringify({ error: 'Not found', requestId: id }));
}
}).listen(3000, '127.0.0.1');Make fields answer real questions
The identifier is generated by the server and returned in a header. A support report can include that identifier without needing a full request body. The route field is a fixed label rather than an arbitrary URL, which keeps the number of distinct values bounded and avoids recording query strings.
The finish event means the response data was handed off for transmission; it does not prove the client received or displayed the result. A production service also needs to observe aborted connections and errors. Do not label every finish event as a completed learner journey.
Protect useful logs from becoming a liability
Do not record passwords, authorization headers, cookies or private learner notes. Choose retention and access rules before centralizing logs. Even ordinary fields can become sensitive when combined. Logging everything and deleting it later is harder to control than collecting a small intentional set of fields.
Test two routes
The catalogue path should return 200. A missing path should return 404 and include the request ID in its JSON body. Find that same ID in the terminal record. Send several requests and confirm each gets a distinct ID. Compare durations as observations of this machine, not a performance benchmark.
Practice
Add a controlled error route in a development-only exercise and record a stable error category. Keep detailed stack traces in restricted server logs and return a generic message to the client. Then write an operational question your logs can answer, such as “Which route produced the most failures after a release?”
Continue learning
Review our semantic HTML project, JavaScript course filter and course platform architecture.
Reference: Technical documentation for this lesson. Examples are learning exercises; test them in your environment.
Comments
Post a Comment