Skip to main content
DevOps & CloudSoftware Engineering

Monitoring and Observability for Web Applications

Set up proper monitoring with structured logging, error tracking, performance metrics, and alerting before your users find the bugs.

Mbeah Essilfie

Mbeah Essilfie

May 22, 2026 at 06:04 AM

10 min read 791 views
Monitoring and Observability for Web Applications

Observability ≠ Monitoring

Monitoring tells you something is wrong (alert: 500 errors spiking). Observability helps you understand why (trace the request through your system).

The three pillars: Logs, Metrics, Traces.

Structured Logging

// ❌ Unstructured — hard to search and parse
console.log('User ' + userId + ' created post ' + postId)

// ✅ Structured — queryable and parseable
logger.info('Post created', {
  userId,
  postId,
  duration: elapsed,
  tags: post.tags,
})

A simple structured logger:

type LogLevel = 'debug' | 'info' | 'warn' | 'error'

function createLogger(service: string) {
  return {
    info: (message: string, meta?: Record<string, unknown>) =>
      emit('info', message, meta),
    error: (message: string, error?: Error, meta?: Record<string, unknown>) =>
      emit('error', message, { ...meta, error: error?.stack }),
  }

  function emit(level: LogLevel, message: string, meta?: Record<string, unknown>) {
    const entry = {
      timestamp: new Date().toISOString(),
      level,
      service,
      message,
      ...meta,
    }
    console.log(JSON.stringify(entry))
  }
}

const logger = createLogger('api')

Error Tracking

// server/plugins/error-tracking.ts
export default defineNitroPlugin((nitroApp) => {
  nitroApp.hooks.hook('error', (error, { event }) => {
    // Send to Sentry, Bugsnag, etc.
    reportError({
      error,
      url: event?.path,
      user: event?.context?.user?.id,
      timestamp: Date.now(),
    })
  })
})
Don't just log errors — alert on them. An error in your logs that nobody sees is the same as no error tracking at all.

Key Metrics to Track

Application metrics:

  • Request rate (requests/second)
  • Error rate (5xx responses / total)
  • Latency (p50, p95, p99)
  • Active users

Infrastructure metrics:

  • CPU / Memory usage
  • Database connection pool utilization
  • Queue depth

Health Check Endpoint

// server/api/health.get.ts
export default defineEventHandler(async () => {
  const checks = {
    database: await checkDb(),
    redis: await checkRedis(),
    storage: await checkS3(),
  }

  const healthy = Object.values(checks).every(c => c.status === 'ok')

  return {
    status: healthy ? 'healthy' : 'degraded',
    checks,
    version: process.env.APP_VERSION,
    uptime: process.uptime(),
  }
})

Alerting Rules

Set alerts based on:

  • Error rate > 1% for 5 minutes
  • P95 latency > 2 seconds
  • Health check failures for 2+ consecutive checks
  • Disk usage > 80%

Key principle: Alert on symptoms (users are affected), not causes (CPU is high). High CPU that doesn't impact users isn't an emergency.

Start Simple

You don't need a full observability platform on day one:

  1. Structured JSON logs → searchable in any log viewer
  2. Health check endpoint → uptime monitoring (free tier from UptimeRobot)
  3. Error tracking → Sentry free tier
  4. Basic metrics → built into your hosting platform

Add complexity only when you need to answer questions your current tools can't.

Node.jsDevOpsPerformance
Mbeah Essilfie

Written by Mbeah Essilfie

Fullstack Software Developer

Read next

The Complete Guide to Vue 3 Composables
12 min read

The Complete Guide to Vue 3 Composables

Understand the power of Vue 3's Composition API through practical, real-world composable patterns that you can use today.

Mbeah EssilfieMbeah Essilfie
981