mirror of
https://github.com/status-im/react-native.git
synced 2025-01-13 19:15:05 +00:00
Add Console agent
Summary: Adds the Console agent which we hook from our console polyfill. It captures the stack and strips the frames of the polyfill. Reviewed By: davidaurelio Differential Revision: D4021502 fbshipit-source-id: 49cb700a139270485b7595e85e52d50c9a620db6
This commit is contained in:
parent
0ac7bf29af
commit
27f504e9e3
152
ReactCommon/inspector/ConsoleAgent.cpp
Normal file
152
ReactCommon/inspector/ConsoleAgent.cpp
Normal file
@ -0,0 +1,152 @@
|
||||
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||
|
||||
#include "ConsoleAgent.h"
|
||||
|
||||
#include "Protocol.h"
|
||||
#include "Util.h"
|
||||
|
||||
#include <jschelpers/JSCHelpers.h>
|
||||
|
||||
#include <JavaScriptCore/config.h>
|
||||
#include <JavaScriptCore/APICast.h>
|
||||
#include <JavaScriptCore/JSContextRef.h>
|
||||
#include <JavaScriptCore/JSObjectRef.h>
|
||||
#include <JavaScriptCore/JSValueRef.h>
|
||||
#include <JavaScriptCore/JSStringRef.h>
|
||||
|
||||
#include <JavaScriptCore/JSLock.h>
|
||||
#include <JavaScriptCore/JSGlobalObject.h>
|
||||
#include <JavaScriptCore/JSArray.h>
|
||||
#include <JavaScriptCore/InjectedScriptManager.h>
|
||||
#include <JavaScriptCore/ScriptArguments.h>
|
||||
#include <JavaScriptCore/ScriptCallStack.h>
|
||||
#include <JavaScriptCore/ScriptCallStackFactory.h>
|
||||
|
||||
#include <folly/json.h>
|
||||
|
||||
namespace facebook {
|
||||
namespace react {
|
||||
|
||||
namespace {
|
||||
|
||||
static JSValueRef inspectorLog(
|
||||
ConsoleAgent* agent,
|
||||
JSContextRef ctx,
|
||||
JSObjectRef thisObject,
|
||||
size_t argumentCount,
|
||||
const JSValueRef arguments[]) {
|
||||
CHECK(argumentCount == 4) << "__inspectorLog takes 4 args";
|
||||
auto execState = toJS(ctx);
|
||||
JSC::JSLockHolder lock(execState);
|
||||
auto params = toJS(execState, arguments[2]);
|
||||
agent->log(
|
||||
execState,
|
||||
Value(ctx, arguments[0]).toString().str(),
|
||||
Value(ctx, arguments[1]).toString().str(),
|
||||
JSC::asArray(params),
|
||||
Value(ctx, arguments[3]).asUnsignedInteger());
|
||||
return JSValueMakeUndefined(ctx);
|
||||
}
|
||||
|
||||
size_t skipNativeCode(const Inspector::ScriptCallStack& callStack, size_t offset) {
|
||||
for (; offset < callStack.size(); offset++) {
|
||||
auto& frame = callStack.at(offset);
|
||||
if (frame.sourceURL() != "[native code]") {
|
||||
return offset;
|
||||
}
|
||||
}
|
||||
|
||||
return callStack.size();
|
||||
}
|
||||
|
||||
const Inspector::ScriptCallFrame* firstUserFrame(const Inspector::ScriptCallStack& callStack, size_t framesToSkip) {
|
||||
// Skip out of native code
|
||||
size_t offset = skipNativeCode(callStack, 0);
|
||||
|
||||
// Skip frames of console polyfill
|
||||
offset = skipNativeCode(callStack, offset + framesToSkip);
|
||||
if (offset >= callStack.size()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (callStack.at(offset).functionName() == "infoLog") {
|
||||
offset += 1;
|
||||
}
|
||||
|
||||
if (offset >= callStack.size()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return &callStack.at(offset);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
ConsoleAgent::ConsoleAgent(JSC::JSGlobalObject& globalObject, Inspector::InjectedScriptManager* injectedScriptManager)
|
||||
: globalObject_(globalObject)
|
||||
, injectedScriptManager_(injectedScriptManager) {
|
||||
registerMethod("enable", [this](folly::dynamic) -> folly::dynamic {
|
||||
using namespace std::placeholders;
|
||||
enabled_ = true;
|
||||
JSGlobalContextRef context = toGlobalRef(globalObject_.globalExec());
|
||||
installGlobalFunction(context, "__inspectorLog", std::bind(&inspectorLog, this, _1, _2, _3, _4));
|
||||
return nullptr;
|
||||
});
|
||||
registerMethod("disable", [this](folly::dynamic) -> folly::dynamic {
|
||||
JSGlobalContextRef context = toGlobalRef(globalObject_.globalExec());
|
||||
removeGlobal(context, "__inspectorLog");
|
||||
enabled_ = false;
|
||||
return nullptr;
|
||||
});
|
||||
}
|
||||
|
||||
void ConsoleAgent::log(JSC::ExecState* execState, std::string message) {
|
||||
log(execState, "log", std::move(message), nullptr, 0);
|
||||
}
|
||||
|
||||
void ConsoleAgent::log(JSC::ExecState* execState, std::string level, std::string message, JSC::JSArray* params, size_t framesToSkip) {
|
||||
if (!enabled_) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto callStack = Inspector::createScriptCallStack(execState, Inspector::ScriptCallStack::maxCallStackSizeToCapture);
|
||||
|
||||
auto logEntry = folly::dynamic::object
|
||||
("source", "console-api")
|
||||
("level", level)
|
||||
("text", std::move(message))
|
||||
("timestamp", Timestamp::now())
|
||||
("stackTrace", folly::parseJson(toStdString(callStack->buildInspectorArray()->toJSONString())));
|
||||
|
||||
if (params) {
|
||||
logEntry("parameters", convertParams(execState, params));
|
||||
}
|
||||
|
||||
if (auto frame = firstUserFrame(*callStack, framesToSkip)) {
|
||||
logEntry
|
||||
("url", toStdString(frame->sourceURL()))
|
||||
("line", frame->lineNumber())
|
||||
("column", frame->columnNumber());
|
||||
}
|
||||
|
||||
sendEvent("messageAdded", folly::dynamic::object("message", std::move(logEntry)));
|
||||
}
|
||||
|
||||
folly::dynamic ConsoleAgent::convertParams(JSC::ExecState* execState, JSC::JSArray* params) {
|
||||
auto injectedScript = injectedScriptManager_->injectedScriptFor(execState->lexicalGlobalObject()->globalExec());
|
||||
if (injectedScript.hasNoValue()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
folly::dynamic remoteParams = folly::dynamic::array;
|
||||
for (size_t i = 0, size = params->length(); i < size; i++) {
|
||||
auto scriptValue = Deprecated::ScriptValue(execState->vm(), params->getIndex(execState, i));
|
||||
auto remoteValue = injectedScript.wrapObject(std::move(scriptValue), "console", true);
|
||||
remoteParams.push_back(folly::parseJson(toStdString(remoteValue->toJSONString())));
|
||||
}
|
||||
|
||||
return remoteParams;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
39
ReactCommon/inspector/ConsoleAgent.h
Normal file
39
ReactCommon/inspector/ConsoleAgent.h
Normal file
@ -0,0 +1,39 @@
|
||||
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Agent.h"
|
||||
|
||||
namespace JSC {
|
||||
class JSGlobalObject;
|
||||
class ExecState;
|
||||
class JSArray;
|
||||
}
|
||||
|
||||
namespace Inspector {
|
||||
class InjectedScriptManager;
|
||||
}
|
||||
|
||||
namespace facebook {
|
||||
namespace react {
|
||||
|
||||
class ConsoleAgent : public Agent {
|
||||
public:
|
||||
ConsoleAgent(JSC::JSGlobalObject& globalObject, Inspector::InjectedScriptManager* injectedScriptManager);
|
||||
|
||||
void log(JSC::ExecState* execState, std::string message);
|
||||
void log(JSC::ExecState* execState, std::string level, std::string message, JSC::JSArray* params, size_t framesToSkip);
|
||||
private:
|
||||
bool enabled_{false};
|
||||
JSC::JSGlobalObject& globalObject_;
|
||||
Inspector::InjectedScriptManager* injectedScriptManager_;
|
||||
|
||||
folly::dynamic convertParams(JSC::ExecState* execState, JSC::JSArray* params);
|
||||
|
||||
std::string getDomain() override {
|
||||
return "Console";
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
}
|
@ -7,6 +7,7 @@
|
||||
#include "LegacyInspectorEnvironment.h"
|
||||
#include "InspectorAgent.h"
|
||||
#include "PageAgent.h"
|
||||
#include "ConsoleAgent.h"
|
||||
#include "LegacyAgents.h"
|
||||
|
||||
#include <folly/Memory.h>
|
||||
@ -142,8 +143,10 @@ InspectorController::InspectorController(JSC::JSGlobalObject& globalObject)
|
||||
dispatchers_.push_back(folly::make_unique<SchemaAgent>());
|
||||
dispatchers_.push_back(folly::make_unique<PageAgent>());
|
||||
|
||||
auto legacyAgents = folly::make_unique<LegacyAgents>(globalObject, std::move(environment), nullptr);
|
||||
auto consoleAgent = folly::make_unique<ConsoleAgent>(globalObject, environment->injectedScriptManager());
|
||||
auto legacyAgents = folly::make_unique<LegacyAgents>(globalObject, std::move(environment), consoleAgent.get());
|
||||
|
||||
dispatchers_.push_back(std::move(consoleAgent));
|
||||
dispatchers_.push_back(std::move(legacyAgents));
|
||||
}
|
||||
|
||||
|
@ -37,8 +37,7 @@ InjectedScript LegacyDebuggerAgent::injectedScriptForEval(ErrorString* error, co
|
||||
}
|
||||
|
||||
void LegacyDebuggerAgent::breakpointActionLog(JSC::ExecState* exec, const String& message) {
|
||||
// TODO: Hook up
|
||||
// consoleAgent_->log(exec, toStdString(message));
|
||||
consoleAgent_->log(exec, toStdString(message));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ConsoleAgent.h"
|
||||
#include "LegacyScriptDebugServer.h"
|
||||
|
||||
#include <JavaScriptCore/config.h>
|
||||
@ -15,8 +16,6 @@ class JSGlobalObject;
|
||||
namespace facebook {
|
||||
namespace react {
|
||||
|
||||
class ConsoleAgent;
|
||||
|
||||
class LegacyDebuggerAgent : public Inspector::InspectorDebuggerAgent {
|
||||
public:
|
||||
LegacyDebuggerAgent(Inspector::InjectedScriptManager*, JSC::JSGlobalObject&, ConsoleAgent*);
|
||||
|
@ -363,6 +363,15 @@ const LOG_LEVELS = {
|
||||
warn: 2,
|
||||
error: 3
|
||||
};
|
||||
const INSPECTOR_LEVELS = [];
|
||||
INSPECTOR_LEVELS[LOG_LEVELS.trace] = 'debug';
|
||||
INSPECTOR_LEVELS[LOG_LEVELS.info] = 'log';
|
||||
INSPECTOR_LEVELS[LOG_LEVELS.warn] = 'warning';
|
||||
INSPECTOR_LEVELS[LOG_LEVELS.error] = 'error';
|
||||
|
||||
// Strip the inner function in getNativeLogFunction(), if in dev also
|
||||
// strip method printing to originalConsole.
|
||||
const INSPECTOR_FRAMES_TO_SKIP = __DEV__ ? 2 : 1;
|
||||
|
||||
function setupConsole(global) {
|
||||
if (!global.nativeLoggingHook) {
|
||||
@ -387,6 +396,13 @@ function setupConsole(global) {
|
||||
// (Note: Logic duplicated in ExceptionsManager.js.)
|
||||
logLevel = LOG_LEVELS.warn;
|
||||
}
|
||||
if (global.__inspectorLog) {
|
||||
global.__inspectorLog(
|
||||
INSPECTOR_LEVELS[logLevel],
|
||||
str,
|
||||
[].slice.call(arguments),
|
||||
INSPECTOR_FRAMES_TO_SKIP);
|
||||
}
|
||||
global.nativeLoggingHook(str, logLevel);
|
||||
};
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user