Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 13 additions & 21 deletions src/async_wrap.cc
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,18 @@ void AsyncWrap::EmitPromiseResolve(Environment* env, double async_id) {
env->async_hooks_promise_resolve_function());
}

void AsyncWrap::EmitTraceAsyncStart() const {
if (*TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(
TRACING_CATEGORY_NODE1(async_hooks))) {
tracing::AsyncWrapArgs data(env()->execution_async_id(),
get_trigger_async_id());
TRACE_EVENT_NESTABLE_ASYNC_BEGIN1(TRACING_CATEGORY_NODE1(async_hooks),
provider_names[provider_type()],
static_cast<int64_t>(get_async_id()),
"data",
tracing::CastTracedValue(data));
}
}

void AsyncWrap::EmitTraceEventBefore() {
switch (provider_type()) {
Expand Down Expand Up @@ -601,27 +613,7 @@ void AsyncWrap::AsyncReset(Local<Object> resource, double execution_async_id) {
}
}

switch (provider_type()) {
#define V(PROVIDER) \
case PROVIDER_ ## PROVIDER: \
if (*TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED( \
TRACING_CATEGORY_NODE1(async_hooks))) { \
auto data = tracing::TracedValue::Create(); \
data->SetInteger("executionAsyncId", \
static_cast<int64_t>(env()->execution_async_id())); \
data->SetInteger("triggerAsyncId", \
static_cast<int64_t>(get_trigger_async_id())); \
TRACE_EVENT_NESTABLE_ASYNC_BEGIN1( \
TRACING_CATEGORY_NODE1(async_hooks), \
#PROVIDER, static_cast<int64_t>(get_async_id()), \
"data", std::move(data)); \
} \
break;
NODE_ASYNC_PROVIDER_TYPES(V)
#undef V
default:
UNREACHABLE();
}
EmitTraceAsyncStart();

context_frame_.Reset(isolate, async_context_frame::current(isolate));

Expand Down
1 change: 1 addition & 0 deletions src/async_wrap.h
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,7 @@ class AsyncWrap : public BaseObject {

void EmitDestroy(bool from_gc = false);

void EmitTraceAsyncStart() const;
void EmitTraceEventBefore();
static void EmitTraceEventAfter(ProviderType type, double async_id);
void EmitTraceEventDestroy();
Expand Down
10 changes: 2 additions & 8 deletions src/env.cc
Original file line number Diff line number Diff line change
Expand Up @@ -894,18 +894,12 @@ Environment::Environment(IsolateData* isolate_data,

if (*TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(
TRACING_CATEGORY_NODE1(environment)) != 0) {
auto traced_value = tracing::TracedValue::Create();
traced_value->BeginArray("args");
for (const std::string& arg : args) traced_value->AppendString(arg);
traced_value->EndArray();
traced_value->BeginArray("exec_args");
for (const std::string& arg : exec_args) traced_value->AppendString(arg);
traced_value->EndArray();
tracing::EnvironmentArgs traced_value(args, exec_args);
TRACE_EVENT_NESTABLE_ASYNC_BEGIN1(TRACING_CATEGORY_NODE1(environment),
"Environment",
this,
"args",
std::move(traced_value));
tracing::CastTracedValue(traced_value));
}

if (options_->permission) {
Expand Down
22 changes: 22 additions & 0 deletions src/node_metadata.cc
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,28 @@ Metadata::Versions::Versions() {
nbytes = NBYTES_VERSION;
}

std::array<std::pair<std::string_view, std::string_view>,
NODE_VERSIONS_KEY_COUNT>
Metadata::Versions::pairs() const {
std::array<std::pair<std::string_view, std::string_view>,
NODE_VERSIONS_KEY_COUNT>
versions_array;
auto slot = versions_array.begin();

#define V(key) \
do { \
*slot++ = std::pair<std::string_view, std::string_view>( \
#key, per_process::metadata.versions.key); \
} while (0);
NODE_VERSIONS_KEYS(V)
#undef V

std::ranges::sort(versions_array,
[](auto& a, auto& b) { return a.first < b.first; });

return versions_array;
}

Metadata::Release::Release() : name(NODE_RELEASE) {
#if NODE_VERSION_IS_LTS
lts = NODE_VERSION_LTS_CODENAME;
Expand Down
10 changes: 10 additions & 0 deletions src/node_metadata.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@

#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS

#include <array>
#include <string>
#include <utility>
#include "node_version.h"

#if HAVE_OPENSSL
Expand Down Expand Up @@ -98,6 +100,10 @@ namespace node {
NODE_VERSIONS_KEY_QUIC(V) \
NODE_VERSIONS_KEY_SQLITE(V)

#define V(key) +1
constexpr int NODE_VERSIONS_KEY_COUNT = NODE_VERSIONS_KEYS(V);
#undef V

class Metadata {
public:
Metadata();
Expand All @@ -118,6 +124,10 @@ class Metadata {
#define V(key) std::string key;
NODE_VERSIONS_KEYS(V)
#undef V

std::array<std::pair<std::string_view, std::string_view>,
NODE_VERSIONS_KEY_COUNT>
pairs() const;
};

struct Release {
Expand Down
19 changes: 1 addition & 18 deletions src/node_process_object.cc
Original file line number Diff line number Diff line change
Expand Up @@ -83,24 +83,7 @@ static void SetVersions(Isolate* isolate, Local<Object> versions) {
READONLY_STRING_PROPERTY(
versions, "node", per_process::metadata.versions.node);

#define V(key) +1
std::pair<std::string_view, std::string_view>
versions_array[NODE_VERSIONS_KEYS(V)];
#undef V
auto* slot = &versions_array[0];

#define V(key) \
do { \
*slot++ = std::pair<std::string_view, std::string_view>( \
#key, per_process::metadata.versions.key); \
} while (0);
NODE_VERSIONS_KEYS(V)
#undef V

std::ranges::sort(versions_array,
[](auto& a, auto& b) { return a.first < b.first; });

for (const auto& version : versions_array) {
for (const auto& version : per_process::metadata.versions.pairs()) {
versions
->DefineOwnProperty(context,
OneByteString(isolate, version.first),
Expand Down
19 changes: 1 addition & 18 deletions src/node_report.cc
Original file line number Diff line number Diff line change
Expand Up @@ -797,24 +797,7 @@ static void PrintComponentVersions(JSONWriter* writer) {

writer->json_objectstart("componentVersions");

#define V(key) +1
std::pair<std::string_view, std::string_view>
versions_array[NODE_VERSIONS_KEYS(V)];
#undef V
auto* slot = &versions_array[0];

#define V(key) \
do { \
*slot++ = std::pair<std::string_view, std::string_view>( \
#key, per_process::metadata.versions.key); \
} while (0);
NODE_VERSIONS_KEYS(V)
#undef V

std::ranges::sort(versions_array,
[](auto& a, auto& b) { return a.first < b.first; });

for (const auto& version : versions_array) {
for (const auto& version : per_process::metadata.versions.pairs()) {
writer->json_keyvalue(version.first, version.second);
}

Expand Down
30 changes: 5 additions & 25 deletions src/node_v8_platform-inl.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,31 +38,11 @@ class NodeTraceStateObserver
TRACE_EVENT_METADATA1(
"__metadata", "thread_name", "name", "JavaScriptMainThread");

auto trace_process = tracing::TracedValue::Create();
trace_process->BeginDictionary("versions");

#define V(key) \
trace_process->SetString(#key, per_process::metadata.versions.key.c_str());

NODE_VERSIONS_KEYS(V)
#undef V

trace_process->EndDictionary();

trace_process->SetString("arch", per_process::metadata.arch.c_str());
trace_process->SetString("platform",
per_process::metadata.platform.c_str());

trace_process->BeginDictionary("release");
trace_process->SetString("name",
per_process::metadata.release.name.c_str());
#if NODE_VERSION_IS_LTS
trace_process->SetString("lts", per_process::metadata.release.lts.c_str());
#endif
trace_process->EndDictionary();
TRACE_EVENT_METADATA1(
"__metadata", "node", "process", std::move(trace_process));

tracing::ProcessMeta trace_process;
TRACE_EVENT_METADATA1("__metadata",
"node",
"process",
tracing::CastTracedValue(trace_process));
// This only runs the first time tracing is enabled
controller_->RemoveTraceStateObserver(this);
}
Expand Down
45 changes: 42 additions & 3 deletions src/tracing/traced_value.cc
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@
#include <unicode/utypes.h>
#endif

#include <cmath>
#include <cstdio>
#include <sstream>
#include <string>

#include "node_metadata.h"
#include "util.h"

#if defined(_STLP_VENDOR_CSTD)
// STLPort doesn't import fpclassify into the std namespace.
Expand Down Expand Up @@ -218,5 +218,44 @@ void TracedValue::AppendAsTraceFormat(std::string* out) const {
*out += root_is_array_ ? ']' : '}';
}

std::unique_ptr<v8::ConvertableToTraceFormat> EnvironmentArgs::Cast() const {
auto traced_value = tracing::TracedValue::Create();
traced_value->BeginArray("args");
for (const std::string& arg : args_) traced_value->AppendString(arg);
traced_value->EndArray();
traced_value->BeginArray("exec_args");
for (const std::string& arg : exec_args_) traced_value->AppendString(arg);
traced_value->EndArray();
return traced_value;
}

std::unique_ptr<v8::ConvertableToTraceFormat> AsyncWrapArgs::Cast() const {
auto data = tracing::TracedValue::Create();
data->SetInteger("executionAsyncId", execution_async_id_);
data->SetInteger("triggerAsyncId", trigger_async_id_);
return data;
}

std::unique_ptr<v8::ConvertableToTraceFormat> ProcessMeta::Cast() const {
auto trace_process = tracing::TracedValue::Create();
trace_process->BeginDictionary("versions");
for (const auto& version : per_process::metadata.versions.pairs()) {
trace_process->SetString(version.first.data(), version.second.data());
}
trace_process->EndDictionary();

trace_process->SetString("arch", per_process::metadata.arch.c_str());
trace_process->SetString("platform", per_process::metadata.platform.c_str());

trace_process->BeginDictionary("release");
trace_process->SetString("name", per_process::metadata.release.name.c_str());
#if NODE_VERSION_IS_LTS
trace_process->SetString("lts", per_process::metadata.release.lts.c_str());
#endif
trace_process->EndDictionary();

return trace_process;
}

} // namespace tracing
} // namespace node
69 changes: 64 additions & 5 deletions src/tracing/traced_value.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,76 @@
#ifndef SRC_TRACING_TRACED_VALUE_H_
#define SRC_TRACING_TRACED_VALUE_H_

#include "node.h"
#include "util.h"
#include "v8.h"
#include "v8-platform.h"

#include <cstddef>
#include <memory>
#include <cstdint>
#include <span>
#include <string>

namespace node {
namespace tracing {

template <typename T>
std::unique_ptr<v8::ConvertableToTraceFormat> CastTracedValue(const T& value) {
return value.Cast();
}

class EnvironmentArgs {
public:
EnvironmentArgs(std::span<const std::string> args,
std::span<const std::string> exec_args)
: args_(args), exec_args_(exec_args) {}

std::unique_ptr<v8::ConvertableToTraceFormat> Cast() const;

private:
std::span<const std::string> args_;
std::span<const std::string> exec_args_;
};

class AsyncWrapArgs {
public:
AsyncWrapArgs(int64_t execution_async_id, int64_t trigger_async_id)
: execution_async_id_(execution_async_id),
trigger_async_id_(trigger_async_id) {}

std::unique_ptr<v8::ConvertableToTraceFormat> Cast() const;

private:
int64_t execution_async_id_;
int64_t trigger_async_id_;
};

class ProcessMeta {
public:
std::unique_ptr<v8::ConvertableToTraceFormat> Cast() const;
};

// Do not use this class directly. Define a custom structured class to provide
// a conversion method so that the class can be used with both V8 legacy
// trace API and perfetto API.
//
// These classes provide a JSON-inspired way to write structed data into traces.
//
// To define how a custom class should be written into the trace, users should
// define one of the two following functions:
// - Foo::Cast(TracedValue) const
// (preferred for code which depends on perfetto directly)
//
// After defining a conversion method, the object can be used as a
// TRACE_EVENT argument:
//
// Foo foo;
// TRACE_EVENT("cat", "Event", "arg", CastTracedValue(foo));
//
// class Foo {
// std::unique_ptr<v8::ConvertableToTraceFormat> Cast() const {
// auto traced_value = tracing::TracedValue::Create();
// dict->SetInteger("key", 42);
// dict->SetString("foo", "bar");
// return traced_value;
// }
// }
class TracedValue : public v8::ConvertableToTraceFormat {
public:
~TracedValue() override = default;
Expand Down
26 changes: 26 additions & 0 deletions test/cctest/test_traced_value.cc
Original file line number Diff line number Diff line change
Expand Up @@ -94,3 +94,29 @@ TEST(TracedValue, EscapingArray) {

EXPECT_EQ(check, string);
}

TEST(TracedValue, EnvironmentArgs) {
std::vector<std::string> args{"a", "bb", "ccc"};
std::vector<std::string> exec_args{"--inspect", "--a-long-arg"};
node::tracing::EnvironmentArgs env_args(args, exec_args);

std::string string;
env_args.Cast()->AppendAsTraceFormat(&string);

static const char* check = "{\"args\":[\"a\",\"bb\",\"ccc\"],"
"\"exec_args\":[\"--inspect\",\"--a-long-arg\"]}";

EXPECT_EQ(check, string);
}

TEST(TracedValue, AsyncWrapArgs) {
node::tracing::AsyncWrapArgs aw_args(1, 1);

std::string string;
aw_args.Cast()->AppendAsTraceFormat(&string);

static const char* check = "{\"executionAsyncId\":1,"
"\"triggerAsyncId\":1}";

EXPECT_EQ(check, string);
}
Loading