Fullstack CourseLearn by building
Back to week 4

Topic

Logging & observability

Definition

Observability is the ability to understand what a running system is doing from the signals it emits — logs, metrics, and traces — and structured logging is the practice of emitting those events as machine-parseable records, typically tagged with a correlation id that ties every log line for one request together.

In simpler words

When something breaks in production you cannot attach a debugger — you rely on the logs and signals the app already emitted. Good logging means you can follow one request end to end.

In a typical Nest app, a correlation id is threaded through every request and stamped onto error responses. Build the mental model on that pattern, then see what structured logging and health checks add.

After this you can

  • Follow one request from a client error to its server log via a correlation id
  • Choose log levels and keep secrets and PII out of logs
  • Explain how health checks, metrics, and traces complement logs

The correlation-id thread

Definition

A correlation id is a unique identifier assigned to each incoming request and propagated through logs and the response so that all work for that request can be linked together, which is what turns scattered log lines into a traceable story.

In simpler words

Every request gets one id; that id appears in the response and in each related log line, so a user-reported error maps to exactly the right server logs.

CorrelationIdMiddleware runs first in the pipeline: it reuses an incoming x-correlation-id header or generates a UUID, stores it on the request, and echoes it back in the response header.

AllExceptionsFilter reads that same id and includes it in the ApiErrorBody, so a client can report the correlationId from a failed response and you can grep server logs for it.

Assigning the id

const incoming = req.header('x-correlation-id');
const correlationId = incoming && incoming.length > 0 ? incoming : randomUUID();
req.correlationId = correlationId;
res.setHeader('x-correlation-id', correlationId);
next();

One id per request, surfaced in the response header — the anchor every log line for this request should carry.

Structured logging and levels

Definition

Structured logging emits each event as a keyed record — level, message, correlation id, and context fields — rather than free-form text, so logs can be filtered and searched by machine, and log levels (error, warn, log/info, debug) let you keep production quiet while enabling detail when investigating.

In simpler words

Log objects, not sentences: a JSON line with a level and a correlation id is searchable; a printf string is not.

Attach the correlationId to every log line for a request so a search returns the whole story; include useful context (route, user id) but never the payload wholesale.

Use levels deliberately: error for failures that need attention, warn for recoverable oddities, info for milestones, debug for detail you switch on temporarily — noisy info logs bury the signal.

Structured vs unstructured

// Unstructured — hard to search, no request linkage
console.log('user ' + userId + ' failed to update ticket');

// Structured — filter by level, correlationId, fields
logger.warn({ correlationId, userId, ticketId, event: 'ticket.update.forbidden' });

The structured line can be queried by correlationId or event across thousands of requests.

Health checks, metrics, and traces

Definition

Logs explain individual events, health checks report whether the service and its dependencies are ready to serve, metrics aggregate behavior over time (request rate, error rate, latency), and traces follow one request across services — together they answer what broke, whether the service is up, how it behaves in aggregate, and where time was spent.

In simpler words

Logs are the story of one request; health checks say ‘am I up?’, metrics say ‘how am I doing overall?’, and traces say ‘where did the time go across services?’.

A Nest app can expose a health endpoint (for example a HealthModule) — a cheap liveness/readiness signal a load balancer or orchestrator can poll to decide whether to send traffic.

Metrics (counters, histograms) and distributed traces are the next layer for a real deployment; the correlation id here is the seed of tracing — a trace id is the same idea propagated across service boundaries.

Four signals, four questions

Logs    -> what happened in this request?      (correlationId)
Health  -> is the service ready to serve?       (GET /health)
Metrics -> error rate / latency over time?      (dashboards, alerts)
Traces  -> where did time go across services?   (trace id spans)

You reach for a different signal depending on the question — no single one covers all four.

Keep in mind

  • Tag every log line with the request’s correlation id so one request is traceable.
  • Prefer structured (keyed) logs over free-form strings for searchability.
  • Never log secrets or full payloads — log identifiers, outcomes, and redacted context.
  • Use health checks, metrics, and traces alongside logs; each answers a different question.

Test

Check your understanding

At least 10 questions — mix of concept, syntax, practical, and logic. Score ≥80% (enforced by the API) to save progress.

Checking your session…

14 questions · concept 4 · syntax 3 · practical 4 · logic 3

1. What is observability?
Concept
2. What is a correlation id used for?
Syntax
3. Where is the correlation id assigned in this API?
Practical
4. How does a client connect its error to server logs?
Logic
5. What is structured logging?
Concept
6. Why use log levels?
Practical
7. What must never appear in logs?
Syntax
8. What question does a health check answer?
Logic
9. What do metrics provide that logs do not?
Concept
10. How does the correlation id relate to tracing?
Practical
11. What does this middleware code do?
Conceptintermediate
const correlationId = incoming && incoming.length > 0 ? incoming : randomUUID();
res.setHeader('x-correlation-id', correlationId);
12. Which log line is searchable by request?
Syntaxintermediate
logger.warn({ correlationId, userId, event: 'ticket.update.forbidden' });
13. What is wrong with this log?
Practicaladvanced
logger.info('login', { email, password });
14. What signal answers whether the service is up?
Logicintermediate
GET /health -> 200 OK

Checking your session…