All posts

React Logging Best Practices for Production

Implement effective logging in React applications with structured client-side logging, error boundaries, and remote log aggregation strategies.

React Logging Best Practices for Production

Client-side logging is often overlooked, but it's essential for debugging production issues. Here's how to set it up properly.

Create a Logging Service

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

class Logger {
  private level: LogLevel;
  private buffer: Array<LogEntry> = [];
  private flushInterval: number;

  constructor() {
    this.level = process.env.NODE_ENV === 'production' ? 'warn' : 'debug';
    this.flushInterval = window.setInterval(() => this.flush(), 30000);
  }

  info(message: string, data?: Record<string, unknown>) {
    this.log('info', message, data);
  }

  error(message: string, error?: Error, data?: Record<string, unknown>) {
    this.log('error', message, {
      ...data,
      stack: error?.stack,
      errorMessage: error?.message,
    });
    this.flush(); // Flush errors immediately
  }

  private log(level: LogLevel, message: string, data?: Record<string, unknown>) {
    const entry = {
      level,
      message,
      timestamp: new Date().toISOString(),
      url: window.location.href,
      ...data,
    };

    if (process.env.NODE_ENV !== 'production') {
      console[level](message, data);
    }

    this.buffer.push(entry);
  }

  private async flush() {
    if (this.buffer.length === 0) return;
    const entries = [...this.buffer];
    this.buffer = [];
    await fetch('/api/logs', {
      method: 'POST',
      body: JSON.stringify(entries),
    }).catch(() => {
      this.buffer.unshift(...entries); // Re-queue on failure
    });
  }
}

export const logger = new Logger();

Log User Actions

function useActionLogger() {
  return useCallback((action: string, data?: Record<string, unknown>) => {
    logger.info(`user_action: ${action}`, {
      ...data,
      sessionId: getSessionId(),
      route: window.location.pathname,
    });
  }, []);
}

// Usage
function CheckoutButton({ orderId }) {
  const logAction = useActionLogger();
  return (
    <button onClick={() => {
      logAction('checkout_clicked', { orderId });
      processCheckout(orderId);
    }}>Checkout</button>
  );
}

What to Log

  • User navigation — page views and route changes
  • API failures — status codes, endpoints, response times
  • Feature usage — which features are actually used
  • Performance events — slow renders, long tasks

What NOT to Log

  • Passwords, tokens, personal data
  • Every keystroke or mouse movement
  • Successful routine API calls (too noisy)

Combine client-side logging with Bugsly's error tracking for complete visibility. Logs show what happened; Bugsly shows what went wrong.

Try Bugsly Free

AI-powered error tracking that explains your bugs. Set up in 2 minutes, free forever for small projects.

Get Started Free