# 19. Monitoring & Observability ## Structured Logging (Pino) ```typescript // src/lib/server/logger.ts import pino from 'pino'; const isDev = process.env.NODE_ENV === 'development'; export const logger = pino({ level: process.env.LOG_LEVEL ?? (isDev ? 'debug' : 'info'), transport: isDev ? { target: 'pino-pretty', options: { colorize: true, translateTime: 'HH:MM:ss', ignore: 'pid,hostname', }, } : undefined, formatters: { level: (label) => ({ level: label }), }, base: { env: process.env.NODE_ENV, version: process.env.APP_VERSION ?? '0.0.0', }, redact: { paths: ['password', 'token', 'authorization'], censor: '[REDACTED]', }, }); export const dbLogger = logger.child({ module: 'database' }); export const apiLogger = logger.child({ module: 'api' }); ``` ## Health Check Endpoint ```typescript // src/server/functions/health.ts import { createServerFn } from '@tanstack/react-start/server'; import { db } from '@/lib/server/db'; interface HealthStatus { status: 'healthy' | 'degraded' | 'unhealthy'; timestamp: string; version: string; checks: { database: boolean; cache: boolean; }; } export const getHealth = createServerFn({ method: 'GET' }).handler( async (): Promise => { const checks = { database: false, cache: true, }; try { await db.$queryRaw`SELECT 1`; checks.database = true; } catch { // Database check failed } const allHealthy = Object.values(checks).every(Boolean); return { status: allHealthy ? 'healthy' : 'degraded', timestamp: new Date().toISOString(), version: process.env.APP_VERSION ?? '0.0.0', checks, }; } ); ``` ## Application Metrics ```typescript // src/lib/server/metrics.ts class MetricsCollector { private startTime = Date.now(); private data = { requests: { total: 0, errors: 0 }, database: { queries: 0, slowQueries: 0 }, cache: { hits: 0, misses: 0 }, }; incrementRequest(isError = false): void { this.data.requests.total++; if (isError) this.data.requests.errors++; } incrementDbQuery(isSlow = false): void { this.data.database.queries++; if (isSlow) this.data.database.slowQueries++; } incrementCacheHit(): void { this.data.cache.hits++; } incrementCacheMiss(): void { this.data.cache.misses++; } getMetrics() { return { ...this.data, uptime: Math.floor((Date.now() - this.startTime) / 1000), }; } } export const metrics = new MetricsCollector(); ``` ---