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; }