mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-04-23 13:05:12 +00:00
LibDevTools+LibWebView+WebContent: Report exceptions to DevTools
This commit is contained in:
parent
2aeed210d9
commit
f2cce8572b
4 changed files with 232 additions and 45 deletions
|
@ -229,48 +229,94 @@ void FrameActor::console_messages_received(i32 start_index, Vector<WebView::Cons
|
|||
return;
|
||||
}
|
||||
|
||||
JsonArray messages;
|
||||
messages.ensure_capacity(console_output.size());
|
||||
JsonArray console_messages;
|
||||
JsonArray error_messages;
|
||||
|
||||
for (auto& output : console_output) {
|
||||
JsonObject message;
|
||||
|
||||
switch (output.level) {
|
||||
case JS::Console::LogLevel::Debug:
|
||||
message.set("level"sv, "debug"sv);
|
||||
break;
|
||||
case JS::Console::LogLevel::Error:
|
||||
message.set("level"sv, "error"sv);
|
||||
break;
|
||||
case JS::Console::LogLevel::Info:
|
||||
message.set("level"sv, "info"sv);
|
||||
break;
|
||||
case JS::Console::LogLevel::Log:
|
||||
message.set("level"sv, "log"sv);
|
||||
break;
|
||||
case JS::Console::LogLevel::Warn:
|
||||
message.set("level"sv, "warn"sv);
|
||||
break;
|
||||
default:
|
||||
// FIXME: Implement remaining console levels.
|
||||
continue;
|
||||
}
|
||||
output.output.visit(
|
||||
[&](WebView::ConsoleLog& log) {
|
||||
switch (log.level) {
|
||||
case JS::Console::LogLevel::Debug:
|
||||
message.set("level"sv, "debug"sv);
|
||||
break;
|
||||
case JS::Console::LogLevel::Error:
|
||||
message.set("level"sv, "error"sv);
|
||||
break;
|
||||
case JS::Console::LogLevel::Info:
|
||||
message.set("level"sv, "info"sv);
|
||||
break;
|
||||
case JS::Console::LogLevel::Log:
|
||||
message.set("level"sv, "log"sv);
|
||||
break;
|
||||
case JS::Console::LogLevel::Warn:
|
||||
message.set("level"sv, "warn"sv);
|
||||
break;
|
||||
default:
|
||||
// FIXME: Implement remaining console levels.
|
||||
return;
|
||||
}
|
||||
|
||||
message.set("filename"sv, "<eval>"sv);
|
||||
message.set("line_number"sv, 1);
|
||||
message.set("column_number"sv, 1);
|
||||
message.set("time_stamp"sv, output.timestamp.milliseconds_since_epoch());
|
||||
message.set("arguments"sv, JsonArray { move(output.arguments) });
|
||||
message.set("filename"sv, "<eval>"sv);
|
||||
message.set("lineNumber"sv, 1);
|
||||
message.set("columnNumber"sv, 1);
|
||||
message.set("timeStamp"sv, output.timestamp.milliseconds_since_epoch());
|
||||
message.set("arguments"sv, JsonArray { move(log.arguments) });
|
||||
|
||||
messages.must_append(move(message));
|
||||
console_messages.must_append(move(message));
|
||||
},
|
||||
[&](WebView::ConsoleError const& error) {
|
||||
StringBuilder stack;
|
||||
|
||||
for (auto const& frame : error.trace) {
|
||||
if (frame.function.has_value())
|
||||
stack.append(*frame.function);
|
||||
stack.append('@');
|
||||
stack.append(frame.file.map([](auto const& file) -> StringView { return file; }).value_or("unknown"sv));
|
||||
stack.appendff(":{}:{}\n", frame.line.value_or(0), frame.column.value_or(0));
|
||||
}
|
||||
|
||||
JsonObject preview;
|
||||
preview.set("kind"sv, "Error"sv);
|
||||
preview.set("message"sv, error.message);
|
||||
preview.set("name"sv, error.name);
|
||||
if (!stack.is_empty())
|
||||
preview.set("stack"sv, MUST(stack.to_string()));
|
||||
|
||||
JsonObject exception;
|
||||
exception.set("class"sv, error.name);
|
||||
exception.set("isError"sv, true);
|
||||
exception.set("preview"sv, move(preview));
|
||||
|
||||
JsonObject page_error;
|
||||
page_error.set("error"sv, true);
|
||||
page_error.set("exception"sv, move(exception));
|
||||
page_error.set("hasException"sv, !error.trace.is_empty());
|
||||
page_error.set("isPromiseRejection"sv, error.inside_promise);
|
||||
page_error.set("timeStamp"sv, output.timestamp.milliseconds_since_epoch());
|
||||
|
||||
message.set("pageError"sv, move(page_error));
|
||||
error_messages.must_append(move(message));
|
||||
});
|
||||
}
|
||||
|
||||
JsonArray console_message;
|
||||
console_message.must_append("console-message"sv);
|
||||
console_message.must_append(move(messages));
|
||||
|
||||
JsonArray array;
|
||||
array.must_append(move(console_message));
|
||||
|
||||
if (!console_messages.is_empty()) {
|
||||
JsonArray console_message;
|
||||
console_message.must_append("console-message"sv);
|
||||
console_message.must_append(move(console_messages));
|
||||
|
||||
array.must_append(move(console_message));
|
||||
}
|
||||
if (!error_messages.is_empty()) {
|
||||
JsonArray error_message;
|
||||
error_message.must_append("error-message"sv);
|
||||
error_message.must_append(move(error_messages));
|
||||
|
||||
array.must_append(move(error_message));
|
||||
}
|
||||
|
||||
JsonObject message;
|
||||
message.set("type"sv, "resources-available-array"sv);
|
||||
|
|
|
@ -9,11 +9,72 @@
|
|||
#include <LibWebView/ConsoleOutput.h>
|
||||
|
||||
template<>
|
||||
ErrorOr<void> IPC::encode(Encoder& encoder, WebView::ConsoleOutput const& console_output)
|
||||
ErrorOr<void> IPC::encode(Encoder& encoder, WebView::ConsoleLog const& log)
|
||||
{
|
||||
TRY(encoder.encode(console_output.level));
|
||||
TRY(encoder.encode(console_output.timestamp));
|
||||
TRY(encoder.encode(console_output.arguments));
|
||||
TRY(encoder.encode(log.level));
|
||||
TRY(encoder.encode(log.arguments));
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
template<>
|
||||
ErrorOr<WebView::ConsoleLog> IPC::decode(Decoder& decoder)
|
||||
{
|
||||
auto level = TRY(decoder.decode<JS::Console::LogLevel>());
|
||||
auto arguments = TRY(decoder.decode<Vector<JsonValue>>());
|
||||
|
||||
return WebView::ConsoleLog { level, move(arguments) };
|
||||
}
|
||||
|
||||
template<>
|
||||
ErrorOr<void> IPC::encode(Encoder& encoder, WebView::StackFrame const& frame)
|
||||
{
|
||||
TRY(encoder.encode(frame.function));
|
||||
TRY(encoder.encode(frame.file));
|
||||
TRY(encoder.encode(frame.line));
|
||||
TRY(encoder.encode(frame.column));
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
template<>
|
||||
ErrorOr<WebView::StackFrame> IPC::decode(Decoder& decoder)
|
||||
{
|
||||
auto function = TRY(decoder.decode<Optional<String>>());
|
||||
auto file = TRY(decoder.decode<Optional<String>>());
|
||||
auto line = TRY(decoder.decode<Optional<size_t>>());
|
||||
auto column = TRY(decoder.decode<Optional<size_t>>());
|
||||
|
||||
return WebView::StackFrame { move(function), move(file), line, column };
|
||||
}
|
||||
|
||||
template<>
|
||||
ErrorOr<void> IPC::encode(Encoder& encoder, WebView::ConsoleError const& error)
|
||||
{
|
||||
TRY(encoder.encode(error.name));
|
||||
TRY(encoder.encode(error.message));
|
||||
TRY(encoder.encode(error.trace));
|
||||
TRY(encoder.encode(error.inside_promise));
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
template<>
|
||||
ErrorOr<WebView::ConsoleError> IPC::decode(Decoder& decoder)
|
||||
{
|
||||
auto name = TRY(decoder.decode<String>());
|
||||
auto message = TRY(decoder.decode<String>());
|
||||
auto trace = TRY(decoder.decode<Vector<WebView::StackFrame>>());
|
||||
auto inside_promise = TRY(decoder.decode<bool>());
|
||||
|
||||
return WebView::ConsoleError { move(name), move(message), move(trace), inside_promise };
|
||||
}
|
||||
|
||||
template<>
|
||||
ErrorOr<void> IPC::encode(Encoder& encoder, WebView::ConsoleOutput const& output)
|
||||
{
|
||||
TRY(encoder.encode(output.timestamp));
|
||||
TRY(encoder.encode(output.output));
|
||||
|
||||
return {};
|
||||
}
|
||||
|
@ -21,9 +82,8 @@ ErrorOr<void> IPC::encode(Encoder& encoder, WebView::ConsoleOutput const& consol
|
|||
template<>
|
||||
ErrorOr<WebView::ConsoleOutput> IPC::decode(Decoder& decoder)
|
||||
{
|
||||
auto level = TRY(decoder.decode<JS::Console::LogLevel>());
|
||||
auto timestamp = TRY(decoder.decode<UnixDateTime>());
|
||||
auto arguments = TRY(decoder.decode<Vector<JsonValue>>());
|
||||
auto output = TRY(decoder.decode<Variant<WebView::ConsoleLog, WebView::ConsoleError>>());
|
||||
|
||||
return WebView::ConsoleOutput { level, timestamp, move(arguments) };
|
||||
return WebView::ConsoleOutput { timestamp, move(output) };
|
||||
}
|
||||
|
|
|
@ -7,23 +7,61 @@
|
|||
#pragma once
|
||||
|
||||
#include <AK/JsonValue.h>
|
||||
#include <AK/String.h>
|
||||
#include <AK/Time.h>
|
||||
#include <AK/Variant.h>
|
||||
#include <AK/Vector.h>
|
||||
#include <LibIPC/Forward.h>
|
||||
#include <LibJS/Console.h>
|
||||
|
||||
namespace WebView {
|
||||
|
||||
struct ConsoleOutput {
|
||||
struct ConsoleLog {
|
||||
JS::Console::LogLevel level;
|
||||
UnixDateTime timestamp;
|
||||
Vector<JsonValue> arguments;
|
||||
};
|
||||
|
||||
struct StackFrame {
|
||||
Optional<String> function;
|
||||
Optional<String> file;
|
||||
Optional<size_t> line;
|
||||
Optional<size_t> column;
|
||||
};
|
||||
|
||||
struct ConsoleError {
|
||||
String name;
|
||||
String message;
|
||||
Vector<StackFrame> trace;
|
||||
bool inside_promise { false };
|
||||
};
|
||||
|
||||
struct ConsoleOutput {
|
||||
UnixDateTime timestamp;
|
||||
Variant<ConsoleLog, ConsoleError> output;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
namespace IPC {
|
||||
|
||||
template<>
|
||||
ErrorOr<void> encode(Encoder&, WebView::ConsoleLog const&);
|
||||
|
||||
template<>
|
||||
ErrorOr<WebView::ConsoleLog> decode(Decoder&);
|
||||
|
||||
template<>
|
||||
ErrorOr<void> encode(Encoder&, WebView::StackFrame const&);
|
||||
|
||||
template<>
|
||||
ErrorOr<WebView::StackFrame> decode(Decoder&);
|
||||
|
||||
template<>
|
||||
ErrorOr<void> encode(Encoder&, WebView::ConsoleError const&);
|
||||
|
||||
template<>
|
||||
ErrorOr<WebView::ConsoleError> decode(Decoder&);
|
||||
|
||||
template<>
|
||||
ErrorOr<void> encode(Encoder&, WebView::ConsoleOutput const&);
|
||||
|
||||
|
|
|
@ -101,8 +101,43 @@ void DevToolsConsoleClient::handle_result(JS::Value result)
|
|||
|
||||
void DevToolsConsoleClient::report_exception(JS::Error const& exception, bool in_promise)
|
||||
{
|
||||
(void)exception;
|
||||
(void)in_promise;
|
||||
auto& vm = exception.vm();
|
||||
|
||||
auto name = exception.get_without_side_effects(vm.names.name).value_or(JS::js_undefined());
|
||||
auto message = exception.get_without_side_effects(vm.names.message).value_or(JS::js_undefined());
|
||||
|
||||
Vector<WebView::StackFrame> trace;
|
||||
trace.ensure_capacity(exception.traceback().size());
|
||||
|
||||
for (auto const& frame : exception.traceback()) {
|
||||
auto const& source_range = frame.source_range();
|
||||
WebView::StackFrame stack_frame;
|
||||
|
||||
if (!frame.function_name.is_empty())
|
||||
stack_frame.function = frame.function_name.to_string();
|
||||
|
||||
if (!source_range.filename().is_empty() || source_range.start.offset != 0 || source_range.end.offset != 0) {
|
||||
stack_frame.file = String::from_utf8_with_replacement_character(source_range.filename());
|
||||
stack_frame.line = source_range.start.line;
|
||||
stack_frame.column = source_range.start.column;
|
||||
}
|
||||
|
||||
if (stack_frame.function.has_value() || stack_frame.file.has_value())
|
||||
trace.unchecked_append(move(stack_frame));
|
||||
}
|
||||
|
||||
WebView::ConsoleOutput console_output {
|
||||
.timestamp = UnixDateTime::now(),
|
||||
.output = WebView::ConsoleError {
|
||||
.name = name.to_string_without_side_effects(),
|
||||
.message = message.to_string_without_side_effects(),
|
||||
.trace = move(trace),
|
||||
.inside_promise = in_promise,
|
||||
},
|
||||
};
|
||||
|
||||
m_console_output.append(move(console_output));
|
||||
m_client->did_output_js_console_message(m_console_output.size() - 1);
|
||||
}
|
||||
|
||||
void DevToolsConsoleClient::send_messages(i32 start_index)
|
||||
|
@ -136,7 +171,15 @@ JS::ThrowCompletionOr<JS::Value> DevToolsConsoleClient::printer(JS::Console::Log
|
|||
for (auto value : argument_values)
|
||||
serialized_arguments.unchecked_append(serialize_js_value(m_console->realm(), value));
|
||||
|
||||
m_console_output.empend(log_level, UnixDateTime::now(), move(serialized_arguments));
|
||||
WebView::ConsoleOutput console_output {
|
||||
.timestamp = UnixDateTime::now(),
|
||||
.output = WebView::ConsoleLog {
|
||||
.level = log_level,
|
||||
.arguments = move(serialized_arguments),
|
||||
},
|
||||
};
|
||||
|
||||
m_console_output.append(move(console_output));
|
||||
m_client->did_output_js_console_message(m_console_output.size() - 1);
|
||||
|
||||
return JS::js_undefined();
|
||||
|
|
Loading…
Add table
Reference in a new issue