Complete Console Exception.

This commit is contained in:
NeetBhagat 2017-06-12 20:24:59 +05:30
parent 71bff04ce0
commit e8fc766c2b
6 changed files with 108 additions and 12 deletions

View file

@ -52,10 +52,46 @@ void ConsoleScriptingInterface::error(QString message) {
void ConsoleScriptingInterface::exception(QString message) {
if (ScriptEngine* scriptEngine = qobject_cast<ScriptEngine*>(engine())) {
scriptEngine->scriptErrorMessage(message);
scriptEngine->logConsoleException(message);
}
}
bool ConsoleScriptingInterface:: hasCorrectSyntax(QScriptProgram& program) {
const auto syntaxCheck = QScriptEngine::checkSyntax(program.sourceCode());
if (syntaxCheck.state() != QScriptSyntaxCheckResult::Valid) {
const auto error = syntaxCheck.errorMessage();
const auto line = QString::number(syntaxCheck.errorLineNumber());
const auto column = QString::number(syntaxCheck.errorColumnNumber());
const auto message = QString("[SyntaxError] %1 in %2:%3(%4)").arg(error, program.fileName(), line, column);
qCritical() << qPrintable(message);
return false;
}
return true;
}
QString ConsoleScriptingInterface::hadUncaughtExceptions(QScriptEngine& engine, QString& fileName) {
log("4");
//if (engine.hasUncaughtException()) {
const auto backtrace = engine.uncaughtExceptionBacktrace();
const auto exception = engine.uncaughtException().toString();
const auto line = QString::number(engine.uncaughtExceptionLineNumber());
engine.clearExceptions();
log("5");
static const QString SCRIPT_EXCEPTION_FORMAT = "[UncaughtException] %1 in %2:%3";
auto message = QString(SCRIPT_EXCEPTION_FORMAT).arg(exception, fileName, line);
if (!backtrace.empty()) {
static const auto lineSeparator = "\n ";
message += QString("\n[Backtrace]%1%2").arg(lineSeparator, backtrace.join(lineSeparator));
}
// qCritical() << qPrintable(message);
log("6");
return message;
//}
//return false;
}
void ConsoleScriptingInterface::time(QString labelName) {
QDateTime _currentTime = QDateTime::currentDateTime().toUTC();
_listOfTimeValues.insert(labelName, _currentTime.toUTC());
@ -126,9 +162,9 @@ void ConsoleScriptingInterface::asserts(bool condition, QString message) {
}
}
void ConsoleScriptingInterface::trace(QString labelName) {
void ConsoleScriptingInterface::trace() {
if (ScriptEngine* scriptEngine = qobject_cast<ScriptEngine*>(engine())) {
scriptEngine->scriptErrorMessage(labelName);
scriptEngine->logTraceException();
}
}

View file

@ -22,6 +22,8 @@
#include <QtCore/QString>
#include <QtScript/QScriptable>
#include <QHash>
#include "EntityEditFilters.h"
#include <QUrl>
#include <QList>
@ -38,15 +40,16 @@ public slots:
void time(QString labelName);
void timeEnd(QString labelName);
void asserts(bool condition, QString message = "");
void trace(QString labelName);
void trace();
void clear();
void group(QString groupName);
void groupCollapsed(QString groupName);
void groupEnd();
void consoleGroupLog(QString currentGroup, QString groupName);
public:
QString secondsToString(qint64 seconds);
bool isInteger(const std::string & s);
QString secondsToString(qint64 seconds);
bool hasCorrectSyntax(QScriptProgram& program);
QString hadUncaughtExceptions(QScriptEngine& engine, QString& fileName);
private:
QHash<QString, QDateTime> _listOfTimeValues;
const qint64 DAY = 86400;

View file

@ -145,6 +145,17 @@ QString encodeEntityIdIntoEntityUrl(const QString& url, const QString& entityID)
return url + " [EntityID:" + entityID + "]";
}
void ScriptEngine::logConsoleException(QString message) {
this->raiseConsoleException(this->makeError(message));
}
QString ScriptEngine::logTraceException() {
QScriptValue value = this->raiseConsoleTraceException(this->makeError(""));
auto trace = formatTrace(value, _enableExtendedJSExceptions.get());
scriptInfoMessage(trace);
return trace;
}
QString ScriptEngine::logException(const QScriptValue& exception) {
auto message = formatException(exception, _enableExtendedJSExceptions.get());
scriptErrorMessage(message);
@ -187,6 +198,15 @@ ScriptEngine::ScriptEngine(Context context, const QString& scriptContents, const
}
logException(output);
});
// this is where all unhandled exceptions end up getting logged
/* connect(this, &BaseScriptEngine::unhandledException, this, [this](const QScriptValue& err) {
auto output = err.engine() == this ? err : makeError(err);
if (!output.property("detail").isValid()) {
output.setProperty("detail", "UnhandledException");
}
logException(output);
});*/
}
QString ScriptEngine::getContext() const {

View file

@ -148,7 +148,8 @@ public:
/// to scripts. we may not need this to be invokable
void loadURL(const QUrl& scriptURL, bool reload);
bool hasValidScriptSuffix(const QString& scriptFileName);
void logConsoleException(QString message);
QString logTraceException();
Q_INVOKABLE QString getContext() const;
Q_INVOKABLE bool isClientScript() const { return _context == CLIENT_SCRIPT; }
Q_INVOKABLE bool isEntityClientScript() const { return _context == ENTITY_CLIENT_SCRIPT; }

View file

@ -22,6 +22,7 @@
#include "Profile.h"
const QString BaseScriptEngine::SCRIPT_EXCEPTION_FORMAT { "[%0] %1 in %2:%3" };
const QString BaseScriptEngine::SCRIPT_TRACE_FORMAT{ "[%0] %1" };
const QString BaseScriptEngine::SCRIPT_BACKTRACE_SEP { "\n " };
bool BaseScriptEngine::IS_THREADSAFE_INVOCATION(const QThread *thread, const QString& method) {
@ -159,7 +160,7 @@ QScriptValue BaseScriptEngine::cloneUncaughtException(const QString& extraDetail
#endif
return err;
}
QString BaseScriptEngine::formatException(const QScriptValue& exception, bool includeExtendedDetails) {
if (!IS_THREADSAFE_INVOCATION(thread(), __FUNCTION__)) {
return QString();
@ -192,6 +193,27 @@ QString BaseScriptEngine::formatException(const QScriptValue& exception, bool in
return result;
}
QString BaseScriptEngine::formatTrace(const QScriptValue& value, bool includeExtendedDetails) {
if (!IS_THREADSAFE_INVOCATION(thread(), __FUNCTION__)) {
return QString();
}
QString note{ "TRACE" };
QString result;
if (!value.isObject()) {
return result;
}
const auto fileName = value.property("fileName").toString();
const auto lineNumber = value.property("lineNumber").toString();
const auto stacktrace = value.property("stack").toString();
result = QString(SCRIPT_TRACE_FORMAT).arg(fileName, lineNumber);
if (!stacktrace.isEmpty()) {
result += QString("\n[Trace]%1%2").arg(SCRIPT_BACKTRACE_SEP).arg(stacktrace);
}
return result;
}
bool BaseScriptEngine::raiseException(const QScriptValue& exception) {
if (!IS_THREADSAFE_INVOCATION(thread(), __FUNCTION__)) {
return false;
@ -208,6 +230,18 @@ bool BaseScriptEngine::raiseException(const QScriptValue& exception) {
return false;
}
void BaseScriptEngine::raiseConsoleException(const QScriptValue& exception) {
if (currentContext()) {
currentContext()->throwValue(makeError(exception));
}
}
QScriptValue BaseScriptEngine::raiseConsoleTraceException(const QScriptValue& exception) {
if (currentContext()) {
return currentContext()->throwValue(makeError(exception));
}
}
bool BaseScriptEngine::maybeEmitUncaughtException(const QString& debugHint) {
if (!IS_THREADSAFE_INVOCATION(thread(), __FUNCTION__)) {
return false;

View file

@ -21,6 +21,7 @@ class BaseScriptEngine : public QScriptEngine, public QEnableSharedFromThis<Base
Q_OBJECT
public:
static const QString SCRIPT_EXCEPTION_FORMAT;
static const QString SCRIPT_TRACE_FORMAT;
static const QString SCRIPT_BACKTRACE_SEP;
// threadsafe "unbound" version of QScriptEngine::nullValue()
@ -29,10 +30,10 @@ public:
BaseScriptEngine() {}
Q_INVOKABLE QScriptValue lintScript(const QString& sourceCode, const QString& fileName, const int lineNumber = 1);
Q_INVOKABLE QScriptValue makeError(const QScriptValue& other = QScriptValue(), const QString& type = "Error");
Q_INVOKABLE QScriptValue makeError(const QScriptValue& other = QScriptValue(), const QString& type = "Error");
Q_INVOKABLE QString formatException(const QScriptValue& exception, bool includeExtendedDetails);
QScriptValue cloneUncaughtException(const QString& detail = QString());
Q_INVOKABLE QString formatTrace(const QScriptValue& val, bool includeExtendedDetails);
QScriptValue cloneUncaughtException(const QString& detail = QString());
QScriptValue evaluateInClosure(const QScriptValue& locals, const QScriptProgram& program);
// if there is a pending exception and we are at the top level (non-recursive) stack frame, this emits and resets it
@ -41,7 +42,8 @@ public:
// if the currentContext() is valid then throw the passed exception; otherwise, immediately emit it.
// note: this is used in cases where C++ code might call into JS API methods directly
bool raiseException(const QScriptValue& exception);
void raiseConsoleException(const QScriptValue& exception);
QScriptValue raiseConsoleTraceException(const QScriptValue& exception);
// helper to detect and log warnings when other code invokes QScriptEngine/BaseScriptEngine in thread-unsafe ways
static bool IS_THREADSAFE_INVOCATION(const QThread *thread, const QString& method);
signals: