Skip to content

Commit 5c94358

Browse files
AshCrippsMylesBorins
AshCripps
authored andcommitted
src: allow setting a dir for all diagnostic output
Add a flag that allows for the setting of a directory where all diagnostic output will be written to. e.g. --redirect-warnings Refs: #33010 (comment) PR-URL: #33584 Reviewed-By: James M Snell <[email protected]> Reviewed-By: Richard Lau <[email protected]> Reviewed-By: Beth Griggs <[email protected]> Reviewed-By: Anna Henningsen <[email protected]>
1 parent 74da2c4 commit 5c94358

File tree

7 files changed

+260
-2
lines changed

7 files changed

+260
-2
lines changed

doc/api/cli.md

+21
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,9 @@ added: v12.0.0
108108
Specify the directory where the CPU profiles generated by `--cpu-prof` will
109109
be placed.
110110

111+
The default value is controlled by the
112+
[--diagnostic-dir](#cli_diagnostic_dir_directory) command line option.
113+
111114
### `--cpu-prof-interval`
112115
<!-- YAML
113116
added: v12.2.0
@@ -127,6 +130,16 @@ added: v12.0.0
127130
128131
Specify the file name of the CPU profile generated by `--cpu-prof`.
129132

133+
### `--diagnostic-dir=directory`
134+
135+
Set the directory to which all diagnostic output files will be written to.
136+
Defaults to current working directory.
137+
138+
Affects the default output directory of:
139+
* [--cpu-prof-dir](#cli_cpu_prof_dir)
140+
* [--heap-prof-dir](#cli_heap_prof_dir)
141+
* [--redirect-warnings](#cli_redirect_warnings_file)
142+
130143
### `--disable-proto=mode`
131144
<!--YAML
132145
added: v13.12.0
@@ -346,6 +359,9 @@ added: v12.4.0
346359
Specify the directory where the heap profiles generated by `--heap-prof` will
347360
be placed.
348361

362+
The default value is controlled by the
363+
[--diagnostic-dir](#cli_diagnostic_dir_directory) command line option.
364+
349365
### `--heap-prof-interval`
350366
<!-- YAML
351367
added: v12.4.0
@@ -626,6 +642,10 @@ file will be created if it does not exist, and will be appended to if it does.
626642
If an error occurs while attempting to write the warning to the file, the
627643
warning will be written to stderr instead.
628644

645+
The `file` name may be an absolute path. If it is not, the default directory it
646+
will be written to is controlled by the
647+
[--diagnostic-dir](#cli_diagnostic_dir_directory) command line option.
648+
629649
### `--report-compact`
630650
<!-- YAML
631651
added: v13.12.0
@@ -1189,6 +1209,7 @@ node --require "./a.js" --require "./b.js"
11891209

11901210
Node.js options that are allowed are:
11911211
<!-- node-options-node start -->
1212+
* `--diagnostic-dir`
11921213
* `--disable-proto`
11931214
* `--enable-fips`
11941215
* `--enable-source-maps`

doc/node.1

+21
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,9 @@ with a generated file name.
8989
The directory where the CPU profiles generated by
9090
.Fl -cpu-prof
9191
will be placed.
92+
The default value is controlled by the
93+
.Fl -diagnostic-dir .
94+
command line option.
9295
.
9396
.It Fl -cpu-prof-interval
9497
The sampling interval in microseconds for the CPU profiles generated by
@@ -100,6 +103,17 @@ The default is
100103
File name of the V8 CPU profile generated with
101104
.Fl -cpu-prof
102105
.
106+
.It Fl -diagnostic-dir
107+
Set the directory for all diagnostic output files.
108+
Default is current working directory.
109+
Set the directory to which all diagnostic output files will be written to.
110+
Defaults to current working directory.
111+
.
112+
Affects the default output directory of:
113+
.Fl -cpu-prof-dir .
114+
.Fl -heap-prof-dir .
115+
.Fl -redirect-warnings .
116+
.
103117
.It Fl -disable-proto Ns = Ns Ar mode
104118
Disable the `Object.prototype.__proto__` property. If
105119
.Ar mode
@@ -181,6 +195,9 @@ with a generated file name.
181195
The directory where the heap profiles generated by
182196
.Fl -heap-prof
183197
will be placed.
198+
The default value is controlled by the
199+
.Fl -diagnostic-dir .
200+
command line option.
184201
.
185202
.It Fl -heap-prof-interval
186203
The average sampling interval in bytes for the heap profiles generated by
@@ -298,6 +315,10 @@ in a compact format, single-line JSON.
298315
Location at which the
299316
.Sy diagnostic report
300317
will be generated.
318+
The `file` name may be an absolute path. If it is not, the default directory it will
319+
be written to is controlled by the
320+
.Fl -diagnostic-dir .
321+
command line option.
301322
.
302323
.It Fl -report-filename
303324
Name of the file to which the

lib/internal/process/warning.js

+10-2
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,21 @@ const { ERR_INVALID_ARG_TYPE } = require('internal/errors').codes;
1212
let fs;
1313
let fd;
1414
let warningFile;
15+
let options;
1516

1617
function lazyOption() {
1718
// This will load `warningFile` only once. If the flag is not set,
1819
// `warningFile` will be set to an empty string.
1920
if (warningFile === undefined) {
20-
warningFile = require('internal/options')
21-
.getOptionValue('--redirect-warnings');
21+
options = require('internal/options');
22+
if (options.getOptionValue('--diagnostic-dir') !== '') {
23+
warningFile = options.getOptionValue('--diagnostic-dir');
24+
}
25+
if (options.getOptionValue('--redirect-warnings') !== '') {
26+
warningFile = options.getOptionValue('--redirect-warnings');
27+
} else {
28+
warningFile = '';
29+
}
2230
}
2331
return warningFile;
2432
}

src/node_options.cc

+14
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,10 @@ void EnvironmentOptions::CheckOptions(std::vector<std::string>* errors) {
146146
}
147147
}
148148

149+
if (cpu_prof && cpu_prof_dir.empty() && !diagnostic_dir.empty()) {
150+
cpu_prof_dir = diagnostic_dir;
151+
}
152+
149153
if (!heap_prof) {
150154
if (!heap_prof_name.empty()) {
151155
errors->push_back("--heap-prof-name must be used with --heap-prof");
@@ -159,6 +163,11 @@ void EnvironmentOptions::CheckOptions(std::vector<std::string>* errors) {
159163
errors->push_back("--heap-prof-interval must be used with --heap-prof");
160164
}
161165
}
166+
167+
if (heap_prof && heap_prof_dir.empty() && !diagnostic_dir.empty()) {
168+
heap_prof_dir = diagnostic_dir;
169+
}
170+
162171
debug_options_.CheckOptions(errors);
163172
#endif // HAVE_INSPECTOR
164173
}
@@ -272,6 +281,11 @@ DebugOptionsParser::DebugOptionsParser() {
272281
}
273282

274283
EnvironmentOptionsParser::EnvironmentOptionsParser() {
284+
AddOption("--diagnostic-dir",
285+
"set dir for all output files"
286+
" (default: current working directory)",
287+
&EnvironmentOptions::diagnostic_dir,
288+
kAllowedInEnvironment);
275289
AddOption("--enable-source-maps",
276290
"experimental Source Map V3 support",
277291
&EnvironmentOptions::enable_source_maps,

src/node_options.h

+1
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,7 @@ class EnvironmentOptions : public Options {
138138
bool heap_prof = false;
139139
#endif // HAVE_INSPECTOR
140140
std::string redirect_warnings;
141+
std::string diagnostic_dir;
141142
bool test_udp_no_try_send = false;
142143
bool throw_deprecation = false;
143144
bool trace_atomics_wait = false;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
'use strict';
2+
3+
// This test is to ensure that --diagnostic-dir does not change the directory
4+
// for --cpu-prof when --cpu-prof-dir is specified
5+
6+
const common = require('../common');
7+
const fixtures = require('../common/fixtures');
8+
common.skipIfInspectorDisabled();
9+
10+
const assert = require('assert');
11+
const fs = require('fs');
12+
const path = require('path');
13+
const { spawnSync } = require('child_process');
14+
15+
const tmpdir = require('../common/tmpdir');
16+
const {
17+
getCpuProfiles,
18+
kCpuProfInterval,
19+
env,
20+
verifyFrames
21+
} = require('../common/cpu-prof');
22+
23+
// Test --diagnostic-dir changes the default for --cpu-prof
24+
25+
{
26+
tmpdir.refresh();
27+
const dir = path.join(tmpdir.path, 'prof');
28+
const output = spawnSync(process.execPath, [
29+
'--cpu-prof',
30+
'--cpu-prof-interval',
31+
kCpuProfInterval,
32+
'--diagnostic-dir',
33+
dir,
34+
fixtures.path('workload', 'fibonacci.js'),
35+
], {
36+
cwd: tmpdir.path,
37+
env
38+
});
39+
if (output.status !== 0) {
40+
console.log(output.stderr.toString());
41+
}
42+
assert.strictEqual(output.status, 0);
43+
assert(fs.existsSync(dir));
44+
const profiles = getCpuProfiles(dir);
45+
assert.strictEqual(profiles.length, 1);
46+
verifyFrames(output, profiles[0], 'fibonacci.js');
47+
}
48+
49+
// Test --cpu-prof-dir overwrites --diagnostic-dir
50+
51+
{
52+
tmpdir.refresh();
53+
const dir = path.join(tmpdir.path, 'diag');
54+
const dir2 = path.join(tmpdir.path, 'prof');
55+
const output = spawnSync(process.execPath, [
56+
'--cpu-prof',
57+
'--cpu-prof-interval',
58+
kCpuProfInterval,
59+
'--diagnostic-dir',
60+
dir,
61+
'--cpu-prof-dir',
62+
dir2,
63+
fixtures.path('workload', 'fibonacci.js'),
64+
], {
65+
cwd: tmpdir.path,
66+
env
67+
});
68+
if (output.status !== 0) {
69+
console.log(output.stderr.toString());
70+
}
71+
assert.strictEqual(output.status, 0);
72+
assert(fs.existsSync(dir2));
73+
const profiles = getCpuProfiles(dir2);
74+
assert.strictEqual(profiles.length, 1);
75+
verifyFrames(output, profiles[0], 'fibonacci.js');
76+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
'use strict';
2+
3+
// This test is to ensure that --diagnostic-dir does not change the directory
4+
// for --cpu-prof when --cpu-prof-dir is specified
5+
6+
const common = require('../common');
7+
const fixtures = require('../common/fixtures');
8+
common.skipIfInspectorDisabled();
9+
10+
const assert = require('assert');
11+
const fs = require('fs');
12+
const path = require('path');
13+
const { spawnSync } = require('child_process');
14+
15+
const tmpdir = require('../common/tmpdir');
16+
17+
function findFirstFrameInNode(root, func) {
18+
const first = root.children.find(
19+
(child) => child.callFrame.functionName === func
20+
);
21+
if (first) {
22+
return first;
23+
}
24+
for (const child of root.children) {
25+
const first = findFirstFrameInNode(child, func);
26+
if (first) {
27+
return first;
28+
}
29+
}
30+
return undefined;
31+
}
32+
33+
function findFirstFrame(file, func) {
34+
const data = fs.readFileSync(file, 'utf8');
35+
const profile = JSON.parse(data);
36+
const first = findFirstFrameInNode(profile.head, func);
37+
return { frame: first, roots: profile.head.children };
38+
}
39+
40+
function verifyFrames(output, file, func) {
41+
const { frame, roots } = findFirstFrame(file, func);
42+
if (!frame) {
43+
// Show native debug output and the profile for debugging.
44+
console.log(output.stderr.toString());
45+
console.log(roots);
46+
}
47+
assert.notDeepStrictEqual(frame, undefined);
48+
}
49+
50+
const kHeapProfInterval = 128;
51+
const TEST_ALLOCATION = kHeapProfInterval * 2;
52+
53+
const env = {
54+
...process.env,
55+
TEST_ALLOCATION,
56+
NODE_DEBUG_NATIVE: 'INSPECTOR_PROFILER'
57+
};
58+
59+
function getHeapProfiles(dir) {
60+
const list = fs.readdirSync(dir);
61+
return list
62+
.filter((file) => file.endsWith('.heapprofile'))
63+
.map((file) => path.join(dir, file));
64+
}
65+
66+
// Test --diagnostic-dir changes the default for --cpu-prof
67+
{
68+
tmpdir.refresh();
69+
const dir = path.join(tmpdir.path, 'prof');
70+
const output = spawnSync(process.execPath, [
71+
'--heap-prof',
72+
'--diagnostic-dir',
73+
dir,
74+
'--heap-prof-interval',
75+
kHeapProfInterval,
76+
fixtures.path('workload', 'allocation.js'),
77+
], {
78+
cwd: tmpdir.path,
79+
env
80+
});
81+
if (output.status !== 0) {
82+
console.log(output.stderr.toString());
83+
}
84+
assert.strictEqual(output.status, 0);
85+
assert(fs.existsSync(dir));
86+
const profiles = getHeapProfiles(dir);
87+
assert.strictEqual(profiles.length, 1);
88+
verifyFrames(output, profiles[0], 'runAllocation');
89+
}
90+
91+
// Test --heap-prof-dir overwrites --diagnostic-dir
92+
{
93+
tmpdir.refresh();
94+
const dir = path.join(tmpdir.path, 'diag');
95+
const dir2 = path.join(tmpdir.path, 'prof');
96+
const output = spawnSync(process.execPath, [
97+
'--heap-prof',
98+
'--heap-prof-interval',
99+
kHeapProfInterval,
100+
'--diagnostic-dir',
101+
dir,
102+
'--heap-prof-dir',
103+
dir2,
104+
fixtures.path('workload', 'allocation.js'),
105+
], {
106+
cwd: tmpdir.path,
107+
env
108+
});
109+
if (output.status !== 0) {
110+
console.log(output.stderr.toString());
111+
}
112+
assert.strictEqual(output.status, 0);
113+
assert(fs.existsSync(dir2));
114+
const profiles = getHeapProfiles(dir2);
115+
assert.strictEqual(profiles.length, 1);
116+
verifyFrames(output, profiles[0], 'runAllocation');
117+
}

0 commit comments

Comments
 (0)