Advanced Debugging
Master advanced debugging techniques for Node.js applications including profiling, memory debugging, and performance analysis. This is a foundational concept in server-side JavaScript development that professional developers rely on daily. The explanations below are written to be beginner-friendly while covering the depth and nuance that comes from real-world Node.js experience. Take your time with each section and practice the examples
Debugging Tools
Learn to use various debugging tools and techniques to identify and fix issues in Node.js applications.. This is an essential concept that every Node.js developer must understand thoroughly. In professional development environments, getting this right can mean the difference between code that works reliably and code that breaks in production. The following sections break this down into clear, digestible pieces with practical examples you can try immediately
Node.js Inspector
// Using Node.js built-in debugger
// Start with: node --inspect app.js
// Or: node --inspect-brk app.js
const debug = require('debug')('myapp');
// Debug logging
debug('This is a debug message');
// Conditional debugging
if (process.env.DEBUG) {
console.log('Debug information:', data);
}
// Using console.trace for stack traces
function problematicFunction() {
console.trace('Function called from:');
// Your code here
}Memory Debugging
// Memory usage monitoring
function logMemoryUsage() {
const used = process.memoryUsage();
console.log('Memory Usage:');
console.log('RSS:', Math.round(used.rss / 1024 / 1024), 'MB');
console.log('Heap Total:', Math.round(used.heapTotal / 1024 / 1024), 'MB');
console.log('Heap Used:', Math.round(used.heapUsed / 1024 / 1024), 'MB');
console.log('External:', Math.round(used.external / 1024 / 1024), 'MB');
}
// Memory leak detection
const heapUsed = process.memoryUsage().heapUsed;
setInterval(() => {
const currentHeap = process.memoryUsage().heapUsed;
const diff = currentHeap - heapUsed;
if (diff > 10 * 1024 * 1024) { // 10MB
console.warn('Potential memory leak detected');
}
}, 30000);Performance Profiling
// Performance profiling
const { performance, PerformanceObserver } = require('perf_hooks');
// Measure function execution time
function measureTime(fn, label) {
const start = performance.now();
const result = fn();
const end = performance.now();
console.log(`${label} took ${end - start} milliseconds`);
return result;
}
// Performance observer
const obs = new PerformanceObserver((list) => {
list.getEntries().forEach((entry) => {
console.log(`${entry.name}: ${entry.duration}ms`);
});
});
obs.observe({ entryTypes: ['measure'] });
// Mark and measure
performance.mark('start');
// Your code here
performance.mark('end');
performance.measure('operation', 'start', 'end');Error Stack Traces
// Enhanced error handling with stack traces
class CustomError extends Error {
constructor(message, code) {
super(message);
this.name = 'CustomError';
this.code = code;
Error.captureStackTrace(this, this.constructor);
}
}
// Stack trace analysis
function analyzeStackTrace(error) {
const stack = error.stack;
const lines = stack.split('
');
console.log('Error:', error.message);
console.log('Stack trace:');
lines.forEach((line, index) => {
if (index > 0) {
console.log(` ${index}: ${line.trim()}`);
}
});
}
// Usage
try {
throw new CustomError('Something went wrong', 'ERR_001');
} catch (error) {
analyzeStackTrace(error);
}Mini-Project: Debugging Toolkit
// Complete debugging toolkit
const fs = require('fs');
const path = require('path');
class Debugger {
constructor(options = {}) {
this.logFile = options.logFile || 'debug.log';
this.level = options.level || 'info';
this.levels = ['error', 'warn', 'info', 'debug'];
}
log(level, message, data = {}) {
if (this.levels.indexOf(level) <= this.levels.indexOf(this.level)) {
const logEntry = {
timestamp: new Date().toISOString(),
level,
message,
data,
memory: process.memoryUsage(),
pid: process.pid
};
console.log(`[${level.toUpperCase()}] ${message}`, data);
// Write to file
fs.appendFileSync(this.logFile, JSON.stringify(logEntry) + '
');
}
}
error(message, data) {
this.log('error', message, data);
}
warn(message, data) {
this.log('warn', message, data);
}
info(message, data) {
this.log('info', message, data);
}
debug(message, data) {
this.log('debug', message, data);
}
// Memory monitoring
startMemoryMonitoring(interval = 30000) {
setInterval(() => {
const memUsage = process.memoryUsage();
this.debug('Memory usage', {
rss: Math.round(memUsage.rss / 1024 / 1024),
heapTotal: Math.round(memUsage.heapTotal / 1024 / 1024),
heapUsed: Math.round(memUsage.heapUsed / 1024 / 1024)
});
}, interval);
}
// Performance monitoring
time(label) {
const start = process.hrtime.bigint();
return {
end: () => {
const end = process.hrtime.bigint();
const duration = Number(end - start) / 1000000; // Convert to milliseconds
this.debug(`${label} completed`, { duration: `${duration}ms` });
return duration;
}
};
}
}
// Usage
const debugger = new Debugger({ level: 'debug' });
debugger.startMemoryMonitoring();
const timer = debugger.time('database-query');
// Simulate database query
setTimeout(() => {
timer.end();
}, 1000);