JSPM

ak-diagnostic

1.0.0
  • ESM via JSPM
  • ES Module Entrypoint
  • Export Map
  • Keywords
  • License
  • Repository URL
  • TypeScript Types
  • README
  • Created
  • Published
  • Downloads 10
  • Score
    100M100P100Q36828F
  • License MIT

A lightweight Node.js diagnostic tool for monitoring runtime performance, memory usage, and system metrics with minimal overhead

Package Exports

  • ak-diagnostic

Readme

ak-diagnostic

A lightweight, zero-dependency Node.js diagnostic tool for monitoring runtime performance, memory usage, and system metrics with minimal overhead.

Features

  • 🚀 Zero Dependencies - Uses only Node.js built-in modules
  • 📊 Comprehensive Metrics - Memory, CPU, event loop lag, and system information
  • 🎯 Low Overhead - Designed to add minimal performance impact
  • 🔔 Threshold Alerts - Get notified when memory usage exceeds limits
  • 📈 Statistical Analysis - Peak, average, and low values for all metrics
  • 🔄 ESM & CommonJS - Full support for both module systems
  • 📝 TypeScript Support - Complete type definitions included
  • 🛡️ Error Resilient - Won't crash your application

Installation

npm install ak-diagnostic

Quick Start

ESM (ES Modules)

import { Diagnostics }

Examples

Basic Usage

import { Diagnostics } from 'ak-diagnostic';

const diagnostics = new Diagnostics({
  name: 'DataProcessor',
  interval: 2000 // Sample every 2 seconds
});

diagnostics.start();

// Simulate some work
const data = await processLargeDataset();
await transformData(data);
await saveResults(data);

const report = diagnostics.report();

console.log('Performance Report:');
console.log(`Duration: ${report.summary.duration}`);
console.log(`Peak Memory: ${report.summary.peakMemory}`);
console.log(`Average CPU: ${report.summary.averageCPU}`);
console.log(`Samples Collected: ${report.summary.samples}`);

Memory Threshold Monitoring

import { Diagnostics } from 'ak-diagnostic';

const diagnostics = new Diagnostics({
  name: 'MemoryIntensiveApp',
  interval: 1000,
  threshold: 200_000_000, // Alert if memory exceeds 200MB
  alert: info => {
    console.warn(`⚠️ Memory threshold exceeded!`);
    console.warn(`Current: ${info.memory.formatted.current}`);
    console.warn(`Threshold: ${info.memory.formatted.threshold}`);

    // Could trigger cleanup, send metrics, etc.
    performEmergencyCleanup();
  }
});

diagnostics.start();

// Your memory-intensive operations
await processImages();
await generateReports();

const report = diagnostics.report();
console.log(`Alert triggered ${report.analysis.numOfAlertTriggers} times`);

Target Memory Tracking

import { Diagnostics } from 'ak-diagnostic';

const diagnostics = new Diagnostics({
  name: 'OptimizedApp',
  interval: 5000,
  target: 50_000_000 // Target 50MB memory usage
});

diagnostics.start();

// Run your application
await runApplication();

const report = diagnostics.report();

console.log('Memory Target Analysis:');
console.log(`Time over target: ${report.analysis.timeOverTargetHuman}`);
console.log(`Time under target: ${report.analysis.timeUnderTargetHuman}`);

const percentOverTarget = (report.analysis.timeOverTarget / report.clock.duration) * 100;
console.log(`Percentage of time over target: ${percentOverTarget.toFixed(2)}%`);

Production Monitoring

import { Diagnostics } from 'ak-diagnostic';
import fs from 'fs/promises';

const diagnostics = new Diagnostics({
  name: 'ProductionAPI',
  interval: 10000, // Sample every 10 seconds
  threshold: 1_000_000_000, // 1GB threshold
  alert: async info => {
    // Log to monitoring service
    await sendToMonitoring({
      event: 'memory_threshold_exceeded',
      timestamp: info.timestamp,
      memory: info.memory.current,
      app: info.name
    });
  }
});

// Start monitoring when server starts
diagnostics.start();

// Periodic reporting
setInterval(async () => {
  const report = diagnostics.report();

  // Save report to file
  await fs.writeFile(`./logs/diagnostics-${Date.now()}.json`, JSON.stringify(report, null, 2));

  // Send summary to monitoring dashboard
  await sendMetrics({
    memory: report.memory.average.bytes,
    cpu: report.cpu.average.percentage,
    eventLoopLag: report.eventLoop.lag.average.ms,
    alerts: report.analysis.numOfAlertTriggers
  });

  // Reset for next period
  diagnostics.reset().start();
}, 3600000); // Every hour

Express.js Middleware

import express from 'express';
import { Diagnostics } from 'ak-diagnostic';

const app = express();
const diagnostics = new Diagnostics({
  name: 'ExpressAPI',
  interval: 5000
});

// Start diagnostics when server starts
diagnostics.start();

// Endpoint to get current diagnostics
app.get('/diagnostics', (req, res) => {
  const report = diagnostics.report();
  diagnostics.reset().start(); // Reset after reporting

  res.json({
    status: 'healthy',
    uptime: report.clock.human,
    memory: {
      current: report.memory.average.human,
      peak: report.memory.peak.human
    },
    cpu: {
      average: report.cpu.average.human,
      peak: report.cpu.peak.human
    },
    eventLoop: {
      avgLag: report.eventLoop.lag.average.human,
      maxLag: report.eventLoop.lag.max.human
    },
    samples: report.analysis.numSamples
  });
});

app.listen(3000);

Best Practices

1. Sampling Interval

  • Development: 1-2 seconds for detailed monitoring
  • Production: 5-10 seconds to minimize overhead
  • Long-running tasks: 30-60 seconds for extended operations

2. Memory Thresholds

Set thresholds based on your application's expected memory usage:

// For a typical web server
threshold: 500_000_000; // 500MB

// For data processing applications
threshold: 2_000_000_000; // 2GB

// For microservices
threshold: 200_000_000; // 200MB

3. Alert Handling

Keep alert handlers lightweight and non-blocking:

alert: info => {
  // Good: Quick, non-blocking operations
  console.error('Memory threshold exceeded');
  metrics.increment('memory.alerts');

  // Avoid: Heavy operations in alert handler
  // Don't do: await saveToDatabase(info);
  // Instead, queue it for processing
  alertQueue.push(info);
};

4. Cleanup

Always stop diagnostics when your application shuts down:

process.on('SIGTERM', () => {
  diagnostics.stop();
  const finalReport = diagnostics.report();
  console.log('Final diagnostics:', finalReport.summary);
  process.exit(0);
});

Performance Impact

ak-diagnostic is designed for minimal overhead:

  • Memory: ~1-2KB per sample (depending on system info cached)
  • CPU: <0.1% for default 5-second sampling
  • Event Loop: Sampling operations are synchronous and fast
  • No Dependencies: Zero external packages means minimal footprint

Requirements

  • Node.js >= 12.0.0
  • No external dependencies required

TypeScript Support

Full TypeScript definitions are included:

import { Diagnostics, DiagnosticReport, DiagnosticsOptions } from 'ak-diagnostic';

const options: DiagnosticsOptions = {
  name: 'TypedApp',
  interval: 5000,
  threshold: 100_000_000
};

const diagnostics = new Diagnostics(options);
diagnostics.start();

// ... your code ...

const report: DiagnosticReport = diagnostics.report();

Troubleshooting

Q: The diagnostics seem to be missing samples

A: Ensure your application isn't blocking the event loop. Long synchronous operations can prevent sampling intervals from firing.

Q: Memory measurements seem incorrect

A: The tool measures heap memory by default. For total process memory, check report.memory.rss values.

Q: CPU percentages exceed 100%

A: On multi-core systems, CPU percentage can exceed 100% if your application uses multiple cores. This is normal behavior.

Q: Event loop lag is consistently high

A: This indicates your application has blocking operations. Consider using worker threads or async operations for CPU-intensive tasks.

Contributing

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

License

MIT

Support

For issues, questions, or suggestions, please open an issue on GitHub.


Made with ❤️ for the Node.js community from 'ak-diagnostic';

const diagnostics = new Diagnostics({ name: 'MyApp', interval: 3000 // Sample every 3 seconds });

diagnostics.start();

// Your application code here await someHeavyOperation();

diagnostics.stop();

const report = diagnostics.report(); console.log(report.summary);


### CommonJS

```javascript
const { Diagnostics } = require('ak-diagnostic');

const diagnostics = new Diagnostics({
  name: 'MyApp',
  interval: 3000
});

diagnostics.start();

// Your application code here
someHeavyOperation(() => {
  diagnostics.stop();
  const report = diagnostics.report();
  console.log(report.summary);
});

API Reference

Constructor Options

const diagnostics = new Diagnostics({
  name: 'MyApp', // Required: A label for the diagnostic session
  interval: 5000, // Optional: Sampling interval in ms (default: 5000)
  threshold: 500_000_000, // Optional: Memory threshold in bytes for alerts
  target: 100_000_000, // Optional: Target memory consumption in bytes
  alert: info => {
    // Optional: Callback when threshold is exceeded
    console.log('Alert!', info);
  },
  monitorEventLoop: true // Optional: Monitor event loop lag (default: true)
});

Methods

start()

Begins collecting diagnostic data.

diagnostics.start();

stop()

Stops collecting diagnostic data.

diagnostics.stop();

report()

Generates a comprehensive diagnostic report with all collected metrics.

const report = diagnostics.report();

reset()

Clears all collected data and resets the diagnostics instance.

diagnostics.reset();

status()

Returns the current status of the diagnostics collector.

const status = diagnostics.status();
// { running: true, name: 'MyApp', samplesCollected: 42, uptime: 126000 }

Report Structure

The report() method returns a comprehensive object with the following structure:

{
  name: 'MyApp',

  // Memory statistics (heapUsed)
  memory: {
    peak: { bytes: 104857600, human: '100.00 MB' },
    average: { bytes: 52428800, human: '50.00 MB' },
    low: { bytes: 31457280, human: '30.00 MB' },

    // Heap memory details
    heap: {
      peak: { bytes: 104857600, human: '100.00 MB' },
      average: { bytes: 52428800, human: '50.00 MB' },
      low: { bytes: 31457280, human: '30.00 MB' }
    },

    // Resident Set Size (total memory allocated)
    rss: {
      peak: { bytes: 157286400, human: '150.00 MB' },
      average: { bytes: 134217728, human: '128.00 MB' },
      low: { bytes: 104857600, human: '100.00 MB' }
    }
  },

  // CPU usage statistics
  cpu: {
    peak: { percentage: 45.67, human: '45.67%' },
    average: { percentage: 22.34, human: '22.34%' },
    low: { percentage: 5.12, human: '5.12%' }
  },

  // Event loop lag statistics
  eventLoop: {
    lag: {
      average: { ms: 2.5, human: '2ms' },
      max: { ms: 15.3, human: '15ms' },
      min: { ms: 0.1, human: '0ms' }
    }
  },

  // System information
  infos: {
    platform: 'darwin',
    arch: 'arm64',
    nodeVersion: 'v18.17.0',
    v8Version: '10.2.154.26',
    cpus: [...],
    totalMemory: 17179869184,
    // ... more system details
  },

  // Timing information
  clock: {
    startTime: 1699123456789,
    endTime: 1699123556789,
    duration: 100000,
    human: '1m 40s'
  },

  // Analysis metrics
  analysis: {
    numSamples: 20,
    numOfAlertTriggers: 3,
    timeOverTarget: 45000,
    timeOverTargetHuman: '45s',
    timeUnderTarget: 55000,
    timeUnderTargetHuman: '55s',
    samplingInterval: 5000,
    threshold: { bytes: 500000000, human: '476.84 MB' },
    target: { bytes: 100000000, human: '95.37 MB' }
  },

  // Quick summary for overview
  summary: {
    duration: '1m 40s',
    peakMemory: '100.00 MB',
    averageMemory: '50.00 MB',
    peakCPU: '45.67%',
    averageCPU: '22.34%',
    samples: 20,
    alerts: 3
  }
}