Skip to content

Commit 06676d9

Browse files
committed
process: add custom dir support for heapsnapshot-signal
1 parent 19fa9f1 commit 06676d9

File tree

2 files changed

+97
-1
lines changed

2 files changed

+97
-1
lines changed

lib/internal/process/pre_execution.js

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,14 @@ const {
88
ObjectGetOwnPropertyDescriptor,
99
SafeMap,
1010
StringPrototypeStartsWith,
11+
Date,
12+
DatePrototypeGetFullYear,
13+
DatePrototypeGetMonth,
14+
DatePrototypeGetDate,
15+
DatePrototypeGetHours,
16+
DatePrototypeGetMinutes,
17+
DatePrototypeGetSeconds,
18+
String,
1119
globalThis,
1220
} = primordials;
1321

@@ -365,6 +373,7 @@ function initializeReportSignalHandlers() {
365373

366374
function initializeHeapSnapshotSignalHandlers() {
367375
const signal = getOptionValue('--heapsnapshot-signal');
376+
const diagnosticDir = getOptionValue('--diagnostic-dir');
368377

369378
if (!signal)
370379
return;
@@ -373,7 +382,8 @@ function initializeHeapSnapshotSignalHandlers() {
373382
const { writeHeapSnapshot } = require('v8');
374383

375384
function doWriteHeapSnapshot() {
376-
writeHeapSnapshot();
385+
const heapSnapshotFilename = getHeapSnapshotFilename(diagnosticDir);
386+
writeHeapSnapshot(heapSnapshotFilename);
377387
}
378388
process.on(signal, doWriteHeapSnapshot);
379389

@@ -650,6 +660,31 @@ function markBootstrapComplete() {
650660
internalBinding('performance').markBootstrapComplete();
651661
}
652662

663+
// Sequence number for diagnostic filenames
664+
let sequenceNumOfheapSnapshot = 0;
665+
666+
// To generate the HeapSnapshotFilename while using custom diagnosticDir
667+
function getHeapSnapshotFilename(diagnosticDir) {
668+
if (!diagnosticDir) return undefined;
669+
670+
const date = new Date();
671+
672+
const year = DatePrototypeGetFullYear(date);
673+
const month = String(DatePrototypeGetMonth(date) + 1).padStart(2, '0');
674+
const day = String(DatePrototypeGetDate(date)).padStart(2, '0');
675+
const hours = String(DatePrototypeGetHours(date)).padStart(2, '0');
676+
const minutes = String(DatePrototypeGetMinutes(date)).padStart(2, '0');
677+
const seconds = String(DatePrototypeGetSeconds(date)).padStart(2, '0');
678+
679+
const dateString = `${year}${month}${day}`;
680+
const timeString = `${hours}${minutes}${seconds}`;
681+
const pid = process.pid;
682+
const threadId = internalBinding('worker').threadId;
683+
const fileSequence = (++sequenceNumOfheapSnapshot).toString().padStart(3, '0');
684+
685+
return `${diagnosticDir}/Heap.${dateString}.${timeString}.${pid}.${threadId}.${fileSequence}.heapsnapshot`;
686+
}
687+
653688
module.exports = {
654689
setupUserModules,
655690
prepareMainThreadExecution,
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
'use strict';
2+
const common = require('../common');
3+
4+
5+
if (common.isWindows)
6+
common.skip('test not supported on Windows');
7+
8+
const assert = require('assert');
9+
10+
const validateDateStringInHeapSnapshotFile = (fileName) => {
11+
const currentDate = new Date();
12+
const currentYear = currentDate.getFullYear();
13+
const currentMonth = (currentDate.getMonth() + 1).toString().padStart(2, '0');
14+
const currentDateValue = currentDate.getDate().toString().padStart(2, '0');
15+
16+
const expectedDateString = `${currentYear}${currentMonth}${currentDateValue}`;
17+
const fileDateString = fileName.split('.')[1];
18+
assert.deepStrictEqual(fileDateString, expectedDateString);
19+
};
20+
21+
const validateHeapSnapshotFile = () => {
22+
const fs = require('fs');
23+
24+
assert.strictEqual(process.listenerCount('SIGUSR2'), 1);
25+
process.kill(process.pid, 'SIGUSR2');
26+
process.kill(process.pid, 'SIGUSR2');
27+
28+
// Asynchronously wait for the snapshot. Use an async loop to be a bit more
29+
// robust in case platform or machine differences throw off the timing.
30+
(function validate() {
31+
const files = fs.readdirSync(process.cwd());
32+
33+
if (files.length === 0)
34+
return setImmediate(validate);
35+
36+
assert.strictEqual(files.length, 2);
37+
38+
for (let i = 0; i < files.length; i++) {
39+
assert.match(files[i], /^Heap\..+\.heapsnapshot$/);
40+
41+
// Check the file is parsable as JSON
42+
JSON.parse(fs.readFileSync(files[i]));
43+
}
44+
})();
45+
};
46+
47+
if (process.argv[2] === 'child') {
48+
validateHeapSnapshotFile();
49+
} else {
50+
// Modify the timezone. So we can check the file date string still returning correctly.
51+
process.env.TZ = 'America/New_York';
52+
const { spawnSync } = require('child_process');
53+
const tmpdir = require('../common/tmpdir');
54+
55+
tmpdir.refresh();
56+
const args = ['--heapsnapshot-signal', 'SIGUSR2', '--diagnostic-dir', tmpdir.path, __filename, 'child'];
57+
const child = spawnSync(process.execPath, args, { cwd: tmpdir.path });
58+
59+
assert.strictEqual(child.status, 0);
60+
assert.strictEqual(child.signal, null);
61+
}

0 commit comments

Comments
 (0)