Skip to content

Commit eaa8dd7

Browse files
committed
fix: Implement console.log inspector with Runtime protocol
Console messages used to be implemented with the Log protocol, which is no longer part of V8. The Runtime protocol provides an equivalent API, Runtime.consoleAPICalled. The Runtime protocol is part of the generated public sources, but the V8 inspector's RuntimeAgent is not. So, for now, we make use of V8's private API, casting V8Inspector* to V8InspectorImpl* and V8InspectorSession* to V8InspectorSessionImpl* in order to access their methods (for which we pulled in the corresponding V8 header files in the V8 sources update, earlier on this branch.)
1 parent 14faf01 commit eaa8dd7

File tree

5 files changed

+99
-18
lines changed

5 files changed

+99
-18
lines changed

NativeScript/NativeScript.mm

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#include <Foundation/Foundation.h>
22
#include "NativeScript.h"
33
#include "inspector/JsV8InspectorClient.h"
4+
#include "runtime/Console.h"
45
#include "runtime/RuntimeConfig.h"
56
#include "runtime/Helpers.h"
67
#include "runtime/Runtime.h"
@@ -52,6 +53,7 @@ - (instancetype)initWithConfig:(Config*)config {
5253
inspectorClient->init();
5354
inspectorClient->registerModules();
5455
inspectorClient->connect([config ArgumentsCount], [config Arguments]);
56+
Console::AttachInspectorClient(inspectorClient);
5557
}
5658
}
5759

NativeScript/inspector/JsV8InspectorClient.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
#include <map>
99

1010
#include "include/v8-inspector.h"
11+
#include "src/inspector/v8-console-message.h"
12+
1113
#include "runtime/Runtime.h"
1214

1315
namespace v8_inspector {
@@ -32,6 +34,9 @@ class JsV8InspectorClient : V8InspectorClient, V8Inspector::Channel {
3234
void scheduleBreak();
3335
void registerModules();
3436

37+
void consoleLog(v8::Isolate* isolate, ConsoleAPIType method,
38+
const std::vector<v8::Local<v8::Value>>& args);
39+
3540
static std::map<std::string, v8::Persistent<v8::Object>*> Domains;
3641
private:
3742
static constexpr int contextGroupId = 1;

NativeScript/inspector/JsV8InspectorClient.mm

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,16 @@
11
#include <Foundation/Foundation.h>
22
#include <notify.h>
33
#include <chrono>
4+
5+
#include "src/inspector/v8-console-message.h"
6+
#include "src/inspector/v8-inspector-impl.h"
7+
#include "src/inspector/v8-inspector-session-impl.h"
8+
#include "src/inspector/v8-runtime-agent-impl.h"
9+
#include "src/inspector/v8-stack-trace-impl.h"
10+
411
#include "JsV8InspectorClient.h"
512
#include "InspectorServer.h"
613
#include "include/libplatform/libplatform.h"
7-
//#include "src/inspector/v8-log-agent-impl.h"
814
#include "Helpers.h"
915
#include "utils.h"
1016

@@ -287,6 +293,8 @@
287293
v8::Locker locker(isolate);
288294
TryCatch tc(isolate);
289295
runtime_->RunModule("inspector_modules");
296+
// FIXME: This triggers some DCHECK failures, due to the entered v8::Context in
297+
// Runtime::init().
290298
}
291299
}
292300

@@ -313,6 +321,31 @@
313321
args.GetReturnValue().Set(timestamp);
314322
}
315323

324+
void JsV8InspectorClient::consoleLog(v8::Isolate* isolate, ConsoleAPIType method,
325+
const std::vector<v8::Local<v8::Value>>& args) {
326+
if (!isConnected_) {
327+
return;
328+
}
329+
330+
// Note, here we access private API
331+
auto* impl = reinterpret_cast<v8_inspector::V8InspectorImpl*>(inspector_.get());
332+
auto* session = reinterpret_cast<v8_inspector::V8InspectorSessionImpl*>(session_.get());
333+
334+
v8::Local<v8::StackTrace> stack = v8::StackTrace::CurrentStackTrace(
335+
isolate, 1, v8::StackTrace::StackTraceOptions::kDetailed);
336+
std::unique_ptr<V8StackTraceImpl> stackImpl = impl->debugger()->createStackTrace(stack);
337+
338+
v8::Local<v8::Context> context = context_.Get(isolate);
339+
const int contextId = V8ContextInfo::executionContextId(context);
340+
341+
std::unique_ptr<v8_inspector::V8ConsoleMessage> msg =
342+
v8_inspector::V8ConsoleMessage::createForConsoleAPI(
343+
context, contextId, contextGroupId, impl, currentTimeMS(),
344+
method, args, String16{}, std::move(stackImpl));
345+
346+
session->runtimeAgent()->messageAdded(msg.get());
347+
}
348+
316349
std::map<std::string, Persistent<Object>*> JsV8InspectorClient::Domains;
317350

318351
}

NativeScript/runtime/Console.cpp

Lines changed: 47 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,10 @@ void Console::Init(Local<Context> context) {
3535
}
3636
}
3737

38+
void Console::AttachInspectorClient(v8_inspector::JsV8InspectorClient* aInspector) {
39+
inspector = aInspector;
40+
}
41+
3842
void Console::LogCallback(const FunctionCallbackInfo<Value>& args) {
3943
// TODO: implement 'forceLog' override option like android has, to force logs in prod if desired
4044
if (!RuntimeConfig.LogToSystemConsole) {
@@ -59,8 +63,8 @@ void Console::LogCallback(const FunctionCallbackInfo<Value>& args) {
5963

6064
std::string msgToLog = ss.str();
6165

62-
std::string level = VerbosityToInspectorVerbosity(verbosityLevel);
63-
// v8_inspector::V8LogAgentImpl::EntryAdded(msgToLog, level, "", 0);
66+
ConsoleAPIType method = VerbosityToInspectorMethod(verbosityLevel);
67+
SendToDevToolsFrontEnd(method, args);
6468
std::string msgWithVerbosity = "CONSOLE " + verbosityLevelUpper + ": " + msgToLog;
6569
Log("%s", msgWithVerbosity.c_str());
6670
}
@@ -86,7 +90,8 @@ void Console::AssertCallback(const FunctionCallbackInfo<Value>& args) {
8690
}
8791

8892
std::string log = ss.str();
89-
// v8_inspector::V8LogAgentImpl::EntryAdded(log, "error", "", 0);
93+
94+
SendToDevToolsFrontEnd(ConsoleAPIType::kAssert, args);
9095
Log("%s", log.c_str());
9196
}
9297
}
@@ -157,11 +162,7 @@ void Console::DirCallback(const FunctionCallbackInfo<Value>& args) {
157162
}
158163

159164
std::string msgToLog = ss.str();
160-
161-
Local<v8::String> data = args.Data().As<v8::String>();
162-
std::string verbosityLevel = tns::ToString(isolate, data);
163-
std::string level = VerbosityToInspectorVerbosity(verbosityLevel);
164-
// v8_inspector::V8LogAgentImpl::EntryAdded(msgToLog, level, "", 0);
165+
SendToDevToolsFrontEnd(ConsoleAPIType::kDir, args);
165166
Log("%s", msgToLog.c_str());
166167
}
167168

@@ -221,11 +222,8 @@ void Console::TimeEndCallback(const FunctionCallbackInfo<Value>& args) {
221222
std::stringstream ss;
222223
ss << "CONSOLE INFO " << label << ": " << std::fixed << std::setprecision(3) << diffMilliseconds << "ms" ;
223224

224-
Local<v8::String> data = args.Data().As<v8::String>();
225-
std::string verbosityLevel = tns::ToString(isolate, data);
226-
std::string level = VerbosityToInspectorVerbosity(verbosityLevel);
227225
std::string msgToLog = ss.str();
228-
// v8_inspector::V8LogAgentImpl::EntryAdded(msgToLog, level, "", 0);
226+
SendToDevToolsFrontEnd(isolate, ConsoleAPIType::kTimeEnd, msgToLog);
229227
Log("%s", msgToLog.c_str());
230228
}
231229

@@ -346,14 +344,47 @@ const Local<v8::String> Console::TransformJSObject(Local<Object> object) {
346344
return resultString;
347345
}
348346

349-
const std::string Console::VerbosityToInspectorVerbosity(const std::string level) {
347+
v8_inspector::ConsoleAPIType Console::VerbosityToInspectorMethod(const std::string level) {
350348
if (level == "error") {
351-
return "error";
349+
return ConsoleAPIType::kError;
352350
} else if (level == "warn") {
353-
return "warning";
351+
return ConsoleAPIType::kWarning;
352+
} else if (level == "info") {
353+
return ConsoleAPIType::kInfo;
354+
} else if (level == "trace") {
355+
return ConsoleAPIType::kTrace;
356+
}
357+
358+
assert(level == "log");
359+
return ConsoleAPIType::kLog;
360+
}
361+
362+
void Console::SendToDevToolsFrontEnd(ConsoleAPIType method,
363+
const v8::FunctionCallbackInfo<v8::Value>& args) {
364+
if (!inspector) {
365+
return;
366+
}
367+
368+
std::vector<v8::Local<v8::Value>> arg_vector;
369+
unsigned nargs = args.Length();
370+
arg_vector.reserve(nargs);
371+
for (unsigned ix = 0; ix < nargs; ix++)
372+
arg_vector.push_back(args[ix]);
373+
374+
inspector->consoleLog(args.GetIsolate(), method, arg_vector);
375+
}
376+
377+
void Console::SendToDevToolsFrontEnd(v8::Isolate* isolate, ConsoleAPIType method, const std::string& msg) {
378+
if (!inspector) {
379+
return;
354380
}
355381

356-
return "info";
382+
v8::Local<v8::String> v8str = v8::String::NewFromUtf8(
383+
isolate, msg.c_str(), v8::NewStringType::kNormal, -1).ToLocalChecked();
384+
std::vector<v8::Local<v8::Value>> args{v8str};
385+
inspector->consoleLog(isolate, method, args);
357386
}
358387

388+
v8_inspector::JsV8InspectorClient* Console::inspector = nullptr;
389+
359390
}

NativeScript/runtime/Console.h

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,18 @@
22
#define Console_h
33

44
#include "Common.h"
5+
#include "JSV8InspectorClient.h"
56
#include <string>
67

78
namespace tns {
89

910
class Console {
1011
public:
1112
static void Init(v8::Local<v8::Context> context);
13+
static void AttachInspectorClient(v8_inspector::JsV8InspectorClient* inspector);
1214
private:
15+
using ConsoleAPIType = v8_inspector::ConsoleAPIType;
16+
1317
static void AttachLogFunction(v8::Local<v8::Context> context, v8::Local<v8::Object> console, const std::string name, v8::FunctionCallback callback = Console::LogCallback);
1418
static void LogCallback(const v8::FunctionCallbackInfo<v8::Value>& args);
1519
static void AssertCallback(const v8::FunctionCallbackInfo<v8::Value>& args);
@@ -19,7 +23,13 @@ class Console {
1923
static std::string BuildStringFromArgs(const v8::FunctionCallbackInfo<v8::Value>& args, int startingIndex = 0);
2024
static const v8::Local<v8::String> BuildStringFromArg(v8::Local<v8::Context> context, const v8::Local<v8::Value>& val);
2125
static const v8::Local<v8::String> TransformJSObject(v8::Local<v8::Object> object);
22-
static const std::string VerbosityToInspectorVerbosity(const std::string level);
26+
static ConsoleAPIType VerbosityToInspectorMethod(const std::string level);
27+
28+
static void SendToDevToolsFrontEnd(ConsoleAPIType method,
29+
const v8::FunctionCallbackInfo<v8::Value>& args);
30+
static void SendToDevToolsFrontEnd(v8::Isolate* isolate, ConsoleAPIType method, const std::string& msg);
31+
32+
static v8_inspector::JsV8InspectorClient* inspector;
2333
};
2434

2535
}

0 commit comments

Comments
 (0)