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 🙏

© 2026 – Pkg Stats / Ryan Hefner

process-stats-sampler

v1.1.3

Published

Sample Node.js process memory and CPU usage to a JSON file

Readme

process-stats-sampler

NPM Version NPM Downloads CI

Samples the Node.js process's memory and CPU usage into a JSON file and measures the Node event-loop execution delay. sample() takes one snapshot; call it on your own schedule (e.g. with setInterval) to build a time series.

This library is maintained primarily for personal use, so compatibility guarantees are pragmatic rather than semver-strict.

Install

npm install process-stats-sampler

Usage

const {sample} = require('process-stats-sampler');

// Call every 30 seconds; the sample is written to /tmp/stats.json.
// sample() rejects on runtime failures (e.g. disk full), so handle errors
// instead of letting them become unhandled rejections.
setInterval(async () => {
    try {
        await sample('/tmp/stats.json');
    } catch (error) {
        console.error('sampling failed:', error.message);
    }
}, 30_000);

ESM

The package ships both require and import entry points. They share the same module instance, so mixing both in one process is safe:

import {sample, lag, reset} from 'process-stats-sampler';

Measuring delay

const {lag} = require('process-stats-sampler');

// Waits 1000ms and returns the difference between the actual and expected time (ms, >= 0)
const delay = await lag(1000);

lag(ms = 1000) measures the Node event-loop execution delay: when the event loop is blocked by synchronous work, timers fire late and the difference between the actual and expected elapsed time is the returned delay.

API

sample(filename?, options?)

| Param | Type | Default | Description | | --- | --- | --- | --- | | filename | string | /tmp/stats.json | Output JSON file path; parent directories are created automatically. Writes use a temp file + atomic rename. Each call overwrites the file with the latest sample | | options.unit | 'ratio' \| 'percent' \| 'machine-percent' | 'ratio' | CPU output unit | | options.lag | boolean \| number | true | Record lag (event-loop delay probe): true probes with 1ms, false skips the probe (field is 0), a number sets a custom probe duration in ms |

Invalid arguments (filename empty, invalid unit/lag, invalid ms) throw a TypeError / RangeError. Runtime failures (e.g. file I/O errors) reject the returned promise with the underlying Error.

CPU units

  • ratio (default): CPU microseconds / wall-clock milliseconds between samples; a fully utilized core is about 1000
  • percent: percent of one core; a fully utilized core is 100
  • machine-percent: percent of the whole machine (percent of one core ÷ number of cores available to the process)

The lag field in the output is the event-loop execution delay probe (same semantics as lag()): each sample waits on a short timer; when the event loop is blocked by synchronous work the timer fires late, so the value is the current Node execution delay in ms (min 0). By default it probes with 1ms; use options.lag to disable it or set a custom probe duration.

lag(ms?)

| Param | Type | Default | Description | | --- | --- | --- | --- | | ms | number | 1000 | Expected wait time in ms; a non-negative finite number up to ~24.8 days |

Returns the difference between the actual elapsed time and ms (ms, min 0).

Example output:

{
  "rss": 41058304,
  "heapTotal": 16777216,
  "heapUsed": 8615928,
  "external": 863268,
  "arrayBuffers": 11358,
  "user": 0.25,
  "system": 0.06,
  "lag": 0,
  "timestamp": 1786320000000
}

Behavior notes

  • The CPU rate is the delta of process.cpuUsage() between two consecutive samples of the same file divided by the actual wall-clock elapsed time (via performance.now()). The first sample of a file is 0 because it only establishes the baseline, and an irregular call cadence does not distort the reading.
  • The timestamp, the memory snapshot and the CPU counters are all captured at the start of the sample, before the lag probe, so they are aligned with each other.
  • user and system are JSON numbers rounded to 3 decimals (CPU µs per ms of wall time, or a percentage per the chosen unit).
  • Calls targeting the same file are serialized internally; different files run independently, each with its own CPU baseline and queue. Note that process.cpuUsage() is process-wide, so overlapping streams each report the whole process's CPU; per-target attribution requires separate processes.
  • machine-percent derives the available core count on Linux from the cgroup CPU quota (v2 cpu.max / v1 cfs_quota_us) and the cpuset, taking the binding constraint and preserving fractional quotas (e.g. 0.5 core). It is re-read on every sample so runtime changes (docker update, HPA) are picked up. On other platforms it falls back to os.cpus().length.
  • reset(filename) clears the sampling state (CPU baseline) for a file; the next sample starts fresh. State for each distinct filename is retained until reset, so callers using dynamic filenames should reset them when done.
  • File writes are atomic (temp file + rename), so the target file is never left truncated. A hard kill between the write and the rename may leave an orphan temp file.
  • The lag timer is not unref()ed, so a process with only a pending lag timer stays alive until it fires (this guarantees the promise always resolves).

Changelog

See CHANGELOG.md for the full release history.

Development

npm run build   # compile to dist/
npm test        # build + run node:test tests