Skip to content

src: internalize v8::ConvertableToTraceFormat in traces #57866

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
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
28 changes: 13 additions & 15 deletions src/async_wrap.cc
Original file line number Diff line number Diff line change
Expand Up @@ -602,21 +602,19 @@ 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;
#define V(PROVIDER) \
case PROVIDER_##PROVIDER: \
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, \
static_cast<int64_t>(get_async_id()), \
"data", \
tracing::CastTracedValue(data)); \
} \
break;
NODE_ASYNC_PROVIDER_TYPES(V)
#undef V
default:
Expand Down
10 changes: 2 additions & 8 deletions src/env.cc
Original file line number Diff line number Diff line change
Expand Up @@ -914,18 +914,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
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
49 changes: 46 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,48 @@ 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");

#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();

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