Image Upload & Thumbnails Tutorial · Module 09 of 11

Observability & Caching

Add structured logging with trace IDs, Prometheus metrics for uploads/transforms/queries, and Redis caching for thumbnails and search results. Build Grafana dashboard. By the end, you have full visibility into service performance and can diagnose issues quickly.

~4–5 hrsAdvancedObservability focus
← Back to Module 09 overview
What You'll Have at the End

Definition of Done

  • Structured JSON logging with trace IDs for every request.
  • Prometheus metrics: uploads_total, transform_latency_seconds, cache_hits, cache_misses, thumbnail_generation_time.
  • Redis caching for: thumbnails, transformed images, search results.
  • Cache TTL: thumbnails 7 days, transforms 1 day, searches 1 hour.
  • Grafana dashboard: upload volume, transform throughput, cache hit rate, storage usage.
  • Can answer: "What's the p95 transform time?" "Cache hit rate?" "Peak upload volume?"
The Steps

Build It

STEP 1

Add structured logging and metrics

Install: npm install pino pino-pretty prom-client

Create src/metrics.ts:

import { Counter, Histogram, Gauge } from 'prom-client';

export const uploadsTotal = new Counter({
  name: 'image_uploads_total',
  help: 'Total number of images uploaded',
  labelNames: ['status']
});

export const transformLatency = new Histogram({
  name: 'image_transform_latency_seconds',
  help: 'Time to apply image transformation',
  buckets: [0.05, 0.1, 0.5, 1, 2, 5]
});

export const cacheHits = new Counter({
  name: 'image_cache_hits_total',
  help: 'Cache hits for thumbnails and transforms',
  labelNames: ['type']
});

export const cacheMisses = new Counter({
  name: 'image_cache_misses_total',
  help: 'Cache misses for thumbnails and transforms',
  labelNames: ['type']
});

export const storageBytes = new Gauge({
  name: 'image_storage_bytes',
  help: 'Total size of stored images'
});

export const thumbnailQueueDepth = new Gauge({
  name: 'thumbnail_queue_depth',
  help: 'Number of pending thumbnail generation jobs'
});