How do you implement effective error handling and logging in production software?
Production error handling requires structured approach at every layer. Error hierarchy: define custom error classes for different error types (ValidationError, NotFoundError, AuthorizationError, ExternalServiceError), each with HTTP status codes, error codes, and user-friendly messages. API error responses: return consistent JSON format with error code, message, and optional details; never expose stack traces or internal implementation details to clients. Logging: implement structured logging (JSON format) with consistent fields (timestamp, level, service, requestid, userid, errorcode, message), use log levels appropriately (ERROR for unexpected failures, WARN for recoverable issues, INFO for business events, DEBUG for development), and correlate logs across services using a request ID propagated through headers. Error tracking: integrate Sentry or Bugsnag for real-time error aggregation with source maps, stack traces, and user context. Implementation: wrap all async operations in try-catch blocks, implement global error handlers in Express/FastAPI for unhandled exceptions, use React error boundaries for UI crash recovery, and implement retry logic for transient failures (network timeouts, rate limits). Monitoring: alert on error rate spikes (not individual errors), track error budget (SLO-based), and create dashboards showing error trends by type, service, and endpoint. Health checks: implement /health endpoints that verify database connectivity, external service availability, and critical configuration. Graceful degradation: when a non-critical dependency fails, continue serving with reduced functionality rather than failing entirely.