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 +4 -0
- package/bin/cli.js +24 -1
- package/package.json +1 -1
- package/src/detective.js +2 -2
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', (
|
|
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
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
|
}
|