1
0
mirror of https://github.com/godotengine/godot.git synced 2025-11-04 12:00:25 +00:00

Ability to print and log script backtraces

Co-authored-by: Mikael Hermansson <mikael@hermansson.io>
This commit is contained in:
reduz
2025-03-31 21:39:43 +02:00
committed by Mikael Hermansson
parent f704113abe
commit d1dcb40d56
32 changed files with 813 additions and 95 deletions

View File

@@ -210,8 +210,79 @@ void ResourceSaver::_bind_methods() {
BIND_BITFIELD_FLAG(FLAG_REPLACE_SUBRESOURCE_PATHS);
}
////// Logger ///////
void Logger::_bind_methods() {
GDVIRTUAL_BIND(_log_error, "function", "file", "line", "code", "rationale", "editor_notify", "error_type", "script_backtraces");
GDVIRTUAL_BIND(_log_message, "message", "error");
BIND_ENUM_CONSTANT(ERROR_TYPE_ERROR);
BIND_ENUM_CONSTANT(ERROR_TYPE_WARNING);
BIND_ENUM_CONSTANT(ERROR_TYPE_SCRIPT);
BIND_ENUM_CONSTANT(ERROR_TYPE_SHADER);
}
void Logger::log_error(const char *p_function, const char *p_file, int p_line, const char *p_code, const char *p_rationale, bool p_editor_notify, ErrorType p_type, const TypedArray<ScriptBacktrace> &p_script_backtraces) {
GDVIRTUAL_CALL(_log_error, String::utf8(p_function), String::utf8(p_file), p_line, String::utf8(p_code), String::utf8(p_rationale), p_editor_notify, p_type, p_script_backtraces);
}
void Logger::log_message(const String &p_text, bool p_error) {
GDVIRTUAL_CALL(_log_message, p_text, p_error);
}
////// OS //////
void OS::LoggerBind::logv(const char *p_format, va_list p_list, bool p_err) {
if (!should_log(p_err) || is_logging) {
return;
}
is_logging = true;
constexpr int static_buf_size = 1024;
char static_buf[static_buf_size] = { '\0' };
char *buf = static_buf;
va_list list_copy;
va_copy(list_copy, p_list);
int len = vsnprintf(buf, static_buf_size, p_format, p_list);
if (len >= static_buf_size) {
buf = (char *)Memory::alloc_static(len + 1);
vsnprintf(buf, len + 1, p_format, list_copy);
}
va_end(list_copy);
String str;
str.append_utf8(buf, len);
for (Ref<CoreBind::Logger> &logger : loggers) {
logger->log_message(str, p_err);
}
if (len >= static_buf_size) {
Memory::free_static(buf);
}
is_logging = false;
}
void OS::LoggerBind::log_error(const char *p_function, const char *p_file, int p_line, const char *p_code, const char *p_rationale, bool p_editor_notify, ErrorType p_type, const Vector<Ref<ScriptBacktrace>> &p_script_backtraces) {
if (!should_log(true) || is_logging) {
return;
}
TypedArray<ScriptBacktrace> backtraces;
backtraces.resize(p_script_backtraces.size());
for (int i = 0; i < p_script_backtraces.size(); i++) {
backtraces[i] = p_script_backtraces[i];
}
is_logging = true;
for (Ref<CoreBind::Logger> &logger : loggers) {
logger->log_error(p_function, p_file, p_line, p_code, p_rationale, p_editor_notify, CoreBind::Logger::ErrorType(p_type), backtraces);
}
is_logging = false;
}
PackedByteArray OS::get_entropy(int p_bytes) {
PackedByteArray pba;
pba.resize(p_bytes);
@@ -628,6 +699,24 @@ String OS::get_unique_id() const {
return ::OS::get_singleton()->get_unique_id();
}
void OS::add_logger(const Ref<Logger> &p_logger) {
ERR_FAIL_COND(p_logger.is_null());
if (!logger_bind) {
logger_bind = memnew(LoggerBind);
::OS::get_singleton()->add_logger(logger_bind);
}
ERR_FAIL_COND_MSG(logger_bind->loggers.find(p_logger) != -1, "Could not add logger, as it has already been added.");
logger_bind->loggers.push_back(p_logger);
}
void OS::remove_logger(const Ref<Logger> &p_logger) {
ERR_FAIL_COND(p_logger.is_null());
ERR_FAIL_COND_MSG(!logger_bind || logger_bind->loggers.find(p_logger) == -1, "Could not remove logger, as it hasn't been added.");
logger_bind->loggers.erase(p_logger);
}
OS *OS::singleton = nullptr;
void OS::_bind_methods() {
@@ -734,6 +823,9 @@ void OS::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_granted_permissions"), &OS::get_granted_permissions);
ClassDB::bind_method(D_METHOD("revoke_granted_permissions"), &OS::revoke_granted_permissions);
ClassDB::bind_method(D_METHOD("add_logger", "logger"), &OS::add_logger);
ClassDB::bind_method(D_METHOD("remove_logger", "logger"), &OS::remove_logger);
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "low_processor_usage_mode"), "set_low_processor_usage_mode", "is_in_low_processor_usage_mode");
ADD_PROPERTY(PropertyInfo(Variant::INT, "low_processor_usage_mode_sleep_usec"), "set_low_processor_usage_mode_sleep_usec", "get_low_processor_usage_mode_sleep_usec");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "delta_smoothing"), "set_delta_smoothing", "is_delta_smoothing_enabled");
@@ -764,6 +856,20 @@ void OS::_bind_methods() {
BIND_ENUM_CONSTANT(STD_HANDLE_UNKNOWN);
}
OS::OS() {
singleton = this;
}
OS::~OS() {
if (singleton == this) {
singleton = nullptr;
}
if (logger_bind) {
logger_bind->clear();
}
}
////// Geometry2D //////
Geometry2D *Geometry2D::singleton = nullptr;
@@ -1901,6 +2007,16 @@ ScriptLanguage *Engine::get_script_language(int p_index) const {
return ScriptServer::get_language(p_index);
}
TypedArray<ScriptBacktrace> Engine::capture_script_backtraces(bool p_include_variables) const {
Vector<Ref<ScriptBacktrace>> backtraces = ScriptServer::capture_script_backtraces(p_include_variables);
TypedArray<ScriptBacktrace> result;
result.resize(backtraces.size());
for (int i = 0; i < backtraces.size(); i++) {
result[i] = backtraces[i];
}
return result;
}
void Engine::set_editor_hint(bool p_enabled) {
::Engine::get_singleton()->set_editor_hint(p_enabled);
}
@@ -1988,6 +2104,7 @@ void Engine::_bind_methods() {
ClassDB::bind_method(D_METHOD("unregister_script_language", "language"), &Engine::unregister_script_language);
ClassDB::bind_method(D_METHOD("get_script_language_count"), &Engine::get_script_language_count);
ClassDB::bind_method(D_METHOD("get_script_language", "index"), &Engine::get_script_language);
ClassDB::bind_method(D_METHOD("capture_script_backtraces", "include_variables"), &Engine::capture_script_backtraces, DEFVAL(false));
ClassDB::bind_method(D_METHOD("is_editor_hint"), &Engine::is_editor_hint);
ClassDB::bind_method(D_METHOD("is_embedded_in_editor"), &Engine::is_embedded_in_editor);