Patterns
Observability Patterns
Debug, profile, and monitor frontend applications effectively
Observability means understanding what's happening inside your application through logs, metrics, and traces. Critical for debugging production issues and optimizing performance.
The Three Pillars
1. Logs: What happened
2. Metrics: How much/how fast
3. Traces: Where time was spentWhy Observability?
Without observability:
- "It's slow for some users" (no data)
- Bugs only in production
- Can't reproduce issues
- No performance baseline
With observability:
- Know exactly what's slow and why
- Catch errors before users report
- Reproduce issues with context
- Track performance over time
Coverage
This section includes:
- Distributed Tracing - OpenTelemetry patterns
- Performance Profiling - Chrome DevTools advanced
- Memory Leak Detection - Find and fix leaks
- CPU Profiling - Identify bottlenecks
- Render Profiling - React Profiler patterns
- Network Waterfall - Analyze request timing
- Logging Strategies - Structured logging
Quick Start
// Basic performance monitoring
const start = performance.now();
await expensiveOperation();
const duration = performance.now() - start;
console.log(`Operation took ${duration}ms`);
// Performance Observer
const observer = new PerformanceObserver((list) => {
list.getEntries().forEach((entry) => {
console.log(`${entry.name}: ${entry.duration}ms`);
});
});
observer.observe({ entryTypes: ['measure', 'navigation'] });Essential Metrics
Core Web Vitals
// Largest Contentful Paint (LCP)
new PerformanceObserver((list) => {
const entries = list.getEntries();
const lastEntry = entries[entries.length - 1];
console.log('LCP:', lastEntry.renderTime || lastEntry.loadTime);
}).observe({ entryTypes: ['largest-contentful-paint'] });
// First Input Delay (FID)
new PerformanceObserver((list) => {
list.getEntries().forEach((entry) => {
console.log('FID:', entry.processingStart - entry.startTime);
});
}).observe({ entryTypes: ['first-input'] });
// Cumulative Layout Shift (CLS)
let clsScore = 0;
new PerformanceObserver((list) => {
list.getEntries().forEach((entry: any) => {
if (!entry.hadRecentInput) {
clsScore += entry.value;
}
});
}).observe({ entryTypes: ['layout-shift'] });Custom Metrics
// Mark and measure
performance.mark('component-render-start');
// ... render component
performance.mark('component-render-end');
performance.measure(
'component-render',
'component-render-start',
'component-render-end'
);
const measure = performance.getEntriesByName('component-render')[0];
console.log(`Render took ${measure.duration}ms`);Error Tracking
// Global error handler
window.addEventListener('error', (event) => {
logError({
message: event.message,
filename: event.filename,
lineno: event.lineno,
colno: event.colno,
stack: event.error?.stack,
});
});
// Unhandled promise rejections
window.addEventListener('unhandledrejection', (event) => {
logError({
message: 'Unhandled promise rejection',
reason: event.reason,
});
});
// React Error Boundary
class ErrorBoundary extends React.Component {
componentDidCatch(error: Error, errorInfo: React.ErrorInfo) {
logError({
error: error.toString(),
componentStack: errorInfo.componentStack,
});
}
}Tools
Browser DevTools
- Performance tab
- Memory tab
- Network tab
- React DevTools Profiler
Third-Party
- Sentry (error tracking)
- DataDog (RUM + APM)
- New Relic (full stack)
- LogRocket (session replay)
Open Source
- OpenTelemetry (tracing)
- Web Vitals library
- Lighthouse CI (performance budgets)
Best Practices
- Monitor Core Web Vitals in production
- Track custom metrics for key flows
- Log errors with context (user, route, state)
- Profile before optimizing (measure, don't guess)
- Set performance budgets and alert on regression
- Sample high-traffic apps (100% = expensive)
- Session replay for hard-to-reproduce bugs
- Distributed tracing for API dependencies
- Memory profiling regularly (catch leaks early)
- Document baselines (know what's "normal")
Monitoring Checklist
- Core Web Vitals tracked
- Error tracking configured
- Performance budgets set
- Memory leaks checked
- Long tasks identified
- Network requests optimized
- React re-renders profiled
- Source maps uploaded
- Alerts configured
- Dashboards created
Next Steps
Explore each pattern in this section to build comprehensive observability into your application and catch issues before users do!