diff --git a/CHANGELOG.md b/CHANGELOG.md index 5b713bbd8..ddb8abaa2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,11 @@ ## Unreleased +### API Changes + +- The Runtime- and BuildTime-Configuration have been merged into a single `OptionsConfiguration` script. This allows for programmatic configuration of the SDK in one place using precompile directives. Note, that the current limitation of options for Android and iOS being baked into the project at build time still remains. ([#1888](https://github.com/getsentry/sentry-unity/pull/1888)) +This is part of a larger effort to simplify the configuration of the native SDKs and enable users to modify their options at runtime. For more information see https://github.com/getsentry/sentry-unity/issues/1907 + ### Features - The SDK now provides a dedicated sentry-cli scriptable config, available on the `Debug Symbols` tab. This allows for programmatic configuration of the used cli-options during build. ([#1887](https://github.com/getsentry/sentry-unity/pull/1887)) diff --git a/modules/sentry-native b/modules/sentry-native index bf14b8533..0f98b0d69 160000 --- a/modules/sentry-native +++ b/modules/sentry-native @@ -1 +1 @@ -Subproject commit bf14b8533a3b26853e4e6fecf2f955deaa29e2d8 +Subproject commit 0f98b0d69c86ab26873899cbf532152656264790 diff --git a/samples/unity-of-bugs/Assets/Resources/Sentry/BuildTimeOptionsConfiguration.asset b/samples/unity-of-bugs/Assets/Resources/Sentry/BuildTimeOptionsConfiguration.asset deleted file mode 100644 index 28ee0cbc4..000000000 --- a/samples/unity-of-bugs/Assets/Resources/Sentry/BuildTimeOptionsConfiguration.asset +++ /dev/null @@ -1,14 +0,0 @@ -%YAML 1.1 -%TAG !u! tag:unity3d.com,2011: ---- !u!114 &11400000 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 59bc41c2bf823704a9122d2a5995ffcf, type: 3} - m_Name: BuildTimeOptionsConfiguration - m_EditorClassIdentifier: diff --git a/samples/unity-of-bugs/Assets/Resources/Sentry/RuntimeOptionsConfiguration.asset.meta b/samples/unity-of-bugs/Assets/Resources/Sentry/RuntimeOptionsConfiguration.asset.meta deleted file mode 100644 index 90305ae84..000000000 --- a/samples/unity-of-bugs/Assets/Resources/Sentry/RuntimeOptionsConfiguration.asset.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: f9a47e8442a604414a84d5ad6da6aa43 -NativeFormatImporter: - externalObjects: {} - mainObjectFileID: 11400000 - userData: - assetBundleName: - assetBundleVariant: diff --git a/samples/unity-of-bugs/Assets/Resources/Sentry/RuntimeOptionsConfiguration.asset b/samples/unity-of-bugs/Assets/Resources/Sentry/SentryOptionConfiguration.asset similarity index 71% rename from samples/unity-of-bugs/Assets/Resources/Sentry/RuntimeOptionsConfiguration.asset rename to samples/unity-of-bugs/Assets/Resources/Sentry/SentryOptionConfiguration.asset index 23cd0536e..dcbc3c583 100644 --- a/samples/unity-of-bugs/Assets/Resources/Sentry/RuntimeOptionsConfiguration.asset +++ b/samples/unity-of-bugs/Assets/Resources/Sentry/SentryOptionConfiguration.asset @@ -9,6 +9,6 @@ MonoBehaviour: m_GameObject: {fileID: 0} m_Enabled: 1 m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 91e386628575c034e89d0f7632eb69b8, type: 3} - m_Name: RuntimeOptionsConfiguration + m_Script: {fileID: 11500000, guid: 674e271c73eb944c58925ab47108ce41, type: 3} + m_Name: SentryOptionConfiguration m_EditorClassIdentifier: diff --git a/samples/unity-of-bugs/Assets/Resources/Sentry/BuildTimeOptionsConfiguration.asset.meta b/samples/unity-of-bugs/Assets/Resources/Sentry/SentryOptionConfiguration.asset.meta similarity index 79% rename from samples/unity-of-bugs/Assets/Resources/Sentry/BuildTimeOptionsConfiguration.asset.meta rename to samples/unity-of-bugs/Assets/Resources/Sentry/SentryOptionConfiguration.asset.meta index f9a4705f8..d9c32e664 100644 --- a/samples/unity-of-bugs/Assets/Resources/Sentry/BuildTimeOptionsConfiguration.asset.meta +++ b/samples/unity-of-bugs/Assets/Resources/Sentry/SentryOptionConfiguration.asset.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 1c61999bd2a61408393cfe218d42287e +guid: cea63afb7c75f429799422326f926abe NativeFormatImporter: externalObjects: {} mainObjectFileID: 11400000 diff --git a/samples/unity-of-bugs/Assets/Resources/Sentry/SentryOptions.asset b/samples/unity-of-bugs/Assets/Resources/Sentry/SentryOptions.asset index 0afef70c5..d8e4a0bfc 100644 --- a/samples/unity-of-bugs/Assets/Resources/Sentry/SentryOptions.asset +++ b/samples/unity-of-bugs/Assets/Resources/Sentry/SentryOptions.asset @@ -13,25 +13,25 @@ MonoBehaviour: m_Name: SentryOptions m_EditorClassIdentifier: k__BackingField: 1 - k__BackingField: https://e9ee299dbf554dfd930bc5f3c90d5d4b@o447951.ingest.sentry.io/4504604988538880 + k__BackingField: https://e9ee299dbf554dfd930bc5f3c90d5d4b@o447951.ingest.us.sentry.io/4504604988538880 k__BackingField: 1 k__BackingField: 0 k__BackingField: 1000 k__BackingField: 1000 k__BackingField: 1000 - k__BackingField: 1 + k__BackingField: 0 k__BackingField: 1 k__BackingField: 1 - k__BackingField: 1 + k__BackingField: 0 k__BackingField: 1 k__BackingField: 30000 k__BackingField: k__BackingField: k__BackingField: 0 - k__BackingField: 1 - k__BackingField: 2 + k__BackingField: 0 + k__BackingField: 1 k__BackingField: 75 - k__BackingField: 1 + k__BackingField: 0 k__BackingField: 100 k__BackingField: 20 k__BackingField: 10 @@ -46,25 +46,30 @@ MonoBehaviour: k__BackingField: 0 k__BackingField: 1 k__BackingField: 30 - k__BackingField: 2000 + k__BackingField: 0 k__BackingField: 1 k__BackingField: 2000 k__BackingField: 30 k__BackingField: 1 k__BackingField: 5000 + k__BackingField: 1 + k__BackingField: f401000057020000 k__BackingField: 1 k__BackingField: 1 k__BackingField: 1 k__BackingField: 1 k__BackingField: 1 + k__BackingField: 1 + k__BackingField: 1 + k__BackingField: 1 k__BackingField: 1 k__BackingField: 1 k__BackingField: 1 k__BackingField: 1 - k__BackingField: {fileID: 11400000, guid: f9a47e8442a604414a84d5ad6da6aa43, - type: 2} - k__BackingField: {fileID: 11400000, guid: 1c61999bd2a61408393cfe218d42287e, + k__BackingField: {fileID: 0} + k__BackingField: {fileID: 0} + k__BackingField: {fileID: 11400000, guid: cea63afb7c75f429799422326f926abe, type: 2} k__BackingField: 1 - k__BackingField: 0 - k__BackingField: 0 + k__BackingField: 1 + k__BackingField: 2 diff --git a/samples/unity-of-bugs/Assets/Scripts/BuildTimeConfiguration.cs b/samples/unity-of-bugs/Assets/Scripts/BuildTimeConfiguration.cs deleted file mode 100644 index 30b60fe5e..000000000 --- a/samples/unity-of-bugs/Assets/Scripts/BuildTimeConfiguration.cs +++ /dev/null @@ -1,22 +0,0 @@ -using UnityEngine; -using Sentry.Unity; - -[CreateAssetMenu(fileName = "Assets/Resources/Sentry/BuildTimeConfiguration.asset", menuName = "Sentry/BuildTimeConfiguration", order = 999)] -public class BuildTimeConfiguration : SentryBuildTimeOptionsConfiguration -{ - /// Called during app build. Changes made here will affect build-time processing, symbol upload, etc. - /// Additionally, because iOS, macOS and Android native error handling is configured at build time, - /// you can make changes to these options here. - /// Learn more at https://docs.sentry.io/platforms/unity/configuration/options/#programmatic-configuration - public override void Configure(SentryUnityOptions options, SentryCliOptions cliOptions) - { - Debug.Log(nameof(BuildTimeConfiguration) + "::Configure() called"); - - // Changes to the options object that will be used during build. - // This means you have access to the Sentry CLI options and also the options that affect the native layer - // on Android, iOS and macOS - // As an example: We use this as part of our integration tests here: https://github.com/getsentry/sentry-unity/blob/main/test/Scripts.Integration.Test/Editor/BuildTimeOptions.cs - - Debug.Log(nameof(BuildTimeConfiguration) + "::Configure() finished"); - } -} diff --git a/samples/unity-of-bugs/Assets/Scripts/BuildTimeConfiguration.cs.meta b/samples/unity-of-bugs/Assets/Scripts/BuildTimeConfiguration.cs.meta deleted file mode 100644 index 6720c826a..000000000 --- a/samples/unity-of-bugs/Assets/Scripts/BuildTimeConfiguration.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 59bc41c2bf823704a9122d2a5995ffcf -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/samples/unity-of-bugs/Assets/Scripts/Editor.meta b/samples/unity-of-bugs/Assets/Scripts/Editor.meta deleted file mode 100644 index fb22f471d..000000000 --- a/samples/unity-of-bugs/Assets/Scripts/Editor.meta +++ /dev/null @@ -1,3 +0,0 @@ -fileFormatVersion: 2 -guid: 094322ed9aa243c68f9d1a1374c21efa -timeCreated: 1702488552 \ No newline at end of file diff --git a/samples/unity-of-bugs/Assets/Scripts/RuntimeConfiguration.cs b/samples/unity-of-bugs/Assets/Scripts/RuntimeConfiguration.cs deleted file mode 100644 index ae63468b8..000000000 --- a/samples/unity-of-bugs/Assets/Scripts/RuntimeConfiguration.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Sentry; -using UnityEngine; -using Sentry.Unity; -using UnityEngine.SceneManagement; - -[CreateAssetMenu(fileName = "Assets/Resources/Sentry/RuntimeConfiguration.asset", menuName = "Sentry/RuntimeConfiguration", order = 999)] -public class RuntimeConfiguration : SentryRuntimeOptionsConfiguration -{ - /// Called at the player startup by SentryInitialization. - /// You can alter configuration for the C# error handling and also - /// native error handling in platforms **other** than iOS, macOS and Android. - /// Learn more at https://docs.sentry.io/platforms/unity/configuration/options/#programmatic-configuration - public override void Configure(SentryUnityOptions options) - { - // Note that changes to the options here will **not** affect iOS, macOS and Android events. (i.e. environment and release) - // Take a look at `SentryBuildTimeOptionsConfiguration` instead. - - Debug.Log(nameof(RuntimeConfiguration) + "::Configure() called"); - - // Making sure the SDK is not already initialized during tests - var sceneName = SceneManager.GetActiveScene().name; - if (sceneName != null && sceneName.Contains("TestScene")) - { - Debug.Log("Disabling the SDK while running tests."); - options.Enabled = false; - } - - // BeforeSend is only relevant at runtime. It wouldn't hurt to be set at build time, just wouldn't do anything. - options.SetBeforeSend((sentryEvent, _) => - { - if (sentryEvent.Tags.ContainsKey("SomeTag")) - { - // Don't send events with a tag SomeTag to Sentry - return null; - } - - return sentryEvent; - }); - - Debug.Log(nameof(RuntimeConfiguration) + "::Configure() finished"); - } -} diff --git a/samples/unity-of-bugs/Assets/Scripts/RuntimeConfiguration.cs.meta b/samples/unity-of-bugs/Assets/Scripts/RuntimeConfiguration.cs.meta deleted file mode 100644 index be1e4f4cd..000000000 --- a/samples/unity-of-bugs/Assets/Scripts/RuntimeConfiguration.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 91e386628575c034e89d0f7632eb69b8 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/samples/unity-of-bugs/Assets/Scripts/SentryCliConfiguration.cs.meta b/samples/unity-of-bugs/Assets/Scripts/SentryCliConfiguration.cs.meta index b9c9ff348..3dd26043f 100644 --- a/samples/unity-of-bugs/Assets/Scripts/SentryCliConfiguration.cs.meta +++ b/samples/unity-of-bugs/Assets/Scripts/SentryCliConfiguration.cs.meta @@ -1,2 +1,11 @@ fileFormatVersion: 2 -guid: be9687ec81ccb4180b0ed8c055df62d8 \ No newline at end of file +guid: be9687ec81ccb4180b0ed8c055df62d8 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/samples/unity-of-bugs/Assets/Scripts/SentryOptionConfiguration.cs b/samples/unity-of-bugs/Assets/Scripts/SentryOptionConfiguration.cs new file mode 100644 index 000000000..e6f33fce9 --- /dev/null +++ b/samples/unity-of-bugs/Assets/Scripts/SentryOptionConfiguration.cs @@ -0,0 +1,88 @@ +using Sentry.Unity; +using UnityEngine; +using UnityEngine.SceneManagement; + +public class SentryOptionConfiguration : SentryOptionsConfiguration +{ + public override void Configure(SentryUnityOptions options) + { + // Here you can programmatically modify the Sentry option properties used for the SDK's initialization + +#if UNITY_ANDROID || UNITY_IOS + // NOTE! + // On Android and iOS, ALL options configured here will be "baked" into the exported project + // during the build process. + // Changes to the options at runtime will not affect the native SDKs (Java, C/C++, Objective-C) + // and only apply to the C# layer. + + /* + * Sentry Unity SDK - Hybrid Architecture + * ====================================== + * + * Build Time Runtime + * ┌─────────────────────────┐ ┌─────────────────────────┐ + * │ Unity Editor │ │ Game Startup │ + * └──────────┬──────────────┘ └───────────┬─────────────┘ + * │ │ + * ▼ ▼ + * ┌────────────────────────────────────────────────────────────┐ + * │ Options Configuration │ + * │ (This Method) │ + * └─────────────────────────────┬──────────────────────────────┘ + * │ + * ┌───────────────────────────────────┐ + * │ Options used for Init │ + * ▼ ▼ + * ┌──────────────────────────┐ ┌──────────────────────┐ + * │ Native SDK │ │ Unity C# SDK │ + * │ Android & iOS │ │ Initialization │ + * │ ┌────────────────────┐ │ └──────────────────────┘ + * │ │ Options "Baked in" │ │ + * │ └────────────────────┘ │ + * │ The configure call made │ + * │ for this part ran on │ + * │ your build-machine │ + * └──────────────────────────┘ + * │ + * ▼ + * ┌──────────────────────────┐ + * │ Native SDK │ + * │ Android & iOS │ + * └──────────────────────────┘ + */ + + // Works as expected and will enable all debug logging + // options.Debug = true; + + // Will NOT work as expected. + // This will run twice. + // 1. Once during the build, being baked into the native SDKs + // 2. And a second time every time when the game starts + // options.Release = ComputeVersion(); +#endif + + Debug.Log("OptionConfigure started."); + + // Making sure the SDK is not already initialized during tests + var sceneName = SceneManager.GetActiveScene().name; + if (sceneName != null && sceneName.Contains("TestScene")) + { + Debug.Log("Disabling the SDK while running tests."); + options.Enabled = false; + } + + // BeforeSend is only relevant at runtime. It wouldn't hurt to be set at build time, just wouldn't do anything. + options.SetBeforeSend((sentryEvent, _) => + { + if (sentryEvent.Tags.ContainsKey("SomeTag")) + { + // Don't send events with a tag SomeTag to Sentry + return null; + } + + return sentryEvent; + }); + + Debug.Log("OptionConfigure finished."); + } +} diff --git a/samples/unity-of-bugs/Assets/Scripts/SentryOptionConfiguration.cs.meta b/samples/unity-of-bugs/Assets/Scripts/SentryOptionConfiguration.cs.meta new file mode 100644 index 000000000..691ab2a6d --- /dev/null +++ b/samples/unity-of-bugs/Assets/Scripts/SentryOptionConfiguration.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 674e271c73eb944c58925ab47108ce41 \ No newline at end of file diff --git a/src/Sentry.Unity.Editor/ConfigurationWindow/ConfigurationCreator.cs b/src/Sentry.Unity.Editor/ConfigurationWindow/ConfigurationCreator.cs index 757f9b804..b41aa5645 100644 --- a/src/Sentry.Unity.Editor/ConfigurationWindow/ConfigurationCreator.cs +++ b/src/Sentry.Unity.Editor/ConfigurationWindow/ConfigurationCreator.cs @@ -13,19 +13,26 @@ internal static class OptionsConfigurationItem public static T? Display(T? value, string fieldName, string scriptName, string toolTip) where T : ScriptableObject { - GUILayout.BeginHorizontal(); + EditorGUILayout.BeginHorizontal(); + var result = EditorGUILayout.ObjectField( new GUIContent(fieldName, toolTip), value, typeof(T), false ) as T; + if (GUILayout.Button("New", GUILayout.ExpandWidth(false))) { var t = typeof(T); if (t == typeof(SentryRuntimeOptionsConfiguration) || t == typeof(SentryBuildTimeOptionsConfiguration)) { - CreateDeprecatedConfigurationScript(fieldName, scriptName); + Debug.LogWarning("Runtime/BuildTime scriptable objects have been deprecated and will be removed in a future version." + + "Please use the 'Option Config Script' below."); + } + else if (t == typeof(SentryOptionsConfiguration)) + { + CreateConfigurationScript(fieldName, SentryOptionsConfiguration.Template, scriptName); } else if (t == typeof(SentryCliOptionsConfiguration)) { @@ -36,80 +43,13 @@ internal static class OptionsConfigurationItem throw new Exception("Attempting to create a new instance of unsupported type " + typeof(T).FullName); } } - GUILayout.EndHorizontal(); + + EditorGUILayout.EndHorizontal(); return result; } private static string SentryAssetPath(string scriptName) => $"Assets/Resources/Sentry/{scriptName}.asset"; - private static void CreateDeprecatedConfigurationScript(string fieldName, string scriptName) - { - const string directory = "Assets/Scripts"; - if (!AssetDatabase.IsValidFolder(directory)) - { - AssetDatabase.CreateFolder(Path.GetDirectoryName(directory), Path.GetFileName(directory)); - } - - var scriptPath = EditorUtility.SaveFilePanel(fieldName, directory, scriptName, "cs"); - if (string.IsNullOrEmpty(scriptPath)) - { - return; - } - - if (scriptPath.StartsWith(Application.dataPath)) - { - // AssetDatabase prefers a relative path - scriptPath = "Assets" + scriptPath.Substring(Application.dataPath.Length); - } - - scriptName = Path.GetFileNameWithoutExtension(scriptPath); - - var template = new StringBuilder(); - template.AppendLine("using UnityEngine;"); - template.AppendLine("using Sentry.Unity;"); - template.AppendLine(); - template.AppendFormat("[CreateAssetMenu(fileName = \"{0}\", menuName = \"Sentry/{1}\", order = 999)]\n", SentryAssetPath(scriptName), scriptName); - template.AppendFormat("public class {0} : {1}\n", scriptName, typeof(T).FullName); - template.AppendLine("{"); - - if (typeof(T) == typeof(SentryBuildTimeOptionsConfiguration)) - { - template.AppendLine(" /// Called during app build. Changes made here will affect build-time processing, symbol upload, etc."); - template.AppendLine(" /// Additionally, because iOS, macOS and Android native error handling is configured at build time,"); - template.AppendLine(" /// you can make changes to these options here."); - } - else - { - template.AppendLine(" /// Called at the player startup by SentryInitialization."); - template.AppendLine(" /// You can alter configuration for the C# error handling and also"); - template.AppendLine(" /// native error handling in platforms **other** than iOS, macOS and Android."); - } - - template.AppendLine(" /// Learn more at https://docs.sentry.io/platforms/unity/configuration/options/#programmatic-configuration"); - template.AppendFormat(" public override void Configure(SentryUnityOptions options{0})\n", - typeof(T) == typeof(SentryBuildTimeOptionsConfiguration) ? ", SentryCliOptions cliOptions" : ""); - template.AppendLine(" {"); - if (typeof(T) != typeof(SentryBuildTimeOptionsConfiguration)) - { - template.AppendLine(" // Note that changes to the options here will **not** affect iOS, macOS and Android events. (i.e. environment and release)"); - template.AppendLine(" // Take a look at `SentryBuildTimeOptionsConfiguration` instead."); - } - template.AppendLine(" // TODO implement"); - template.AppendLine(" }"); - template.AppendLine("}"); - - File.WriteAllText(scriptPath, template.ToString().Replace("\r\n", "\n")); - - // The created script has to be compiled and the scriptable object can't immediately be instantiated. - // So instead we work around this by setting a 'CreateScriptableObjectFlag' flag in the EditorPrefs to - // trigger the creation after the scripts reloaded. - EditorPrefs.SetBool(CreateScriptableObjectFlag, true); - EditorPrefs.SetString(ScriptNameKey, scriptName); - - AssetDatabase.ImportAsset(scriptPath); - Selection.activeObject = AssetDatabase.LoadAssetAtPath(scriptPath); - } - private static void CreateConfigurationScript(string fieldName, string template, string scriptName) { const string directory = "Assets/Scripts"; @@ -177,6 +117,9 @@ internal static void SetScript(string scriptNameWithoutExtension) case SentryBuildTimeOptionsConfiguration buildTimeConfiguration: options.BuildTimeOptionsConfiguration ??= buildTimeConfiguration; // Don't overwrite if already set break; + case SentryOptionsConfiguration configuration: + options.OptionsConfiguration ??= configuration; // Don't overwrite if already set + break; case SentryCliOptionsConfiguration cliConfiguration: cliOptions.CliOptionsConfiguration ??= cliConfiguration; // Don't overwrite if already set break; diff --git a/src/Sentry.Unity.Editor/ConfigurationWindow/OptionsConfigurationTab.cs b/src/Sentry.Unity.Editor/ConfigurationWindow/OptionsConfigurationTab.cs index 389f366d7..55bf05fd7 100644 --- a/src/Sentry.Unity.Editor/ConfigurationWindow/OptionsConfigurationTab.cs +++ b/src/Sentry.Unity.Editor/ConfigurationWindow/OptionsConfigurationTab.cs @@ -1,5 +1,3 @@ -using System.IO; -using System.Text; using UnityEditor; using UnityEngine; @@ -11,42 +9,60 @@ public static void Display(ScriptableSentryUnityOptions options) { GUILayout.Label("Scriptable Options Configuration", EditorStyles.boldLabel); - EditorGUILayout.Space(); - - EditorGUILayout.HelpBox( - "The scriptable options configuration allows you to programmatically modify Sentry options." + - "\n" + - "\n" + - "You can use the 'Runtime Configuration Script' to modify options just before Sentry SDK gets " + - "initialized. This allows you to access options and functionality otherwise unavailable from the " + - "Editor UI, e.g. set a custom BeforeSend callback." + - "\n" + - "\n" + - "Use the 'Build Time Configuration Script' in case you need to change build-time behavior, " + - "e.g. specify custom Sentry-CLI options or change settings for native SDKs that start before the " + - "managed layer does (such as Android, iOS, macOS).", - MessageType.Info); - EditorGUILayout.HelpBox("Clicking the 'New' button will prompt you with selecting a location for " + "your custom 'SentryConfiguration' script and automatically " + "create a new asset instance.", MessageType.Info); EditorGUILayout.Space(); - options.RuntimeOptionsConfiguration = OptionsConfigurationItem.Display( - options.RuntimeOptionsConfiguration, - "Runtime Configuration Script", - "SentryRuntimeConfiguration", - "A scriptable object that inherits from 'ScriptableOptionsConfiguration' " + - "and allows you to programmatically modify Sentry options." - ); + if (options.RuntimeOptionsConfiguration != null || options.BuildTimeOptionsConfiguration != null) + { + EditorGUILayout.BeginVertical("box"); + + EditorGUILayout.HelpBox( + "The Runtime/BuildTime scriptable objects have been deprecated and will be removed in a future version." + + "\nPlease use the 'Option Config Script' below." + + "\nInstead of implementing your configuration in two places you can control the options via precompile directives.", + MessageType.Warning); + + if (options.RuntimeOptionsConfiguration != null) + { + options.RuntimeOptionsConfiguration = OptionsConfigurationItem.Display( + options.RuntimeOptionsConfiguration, + "Runtime Config Script", + "SentryRuntimeConfiguration", + "DEPRECATED: A scriptable object that inherits from 'ScriptableOptionsConfiguration' " + + "and allows you to programmatically modify Sentry options."); + } - options.BuildTimeOptionsConfiguration = OptionsConfigurationItem.Display( - options.BuildTimeOptionsConfiguration, - "Build Time Configuration Script", - "SentryBuildTimeConfiguration", - "A scriptable object that inherits from 'ScriptableOptionsConfiguration' " + + if (options.BuildTimeOptionsConfiguration != null) + { + options.BuildTimeOptionsConfiguration = OptionsConfigurationItem.Display( + options.BuildTimeOptionsConfiguration, + "Build Time Config Script", + "SentryBuildTimeConfiguration", + "DEPRECATED: A scriptable object that inherits from 'ScriptableOptionsConfiguration' " + + "and allows you to programmatically modify Sentry options."); + } + + EditorGUILayout.EndVertical(); + + EditorGUILayout.Space(); + } + + EditorGUILayout.BeginVertical("box"); + + EditorGUILayout.HelpBox("The 'Option Config Script' allows you to programmatically configure and " + + "modify the options used by the Sentry SDK.", MessageType.Info); + + options.OptionsConfiguration = OptionsConfigurationItem.Display( + options.OptionsConfiguration, + "Option Config Script", + "SentryOptionConfiguration", + "A scriptable object that inherits from 'SentryOptionsConfiguration' " + "and allows you to programmatically modify Sentry options." ); + + EditorGUILayout.EndVertical(); } } diff --git a/src/Sentry.Unity.Editor/ConfigurationWindow/SentryEditorWindowInstrumentation.cs b/src/Sentry.Unity.Editor/ConfigurationWindow/SentryEditorWindowInstrumentation.cs index 81773234c..b7947ad2f 100644 --- a/src/Sentry.Unity.Editor/ConfigurationWindow/SentryEditorWindowInstrumentation.cs +++ b/src/Sentry.Unity.Editor/ConfigurationWindow/SentryEditorWindowInstrumentation.cs @@ -33,13 +33,19 @@ private static void ConfigureOptions(Dictionary args, [CallerMem Debug.LogFormat("{0}: Found SentryOptions", functionName); var value = ""; - if (args.TryGetValue("runtimeOptionsScript", out value)) + if (args.TryGetValue("deprecatedRuntimeOptionsScript", out value)) { Debug.LogFormat("{0}: Configuring Runtime Options Script to {1}", functionName, value); OptionsConfigurationItem.SetScript(value); } - if (args.TryGetValue("buildTimeOptionsScript", out value)) + if (args.TryGetValue("deprecatedBuildTimeOptionsScript", out value)) + { + Debug.LogFormat("{0}: Configuring Build Time Options Script to {1}", functionName, value); + OptionsConfigurationItem.SetScript(value); + } + + if (args.TryGetValue("optionsScript", out value)) { Debug.LogFormat("{0}: Configuring Build Time Options Script to {1}", functionName, value); OptionsConfigurationItem.SetScript(value); @@ -51,6 +57,12 @@ private static void ConfigureOptions(Dictionary args, [CallerMem cliOptions.UrlOverride = value; } + if (args.TryGetValue("cliOptionsScript", out value)) + { + Debug.LogFormat("{0}: Configuring CliOptions Script to {1}", functionName, value); + OptionsConfigurationItem.SetScript(value); + } + optionsWindow.Close(); Debug.LogFormat("{0}: SUCCESS", functionName); } diff --git a/src/Sentry.Unity.Editor/SentryScriptableObject.cs b/src/Sentry.Unity.Editor/SentryScriptableObject.cs index 2a64e6e52..7764c119f 100644 --- a/src/Sentry.Unity.Editor/SentryScriptableObject.cs +++ b/src/Sentry.Unity.Editor/SentryScriptableObject.cs @@ -37,12 +37,17 @@ internal static (SentryUnityOptions?, SentryCliOptions?) ConfiguredBuildTimeOpti if (scriptableOptions is not null) { options = scriptableOptions.ToSentryUnityOptions(isBuilding: true, unityInfo: null); + + // TODO: Move this into `Load` once we remove Runtime- and BuildTimeConfig + // We're calling `Configure` here and not in `Load` so the new Config does not overwrite the BuildTimeConfig + cliOptions?.CliOptionsConfiguration?.Configure(cliOptions); // Must be non-nullable in the interface otherwise Unity script compilation fails... cliOptions ??= ScriptableObject.CreateInstance(); - var setupScript = scriptableOptions.BuildTimeOptionsConfiguration; - if (setupScript != null) + + var deprecatedConfiguration = scriptableOptions.BuildTimeOptionsConfiguration; + if (deprecatedConfiguration != null) { - setupScript.Configure(options, cliOptions); + deprecatedConfiguration.Configure(options, cliOptions); } } diff --git a/src/Sentry.Unity/ScriptableSentryUnityOptions.cs b/src/Sentry.Unity/ScriptableSentryUnityOptions.cs index 72de8fb81..00ce0a66c 100644 --- a/src/Sentry.Unity/ScriptableSentryUnityOptions.cs +++ b/src/Sentry.Unity/ScriptableSentryUnityOptions.cs @@ -106,6 +106,7 @@ public static string GetConfigPath(string? notDefaultConfigName = null) [field: SerializeField] public SentryRuntimeOptionsConfiguration? RuntimeOptionsConfiguration { get; set; } [field: SerializeField] public SentryBuildTimeOptionsConfiguration? BuildTimeOptionsConfiguration { get; set; } + [field: SerializeField] public SentryOptionsConfiguration? OptionsConfiguration { get; set; } [field: SerializeField] public bool Debug { get; set; } = true; [field: SerializeField] public bool DebugOnlyInEditor { get; set; } = true; @@ -174,6 +175,7 @@ internal SentryUnityOptions ToSentryUnityOptions(bool isBuilding, ISentryUnityIn IosNativeSupportEnabled = IosNativeSupportEnabled, AndroidNativeSupportEnabled = AndroidNativeSupportEnabled, NdkIntegrationEnabled = NdkIntegrationEnabled, + NdkScopeSyncEnabled = NdkScopeSyncEnabled, WindowsNativeSupportEnabled = WindowsNativeSupportEnabled, MacosNativeSupportEnabled = MacosNativeSupportEnabled, LinuxNativeSupportEnabled = LinuxNativeSupportEnabled, @@ -206,6 +208,9 @@ internal SentryUnityOptions ToSentryUnityOptions(bool isBuilding, ISentryUnityIn options.SetupLogging(); + OptionsConfiguration?.Configure(options); + + // TODO: Deprecated and to be removed in the next major if (RuntimeOptionsConfiguration != null && !isBuilding) { // This has to happen in between options object creation and updating the options based on programmatic changes diff --git a/src/Sentry.Unity/SentryOptionsConfiguration.cs b/src/Sentry.Unity/SentryOptionsConfiguration.cs new file mode 100644 index 000000000..adc249d99 --- /dev/null +++ b/src/Sentry.Unity/SentryOptionsConfiguration.cs @@ -0,0 +1,77 @@ +using UnityEngine; + +namespace Sentry.Unity; + +public abstract class SentryOptionsConfiguration : ScriptableObject +{ + public static readonly string Template = + """ + using Sentry.Unity; + + public class {{ScriptName}} : SentryOptionsConfiguration + { + public override void Configure(SentryUnityOptions options) + { + // Here you can programmatically modify the Sentry option properties used for the SDK's initialization + + #if UNITY_ANDROID || UNITY_IOS + // NOTE! + // On Android and iOS, ALL options configured here will be "baked" into the exported project + // during the build process. + // Changes to the options at runtime will not affect the native SDKs (Java, C/C++, Objective-C) + // and only apply to the C# layer. + + /* + * Sentry Unity SDK - Hybrid Architecture + * ====================================== + * + * Build Time Runtime + * ┌─────────────────────────┐ ┌─────────────────────────┐ + * │ Unity Editor │ │ Game Startup │ + * └──────────┬──────────────┘ └───────────┬─────────────┘ + * │ │ + * ▼ ▼ + * ┌────────────────────────────────────────────────────────────┐ + * │ Options Configuration │ + * │ (This Method) │ + * └─────────────────────────────┬──────────────────────────────┘ + * │ + * ┌───────────────────────────────────┐ + * │ Options used for Init │ + * ▼ ▼ + * ┌──────────────────────────┐ ┌──────────────────────┐ + * │ Native SDK │ │ Unity C# SDK │ + * │ Android & iOS │ │ Initialization │ + * │ ┌────────────────────┐ │ └──────────────────────┘ + * │ │ Options "Baked in" │ │ + * │ └────────────────────┘ │ + * │ The configure call made │ + * │ for this part ran on │ + * │ your build-machine │ + * └──────────────────────────┘ + * │ + * ▼ + * ┌──────────────────────────┐ + * │ Native SDK │ + * │ Android & iOS │ + * └──────────────────────────┘ + */ + + // Works as expected and will enable all debug logging + // options.Debug = true; + + // Will NOT work as expected. + // This will run twice. + // 1. Once during the build, being baked into the native SDKs + // 2. And a second time every time when the game starts + // options.Release = ComputeVersion(); + #endif + } + } + """; + + /// + /// Called during build and during the game's startup to configure the options used to initialize the SDK + /// + public abstract void Configure(SentryUnityOptions options); +} diff --git a/test/Scripts.Integration.Test/Editor/BuildTimeOptions.cs b/test/Scripts.Integration.Test/Editor/BuildTimeOptions.cs index ba59364d0..4416e85cc 100644 --- a/test/Scripts.Integration.Test/Editor/BuildTimeOptions.cs +++ b/test/Scripts.Integration.Test/Editor/BuildTimeOptions.cs @@ -3,6 +3,7 @@ using Sentry.Unity.Editor; using UnityEngine; using UnityEditor; +using UnityEngine.Assertions; [CreateAssetMenu(fileName = "Assets/Resources/Sentry/BuildTimeOptions.cs", menuName = "Sentry/BuildTimeOptions", order = 999)] public class BuildTimeOptions : SentryBuildTimeOptionsConfiguration @@ -11,33 +12,10 @@ public override void Configure(SentryUnityOptions options, SentryCliOptions cliO { Debug.Log("Sentry: BuildTimeOptions::Configure() called"); - switch (EditorUserBuildSettings.selectedBuildTargetGroup) - { - case BuildTargetGroup.Android: - options.Dsn = "http://publickey@10.0.2.2:8000/12345"; - break; - case BuildTargetGroup.WebGL: - options.Dsn = "http://publickey@127.0.0.1:8000/12345"; - break; - default: - options.Dsn = "http://publickey@localhost:8000/12345"; - break; - } - - Debug.LogFormat("Sentry: Setting options.Dsn = {0}", options.Dsn); - - options.Il2CppLineNumberSupportEnabled = true; - options.Debug = true; - options.DiagnosticLevel = SentryLevel.Debug; - options.TracesSampleRate = 1.0d; - options.PerformanceAutoInstrumentationEnabled = true; - - cliOptions.UploadSymbols = !string.IsNullOrEmpty(cliOptions.UrlOverride); - cliOptions.UploadSources = cliOptions.UploadSymbols; - cliOptions.Organization = "sentry-sdks"; - cliOptions.Project = "sentry-unity"; - cliOptions.Auth = "dummy-token"; - + // Make sure the config is still called and the DSN has been set + Assert.IsFalse(string.IsNullOrWhiteSpace(options.Dsn)); + Assert.IsFalse(string.IsNullOrWhiteSpace(cliOptions.Auth)); + Debug.Log("Sentry: BuildTimeOptions::Configure() finished"); } } diff --git a/test/Scripts.Integration.Test/Scripts/CliConfiguration.cs b/test/Scripts.Integration.Test/Scripts/CliConfiguration.cs new file mode 100644 index 000000000..95b6ed321 --- /dev/null +++ b/test/Scripts.Integration.Test/Scripts/CliConfiguration.cs @@ -0,0 +1,20 @@ +using System; +using Sentry.Unity; +using UnityEngine; +using UnityEngine.Assertions; + +public class CliConfiguration : SentryCliOptionsConfiguration +{ + public override void Configure(SentryCliOptions cliOptions) + { + Debug.Log("Sentry: CliConfiguration::Configure() called"); + + cliOptions.UploadSymbols = !string.IsNullOrEmpty(cliOptions.UrlOverride); + cliOptions.UploadSources = cliOptions.UploadSymbols; + cliOptions.Organization = "sentry-sdks"; + cliOptions.Project = "sentry-unity"; + cliOptions.Auth = "dummy-token"; + + Debug.Log("Sentry: CliConfiguration::Configure() finished"); + } +} diff --git a/test/Scripts.Integration.Test/Scripts/OptionsConfiguration.cs b/test/Scripts.Integration.Test/Scripts/OptionsConfiguration.cs new file mode 100644 index 000000000..621d182b7 --- /dev/null +++ b/test/Scripts.Integration.Test/Scripts/OptionsConfiguration.cs @@ -0,0 +1,45 @@ +using Sentry; +using Sentry.Unity; +using UnityEngine; + +public class OptionsConfiguration : SentryOptionsConfiguration +{ + public override void Configure(SentryUnityOptions options) + { + Debug.Log("Sentry: OptionsConfig::Configure() called"); + + options.Dsn = "http://publickey@" +#if UNITY_ANDROID + + "10.0.2.2" +#elif UNITY_WEBGL + + "127.0.0.1" +#else + + "localhost" +#endif + + ":8000/12345"; + + Debug.LogFormat("Sentry: Setting options.Dsn = {0}", options.Dsn); + + options.AttachScreenshot = true; + options.Il2CppLineNumberSupportEnabled = true; + options.Debug = true; + options.DiagnosticLevel = SentryLevel.Debug; + options.TracesSampleRate = 1.0d; + options.PerformanceAutoInstrumentationEnabled = true; + + options.CreateHttpMessageHandler = () => SmokeTester.t; + SmokeTester.CrashedLastRun = () => + { + if (options.CrashedLastRun != null) + { + return options.CrashedLastRun() ? 1 : 0; + } + return -2; + }; + + // If an ANR triggers while the smoke test runs, the test would fail because we expect exact order of events. + options.DisableAnrIntegration(); + + Debug.Log("Sentry: BuildTimeOptions::Configure() finished"); + } +} diff --git a/test/Scripts.Integration.Test/Scripts/RuntimeOptions.cs b/test/Scripts.Integration.Test/Scripts/RuntimeOptions.cs index 1f30128ba..5a9d7ee6d 100644 --- a/test/Scripts.Integration.Test/Scripts/RuntimeOptions.cs +++ b/test/Scripts.Integration.Test/Scripts/RuntimeOptions.cs @@ -1,6 +1,7 @@ using Sentry; using Sentry.Unity; using UnityEngine; +using UnityEngine.Assertions; [CreateAssetMenu(fileName = "Assets/Resources/Sentry/RuntimeOptions.cs", menuName = "Sentry/RuntimeOptions", order = 999)] public class RuntimeOptions : SentryRuntimeOptionsConfiguration @@ -9,36 +10,8 @@ public override void Configure(SentryUnityOptions options) { Debug.Log("Sentry: RuntimeOptions::Configure() called"); - options.Dsn = string.Format("http://publickey@{0}:8000/12345", -#if UNITY_ANDROID - "10.0.2.2"); -#elif UNITY_WEBGL - "127.0.0.1"); -#else - "localhost"); -#endif - - Debug.LogFormat("Sentry: Setting options.Dsn = {0}", options.Dsn); - - options.AttachScreenshot = true; - options.Il2CppLineNumberSupportEnabled = true; - options.Debug = true; - options.DiagnosticLevel = SentryLevel.Debug; - options.TracesSampleRate = 1.0d; - options.PerformanceAutoInstrumentationEnabled = true; - - options.CreateHttpMessageHandler = () => SmokeTester.t; - SmokeTester.CrashedLastRun = () => - { - if (options.CrashedLastRun != null) - { - return options.CrashedLastRun() ? 1 : 0; - } - return -2; - }; - - // If an ANR triggers while the smoke test runs, the test would fail because we expect exact order of events. - options.DisableAnrIntegration(); + // Make sure the config is still called and the DSN has been set + Assert.IsFalse(string.IsNullOrWhiteSpace(options.Dsn)); Debug.Log("Sentry: RuntimeOptions::Configure() finished"); } diff --git a/test/Scripts.Integration.Test/configure-sentry.ps1 b/test/Scripts.Integration.Test/configure-sentry.ps1 index a6ee351d6..eb366437f 100644 --- a/test/Scripts.Integration.Test/configure-sentry.ps1 +++ b/test/Scripts.Integration.Test/configure-sentry.ps1 @@ -16,8 +16,10 @@ $UnityPath = FormatUnityPath $UnityPath $unityArgs = @( ` "-quit", "-batchmode", "-nographics", "-disable-assembly-updater", "-projectPath ", $(GetNewProjectPath), ` "-executeMethod", "Sentry.Unity.Editor.ConfigurationWindow.SentryEditorWindowInstrumentation.ConfigureOptions", ` - "-buildTimeOptionsScript", "BuildTimeOptions", ` - "-runtimeOptionsScript", "RuntimeOptions", ` + "-deprecatedBuildTimeOptionsScript", "BuildTimeOptions", ` + "-deprecatedRuntimeOptionsScript", "RuntimeOptions", ` + "-optionsScript", "OptionsConfiguration", ` + "-cliOptionsScript", "CliConfiguration", ` "-cliOptions.UrlOverride", ($CheckSymbols ? (SymbolServerUrlFor $UnityPath $Platform) : "") ) RunUnityAndExpect $UnityPath "ConfigureSentryOptions" "ConfigureOptions: SUCCESS" $unityArgs diff --git a/test/Scripts.Tests/package-release.zip.snapshot b/test/Scripts.Tests/package-release.zip.snapshot index 6120ced79..23d0d0a13 100644 --- a/test/Scripts.Tests/package-release.zip.snapshot +++ b/test/Scripts.Tests/package-release.zip.snapshot @@ -1373,15 +1373,13 @@ Samples~/unity-of-bugs/Scripts/AdditionalButtons.cs Samples~/unity-of-bugs/Scripts/AdditionalButtons.cs.meta Samples~/unity-of-bugs/Scripts/BugFarmButtons.cs Samples~/unity-of-bugs/Scripts/BugFarmButtons.cs.meta -Samples~/unity-of-bugs/Scripts/BuildTimeConfiguration.cs -Samples~/unity-of-bugs/Scripts/BuildTimeConfiguration.cs.meta Samples~/unity-of-bugs/Scripts/NativeSupport.meta -Samples~/unity-of-bugs/Scripts/RuntimeConfiguration.cs -Samples~/unity-of-bugs/Scripts/RuntimeConfiguration.cs.meta Samples~/unity-of-bugs/Scripts/SceneButtons.cs Samples~/unity-of-bugs/Scripts/SceneButtons.cs.meta Samples~/unity-of-bugs/Scripts/SentryCliConfiguration.cs Samples~/unity-of-bugs/Scripts/SentryCliConfiguration.cs.meta +Samples~/unity-of-bugs/Scripts/SentryOptionConfiguration.cs +Samples~/unity-of-bugs/Scripts/SentryOptionConfiguration.cs.meta Samples~/unity-of-bugs/Scripts/ThreadingSamples.cs Samples~/unity-of-bugs/Scripts/ThreadingSamples.cs.meta Samples~/unity-of-bugs/Scripts/NativeSupport/AndroidButtons.cs