DEV Community

Cover image for 5 Essential JavaScript Performance Monitoring Techniques for Production Apps [2024 Guide]
Aarav Joshi
Aarav Joshi

Posted on

5 Essential JavaScript Performance Monitoring Techniques for Production Apps [2024 Guide]

As a best-selling author, I invite you to explore my books on Amazon. Don't forget to follow me on Medium and show your support. Thank you! Your support means the world!

JavaScript Performance Monitoring: Essential Techniques for Production Applications

Performance monitoring forms the backbone of maintaining robust JavaScript applications in production. Let's explore five critical monitoring techniques that help maintain optimal application performance.

Application Logging

Effective logging provides insights into application behavior and helps troubleshoot issues quickly. I implement structured logging using libraries like Winston or Pino:

const winston = require('winston');

const logger = winston.createLogger({
  level: 'info',
  format: winston.format.json(),
  transports: [
    new winston.transports.File({ filename: 'error.log', level: 'error' }),
    new winston.transports.File({ filename: 'combined.log' })
  ]
});

// Sample logging with context
logger.info('User action completed', {
  userId: user.id,
  action: 'checkout',
  duration: performance.now() - startTime
});
Enter fullscreen mode Exit fullscreen mode

I recommend implementing log sampling for high-volume events to manage storage and processing costs:

function shouldSampleLog(eventName, samplingRate) {
  return Math.random() < samplingRate;
}

function logEvent(eventName, data) {
  if (shouldSampleLog(eventName, 0.1)) { // 10% sampling rate
    logger.info(eventName, data);
  }
}
Enter fullscreen mode Exit fullscreen mode

Error Tracking

Capturing and analyzing errors provides crucial insights into application stability. I set up global error handlers to catch unhandled exceptions:

window.onerror = function(message, source, lineno, colno, error) {
  const errorData = {
    message,
    source,
    lineno,
    colno,
    stack: error?.stack,
    userAgent: navigator.userAgent,
    timestamp: new Date().toISOString()
  };

  sendErrorToAnalytics(errorData);
  return false;
};

// Handle promise rejections
window.addEventListener('unhandledrejection', function(event) {
  const errorData = {
    message: event.reason?.message || 'Promise rejection',
    stack: event.reason?.stack,
    timestamp: new Date().toISOString()
  };

  sendErrorToAnalytics(errorData);
});
Enter fullscreen mode Exit fullscreen mode

Performance Metrics

The Performance API provides powerful tools for measuring critical metrics. I use it to track key performance indicators:

// Monitor First Contentful Paint
new PerformanceObserver((entryList) => {
  for (const entry of entryList.getEntries()) {
    console.log('FCP:', entry.startTime);
    sendMetric('FCP', entry.startTime);
  }
}).observe({entryTypes: ['paint']});

// Track long tasks
new PerformanceObserver((entryList) => {
  for (const entry of entryList.getEntries()) {
    if (entry.duration > 50) {
      console.log('Long Task:', entry.duration);
      sendMetric('LongTask', entry.duration);
    }
  }
}).observe({entryTypes: ['longtask']});

// Custom business metrics
function measureBusinessTransaction(transactionName, func) {
  const start = performance.now();
  const result = func();
  const duration = performance.now() - start;

  sendMetric(transactionName, duration);
  return result;
}
Enter fullscreen mode Exit fullscreen mode

Resource Usage Monitoring

Tracking resource consumption helps prevent performance degradation. I implement memory and CPU monitoring:

// Memory monitoring
function checkMemoryUsage() {
  if (performance.memory) {
    const usage = {
      usedJSHeapSize: performance.memory.usedJSHeapSize,
      totalJSHeapSize: performance.memory.totalJSHeapSize,
      jsHeapSizeLimit: performance.memory.jsHeapSizeLimit
    };

    if (usage.usedJSHeapSize > usage.jsHeapSizeLimit * 0.9) {
      alertMemoryIssue(usage);
    }

    sendMetric('memoryUsage', usage);
  }
}

// Network request monitoring
const originalFetch = window.fetch;
window.fetch = async function(...args) {
  const startTime = performance.now();
  try {
    const response = await originalFetch.apply(this, args);
    const duration = performance.now() - startTime;

    sendMetric('networkRequest', {
      url: args[0],
      duration,
      status: response.status
    });

    return response;
  } catch (error) {
    sendMetric('networkError', {
      url: args[0],
      error: error.message
    });
    throw error;
  }
};
Enter fullscreen mode Exit fullscreen mode

User Experience Monitoring

Understanding real user experience is crucial for application success. I implement comprehensive user monitoring:

// Page load timing
window.addEventListener('load', () => {
  const timing = performance.timing;
  const metrics = {
    dnsLookup: timing.domainLookupEnd - timing.domainLookupStart,
    tcpConnection: timing.connectEnd - timing.connectStart,
    serverResponse: timing.responseEnd - timing.requestStart,
    domProcessing: timing.domComplete - timing.domLoading,
    totalLoadTime: timing.loadEventEnd - timing.navigationStart
  };

  sendMetrics('pageLoad', metrics);
});

// User interactions
function trackUserInteraction(element, eventType) {
  element.addEventListener(eventType, (event) => {
    const startTime = performance.now();

    // Wait for next frame to measure response time
    requestAnimationFrame(() => {
      const duration = performance.now() - startTime;
      sendMetric('interaction', {
        type: eventType,
        element: element.tagName,
        duration
      });
    });
  });
}

// Session recording
class SessionRecorder {
  constructor() {
    this.events = [];
    this.isRecording = false;
  }

  startRecording() {
    this.isRecording = true;
    this.recordUserActions();
  }

  recordUserActions() {
    document.addEventListener('click', (e) => {
      if (this.isRecording) {
        this.events.push({
          type: 'click',
          target: e.target.tagName,
          timestamp: Date.now()
        });
      }
    });

    // Add more event listeners as needed
  }

  stopRecording() {
    this.isRecording = false;
    this.sendRecordingToAnalytics();
  }
}
Enter fullscreen mode Exit fullscreen mode

These monitoring techniques provide comprehensive insights into application performance. I recommend implementing them gradually, starting with the most critical aspects for your application. Regular analysis of collected data helps identify optimization opportunities and maintain high performance standards.

Remember to consider privacy implications and obtain necessary user consent when implementing monitoring solutions. Additionally, ensure that monitoring code itself doesn't impact application performance by using techniques like throttling and batching when sending data to analytics servers.

The combination of these monitoring techniques creates a robust system for maintaining and improving JavaScript application performance in production environments. Regular review and adjustment of monitoring strategies ensure continued effectiveness as applications evolve.


101 Books

101 Books is an AI-driven publishing company co-founded by author Aarav Joshi. By leveraging advanced AI technology, we keep our publishing costs incredibly low—some books are priced as low as $4—making quality knowledge accessible to everyone.

Check out our book Golang Clean Code available on Amazon.

Stay tuned for updates and exciting news. When shopping for books, search for Aarav Joshi to find more of our titles. Use the provided link to enjoy special discounts!

Our Creations

Be sure to check out our creations:

Investor Central | Investor Central Spanish | Investor Central German | Smart Living | Epochs & Echoes | Puzzling Mysteries | Hindutva | Elite Dev | JS Schools


We are on Medium

Tech Koala Insights | Epochs & Echoes World | Investor Central Medium | Puzzling Mysteries Medium | Science & Epochs Medium | Modern Hindutva

Top comments (0)