typescriptadvanced

Debug with Inspector Protocol

Programmatic debugging with Node.js inspector module for heap snapshots, CPU profiling, and breakpoints.

typescript
import inspector from 'inspector';
import fs from 'fs';

// CPU Profiling
async function profileCPU(fn: () => void | Promise<void>, outputFile = 'profile.cpuprofile') {
  const session = new inspector.Session();
  session.connect();

  session.post('Profiler.enable');
  session.post('Profiler.start');

  await fn();

  return new Promise<void>((resolve) => {
    session.post('Profiler.stop', (err, { profile }) => {
      if (!err && profile) {
        fs.writeFileSync(outputFile, JSON.stringify(profile));
        console.log(`CPU profile saved to ${outputFile}`);
        console.log('Open in Chrome DevTools: Performance > Load Profile');
      }
      session.disconnect();
      resolve();
    });
  });
}

// Heap snapshot
async function takeHeapSnapshot(outputFile = 'heap.heapsnapshot') {
  const session = new inspector.Session();
  session.connect();

  const chunks: string[] = [];
  session.on('HeapProfiler.addHeapSnapshotChunk', (m) => {
    chunks.push(m.params.chunk);
  });

  return new Promise<void>((resolve) => {
    session.post('HeapProfiler.takeHeapSnapshot', undefined, () => {
      fs.writeFileSync(outputFile, chunks.join(''));
      console.log(`Heap snapshot saved to ${outputFile}`);
      session.disconnect();
      resolve();
    });
  });
}

// Memory usage tracking
function trackMemory(intervalMs = 5000) {
  const baseline = process.memoryUsage();
  console.log('Memory baseline:', formatMemory(baseline));

  const timer = setInterval(() => {
    const current = process.memoryUsage();
    console.log('Memory:', formatMemory(current), '| Growth:', {
      rss: `+${((current.rss - baseline.rss) / 1e6).toFixed(1)}MB`,
      heap: `+${((current.heapUsed - baseline.heapUsed) / 1e6).toFixed(1)}MB`,
    });
  }, intervalMs);

  return () => clearInterval(timer);
}

function formatMemory(m: NodeJS.MemoryUsage) {
  return {
    rss: `${(m.rss / 1e6).toFixed(1)}MB`,
    heapUsed: `${(m.heapUsed / 1e6).toFixed(1)}MB`,
    heapTotal: `${(m.heapTotal / 1e6).toFixed(1)}MB`,
    external: `${(m.external / 1e6).toFixed(1)}MB`,
  };
}

// Usage
async function main() {
  const stopTracking = trackMemory(2000);

  await profileCPU(() => {
    let sum = 0;
    for (let i = 0; i < 1e7; i++) sum += Math.sqrt(i);
    console.log('CPU work done:', sum.toFixed(2));
  });

  await takeHeapSnapshot();
  stopTracking();
}

main();

Use Cases

  • Production performance profiling
  • Memory leak detection
  • CPU bottleneck analysis

Tags

Related Snippets

Similar patterns you can reuse in the same workflow.