Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
- Detect when we're inside message logging to prevent SDK print operations through the Godot logger which cause runtime errors. ([#414](https://github.com/getsentry/sentry-godot/pull/414))
- Relax throttling limits on app startup ([#423](https://github.com/getsentry/sentry-godot/pull/423))
- Set app hang timeout to 5s on Apple platforms ([#416](https://github.com/getsentry/sentry-godot/pull/416))
- Add app hang tracking options and disable this feature by default ([#429](https://github.com/getsentry/sentry-godot/pull/429))

### Dependencies

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -160,45 +160,56 @@ class SentryAndroidGodotPlugin(godot: Godot) : GodotPlugin(godot) {

@UsedByGodot
fun init(
optionsData: Dictionary,
beforeSendHandlerId: Long,
dsn: String,
debug: Boolean,
release: String,
dist: String,
environment: String,
sampleRate: Float,
maxBreadcrumbs: Int,
enableLogs: Boolean,
beforeSendLogHandlerId: Long
) {
Log.v(TAG, "Initializing Sentry Android")
SentryAndroid.init(godot.getActivity()!!.applicationContext) { options ->
options.dsn = dsn.ifEmpty { null }
options.isDebug = debug
options.release = release.ifEmpty { null }
options.dist = dist.ifEmpty { null }
options.environment = environment.ifEmpty { null }
options.sampleRate = sampleRate.toDouble()
options.maxBreadcrumbs = maxBreadcrumbs
options.sdkVersion?.name = "sentry.java.android.godot"
options.nativeSdkName = "sentry.native.android.godot"
options.logs.isEnabled = enableLogs
options.beforeSend =
SentryOptions.BeforeSendCallback { event: SentryEvent, hint: Hint ->
Log.v(TAG, "beforeSend: ${event.eventId} isCrashed: ${event.isCrashed}")
val handle: Int = registerEvent(event)
Callable.call(beforeSendHandlerId, "before_send", handle)
eventsByHandle.get()?.remove(handle) // Returns the event or null if it was discarded.
}
if (beforeSendLogHandlerId != 0L) {
options.logs.beforeSend =
SentryOptions.Logs.BeforeSendLogCallback { logEvent ->
val handle: Int = registerLog(logEvent)
Callable.call(beforeSendLogHandlerId, "before_send_log", handle)
logsByHandle.get()?.remove(handle) // Returns the log or null if it was discarded.

try {
val dsn = optionsData["dsn"] as String
val debug = optionsData["debug"] as Boolean
val release = optionsData["release"] as String
val dist = optionsData["dist"] as String
val environment = optionsData["environment"] as String
val sampleRate = optionsData["sample_rate"] as Double
val maxBreadcrumbs = optionsData["max_breadcrumbs"].toIntOrThrow()
val enableLogs = optionsData["enable_logs"] as Boolean
val appHangTracking = optionsData["app_hang_tracking"] as Boolean
val appHangTimeoutSec = optionsData["app_hang_timeout_sec"] as Double

SentryAndroid.init(godot.getActivity()!!.applicationContext) { options ->
options.dsn = dsn.ifEmpty { null }
options.isDebug = debug
options.release = release.ifEmpty { null }
options.dist = dist.ifEmpty { null }
options.environment = environment.ifEmpty { null }
options.sampleRate = sampleRate.toDouble()
options.maxBreadcrumbs = maxBreadcrumbs
options.sdkVersion?.name = "sentry.java.android.godot"
options.nativeSdkName = "sentry.native.android.godot"
options.logs.isEnabled = enableLogs
options.isAnrEnabled = appHangTracking
options.anrTimeoutIntervalMillis = (appHangTimeoutSec * 1000.0).toLong()
options.beforeSend =
SentryOptions.BeforeSendCallback { event: SentryEvent, hint: Hint ->
Log.v(TAG, "beforeSend: ${event.eventId} isCrashed: ${event.isCrashed}")
val handle: Int = registerEvent(event)
Callable.call(beforeSendHandlerId, "before_send", handle)
eventsByHandle.get()?.remove(handle) // Returns the event or null if it was discarded.
}
if (beforeSendLogHandlerId != 0L) {
options.logs.beforeSend =
SentryOptions.Logs.BeforeSendLogCallback { logEvent ->
val handle: Int = registerLog(logEvent)
Callable.call(beforeSendLogHandlerId, "before_send_log", handle)
logsByHandle.get()?.remove(handle) // Returns the log or null if it was discarded.
}
}
}

} catch (e: Exception) {
Log.e(TAG, "Error initializing Sentry for Android", e)
return
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,14 @@ fun Long.microsecondsToTimestamp(): Date {
return Date(millis)
}


fun Date.toMicros(): Long {
val date: Date = this@toMicros
return date.time * 1000
}

fun Any?.toIntOrThrow(): Int =
when (this) {
is Int -> this
is Long -> this.toInt()
else -> throw IllegalArgumentException("Expected Int or Long, got ${this?.let { it::class } ?: "null"}")
}
7 changes: 7 additions & 0 deletions doc_classes/SentryOptions.xml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,13 @@
<tutorials>
</tutorials>
<members>
<member name="app_hang_timeout_sec" type="float" setter="set_app_hang_timeout_sec" getter="get_app_hang_timeout_sec" default="5.0">
Specifies the timeout duration in seconds after which the application is considered to have hanged. When [member app_hang_tracking] is enabled, if the main thread is blocked for longer than this duration, it will be reported as an application hang event to Sentry.
</member>
<member name="app_hang_tracking" type="bool" setter="set_app_hang_tracking" getter="is_app_hang_tracking_enabled" default="false">
If [code]true[/code], enables automatic detection and reporting of application hangs. The SDK will monitor the main thread and report hang events when it becomes unresponsive for longer than the duration specified in [member app_hang_timeout_sec]. This helps identify performance issues where the application becomes frozen or unresponsive.
[b]Note:[/b] This feature is only supported on Android, iOS, and macOS platforms.
</member>
<member name="attach_log" type="bool" setter="set_attach_log" getter="is_attach_log_enabled" default="true">
If [code]true[/code], the SDK will attach the Godot log file to the event.
</member>
Expand Down
21 changes: 13 additions & 8 deletions src/sentry/android/android_sdk.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -226,16 +226,21 @@ void AndroidSDK::init(const PackedStringArray &p_global_attachments, const Calla
is_view_hierarchy ? "event.view_hierarchy" : String());
}

Dictionary optionsData;
optionsData["dsn"] = SentryOptions::get_singleton()->get_dsn();
optionsData["debug"] = SentryOptions::get_singleton()->is_debug_enabled();
optionsData["release"] = SentryOptions::get_singleton()->get_release();
optionsData["dist"] = SentryOptions::get_singleton()->get_dist();
optionsData["environment"] = SentryOptions::get_singleton()->get_environment();
optionsData["sample_rate"] = SentryOptions::get_singleton()->get_sample_rate();
optionsData["max_breadcrumbs"] = SentryOptions::get_singleton()->get_max_breadcrumbs();
optionsData["enable_logs"] = SentryOptions::get_singleton()->get_experimental()->get_enable_logs();
optionsData["app_hang_tracking"] = SentryOptions::get_singleton()->is_app_hang_tracking_enabled();
optionsData["app_hang_timeout_sec"] = SentryOptions::get_singleton()->get_app_hang_timeout_sec();

android_plugin->call(ANDROID_SN(init),
optionsData,
before_send_handler->get_instance_id(),
SentryOptions::get_singleton()->get_dsn(),
SentryOptions::get_singleton()->is_debug_enabled(),
SentryOptions::get_singleton()->get_release(),
SentryOptions::get_singleton()->get_dist(),
SentryOptions::get_singleton()->get_environment(),
SentryOptions::get_singleton()->get_sample_rate(),
SentryOptions::get_singleton()->get_max_breadcrumbs(),
SentryOptions::get_singleton()->get_experimental()->get_enable_logs(),
SentryOptions::get_singleton()->get_experimental()->before_send_log.is_valid() ? before_send_log_handler->get_instance_id() : 0);

if (is_enabled()) {
Expand Down
4 changes: 3 additions & 1 deletion src/sentry/cocoa/cocoa_sdk.mm
Original file line number Diff line number Diff line change
Expand Up @@ -258,10 +258,12 @@
options.dist = string_to_objc(dist);
}

options.enableAppHangTracking = SentryOptions::get_singleton()->is_app_hang_tracking_enabled();
options.appHangTimeoutInterval = SentryOptions::get_singleton()->get_app_hang_timeout_sec();

// NOTE: This only works for captureMessage(), unfortunately.
options.attachStacktrace = false;

options.appHangTimeoutInterval = 5; // 5 seconds
options.experimental.enableLogs = SentryOptions::get_singleton()->get_experimental()->get_enable_logs();

options.initialScope = ^(objc::SentryScope *scope) {
Expand Down
9 changes: 9 additions & 0 deletions src/sentry/sentry_options.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,9 @@ void SentryOptions::_define_project_settings(const Ref<SentryOptions> &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/app_hang/tracking", p_options->app_hang_tracking, false);
_define_setting("sentry/options/app_hang/timeout_sec", p_options->app_hang_timeout_sec, false);

_define_setting("sentry/logger/logger_enabled", p_options->logger_enabled);
_define_setting("sentry/logger/include_source", p_options->logger_include_source, false);
_define_setting("sentry/logger/include_variables", p_options->logger_include_variables, false);
Expand Down Expand Up @@ -121,6 +124,9 @@ void SentryOptions::_load_project_settings(const Ref<SentryOptions> &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->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);

p_options->logger_enabled = ProjectSettings::get_singleton()->get_setting("sentry/logger/logger_enabled", p_options->logger_enabled);
p_options->logger_include_source = ProjectSettings::get_singleton()->get_setting("sentry/logger/include_source", p_options->logger_include_source);
p_options->logger_include_variables = ProjectSettings::get_singleton()->get_setting("sentry/logger/include_variables", p_options->logger_include_variables);
Expand Down Expand Up @@ -203,6 +209,9 @@ void SentryOptions::_bind_methods() {
BIND_PROPERTY(SentryOptions, sentry::make_level_enum_property("screenshot_level"), set_screenshot_level, get_screenshot_level);
BIND_PROPERTY(SentryOptions, PropertyInfo(Variant::BOOL, "attach_scene_tree"), set_attach_scene_tree, is_attach_scene_tree_enabled);

BIND_PROPERTY(SentryOptions, PropertyInfo(Variant::BOOL, "app_hang_tracking"), set_app_hang_tracking, is_app_hang_tracking_enabled);
BIND_PROPERTY(SentryOptions, PropertyInfo(Variant::FLOAT, "app_hang_timeout_sec"), set_app_hang_timeout_sec, get_app_hang_timeout_sec);

BIND_PROPERTY(SentryOptions, PropertyInfo(Variant::BOOL, "logger_enabled"), set_logger_enabled, is_logger_enabled);
BIND_PROPERTY(SentryOptions, PropertyInfo(Variant::BOOL, "logger_include_source"), set_logger_include_source, is_logger_include_source_enabled);
BIND_PROPERTY(SentryOptions, PropertyInfo(Variant::BOOL, "logger_include_variables"), set_logger_include_variables, is_logger_include_variables_enabled);
Expand Down
9 changes: 9 additions & 0 deletions src/sentry/sentry_options.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,9 @@ class SentryOptions : public RefCounted {
sentry::Level screenshot_level = sentry::LEVEL_FATAL;
bool attach_scene_tree = false;

bool app_hang_tracking = false;
double app_hang_timeout_sec = 5.0;

bool logger_enabled = true;
bool logger_include_source = true;
bool logger_include_variables = false;
Expand Down Expand Up @@ -152,6 +155,12 @@ class SentryOptions : public RefCounted {
_FORCE_INLINE_ void set_attach_scene_tree(bool p_enable) { attach_scene_tree = p_enable; }
_FORCE_INLINE_ bool is_attach_scene_tree_enabled() const { return attach_scene_tree; }

_FORCE_INLINE_ bool is_app_hang_tracking_enabled() const { return app_hang_tracking; }
_FORCE_INLINE_ void set_app_hang_tracking(bool p_enabled) { app_hang_tracking = p_enabled; }

_FORCE_INLINE_ double get_app_hang_timeout_sec() const { return app_hang_timeout_sec; }
_FORCE_INLINE_ void set_app_hang_timeout_sec(double p_seconds) { app_hang_timeout_sec = p_seconds; }

_FORCE_INLINE_ bool is_logger_enabled() const { return logger_enabled; }
_FORCE_INLINE_ void set_logger_enabled(bool p_enabled) { logger_enabled = p_enabled; }

Expand Down
Loading