1 #include "base_object-inl.h"
2 #include "env-inl.h"
3 #include "memory_tracker-inl.h"
4 #include "node.h"
5 #include "node_internals.h"
6 #include "node_v8_platform-inl.h"
7 #include "tracing/agent.h"
8 #include "util-inl.h"
9
10 #include <set>
11 #include <string>
12
13 namespace node {
14
15 using v8::Array;
16 using v8::Context;
17 using v8::Function;
18 using v8::FunctionCallbackInfo;
19 using v8::FunctionTemplate;
20 using v8::Local;
21 using v8::NewStringType;
22 using v8::Object;
23 using v8::String;
24 using v8::Value;
25
26 class NodeCategorySet : public BaseObject {
27 public:
28 static void Initialize(Local<Object> target,
29 Local<Value> unused,
30 Local<Context> context,
31 void* priv);
32
33 static void New(const FunctionCallbackInfo<Value>& args);
34 static void Enable(const FunctionCallbackInfo<Value>& args);
35 static void Disable(const FunctionCallbackInfo<Value>& args);
36
GetCategories() const37 const std::set<std::string>& GetCategories() const { return categories_; }
38
MemoryInfo(MemoryTracker * tracker) const39 void MemoryInfo(MemoryTracker* tracker) const override {
40 tracker->TrackField("categories", categories_);
41 }
42
43 SET_MEMORY_INFO_NAME(NodeCategorySet)
44 SET_SELF_SIZE(NodeCategorySet)
45
46 private:
NodeCategorySet(Environment * env,Local<Object> wrap,std::set<std::string> && categories)47 NodeCategorySet(Environment* env,
48 Local<Object> wrap,
49 std::set<std::string>&& categories) :
50 BaseObject(env, wrap), categories_(std::move(categories)) {
51 MakeWeak();
52 }
53
54 bool enabled_ = false;
55 const std::set<std::string> categories_;
56 };
57
New(const FunctionCallbackInfo<Value> & args)58 void NodeCategorySet::New(const FunctionCallbackInfo<Value>& args) {
59 Environment* env = Environment::GetCurrent(args);
60 std::set<std::string> categories;
61 CHECK(args[0]->IsArray());
62 Local<Array> cats = args[0].As<Array>();
63 for (size_t n = 0; n < cats->Length(); n++) {
64 Local<Value> category;
65 if (!cats->Get(env->context(), n).ToLocal(&category)) return;
66 Utf8Value val(env->isolate(), category);
67 if (!*val) return;
68 categories.emplace(*val);
69 }
70 CHECK_NOT_NULL(GetTracingAgentWriter());
71 new NodeCategorySet(env, args.This(), std::move(categories));
72 }
73
Enable(const FunctionCallbackInfo<Value> & args)74 void NodeCategorySet::Enable(const FunctionCallbackInfo<Value>& args) {
75 NodeCategorySet* category_set;
76 ASSIGN_OR_RETURN_UNWRAP(&category_set, args.Holder());
77 CHECK_NOT_NULL(category_set);
78 const auto& categories = category_set->GetCategories();
79 if (!category_set->enabled_ && !categories.empty()) {
80 // Starts the Tracing Agent if it wasn't started already (e.g. through
81 // a command line flag.)
82 StartTracingAgent();
83 GetTracingAgentWriter()->Enable(categories);
84 category_set->enabled_ = true;
85 }
86 }
87
Disable(const FunctionCallbackInfo<Value> & args)88 void NodeCategorySet::Disable(const FunctionCallbackInfo<Value>& args) {
89 NodeCategorySet* category_set;
90 ASSIGN_OR_RETURN_UNWRAP(&category_set, args.Holder());
91 CHECK_NOT_NULL(category_set);
92 const auto& categories = category_set->GetCategories();
93 if (category_set->enabled_ && !categories.empty()) {
94 GetTracingAgentWriter()->Disable(categories);
95 category_set->enabled_ = false;
96 }
97 }
98
GetEnabledCategories(const FunctionCallbackInfo<Value> & args)99 void GetEnabledCategories(const FunctionCallbackInfo<Value>& args) {
100 Environment* env = Environment::GetCurrent(args);
101 std::string categories =
102 GetTracingAgentWriter()->agent()->GetEnabledCategories();
103 if (!categories.empty()) {
104 args.GetReturnValue().Set(
105 String::NewFromUtf8(env->isolate(),
106 categories.c_str(),
107 NewStringType::kNormal,
108 categories.size()).ToLocalChecked());
109 }
110 }
111
SetTraceCategoryStateUpdateHandler(const FunctionCallbackInfo<Value> & args)112 static void SetTraceCategoryStateUpdateHandler(
113 const FunctionCallbackInfo<Value>& args) {
114 Environment* env = Environment::GetCurrent(args);
115 CHECK(args[0]->IsFunction());
116 env->set_trace_category_state_function(args[0].As<Function>());
117 }
118
Initialize(Local<Object> target,Local<Value> unused,Local<Context> context,void * priv)119 void NodeCategorySet::Initialize(Local<Object> target,
120 Local<Value> unused,
121 Local<Context> context,
122 void* priv) {
123 Environment* env = Environment::GetCurrent(context);
124
125 env->SetMethod(target, "getEnabledCategories", GetEnabledCategories);
126 env->SetMethod(
127 target, "setTraceCategoryStateUpdateHandler",
128 SetTraceCategoryStateUpdateHandler);
129
130 Local<FunctionTemplate> category_set =
131 env->NewFunctionTemplate(NodeCategorySet::New);
132 category_set->InstanceTemplate()->SetInternalFieldCount(
133 NodeCategorySet::kInternalFieldCount);
134 category_set->Inherit(BaseObject::GetConstructorTemplate(env));
135 env->SetProtoMethod(category_set, "enable", NodeCategorySet::Enable);
136 env->SetProtoMethod(category_set, "disable", NodeCategorySet::Disable);
137
138 env->SetConstructorFunction(target, "CategorySet", category_set);
139
140 Local<String> isTraceCategoryEnabled =
141 FIXED_ONE_BYTE_STRING(env->isolate(), "isTraceCategoryEnabled");
142 Local<String> trace = FIXED_ONE_BYTE_STRING(env->isolate(), "trace");
143
144 // Grab the trace and isTraceCategoryEnabled intrinsics from the binding
145 // object and expose those to our binding layer.
146 Local<Object> binding = context->GetExtrasBindingObject();
147 target->Set(context, isTraceCategoryEnabled,
148 binding->Get(context, isTraceCategoryEnabled).ToLocalChecked())
149 .Check();
150 target->Set(context, trace,
151 binding->Get(context, trace).ToLocalChecked()).Check();
152 }
153
154 } // namespace node
155
156 NODE_MODULE_CONTEXT_AWARE_INTERNAL(trace_events,
157 node::NodeCategorySet::Initialize)
158