Skip to content

Commit 141e3e9

Browse files
AndreasMadsenMylesBorins
authored andcommitted
trace_events: add file pattern cli option
Allow the user to specify the filepath for the trace_events log file using a template string. Backport-PR-URL: #19145 PR-URL: #18480 Reviewed-By: Ali Ijaz Sheikh <ofrobots@google.com> Reviewed-By: Richard Lau <riclau@uk.ibm.com> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de>
1 parent bdbef5f commit 141e3e9

10 files changed

+103
-10
lines changed

doc/api/cli.md

+9
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,14 @@ added: v7.7.0
238238
A comma separated list of categories that should be traced when trace event
239239
tracing is enabled using `--trace-events-enabled`.
240240

241+
### `--trace-event-file-pattern`
242+
<!-- YAML
243+
added: REPLACEME
244+
-->
245+
246+
Template string specifying the filepath for the trace event data, it
247+
supports `${rotation}` and `${pid}`.
248+
241249
### `--zero-fill-buffers`
242250
<!-- YAML
243251
added: v6.0.0
@@ -474,6 +482,7 @@ Node options that are allowed are:
474482
- `--trace-deprecation`
475483
- `--trace-events-categories`
476484
- `--trace-events-enabled`
485+
- `--trace-event-file-pattern`
477486
- `--trace-sync-io`
478487
- `--trace-warnings`
479488
- `--track-heap-objects`

doc/api/tracing.md

+13
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,16 @@ node --trace-events-enabled --trace-event-categories v8,node,node.async_hooks se
1919
Running Node.js with tracing enabled will produce log files that can be opened
2020
in the [`chrome://tracing`](https://www.chromium.org/developers/how-tos/trace-event-profiling-tool)
2121
tab of Chrome.
22+
23+
The logging file is by default called `node_trace.${rotation}.log`, where
24+
`${rotation}` is an incrementing log-rotation id. The filepath pattern can
25+
be specified with `--trace-event-file-pattern` that accepts a template
26+
string that supports `${rotation}` and `${pid}`. For example:
27+
28+
```txt
29+
node --trace-events-enabled --trace-event-file-pattern '${pid}-${rotation}.log' server.js
30+
```
31+
32+
Starting with Node 10.0.0, the tracing system uses the same time source as the
33+
one used by `process.hrtime()` however the trace-event timestamps are expressed
34+
in microseconds, unlike `process.hrtime()` which returns nanoseconds.

doc/node.1

+5
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,11 @@ Enables the collection of trace event tracing information.
166166
A comma separated list of categories that should be traced when trace event
167167
tracing is enabled using \fB--trace-events-enabled\fR.
168168

169+
.TP
170+
.BR \-\-trace-event\-file\-pattern " " \fIpattern\fR
171+
Template string specifying the filepath for the trace event data, it
172+
supports \fB${rotation}\fR and \fB${pid}\fR.
173+
169174
.TP
170175
.BR \-\-zero\-fill\-buffers
171176
Automatically zero-fills all newly allocated Buffer and SlowBuffer instances.

src/node.cc

+16-1
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,8 @@ static node_module* modlist_linked;
192192
static node_module* modlist_addon;
193193
static bool trace_enabled = false;
194194
static std::string trace_enabled_categories; // NOLINT(runtime/string)
195+
static std::string trace_file_pattern = // NOLINT(runtime/string)
196+
"node_trace.${rotation}.log";
195197
static bool abort_on_uncaught_exception = false;
196198

197199
// Bit flag used to track security reverts (see node_revert.h)
@@ -273,7 +275,7 @@ static struct {
273275
#if NODE_USE_V8_PLATFORM
274276
void Initialize(int thread_pool_size, uv_loop_t* loop) {
275277
if (trace_enabled) {
276-
tracing_agent_.reset(new tracing::Agent());
278+
tracing_agent_.reset(new tracing::Agent(trace_file_pattern));
277279
platform_ = new NodePlatform(thread_pool_size, loop,
278280
tracing_agent_->GetTracingController());
279281
V8::InitializePlatform(platform_);
@@ -3853,6 +3855,10 @@ static void PrintHelp() {
38533855
" --trace-events-enabled track trace events\n"
38543856
" --trace-event-categories comma separated list of trace event\n"
38553857
" categories to record\n"
3858+
" --trace-event-file-pattern Template string specifying the\n"
3859+
" filepath for the trace-events data, it\n"
3860+
" supports ${rotation} and ${pid}\n"
3861+
" log-rotation id. %%2$u is the pid.\n"
38563862
" --track-heap-objects track heap object allocations for heap "
38573863
"snapshots\n"
38583864
" --prof-process process v8 profiler output generated\n"
@@ -3979,6 +3985,7 @@ static void CheckIfAllowedInEnv(const char* exe, bool is_env,
39793985
"--force-async-hooks-checks",
39803986
"--trace-events-enabled",
39813987
"--trace-event-categories",
3988+
"--trace-event-file-pattern",
39823989
"--track-heap-objects",
39833990
"--zero-fill-buffers",
39843991
"--v8-pool-size",
@@ -4128,6 +4135,14 @@ static void ParseArgs(int* argc,
41284135
}
41294136
args_consumed += 1;
41304137
trace_enabled_categories = categories;
4138+
} else if (strcmp(arg, "--trace-event-file-pattern") == 0) {
4139+
const char* file_pattern = argv[index + 1];
4140+
if (file_pattern == nullptr) {
4141+
fprintf(stderr, "%s: %s requires an argument\n", argv[0], arg);
4142+
exit(9);
4143+
}
4144+
args_consumed += 1;
4145+
trace_file_pattern = file_pattern;
41314146
} else if (strcmp(arg, "--track-heap-objects") == 0) {
41324147
track_heap_objects = true;
41334148
} else if (strcmp(arg, "--throw-deprecation") == 0) {

src/tracing/agent.cc

+3-2
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,12 @@ namespace tracing {
1313
using v8::platform::tracing::TraceConfig;
1414
using std::string;
1515

16-
Agent::Agent() {
16+
Agent::Agent(const std::string& log_file_pattern) {
1717
int err = uv_loop_init(&tracing_loop_);
1818
CHECK_EQ(err, 0);
1919

20-
NodeTraceWriter* trace_writer = new NodeTraceWriter(&tracing_loop_);
20+
NodeTraceWriter* trace_writer = new NodeTraceWriter(
21+
log_file_pattern, &tracing_loop_);
2122
TraceBuffer* trace_buffer = new NodeTraceBuffer(
2223
NodeTraceBuffer::kBufferChunks, trace_writer, &tracing_loop_);
2324
tracing_controller_ = new TracingController();

src/tracing/agent.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ using v8::platform::tracing::TracingController;
1212

1313
class Agent {
1414
public:
15-
Agent();
15+
explicit Agent(const std::string& log_file_pattern);
1616
void Start(const std::string& enabled_categories);
1717
void Stop();
1818

src/tracing/node_trace_writer.cc

+21-5
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,9 @@
88
namespace node {
99
namespace tracing {
1010

11-
NodeTraceWriter::NodeTraceWriter(uv_loop_t* tracing_loop)
12-
: tracing_loop_(tracing_loop) {
11+
NodeTraceWriter::NodeTraceWriter(const std::string& log_file_pattern,
12+
uv_loop_t* tracing_loop)
13+
: tracing_loop_(tracing_loop), log_file_pattern_(log_file_pattern) {
1314
flush_signal_.data = this;
1415
int err = uv_async_init(tracing_loop_, &flush_signal_, FlushSignalCb);
1516
CHECK_EQ(err, 0);
@@ -54,12 +55,27 @@ NodeTraceWriter::~NodeTraceWriter() {
5455
}
5556
}
5657

58+
void replace_substring(std::string* target,
59+
const std::string& search,
60+
const std::string& insert) {
61+
size_t pos = target->find(search);
62+
for (; pos != std::string::npos; pos = target->find(search, pos)) {
63+
target->replace(pos, search.size(), insert);
64+
pos += insert.size();
65+
}
66+
}
67+
5768
void NodeTraceWriter::OpenNewFileForStreaming() {
5869
++file_num_;
5970
uv_fs_t req;
60-
std::ostringstream log_file;
61-
log_file << "node_trace." << file_num_ << ".log";
62-
fd_ = uv_fs_open(tracing_loop_, &req, log_file.str().c_str(),
71+
72+
// Evaluate a JS-style template string, it accepts the values ${pid} and
73+
// ${rotation}
74+
std::string filepath(log_file_pattern_);
75+
replace_substring(&filepath, "${pid}", std::to_string(uv_os_getpid()));
76+
replace_substring(&filepath, "${rotation}", std::to_string(file_num_));
77+
78+
fd_ = uv_fs_open(tracing_loop_, &req, filepath.c_str(),
6379
O_CREAT | O_WRONLY | O_TRUNC, 0644, nullptr);
6480
CHECK_NE(fd_, -1);
6581
uv_fs_req_cleanup(&req);

src/tracing/node_trace_writer.h

+3-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@ using v8::platform::tracing::TraceWriter;
1616

1717
class NodeTraceWriter : public TraceWriter {
1818
public:
19-
explicit NodeTraceWriter(uv_loop_t* tracing_loop);
19+
explicit NodeTraceWriter(const std::string& log_file_pattern,
20+
uv_loop_t* tracing_loop);
2021
~NodeTraceWriter();
2122

2223
void AppendTraceEvent(TraceObject* trace_event) override;
@@ -62,6 +63,7 @@ class NodeTraceWriter : public TraceWriter {
6263
int highest_request_id_completed_ = 0;
6364
int total_traces_ = 0;
6465
int file_num_ = 0;
66+
const std::string& log_file_pattern_;
6567
std::ostringstream stream_;
6668
TraceWriter* json_trace_writer_ = nullptr;
6769
bool exited_ = false;

test/parallel/test-cli-node-options.js

+2
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ expect('--throw-deprecation', 'B\n');
2525
expect('--zero-fill-buffers', 'B\n');
2626
expect('--v8-pool-size=10', 'B\n');
2727
expect('--trace-event-categories node', 'B\n');
28+
// eslint-disable-next-line no-template-curly-in-string
29+
expect('--trace-event-file-pattern {pid}-${rotation}.trace_events', 'B\n');
2830

2931
if (common.hasCrypto) {
3032
expect('--use-openssl-ca', 'B\n');
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
'use strict';
2+
const common = require('../common');
3+
const tmpdir = require('../common/tmpdir');
4+
const assert = require('assert');
5+
const cp = require('child_process');
6+
const fs = require('fs');
7+
8+
tmpdir.refresh();
9+
process.chdir(tmpdir.path);
10+
11+
const CODE =
12+
'setTimeout(() => { for (var i = 0; i < 100000; i++) { "test" + i } }, 1)';
13+
14+
const proc = cp.spawn(process.execPath, [
15+
'--trace-events-enabled',
16+
'--trace-event-file-pattern',
17+
// eslint-disable-next-line no-template-curly-in-string
18+
'${pid}-${rotation}-${pid}-${rotation}.tracing.log',
19+
'-e', CODE
20+
]);
21+
22+
proc.once('exit', common.mustCall(() => {
23+
const expectedFilename = `${proc.pid}-1-${proc.pid}-1.tracing.log`;
24+
25+
assert(common.fileExists(expectedFilename));
26+
fs.readFile(expectedFilename, common.mustCall((err, data) => {
27+
const traces = JSON.parse(data.toString()).traceEvents;
28+
assert(traces.length > 0);
29+
}));
30+
}));

0 commit comments

Comments
 (0)