Course navigationPhase 30
Volume 08 · Phase 30

Logging & Observability

Make production behavior observable with structured logs, request correlation, error monitoring, metrics, traces/signals, and actionable alerts.

16lessons + labs
4klesson words
12source references
What you will ship

Phase outcome and project increment

Learning outcome

Make production behavior observable with structured logs, request correlation, error monitoring, metrics, traces/signals, and actionable alerts.

Concrete deliverable

Observability layer connecting Next.js/API errors and request IDs to structured logs and monitoring releases.

Figure 30.1 — Where this phase lives in TaskFlow
request/user action
correlation ID
structured events
error monitor/metrics
dashboard/alert
diagnosis
Trace the flow left-to-right for implementation and right-to-left for debugging. At every arrow, ask what data crosses the boundary and what proves it is trustworthy.
Instructor mental model

Principles to keep while coding

01

Logs should answer what happened, where, and for which request without exposing sensitive data.

02

Use request or correlation identifiers to connect events across application boundaries.

03

Metrics reveal system trends while traces and structured logs help explain individual failures.

04

Alert on user-impacting symptoms and actionable conditions rather than every noisy internal event.

Code-along path

Guided phase lab

Do these in order. Each step should end with evidence before the next one starts.

  1. 01

    Define the minimum structured fields every API request/error log should carry.

  2. 02

    Generate or propagate a request ID and return it so support can correlate client reports.

  3. 03

    Redact secrets and PII deliberately before adding rich context.

  4. 04

    Integrate error monitoring for both Next.js and NestJS and tag releases by commit SHA.

  5. 05

    Add a few meaningful application/HTTP/database signals rather than hundreds of vanity metrics.

  6. 06

    Simulate a production-style error and walk from user-visible request ID to logs/monitoring evidence.

Debugging studio

Failures you should know how to diagnose

Failure drill 1

console.log strings with no searchable structure

Predict the symptom, capture evidence at the nearest boundary, change one variable, and verify the same reproduction after the fix.

Failure drill 2

Tokens/passwords in logs

Predict the symptom, capture evidence at the nearest boundary, change one variable, and verify the same reproduction after the fix.

Failure drill 3

Alerts on every exception rather than user-impacting symptoms

Predict the symptom, capture evidence at the nearest boundary, change one variable, and verify the same reproduction after the fix.

Failure drill 4

No release/environment tags so errors cannot be tied to deployments

Predict the symptom, capture evidence at the nearest boundary, change one variable, and verify the same reproduction after the fix.

Watch-order style

Lessons

The source chapters come first. Every phase now ends with a guided build, a debugging workshop, and an independent challenge so reading turns into transferable skill.

01

Observability Mental Model

Observability Mental Model Full Stack Developer 2026 Complete - TaskFlow Monitoring asks known questions such as “is error rate above 5%?” Observability is broader: it lets engineers investi

2 min
02

Structured Logging Log Levels and Events

Structured Logging, Levels, and Events Full Stack Developer 2026 Complete - TaskFlow NestJS 12 can emit JSON directly through ConsoleLogger and treats plain objects passed after the message

2 min
03

Correlation IDs and Request Context

Correlation IDs and Request Context Full Stack Developer 2026 Complete - TaskFlow TaskFlow already uses Fastify request.id. Phase 30 formalizes it as correlation context and returns x-reques

2 min
04

Request Logging and Latency Metrics

Request Logging and Latency Metrics Full Stack Developer 2026 Complete - TaskFlow A single request-completion record is more valuable than several disconnected “started / controller entered

2 min
05

Health Liveness Readiness and Graceful Shutdown

Health, Liveness, Readiness, and Graceful Shutdown Full Stack Developer 2026 Complete - TaskFlow A process can be alive but not ready to serve real traffic. TaskFlow separates those concepts

2 min
06

Sentry Error Monitoring for NestJS and Next.js

Sentry Error Monitoring for NestJS and Next.js Full Stack Developer 2026 Complete - TaskFlow Sentry complements the public error envelope from Phase 13. Clients still receive safe error resp

2 min
07

Traces and OpenTelemetry Concepts

Traces and OpenTelemetry Concepts Full Stack Developer 2026 Complete - TaskFlow A trace models one operation as related spans. For TaskFlow, an HTTP request may contain spans for authorizati

2 min
08

Database Realtime Storage and Background Work Observability

Database, Realtime, Storage, and Background Work Full Stack Developer 2026 Complete - TaskFlow Request logs alone are not enough once TaskFlow performs database, Realtime, Storage, and later

2 min
09

Dashboards SLOs and Alert Design

Dashboards, SLOs, and Alert Design Full Stack Developer 2026 Complete - TaskFlow A dashboard should answer an operational question. A good first TaskFlow dashboard focuses on traffic, errors

2 min
10

Privacy Redaction and Telemetry Cost

Privacy, Redaction, and Telemetry Cost Full Stack Developer 2026 Complete - TaskFlow Telemetry is a data system. Treat it with the same care as application data. Every log field, trace attri

2 min
11

Incident Debugging Runbooks and Testing

Incident Debugging, Runbooks, and Testing Full Stack Developer 2026 Complete - TaskFlow Observability becomes valuable during an incident only if engineers know how to use it. Phase 30 adds

2 min
12

Hands On Lab and Phase Exit

Hands-On Lab and Phase Exit Full Stack Developer 2026 Complete - TaskFlow Level 1 - Follow • Enable JSON logging in production mode. • Add a request completion interceptor/middleware with re

2 min
LAB

Guided Build Lab

Purpose Make production behavior observable with structured logs, request correlation, error monitoring, metrics, traces/signals, and actionable alerts.

3 min
LAB

Debugging Workshop

Goal Learn to diagnose this phase's failures systematically instead of reinstalling packages, changing random configuration, or copying a fix without understanding it.

2 min
LAB

Phase Synthesis & Independent Challenge

Mission Rebuild the capability of Phase 30 without following the exact code line-by-line. The goal is transfer: can you use the ideas when the variable names, UI, or route shape changes?

2 min
LAB

Mastery Capstone Lab

Integrate Phase 30 without following a transcript.

2 min
Practice ladder

Exercises that increase independence

Guided

Define the minimum structured fields every API request/error log should carry.

Practice

Redact secrets and PII deliberately before adding rich context.

Debug

reproduce and diagnose — console.log strings with no searchable structure.

Independent

deliver Observability layer connecting Next.js/API errors and request IDs to structured logs and monitoring releases.

Explain-back

Can correlate one request across layers and Can log useful context safely.

Mastery gate

Do not leave the phase only because you reached the bottom

Phase exit criteria

Knowledge check

Scenario and concept quiz

These questions test engineering choices rather than whether you remember a lesson title.

0/0 correct · 0/8 answered
01Which practice best matches Phase 30's engineering goal?
02Which practice best matches Phase 30's engineering goal?
03Which practice best matches Phase 30's engineering goal?
04Which practice best matches Phase 30's engineering goal?
05You are working through the Phase 30 lab. Which next action is the most disciplined step?
06You are working through the Phase 30 lab. Which next action is the most disciplined step?
07You are working through the Phase 30 lab. Which next action is the most disciplined step?
08You are working through the Phase 30 lab. Which next action is the most disciplined step?
Source snapshot

Reference files

Attempt the work first. Use snapshots to compare a checkpoint, not as a substitute for understanding.

reference/TaskFlow_Observability_Snapshot/INCIDENT_RUNBOOK.md
# TaskFlow incident runbook
1. Confirm symptom, start time, affected route/workflow, environment, release.
2. Inspect request/error rate and p95/p99 latency.
3. Select a representative request/error and correlate by requestId.
4. Use traces/logs to isolate the slow/failing boundary.
5. Mitigate first; verify recovery with metrics and health checks.
6. Create follow-up action for root cause, missing telemetry, and test coverage.
reference/TaskFlow_Observability_Snapshot/OBSERVABILITY_FIELD_CATALOG.md
# Observability field catalog

Allowed common fields: requestId, event, context, method, normalizedRoute, statusCode, durationMs, environment, release, workspaceId (logs/traces only where needed), internal userId (policy-dependent).

Never record: Authorization headers, cookies, access/refresh tokens, passwords, service-role keys, DATABASE_URL, signed upload tokens, raw uploaded content.

Metric labels should remain low-cardinality: method, normalized route, status class, environment.
reference/TaskFlow_Observability_Snapshot/README.md
# TaskFlow Phase 30 observability snapshot
Study snapshot only. Merge into the evolving TaskFlow repository intentionally. Do not copy secrets into examples. The design keeps NestJS structured logging, Terminus health checks, Sentry error/performance monitoring, and vendor-neutral OpenTelemetry concepts separated by responsibility.
reference/TaskFlow_Observability_Snapshot/SOURCES.md
# Official references
- https://docs.nestjs.com/techniques/logger
- https://docs.nestjs.com/recipes/terminus
- https://opentelemetry.io/docs/concepts/signals/
- https://opentelemetry.io/docs/concepts/signals/metrics/
- https://prometheus.io/docs/practices/histograms/
- https://www.npmjs.com/package/@sentry/nestjs
- https://www.npmjs.com/package/@sentry/nextjs
- https://www.npmjs.com/package/@nestjs/terminus
- https://www.npmjs.com/package/@opentelemetry/api
reference/TaskFlow_Observability_Snapshot/VERSION_LOCK.md
# Phase 30 version lock
- @nestjs/terminus 12.0.0
- @sentry/nestjs 10.75.0
- @sentry/nextjs 10.75.0
- @opentelemetry/api 1.9.1
- @opentelemetry/sdk-node 0.222.0 is discussed but not hard-locked as a production dependency because the package describes itself as experimental.
reference/TaskFlow_Observability_Snapshot/apps/api/package.phase30.json
{
  "dependencies": {
    "@nestjs/terminus": "12.0.0",
    "@sentry/nestjs": "10.75.0",
    "@opentelemetry/api": "1.9.1"
  }
}
reference/TaskFlow_Observability_Snapshot/apps/api/src/health/health.controller.ts
import { Controller, Get } from '@nestjs/common';
import { HealthCheck, HealthCheckService, PrismaHealthIndicator } from '@nestjs/terminus';
import { PrismaService } from '../prisma/prisma.service';

@Controller('health')
export class HealthController {
  constructor(
    private readonly health: HealthCheckService,
    private readonly prismaHealth: PrismaHealthIndicator,
    private readonly prisma: PrismaService,
  ) {}

  @Get('live')
  live() { return { status: 'ok' }; }

  @Get('ready')
  @HealthCheck()
  ready() {
    return this.health.check([
      () => this.prismaHealth.pingCheck('database', this.prisma),
reference/TaskFlow_Observability_Snapshot/apps/api/src/instrument.ts
import * as Sentry from '@sentry/nestjs';

Sentry.init({
  dsn: process.env.SENTRY_DSN,
  environment: process.env.NODE_ENV,
  tracesSampleRate: Number(process.env.SENTRY_TRACES_SAMPLE_RATE ?? '0.1'),
});
reference/TaskFlow_Observability_Snapshot/apps/api/src/main.observability-example.ts
import { ConsoleLogger } from '@nestjs/common';
import { NestFactory } from '@nestjs/core';
import './instrument';
import { AppModule } from './app.module';

async function bootstrap() {
  const app = await NestFactory.create(AppModule, {
    logger: new ConsoleLogger({
      json: process.env.NODE_ENV === 'production',
    }),
  });

  app.enableShutdownHooks();
  await app.listen(process.env.PORT ?? 3001);
}
void bootstrap();
reference/TaskFlow_Observability_Snapshot/apps/api/src/observability/request-logging.interceptor.ts
import { CallHandler, ExecutionContext, Injectable, Logger, NestInterceptor } from '@nestjs/common';
import type { FastifyReply, FastifyRequest } from 'fastify';
import { Observable, finalize } from 'rxjs';

@Injectable()
export class RequestLoggingInterceptor implements NestInterceptor {
  private readonly logger = new Logger('HTTP');

  intercept(context: ExecutionContext, next: CallHandler): Observable<unknown> {
    const http = context.switchToHttp();
    const request = http.getRequest<FastifyRequest>();
    const reply = http.getResponse<FastifyReply>();
    const started = performance.now();

    reply.header('x-request-id', request.id);

    return next.handle().pipe(
      finalize(() => {
        this.logger.log('HTTP request completed', {
          requestId: request.id,
reference/TaskFlow_Observability_Snapshot/apps/web/package.phase30.json
{
  "dependencies": {
    "@sentry/nextjs": "10.75.0"
  }
}
reference/TaskFlow_Observability_Snapshot/tests/observability-test-matrix.md
# Observability verification matrix
- x-request-id returned on API responses.
- request completion log contains requestId, normalized route, status, duration.
- logs contain no Authorization/Cookie/secret values.
- /health/live remains 200 while process is healthy.
- /health/ready fails when test PostgreSQL is unavailable.
- synthetic error appears in non-production Sentry with requestId.
- p95/p99 latency can be derived from histogram/distribution telemetry.
- metrics contain no userId/taskId/requestId labels.
- alert test reaches the intended channel and points to a runbook.