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