node-loop-detective 1.3.0 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -77,6 +77,9 @@ loop-detective -p 12345 --io-threshold 1000
77
77
  # Connect to a remote inspector (Docker, K8s, remote server)
78
78
  loop-detective --host 192.168.1.100 --port 9229
79
79
 
80
+ # Save raw CPU profile for Chrome DevTools / speedscope
81
+ loop-detective -p 12345 --save-profile ./profile.cpuprofile
82
+
80
83
  # Continuous monitoring mode
81
84
  loop-detective -p 12345 --watch
82
85
 
@@ -95,6 +98,7 @@ loop-detective -p 12345 --json
95
98
  | `-t, --threshold <ms>` | Event loop lag threshold | 50 |
96
99
  | `-i, --interval <ms>` | Lag sampling interval | 100 |
97
100
  | `--io-threshold <ms>` | Slow I/O threshold | 500 |
101
+ | `--save-profile <path>` | Save raw CPU profile to file | — |
98
102
  | `-j, --json` | Output as JSON | false |
99
103
  | `-w, --watch` | Continuous monitoring | false |
100
104
 
package/bin/cli.js CHANGED
@@ -4,6 +4,8 @@
4
4
 
5
5
  const { Detective } = require('../src/detective');
6
6
  const { Reporter } = require('../src/reporter');
7
+ const fs = require('node:fs');
8
+ const path = require('node:path');
7
9
 
8
10
  // Simple arg parser compatible with Node.js 16+
9
11
  function parseCliArgs(argv) {
@@ -16,6 +18,7 @@ function parseCliArgs(argv) {
16
18
  threshold: '50',
17
19
  interval: '100',
18
20
  'io-threshold': '500',
21
+ 'save-profile': null,
19
22
  json: false,
20
23
  watch: false,
21
24
  help: false,
@@ -31,6 +34,7 @@ function parseCliArgs(argv) {
31
34
  '-t': 'threshold', '--threshold': 'threshold',
32
35
  '-i': 'interval', '--interval': 'interval',
33
36
  '--io-threshold': 'io-threshold',
37
+ '--save-profile': 'save-profile',
34
38
  };
35
39
  const boolMap = {
36
40
  '-j': 'json', '--json': 'json',
@@ -97,6 +101,7 @@ function printUsage() {
97
101
  -t, --threshold <ms> Event loop lag threshold in ms (default: 50)
98
102
  -i, --interval <ms> Sampling interval in ms (default: 100)
99
103
  --io-threshold <ms> Slow I/O threshold in ms (default: 500)
104
+ --save-profile <path> Save raw CPU profile to .cpuprofile file
100
105
  -j, --json Output results as JSON
101
106
  -w, --watch Continuous monitoring mode
102
107
  -h, --help Show this help
@@ -127,6 +132,7 @@ async function main() {
127
132
  threshold: parseInt(values.threshold, 10),
128
133
  interval: parseInt(values.interval, 10),
129
134
  ioThreshold: parseInt(values['io-threshold'], 10),
135
+ saveProfile: values['save-profile'],
130
136
  watch: values.watch,
131
137
  json: values.json,
132
138
  };
@@ -142,7 +148,24 @@ async function main() {
142
148
  detective.on('connected', () => reporter.onConnected());
143
149
  detective.on('lag', (data) => reporter.onLag(data));
144
150
  detective.on('slowIO', (data) => reporter.onSlowIO(data));
145
- detective.on('profile', (data) => reporter.onProfile(data));
151
+ detective.on('profile', (analysis, rawProfile) => {
152
+ reporter.onProfile(analysis);
153
+
154
+ // Save raw CPU profile if requested
155
+ if (config.saveProfile && rawProfile) {
156
+ try {
157
+ const filePath = path.resolve(config.saveProfile);
158
+ fs.writeFileSync(filePath, JSON.stringify(rawProfile));
159
+ if (!config.json) {
160
+ console.log(`\n \x1b[32m✔\x1b[0m CPU profile saved to ${filePath}`);
161
+ console.log(` Open in Chrome DevTools: Performance tab → Load profile`);
162
+ console.log(` Or visit https://www.speedscope.app\n`);
163
+ }
164
+ } catch (err) {
165
+ console.error(`\n \x1b[31m✖ Failed to save profile: ${err.message}\x1b[0m\n`);
166
+ }
167
+ }
168
+ });
146
169
  detective.on('error', (err) => reporter.onError(err));
147
170
  detective.on('disconnected', () => reporter.onDisconnected());
148
171
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "node-loop-detective",
3
- "version": "1.3.0",
3
+ "version": "1.4.0",
4
4
  "description": "Detect event loop blocking & lag in running Node.js apps without code changes or restarts",
5
5
  "main": "src/index.js",
6
6
  "bin": {
package/src/detective.js CHANGED
@@ -424,7 +424,7 @@ class Detective extends EventEmitter {
424
424
 
425
425
  const profile = await this._captureProfile(this.config.duration);
426
426
  const analysis = this.analyzer.analyzeProfile(profile);
427
- this.emit('profile', analysis);
427
+ this.emit('profile', analysis, profile);
428
428
  } finally {
429
429
  await this.stop();
430
430
  }
@@ -444,7 +444,7 @@ class Detective extends EventEmitter {
444
444
  try {
445
445
  const profile = await this._captureProfile(this.config.duration);
446
446
  const analysis = this.analyzer.analyzeProfile(profile);
447
- this.emit('profile', analysis);
447
+ this.emit('profile', analysis, profile);
448
448
  } catch (err) {
449
449
  this.emit('error', err);
450
450
  }