diff --git a/CHANGELOG.md b/CHANGELOG.md
index 9b83d3fc..a03a7f24 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,12 @@
# Changelog
+## Unreleased
+
+### Improvements
+
+- Print logs created through the `SentrySDK.logger` API to Godot Output ([#463](https://github.com/getsentry/sentry-godot/pull/463))
+ - This behavior is enabled by default and can be disabled by setting `SentryOptions.print_logs` to `false`.
+
## 1.2.0
### Features
diff --git a/doc_classes/SentryOptions.xml b/doc_classes/SentryOptions.xml
index 677acf6c..db93807c 100644
--- a/doc_classes/SentryOptions.xml
+++ b/doc_classes/SentryOptions.xml
@@ -116,6 +116,10 @@
Maximum number of breadcrumbs to send with an event. You should be aware that Sentry has a maximum payload size and any events exceeding that payload size will be dropped.
+
+ If [code]true[/code], the SDK will print log messages added with [member SentrySDK.logger] API to the Godot console in addition to sending them to Sentry. When disabled, log messages will only be sent to Sentry without appearing in the local console output.
+ [b]Note:[/b] When both [member logger_messages_as_breadcrumbs] and [member print_logs] are enabled, log messages created through the [member SentrySDK.logger] API will be captured as breadcrumbs in addition to being displayed in the console and sent to Sentry as log entries.
+
Release version of the application. This value must be unique across all projects in your organization. Suggested format is [code]my-game@1.0.0[/code].
You can use the [code]{app_name}[/code] and [code]{app_version}[/code] placeholders to insert the application name and version from the Project Settings.
diff --git a/src/sentry/logging/sentry_godot_logger.cpp b/src/sentry/logging/sentry_godot_logger.cpp
index 089dfb14..b21c27fe 100644
--- a/src/sentry/logging/sentry_godot_logger.cpp
+++ b/src/sentry/logging/sentry_godot_logger.cpp
@@ -453,7 +453,7 @@ void SentryGodotLogger::_log_message(const String &p_message, bool p_error) {
return;
}
- bool as_log = SentryOptions::get_singleton()->get_enable_logs();
+ bool as_log = SentryOptions::get_singleton()->get_enable_logs() && !sentry::logging::skip_logging_messages;
bool as_breadcrumb = SentryOptions::get_singleton()->is_logger_messages_as_breadcrumbs_enabled();
if (!as_log && !as_breadcrumb) {
diff --git a/src/sentry/logging/state.cpp b/src/sentry/logging/state.cpp
index 153b6a3b..93964f43 100644
--- a/src/sentry/logging/state.cpp
+++ b/src/sentry/logging/state.cpp
@@ -3,5 +3,6 @@
namespace sentry::logging {
thread_local bool in_message_logging = false;
+thread_local bool skip_logging_messages = false;
} //namespace sentry::logging
diff --git a/src/sentry/logging/state.h b/src/sentry/logging/state.h
index 6de74e1d..94ad2167 100644
--- a/src/sentry/logging/state.h
+++ b/src/sentry/logging/state.h
@@ -13,4 +13,11 @@ struct MessageScope {
~MessageScope() { in_message_logging = false; }
};
+// Controls whether Godot logger messages should be forwarded to Sentry Logs.
+// When true, Godot logger messages are suppressed and not sent to Logs.
+// This flag is used by SentryLogger to send log messages with custom structure
+// while avoiding duplicate messages that would otherwise be produced by the
+// Godot logging system.
+extern thread_local bool skip_logging_messages;
+
} //namespace sentry::logging
diff --git a/src/sentry/sentry_logger.cpp b/src/sentry/sentry_logger.cpp
index a3c57a70..58be0aa3 100644
--- a/src/sentry/sentry_logger.cpp
+++ b/src/sentry/sentry_logger.cpp
@@ -1,8 +1,11 @@
#include "sentry_logger.h"
+#include "sentry/logging/state.h"
#include "sentry/sentry_log.h" // Needed for VariantCaster
#include "sentry/sentry_sdk.h"
+#include
+
namespace sentry {
void SentryLogger::log(LogLevel p_level, const String &p_body, const Array &p_params, const Dictionary &p_attributes) {
@@ -17,7 +20,26 @@ void SentryLogger::log(LogLevel p_level, const String &p_body, const Array &p_pa
}
body = p_body % p_params;
}
+
INTERNAL_SDK()->log(p_level, body, attributes);
+
+ if (SentryOptions::get_singleton()->is_print_logs_enabled()) {
+ // Add log to Godot's logging system without triggering recursive logging to Sentry Logs.
+ sentry::logging::skip_logging_messages = true;
+ switch (p_level) {
+ case LOG_LEVEL_TRACE:
+ case LOG_LEVEL_DEBUG:
+ case LOG_LEVEL_INFO: {
+ UtilityFunctions::print(body);
+ } break;
+ case LOG_LEVEL_WARN:
+ case LOG_LEVEL_ERROR:
+ case LOG_LEVEL_FATAL: {
+ UtilityFunctions::printerr(body);
+ } break;
+ }
+ sentry::logging::skip_logging_messages = false;
+ }
}
void SentryLogger::trace(const String &p_body, const Array &p_params, const Dictionary &p_attributes) {
diff --git a/src/sentry/sentry_options.cpp b/src/sentry/sentry_options.cpp
index d462ca83..d9cd88dc 100644
--- a/src/sentry/sentry_options.cpp
+++ b/src/sentry/sentry_options.cpp
@@ -95,7 +95,8 @@ void SentryOptions::_define_project_settings(const Ref &p_options
ERR_FAIL_NULL(ProjectSettings::get_singleton());
// Migrate renamed project settings to their new locations
- _migrate_setting("sentry/experimental/enable_logs", "sentry/options/enable_logs");
+ _migrate_setting("sentry/experimental/enable_logs", "sentry/options/logs/enable_logs");
+ _migrate_setting("sentry/options/enable_logs", "sentry/options/logs/enable_logs");
_define_setting("sentry/options/auto_init", p_options->auto_init);
_define_setting("sentry/options/skip_auto_init_on_editor_play", p_options->skip_auto_init_on_editor_play);
@@ -112,7 +113,8 @@ void SentryOptions::_define_project_settings(const Ref &p_options
_define_setting("sentry/options/attach_log", p_options->attach_log, false);
_define_setting("sentry/options/attach_scene_tree", p_options->attach_scene_tree);
- _define_setting("sentry/options/enable_logs", p_options->enable_logs, false);
+ _define_setting("sentry/options/logs/enable_logs", p_options->enable_logs, false);
+ _define_setting("sentry/options/logs/print_logs", p_options->print_logs, false);
_define_setting("sentry/options/app_hang/tracking", p_options->app_hang_tracking, false);
_define_setting("sentry/options/app_hang/timeout_sec", p_options->app_hang_timeout_sec, false);
@@ -158,7 +160,8 @@ void SentryOptions::_load_project_settings(const Ref &p_options)
p_options->attach_log = ProjectSettings::get_singleton()->get_setting("sentry/options/attach_log", p_options->attach_log);
p_options->attach_scene_tree = ProjectSettings::get_singleton()->get_setting("sentry/options/attach_scene_tree", p_options->attach_scene_tree);
- p_options->enable_logs = ProjectSettings::get_singleton()->get_setting("sentry/options/enable_logs", p_options->enable_logs);
+ p_options->enable_logs = ProjectSettings::get_singleton()->get_setting("sentry/options/logs/enable_logs", p_options->enable_logs);
+ p_options->print_logs = ProjectSettings::get_singleton()->get_setting("sentry/options/logs/print_logs", p_options->print_logs);
p_options->app_hang_tracking = ProjectSettings::get_singleton()->get_setting("sentry/options/app_hang/tracking", p_options->app_hang_tracking);
p_options->app_hang_timeout_sec = ProjectSettings::get_singleton()->get_setting("sentry/options/app_hang/timeout_sec", p_options->app_hang_timeout_sec);
@@ -245,6 +248,7 @@ void SentryOptions::_bind_methods() {
BIND_PROPERTY(SentryOptions, PropertyInfo(Variant::BOOL, "attach_scene_tree"), set_attach_scene_tree, is_attach_scene_tree_enabled);
BIND_PROPERTY(SentryOptions, PropertyInfo(Variant::BOOL, "enable_logs"), set_enable_logs, get_enable_logs);
+ BIND_PROPERTY(SentryOptions, PropertyInfo(Variant::BOOL, "print_logs"), set_print_logs, is_print_logs_enabled);
BIND_PROPERTY(SentryOptions, PropertyInfo(Variant::CALLABLE, "before_send_log"), set_before_send_log, get_before_send_log);
BIND_PROPERTY(SentryOptions, PropertyInfo(Variant::BOOL, "app_hang_tracking"), set_app_hang_tracking, is_app_hang_tracking_enabled);
diff --git a/src/sentry/sentry_options.h b/src/sentry/sentry_options.h
index 6d3cf6c7..8362ad37 100644
--- a/src/sentry/sentry_options.h
+++ b/src/sentry/sentry_options.h
@@ -83,7 +83,7 @@ class SentryOptions : public RefCounted {
bool attach_scene_tree = false;
bool enable_logs = true;
- Callable before_send_log;
+ bool print_logs = true;
bool app_hang_tracking = false;
double app_hang_timeout_sec = 5.0;
@@ -100,6 +100,7 @@ class SentryOptions : public RefCounted {
Callable before_send;
Callable before_capture_screenshot;
+ Callable before_send_log;
Vector[> event_processors;
@@ -164,6 +165,9 @@ class SentryOptions : public RefCounted {
_FORCE_INLINE_ bool get_enable_logs() const { return enable_logs; }
_FORCE_INLINE_ void set_enable_logs(bool p_enabled) { enable_logs = p_enabled; }
+ _FORCE_INLINE_ bool is_print_logs_enabled() const { return print_logs; }
+ _FORCE_INLINE_ void set_print_logs(bool p_enabled) { print_logs = p_enabled; }
+
_FORCE_INLINE_ Callable get_before_send_log() const { return before_send_log; }
_FORCE_INLINE_ void set_before_send_log(const Callable &p_callback) { before_send_log = p_callback; }
]