Skip to content

Commit 403deb7

Browse files
AshCrippsaddaleax
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 9b27933 commit 403deb7

File tree

7 files changed

+260
-2
lines changed

7 files changed

+260
-2
lines changed

doc/api/cli.md

Lines changed: 21 additions & 0 deletions
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: v12.17.0
@@ -325,6 +338,9 @@ added: v12.4.0
325338
Specify the directory where the heap profiles generated by `--heap-prof` will
326339
be placed.
327340

341+
The default value is controlled by the
342+
[--diagnostic-dir](#cli_diagnostic_dir_directory) command line option.
343+
328344
### `--heap-prof-interval`
329345
<!-- YAML
330346
added: v12.4.0
@@ -623,6 +639,10 @@ file will be created if it does not exist, and will be appended to if it does.
623639
If an error occurs while attempting to write the warning to the file, the
624640
warning will be written to stderr instead.
625641

642+
The `file` name may be an absolute path. If it is not, the default directory it
643+
will be written to is controlled by the
644+
[--diagnostic-dir](#cli_diagnostic_dir_directory) command line option.
645+
626646
### `--report-compact`
627647
<!-- YAML
628648
added: v12.17.0
@@ -1141,6 +1161,7 @@ node --require "./a.js" --require "./b.js"
11411161

11421162
Node.js options that are allowed are:
11431163
<!-- node-options-node start -->
1164+
* `--diagnostic-dir`
11441165
* `--disable-proto`
11451166
* `--enable-fips`
11461167
* `--enable-source-maps`

doc/node.1

Lines changed: 21 additions & 0 deletions
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
@@ -178,6 +192,9 @@ with a generated file name.
178192
The directory where the heap profiles generated by
179193
.Fl -heap-prof
180194
will be placed.
195+
The default value is controlled by the
196+
.Fl -diagnostic-dir .
197+
command line option.
181198
.
182199
.It Fl -heap-prof-interval
183200
The average sampling interval in bytes for the heap profiles generated by
@@ -304,6 +321,10 @@ in a compact format, single-line JSON.
304321
Location at which the
305322
.Sy diagnostic report
306323
will be generated.
324+
The `file` name may be an absolute path. If it is not, the default directory it will
325+
be written to is controlled by the
326+
.Fl -diagnostic-dir .
327+
command line option.
307328
.
308329
.It Fl -report-filename
309330
Name of the file to which the

lib/internal/process/warning.js

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,21 @@ const { ERR_INVALID_ARG_TYPE } = require('internal/errors').codes;
1111
let fs;
1212
let fd;
1313
let warningFile;
14+
let options;
1415

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

src/node_options.cc

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,10 @@ void EnvironmentOptions::CheckOptions(std::vector<std::string>* errors) {
148148
}
149149
}
150150

151+
if (cpu_prof && cpu_prof_dir.empty() && !diagnostic_dir.empty()) {
152+
cpu_prof_dir = diagnostic_dir;
153+
}
154+
151155
if (!heap_prof) {
152156
if (!heap_prof_name.empty()) {
153157
errors->push_back("--heap-prof-name must be used with --heap-prof");
@@ -161,6 +165,11 @@ void EnvironmentOptions::CheckOptions(std::vector<std::string>* errors) {
161165
errors->push_back("--heap-prof-interval must be used with --heap-prof");
162166
}
163167
}
168+
169+
if (heap_prof && heap_prof_dir.empty() && !diagnostic_dir.empty()) {
170+
heap_prof_dir = diagnostic_dir;
171+
}
172+
164173
debug_options_.CheckOptions(errors);
165174
#endif // HAVE_INSPECTOR
166175
}
@@ -274,6 +283,11 @@ DebugOptionsParser::DebugOptionsParser() {
274283
}
275284

276285
EnvironmentOptionsParser::EnvironmentOptionsParser() {
286+
AddOption("--diagnostic-dir",
287+
"set dir for all output files"
288+
" (default: current working directory)",
289+
&EnvironmentOptions::diagnostic_dir,
290+
kAllowedInEnvironment);
277291
AddOption("--enable-source-maps",
278292
"experimental Source Map V3 support",
279293
&EnvironmentOptions::enable_source_maps,

src/node_options.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,7 @@ class EnvironmentOptions : public Options {
139139
bool heap_prof = false;
140140
#endif // HAVE_INSPECTOR
141141
std::string redirect_warnings;
142+
std::string diagnostic_dir;
142143
bool test_udp_no_try_send = false;
143144
bool throw_deprecation = false;
144145
bool trace_deprecation = false;
Lines changed: 76 additions & 0 deletions
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+
}
Lines changed: 117 additions & 0 deletions
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)