• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #include "tracing_agent.h"
2 #include "main_thread_interface.h"
3 #include "node_internals.h"
4 #include "node_v8_platform-inl.h"
5 #include "v8.h"
6 
7 #include <set>
8 #include <sstream>
9 
10 namespace node {
11 namespace inspector {
12 namespace protocol {
13 
14 namespace {
15 using v8::platform::tracing::TraceWriter;
16 
17 class DeletableFrontendWrapper : public Deletable {
18  public:
DeletableFrontendWrapper(std::weak_ptr<NodeTracing::Frontend> frontend)19   explicit DeletableFrontendWrapper(
20       std::weak_ptr<NodeTracing::Frontend> frontend)
21       : frontend_(frontend) {}
22 
23   // This should only be called from the main thread, meaning frontend should
24   // not be destroyed concurrently.
get()25   NodeTracing::Frontend* get() { return frontend_.lock().get(); }
26 
27  private:
28   std::weak_ptr<NodeTracing::Frontend> frontend_;
29 };
30 
31 class CreateFrontendWrapperRequest : public Request {
32  public:
CreateFrontendWrapperRequest(int object_id,std::weak_ptr<NodeTracing::Frontend> frontend)33   CreateFrontendWrapperRequest(int object_id,
34                                std::weak_ptr<NodeTracing::Frontend> frontend)
35       : object_id_(object_id) {
36     frontend_wrapper_ = std::make_unique<DeletableFrontendWrapper>(frontend);
37   }
38 
Call(MainThreadInterface * thread)39   void Call(MainThreadInterface* thread) override {
40     thread->AddObject(object_id_, std::move(frontend_wrapper_));
41   }
42 
43  private:
44   int object_id_;
45   std::unique_ptr<DeletableFrontendWrapper> frontend_wrapper_;
46 };
47 
48 class DestroyFrontendWrapperRequest : public Request {
49  public:
DestroyFrontendWrapperRequest(int object_id)50   explicit DestroyFrontendWrapperRequest(int object_id)
51       : object_id_(object_id) {}
52 
Call(MainThreadInterface * thread)53   void Call(MainThreadInterface* thread) override {
54     thread->RemoveObject(object_id_);
55   }
56 
57  private:
58   int object_id_;
59 };
60 
61 class SendMessageRequest : public Request {
62  public:
SendMessageRequest(int object_id,const std::string & message)63   explicit SendMessageRequest(int object_id, const std::string& message)
64       : object_id_(object_id), message_(message) {}
65 
Call(MainThreadInterface * thread)66   void Call(MainThreadInterface* thread) override {
67     DeletableFrontendWrapper* frontend_wrapper =
68         static_cast<DeletableFrontendWrapper*>(
69             thread->GetObjectIfExists(object_id_));
70     if (frontend_wrapper == nullptr) return;
71     auto frontend = frontend_wrapper->get();
72     if (frontend != nullptr) {
73       frontend->sendRawJSONNotification(message_);
74     }
75   }
76 
77  private:
78   int object_id_;
79   std::string message_;
80 };
81 
82 class InspectorTraceWriter : public node::tracing::AsyncTraceWriter {
83  public:
InspectorTraceWriter(int frontend_object_id,std::shared_ptr<MainThreadHandle> main_thread)84   explicit InspectorTraceWriter(int frontend_object_id,
85                                 std::shared_ptr<MainThreadHandle> main_thread)
86       : frontend_object_id_(frontend_object_id), main_thread_(main_thread) {}
87 
AppendTraceEvent(v8::platform::tracing::TraceObject * trace_event)88   void AppendTraceEvent(
89       v8::platform::tracing::TraceObject* trace_event) override {
90     if (!json_writer_)
91       json_writer_.reset(TraceWriter::CreateJSONTraceWriter(stream_, "value"));
92     json_writer_->AppendTraceEvent(trace_event);
93   }
94 
Flush(bool)95   void Flush(bool) override {
96     if (!json_writer_)
97       return;
98     json_writer_.reset();
99     std::ostringstream result(
100         "{\"method\":\"NodeTracing.dataCollected\",\"params\":",
101         std::ostringstream::ate);
102     result << stream_.str();
103     result << "}";
104     main_thread_->Post(std::make_unique<SendMessageRequest>(frontend_object_id_,
105                                                             result.str()));
106     stream_.str("");
107   }
108 
109  private:
110   std::unique_ptr<TraceWriter> json_writer_;
111   std::ostringstream stream_;
112   int frontend_object_id_;
113   std::shared_ptr<MainThreadHandle> main_thread_;
114 };
115 }  // namespace
116 
TracingAgent(Environment * env,std::shared_ptr<MainThreadHandle> main_thread)117 TracingAgent::TracingAgent(Environment* env,
118                            std::shared_ptr<MainThreadHandle> main_thread)
119     : env_(env), main_thread_(main_thread) {}
120 
~TracingAgent()121 TracingAgent::~TracingAgent() {
122   trace_writer_.reset();
123   main_thread_->Post(
124       std::make_unique<DestroyFrontendWrapperRequest>(frontend_object_id_));
125 }
126 
Wire(UberDispatcher * dispatcher)127 void TracingAgent::Wire(UberDispatcher* dispatcher) {
128   // Note that frontend is still owned by TracingAgent
129   frontend_ = std::make_shared<NodeTracing::Frontend>(dispatcher->channel());
130   frontend_object_id_ = main_thread_->newObjectId();
131   main_thread_->Post(std::make_unique<CreateFrontendWrapperRequest>(
132       frontend_object_id_, frontend_));
133   NodeTracing::Dispatcher::wire(dispatcher, this);
134 }
135 
start(std::unique_ptr<protocol::NodeTracing::TraceConfig> traceConfig)136 DispatchResponse TracingAgent::start(
137     std::unique_ptr<protocol::NodeTracing::TraceConfig> traceConfig) {
138   if (!trace_writer_.empty()) {
139     return DispatchResponse::Error(
140         "Call NodeTracing::end to stop tracing before updating the config");
141   }
142   if (!env_->owns_process_state()) {
143     return DispatchResponse::Error(
144         "Tracing properties can only be changed through main thread sessions");
145   }
146 
147   std::set<std::string> categories_set;
148   protocol::Array<std::string>* categories =
149       traceConfig->getIncludedCategories();
150   for (size_t i = 0; i < categories->length(); i++)
151     categories_set.insert(categories->get(i));
152 
153   if (categories_set.empty())
154     return DispatchResponse::Error("At least one category should be enabled");
155 
156   tracing::AgentWriterHandle* writer = GetTracingAgentWriter();
157   if (writer != nullptr) {
158     trace_writer_ =
159         writer->agent()->AddClient(categories_set,
160                                    std::make_unique<InspectorTraceWriter>(
161                                        frontend_object_id_, main_thread_),
162                                    tracing::Agent::kIgnoreDefaultCategories);
163   }
164   return DispatchResponse::OK();
165 }
166 
stop()167 DispatchResponse TracingAgent::stop() {
168   trace_writer_.reset();
169   frontend_->tracingComplete();
170   return DispatchResponse::OK();
171 }
172 
getCategories(std::unique_ptr<protocol::Array<String>> * categories)173 DispatchResponse TracingAgent::getCategories(
174     std::unique_ptr<protocol::Array<String>>* categories) {
175   *categories = Array<String>::create();
176   categories->get()->addItem("node");
177   categories->get()->addItem("node.async");
178   categories->get()->addItem("node.bootstrap");
179   categories->get()->addItem("node.fs.sync");
180   categories->get()->addItem("node.perf");
181   categories->get()->addItem("node.perf.usertiming");
182   categories->get()->addItem("node.perf.timerify");
183   categories->get()->addItem("v8");
184   return DispatchResponse::OK();
185 }
186 
187 }  // namespace protocol
188 }  // namespace inspector
189 }  // namespace node
190