diff --git a/CHANGELOG.md b/CHANGELOG.md index fa7dd6a2c..b4a2c96d3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ ### Breaking Changes +- The SDK will now always add a breadcrumb when capturing an exception. The option to opt-out of this has been removed. ([#2335](https://github.com/getsentry/sentry-unity/pull/2335)) - The deprecated Runtime- and BuildTime-Configuration have been removed in favor of the single `OptionsConfiguration` script. When migrating you can make use of preprocessor directives to set specific options for specific platforms. Check out the ([Migration Guide](https://docs.sentry.io/platforms/unity/migration/#changes-to-the-programmatic-configuration)). ([#2337](https://github.com/getsentry/sentry-unity/pull/2337)) ### Features diff --git a/src/Sentry.Unity.Editor/ConfigurationWindow/LoggingTab.cs b/src/Sentry.Unity.Editor/ConfigurationWindow/LoggingTab.cs index be81ad3af..da13dd041 100644 --- a/src/Sentry.Unity.Editor/ConfigurationWindow/LoggingTab.cs +++ b/src/Sentry.Unity.Editor/ConfigurationWindow/LoggingTab.cs @@ -66,9 +66,6 @@ internal static void Display(ScriptableSentryUnityOptions options) options.BreadcrumbsForErrors = EditorGUILayout.Toggle( new GUIContent("Debug.Error", "Whether the SDK automatically adds breadcrumbs for 'Debug.LogError'."), options.BreadcrumbsForErrors); - options.BreadcrumbsForExceptions = EditorGUILayout.Toggle( - new GUIContent("Debug.Exception", "Whether the SDK automatically adds breadcrumbs for exceptions and 'Debug.LogException'."), - options.BreadcrumbsForExceptions); EditorGUI.indentLevel--; } diff --git a/src/Sentry.Unity/Integrations/UnityApplicationLoggingIntegration.cs b/src/Sentry.Unity/Integrations/UnityApplicationLoggingIntegration.cs index 11c4ac0f7..52143fe65 100644 --- a/src/Sentry.Unity/Integrations/UnityApplicationLoggingIntegration.cs +++ b/src/Sentry.Unity/Integrations/UnityApplicationLoggingIntegration.cs @@ -1,10 +1,13 @@ -using Sentry.Extensibility; using Sentry.Integrations; -using Sentry.Protocol; using UnityEngine; namespace Sentry.Unity.Integrations; +/// +/// Hooks into Unity's `Application.LogMessageReceived` to capture breadcrumbs for Debug log methods +/// and optionally capture LogError events. Does not handle `Debug.LogException` since it lacks the +/// actual exception object needed for IL2CPP processing, except on WebGL where it's treated as a log message. +/// internal class UnityApplicationLoggingIntegration : ISdkIntegration { private readonly IApplication _application; @@ -80,8 +83,12 @@ internal void OnLogMessageReceived(string message, string stacktrace, LogType lo { var ule = new UnityErrorLogException(message, stacktrace, _options); _hub.CaptureException(ule); + + // We don't capture breadcrumbs for exceptions - the .NET SDK handles this + return; } - else if (logType is LogType.Error && _options?.CaptureLogErrorEvents is true) + + if (logType is LogType.Error && _options?.CaptureLogErrorEvents is true) { if (_options?.AttachStacktrace is true && !string.IsNullOrEmpty(stacktrace)) { diff --git a/src/Sentry.Unity/Integrations/UnityErrorLogException.cs b/src/Sentry.Unity/Integrations/UnityErrorLogException.cs index c62d966a0..8d7a6daeb 100644 --- a/src/Sentry.Unity/Integrations/UnityErrorLogException.cs +++ b/src/Sentry.Unity/Integrations/UnityErrorLogException.cs @@ -49,8 +49,8 @@ public SentryException ToSentryException() return new SentryException { Stacktrace = stacktrace, - Type = ExceptionType, Value = _logString, + Type = ExceptionType, Mechanism = new Mechanism { Handled = true, diff --git a/src/Sentry.Unity/Integrations/UnityLogHandlerIntegration.cs b/src/Sentry.Unity/Integrations/UnityLogHandlerIntegration.cs index 79a610685..b93b15a1a 100644 --- a/src/Sentry.Unity/Integrations/UnityLogHandlerIntegration.cs +++ b/src/Sentry.Unity/Integrations/UnityLogHandlerIntegration.cs @@ -6,10 +6,12 @@ namespace Sentry.Unity.Integrations; +/// +/// Intercepts Unity's log handler to capture `Debug.LogException` calls with actual exception objects. +/// Other log types are handled by ApplicationLoggingIntegration. +/// internal sealed class UnityLogHandlerIntegration : ISdkIntegration, ILogHandler { - - private readonly IApplication _application; private IHub? _hub; @@ -73,12 +75,6 @@ internal void CaptureException(Exception exception, UnityEngine.Object? context) exception.Data[Mechanism.HandledKey] = false; exception.Data[Mechanism.MechanismKey] = "Unity.LogException"; _ = _hub.CaptureException(exception); - - if (_sentryOptions?.AddBreadcrumbsForLogType[LogType.Exception] is true) - { - // So the next event includes this error as a breadcrumb - _hub.AddBreadcrumb(message: $"{exception.GetType()}: {exception.Message}", category: "unity.logger", level: BreadcrumbLevel.Error); - } } public void LogFormat(LogType logType, UnityEngine.Object? context, string format, params object[] args) diff --git a/src/Sentry.Unity/ScriptableSentryUnityOptions.cs b/src/Sentry.Unity/ScriptableSentryUnityOptions.cs index 5e480ad5e..90e5808fb 100644 --- a/src/Sentry.Unity/ScriptableSentryUnityOptions.cs +++ b/src/Sentry.Unity/ScriptableSentryUnityOptions.cs @@ -62,7 +62,6 @@ public static string GetConfigPath(string? notDefaultConfigName = null) [field: SerializeField] public bool BreadcrumbsForWarnings { get; set; } = true; [field: SerializeField] public bool BreadcrumbsForAsserts { get; set; } = true; [field: SerializeField] public bool BreadcrumbsForErrors { get; set; } = true; - [field: SerializeField] public bool BreadcrumbsForExceptions { get; set; } = true; [field: SerializeField] public bool CaptureLogErrorEvents { get; set; } = true; [field: SerializeField] public int MaxBreadcrumbs { get; set; } = SentryConstants.DefaultMaxBreadcrumbs; @@ -207,7 +206,6 @@ internal SentryUnityOptions ToSentryUnityOptions( options.AddBreadcrumbsForLogType[LogType.Warning] = BreadcrumbsForWarnings; options.AddBreadcrumbsForLogType[LogType.Assert] = BreadcrumbsForAsserts; options.AddBreadcrumbsForLogType[LogType.Error] = BreadcrumbsForErrors; - options.AddBreadcrumbsForLogType[LogType.Exception] = BreadcrumbsForExceptions; options.FailedRequestStatusCodes = new List(); for (var i = 0; i < FailedRequestStatusCodes.Count; i += 2) diff --git a/src/Sentry.Unity/SentryUnityOptions.cs b/src/Sentry.Unity/SentryUnityOptions.cs index 9d5c05ec8..e0008f79c 100644 --- a/src/Sentry.Unity/SentryUnityOptions.cs +++ b/src/Sentry.Unity/SentryUnityOptions.cs @@ -388,7 +388,6 @@ internal SentryUnityOptions(IApplication? application = null, { LogType.Warning, true}, { LogType.Assert, true}, { LogType.Error, true}, - { LogType.Exception, true}, }; // Only assign the cache directory path if we're on a "known" platform. Accessing `Application.persistentDataPath` diff --git a/test/Sentry.Unity.Tests/UnityLogHandlerIntegrationTests.cs b/test/Sentry.Unity.Tests/UnityLogHandlerIntegrationTests.cs index a17a5a5d3..9070daa95 100644 --- a/test/Sentry.Unity.Tests/UnityLogHandlerIntegrationTests.cs +++ b/test/Sentry.Unity.Tests/UnityLogHandlerIntegrationTests.cs @@ -37,34 +37,6 @@ public void SetUp() }; } - [Test] - public void CaptureException_AddAsBreadcrumbEnabled_AddedAsBreadcrumb() - { - _fixture.SentryOptions.AddBreadcrumbsForLogType[LogType.Exception] = true; - var sut = _fixture.GetSut(); - var message = NUnit.Framework.TestContext.CurrentContext.Test.Name; - - sut.CaptureException(new Exception(message), null); - - var scope = new Scope(_fixture.SentryOptions); - _fixture.Hub.ConfigureScopeCalls.Single().Invoke(scope); - var breadcrumb = scope.Breadcrumbs.Single(); - - StringAssert.Contains(message, breadcrumb.Message); - } - - [Test] - public void CaptureException_AddAsBreadcrumbEnabled_NotAddedAsBreadcrumb() - { - _fixture.SentryOptions.AddBreadcrumbsForLogType[LogType.Exception] = false; - var sut = _fixture.GetSut(); - var message = NUnit.Framework.TestContext.CurrentContext.Test.Name; - - sut.CaptureException(new Exception("Test Exception"), null); - - Assert.IsFalse(_fixture.Hub.ConfigureScopeCalls.Count > 0); - } - [Test] public void CaptureException_ExceptionCapturedAndMechanismSet() { @@ -88,26 +60,6 @@ public void CaptureException_ExceptionCapturedAndMechanismSet() Assert.AreEqual("Unity.LogException", (string)capturedEvent.Exception!.Data[Mechanism.MechanismKey]); } - [Test] - public void CaptureException_CapturedExceptionAddedAsBreadcrumb() - { - var sut = _fixture.GetSut(); - var message = NUnit.Framework.TestContext.CurrentContext.Test.Name; - var exception = new Exception(message); - - sut.CaptureException(exception, null); - - Assert.AreEqual(1, _fixture.Hub.CapturedEvents.Count); // Sanity check - - var scope = new Scope(_fixture.SentryOptions); - _fixture.Hub.ConfigureScopeCalls.Single().Invoke(scope); - var breadcrumb = scope.Breadcrumbs.Single(); - - Assert.AreEqual(exception.GetType() + ": " + message, breadcrumb.Message); - Assert.AreEqual("unity.logger", breadcrumb.Category); - Assert.AreEqual(BreadcrumbLevel.Error, breadcrumb.Level); - } - [Test] public void Register_RegisteredASecondTime_LogsWarningAndReturns() {