npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

memory-watch

v1.0.0

Published

Advanced Node.js memory monitoring with stack trace analysis, user code detection, and memory leak identification

Readme

Memory Watch 🚨

Advanced Node.js Memory Monitoring with Stack Trace Analysis

A powerful Node.js library that not only monitors memory usage but also identifies exactly which functions and files are causing memory issues. Unlike basic memory monitors, Memory Watch provides detailed stack traces, user code detection, and actionable insights for fixing memory leaks.

🚀 Key Features

  • 📊 Real-time memory monitoring with customizable thresholds
  • 🎯 User code detection - identifies YOUR functions causing memory issues (not just Node.js internals)
  • 🔍 Advanced stack trace analysis - shows exact file paths and line numbers
  • Automatic memory leak detection with smart recommendations
  • 📈 Comprehensive diagnostics - heap breakdown, active handles, CPU usage
  • 💾 Manual context capture for better tracking with captureContext()
  • 🎬 Multiple action callbacks for alerts, logging, notifications
  • 📋 Detailed diagnostic reports with actionable insights

What Makes It Different

Basic memory monitors tell you:

  • "Memory usage is high: 85%"

Memory Watch tells you:

  • "Memory spike in processUserData() function"
  • "File: src/services/userService.js:123"
  • "Cause: Creating too many objects in loop"
  • "Recommendation: Implement data streaming"

Installation

npm install memory-watch

Quick Start

Basic Memory Monitoring

const { MemoryWatch } = require("memory-watch");

const watch = new MemoryWatch({
  threshold: 0.8, // 80% of max heap
  interval: 30000, // Check every 30 seconds
  actions: [
    (data) => {
      console.log("🚨 Memory threshold reached!");
      console.log(`Usage: ${(data.percentage * 100).toFixed(2)}%`);

      // See which function caused the issue
      if (data.context?.stackTrace?.[0]) {
        const trace = data.context.stackTrace[0];
        console.log(`Problem in: ${trace.functionName}`);
        console.log(`File: ${trace.fileName}:${trace.lineNumber}`);
      }
    },
  ],
});

watch.start();

Advanced User Code Tracking

const { MemoryWatch } = require("memory-watch");

const watch = new MemoryWatch({
  threshold: 0.7,
  interval: 10000,
  actions: [
    (data) => {
      // Get detailed diagnostic report
      const report = generateDiagnosticReport(data);
      console.log(report);

      // Send alert with specific function details
      sendSlackAlert({
        message: `Memory leak detected in ${data.context?.stackTrace?.[0]?.functionName}`,
        file: data.context?.stackTrace?.[0]?.fileName,
        line: data.context?.stackTrace?.[0]?.lineNumber,
      });
    },
  ],
});

// Manually track important functions
function processLargeDataset() {
  watch.captureContext("processLargeDataset", __filename, 45);
  // Your memory-intensive code here
}

watch.start();

API Reference

Constructor Options

interface MemoryWatchOptions {
  threshold: number; // Memory threshold (0-1)
  interval: number; // Check interval in milliseconds
  actions: Array<(data: MemoryData) => void | Promise<void>>;
  continuous?: boolean; // Continue monitoring after threshold (default: true)
  customMemoryCheck?: () => { used: number; total: number };
}

MemoryData Object

interface MemoryData {
  used: number; // Current memory usage
  total: number; // Total available memory
  percentage: number; // Usage percentage (0-1)
  usedBytes: number; // Memory usage in bytes
  totalBytes: number; // Total memory in bytes
  timestamp: Date; // Measurement timestamp
  breakdown: {
    rss: number; // Resident Set Size (physical memory)
    heapUsed: number; // Heap memory used
    heapTotal: number; // Total heap allocated
    external: number; // External memory (C++ objects)
    arrayBuffers: number; // ArrayBuffer memory
  };
  context?: {
    triggerSource?: string; // What triggered the measurement
    pid: number; // Process ID
    nodeVersion: string; // Node.js version
    platform: string; // Platform information
    stackTrace?: Array<{
      functionName: string;
      fileName?: string;
      lineNumber?: number;
      columnNumber?: number;
    }>;
    activeHandles?: number; // Active timers, servers, etc.
    activeRequests?: number; // Active HTTP requests
    uptime: number; // Process uptime in seconds
    cpuUsage?: {
      user: number; // CPU user time
      system: number; // CPU system time
    };
  };
}

Diagnostic Utilities

// Generate detailed diagnostic report
import {
  generateDiagnosticReport,
  getMemoryLeakIndicators,
} from "memory-watch";

const data = watch.getCurrentMemory();
const report = generateDiagnosticReport(data);
console.log(report);

// Check for memory leak indicators
const leakIndicators = getMemoryLeakIndicators(data);
if (leakIndicators.length > 0) {
  console.log("Potential memory leaks detected:", leakIndicators);
}

Methods

  • start() - Start monitoring
  • stop() - Stop monitoring
  • getCurrentMemory() - Get current memory status
  • isRunning() - Check if monitoring is active
  • captureContext(functionName, fileName?, lineNumber?) - NEW! Manually capture user context for better tracking
  • MemoryWatch.checkOnce(threshold) - One-time memory check (static method)

Usage Examples

1. Basic Memory Monitoring with User Code Detection

const { MemoryWatch, generateDiagnosticReport } = require("memory-watch");

const watch = new MemoryWatch({
  threshold: 0.8,
  interval: 30000,
  actions: [
    (data) => {
      // Show which user function caused the issue
      if (data.context?.stackTrace?.[0]) {
        const trace = data.context.stackTrace[0];
        console.log(`🎯 Problem in function: ${trace.functionName}`);
        console.log(`📁 File: ${trace.fileName}:${trace.lineNumber}`);
      }

      // Send detailed alert
      sendSlackNotification({
        message: `Memory threshold reached: ${(data.percentage * 100).toFixed(
          1
        )}%`,
        function: data.context?.stackTrace?.[0]?.functionName,
        file: data.context?.stackTrace?.[0]?.fileName,
        line: data.context?.stackTrace?.[0]?.lineNumber,
      });
    },
  ],
});

watch.start();

2. Manual Context Tracking for Better Analysis

const { MemoryWatch } = require("memory-watch");

const watch = new MemoryWatch({
  threshold: 0.7,
  interval: 15000,
  actions: [
    (data) => {
      const report = generateDiagnosticReport(data);
      console.log(report);

      // Get memory leak indicators
      const leakIndicators = getMemoryLeakIndicators(data);
      if (leakIndicators.length > 0) {
        console.log('🔴 Memory leak detected:', leakIndicators);
      }
    }
  ]
});

// In your application functions, add manual tracking:
function processLargeDataset(data) {
  // Track this function for better memory analysis
  watch.captureContext('processLargeDataset', __filename, 25);

  // Your processing logic here...
  const result = data.map(item => /* heavy processing */);
  return result;
}

function handleAPIRequest(req, res) {
  watch.captureContext('handleAPIRequest', __filename, 35);

  // Your API logic here...
}

watch.start();

Advanced Diagnostic Monitoring

const {
  MemoryWatch,
  generateDiagnosticReport,
  getMemoryLeakIndicators,
} = require("memory-watch");

const watch = new MemoryWatch({
  threshold: 0.7,
  interval: 10000,
  actions: [
    (data) => {
      // Generate comprehensive diagnostic report
      const report = generateDiagnosticReport(data);
      console.log(report);

      // Check for memory leak indicators
      const leakIndicators = getMemoryLeakIndicators(data);
      if (leakIndicators.length > 0) {
        console.log("🔴 Memory leak indicators:", leakIndicators);

        // Send alert with specific details
        sendAlert({
          type: "memory_leak",
          indicators: leakIndicators,
          stackTrace: data.context?.stackTrace,
          file: data.context?.stackTrace?.[0]?.fileName,
          function: data.context?.stackTrace?.[0]?.functionName,
        });
      }

      // Log problematic source files
      if (data.context?.stackTrace) {
        const sourceFiles = data.context.stackTrace
          .filter((trace) => trace.fileName)
          .map((trace) => `${trace.fileName}:${trace.lineNumber}`)
          .slice(0, 3);

        console.log("🎯 Check these files for memory issues:", sourceFiles);
      }
    },
  ],
});

Production Server Monitoring

const watch = new MemoryWatch({
  threshold: 0.85,
  interval: 60000, // Check every minute
  actions: [
    async (data) => {
      // Send to monitoring service with detailed context
      await sendToDatadog({
        metric: "memory.usage.high",
        value: data.percentage,
        tags: [
          `pid:${data.context?.pid}`,
          `platform:${data.context?.platform}`,
          `trigger:${data.context?.triggerSource}`,
          `active_handles:${data.context?.activeHandles}`,
          `active_requests:${data.context?.activeRequests}`,
        ],
        stackTrace: data.context?.stackTrace,
      });

      // Log detailed breakdown for ops team
      console.log("Memory breakdown:", {
        heap: `${(data.breakdown.heapUsed / 1024 / 1024).toFixed(2)}MB`,
        rss: `${(data.breakdown.rss / 1024 / 1024).toFixed(2)}MB`,
        external: `${(data.breakdown.external / 1024 / 1024).toFixed(2)}MB`,
        activeHandles: data.context?.activeHandles,
        topFunction: data.context?.stackTrace?.[0]?.functionName,
      });
    },
  ],
});

One-time Memory Check

// Check if memory usage is above 50%
const result = await MemoryWatch.checkOnce(0.5);
if (result) {
  console.log("Memory usage is high:", result);
}

Real-world Use Cases

Real-world Use Cases

1. API Memory Leak Detection

Identify which API endpoints are causing memory leaks:

const watch = new MemoryWatch({
  threshold: 0.8,
  interval: 30000,
  actions: [
    (data) => {
      const apiEndpoint = data.context?.stackTrace?.find(
        (trace) =>
          trace.fileName?.includes("routes") ||
          trace.fileName?.includes("controllers")
      );

      if (apiEndpoint) {
        console.log(
          `🚨 Memory issue in API: ${apiEndpoint.fileName}:${apiEndpoint.lineNumber}`
        );
        console.log(`   Function: ${apiEndpoint.functionName}`);
        console.log(`   Memory: ${(data.percentage * 100).toFixed(1)}%`);
      }
    },
  ],
});

2. Database Connection Monitoring

Monitor for unclosed database connections:

const watch = new MemoryWatch({
  threshold: 0.7,
  interval: 15000,
  actions: [
    (data) => {
      if (data.context?.activeHandles > 50) {
        console.log(`⚠️ High active handles: ${data.context.activeHandles}`);
        console.log("Possible unclosed database connections or timers");

        // Check stack trace for database-related functions
        const dbTrace = data.context?.stackTrace?.find(
          (trace) =>
            trace.functionName?.includes("query") ||
            trace.functionName?.includes("connection") ||
            trace.fileName?.includes("database")
        );

        if (dbTrace) {
          console.log(
            `🔍 Check database code: ${dbTrace.fileName}:${dbTrace.lineNumber}`
          );
        }
      }
    },
  ],
});

3. Development Memory Profiling

Use during development to catch memory issues early:

const watch = new MemoryWatch({
  threshold: 0.6,
  interval: 5000,
  continuous: false, // Stop after first alert
  actions: [
    (data) => {
      const report = generateDiagnosticReport(data);
      console.log(report);

      // Save detailed report to file for analysis
      require("fs").writeFileSync(`memory-report-${Date.now()}.txt`, report);

      console.log(
        "💡 Tip: Check the stack trace above for the problematic code"
      );
    },
  ],
});

What Makes This Different

Unlike basic memory monitoring tools, Memory Watch provides:

  • 🎯 Exact source identification: Tells you which file and function is causing memory issues
  • 📊 Detailed breakdown: Shows heap, RSS, external memory separately
  • 🔍 Root cause analysis: Identifies patterns like unclosed handles or large buffers
  • 🚨 Smart leak detection: Automatically detects common memory leak patterns
  • 📈 Process insights: Tracks active handles, requests, and CPU usage
  • 💡 Actionable recommendations: Provides specific suggestions for fixing issues

Examples Output

When memory threshold is reached, you'll see detailed reports like:

🔍 MEMORY DIAGNOSTIC REPORT
================================
📊 Overall Usage: 78.5% (245MB / 312MB)
⏰ Timestamp: 2025-09-10T11:30:15.123Z

📈 MEMORY BREAKDOWN:
   • Heap Used: 178MB
   • Heap Total: 245MB
   • RSS (Physical): 312MB
   • External: 45MB
   • Array Buffers: 12MB

🖥️  PROCESS INFO:
   • PID: 12345
   • Node.js: v18.20.4
   • Platform: linux
   • Uptime: 2h 15m 30s
   • Active Handles: 15
   • Active Requests: 3

🎯 POTENTIAL SOURCES (Stack Trace):
   1. processLargeDataset (/app/src/data-processor.js:45:12)
   2. handleApiRequest (/app/src/routes/api.js:123:8)
   3. middleware (/app/src/middleware/auth.js:67:15)

💡 RECOMMENDATIONS:
   ⚠️  Heap usage is very high - possible memory leak
   ⚠️  Check the stack trace above for problematic functions

Available Scripts

Test the library with included examples:

# Simple memory monitoring
npm run example

# Basic usage with multiple actions
npm run example-basic

# Advanced diagnostics with detailed analysis
npm run example-advanced

# User code tracking demonstration
npm run example-tracking

# Build the project
npm run build

# Development mode with watch
npm run dev

Development & Testing

To test the library locally:

  1. Clone the repository
  2. Install dependencies: npm install
  3. Build the project: npm run build
  4. Run examples: npm run example-tracking

NPM Package Information

  • Package Name: memory-watch
  • Version: 1.0.0
  • Node.js Support: >=14.0.0
  • TypeScript: Full TypeScript support with type definitions
  • License: MIT
  • Bundle Size: Lightweight (~50KB)

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

Development Setup

git clone https://github.com/muhcen/memory-watch.git
cd memory-watch
npm install
npm run build
npm run example-tracking

License

MIT

Copyright (c) 2025 Mohsen Moradi

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.