public AndroidManifestConfiguration() : this(() => ScriptableSentryUnityOptions.LoadSentryUnityOptions(BuildPipeline.isBuildingPlayer), () => SentryCliOptions.LoadCliOptions(), isDevelopmentBuild : EditorUserBuildSettings.development, scriptingImplementation : PlayerSettings.GetScriptingBackend(BuildTargetGroup.Android)) { }
public IEnumerator BugFarmScene_MultipleSentryInit_SendEventForTheLatest() { yield return(SetupSceneCoroutine("1_BugFarm")); // We should use the sample Dsn for the nextDsn // to avoid static dsn. var options = AssetDatabase.LoadAssetAtPath(ScriptableSentryUnityOptions.GetConfigPath(ScriptableSentryUnityOptions.ConfigName), typeof(ScriptableSentryUnityOptions)) as ScriptableSentryUnityOptions; var sourceEventCapture = new TestEventCapture(); var sourceDsn = "https://[email protected]/5439417"; using var firstDisposable = InitSentrySdk(o => { o.Dsn = sourceDsn; o.AddIntegration(new UnityApplicationLoggingIntegration(eventCapture: sourceEventCapture)); }); var nextEventCapture = new TestEventCapture(); var nextDsn = options?.Dsn; using var secondDisposable = InitSentrySdk(o => { o.Dsn = nextDsn; o.AddIntegration(new UnityApplicationLoggingIntegration(eventCapture: nextEventCapture)); }); var testBehaviour = new GameObject("TestHolder").AddComponent <TestMonoBehaviour>(); testBehaviour.gameObject.SendMessage(nameof(testBehaviour.TestException)); Assert.NotNull(nextDsn); Assert.AreEqual(0, sourceEventCapture.Events.Count, sourceDsn); Assert.AreEqual(1, nextEventCapture.Events.Count); }
internal static void ToScriptableOptions(TextAsset sentryOptionsTextAsset, ScriptableSentryUnityOptions scriptableOptions) { var jsonOptions = LoadFromJson(sentryOptionsTextAsset); scriptableOptions.Enabled = jsonOptions.Enabled; if (jsonOptions.Dsn is { } dsn) { scriptableOptions.Dsn = dsn; } scriptableOptions.CaptureInEditor = jsonOptions.CaptureInEditor; scriptableOptions.Debug = jsonOptions.Debug; scriptableOptions.DebugOnlyInEditor = jsonOptions.DebugOnlyInEditor; scriptableOptions.DiagnosticLevel = jsonOptions.DiagnosticLevel; scriptableOptions.AttachStacktrace = jsonOptions.AttachStacktrace; if (jsonOptions.SampleRate is { } sampleRate) { scriptableOptions.SampleRate = sampleRate; } if (jsonOptions.Release is { } release) { scriptableOptions.ReleaseOverride = release; } if (jsonOptions.Environment is { } environment) { scriptableOptions.EnvironmentOverride = environment; } }
internal static void Display(ScriptableSentryUnityOptions options) { GUILayout.Label("Base Options", EditorStyles.boldLabel); options.Dsn = EditorGUILayout.TextField( new GUIContent("DSN", "The URL to your Sentry project. " + "Get yours on sentry.io -> Project Settings."), options.Dsn)?.Trim(); options.CaptureInEditor = EditorGUILayout.Toggle( new GUIContent("Capture In Editor", "Capture errors while running in the Editor."), options.CaptureInEditor); options.EnableLogDebouncing = EditorGUILayout.Toggle( new GUIContent("Enable Log Debouncing", "The SDK debounces log messages of the same type if " + "they are more frequent than once per second."), options.EnableLogDebouncing); EditorGUILayout.Space(); EditorGUI.DrawRect(EditorGUILayout.GetControlRect(false, 1), Color.gray); EditorGUILayout.Space(); GUILayout.Label("Tracing - Performance Monitoring", EditorStyles.boldLabel); options.TracesSampleRate = EditorGUILayout.Slider( new GUIContent("Traces Sample Rate", "Indicates the percentage of transactions that are " + "captured. Setting this to 0 discards all trace data. " + "Setting this to 1.0 captures all."), (float)options.TracesSampleRate, 0.0f, 1.0f); }
public void ToSentryUnityOptions_ValueMapping_AreEqual(bool isBuilding, bool enableOfflineCaching) { var expectedOptions = new SentryUnityOptions { Enabled = false, Dsn = "test", CaptureInEditor = false, EnableLogDebouncing = true, TracesSampleRate = 1.0f, AutoSessionTracking = false, AutoSessionTrackingInterval = TimeSpan.FromSeconds(1), AttachStacktrace = true, MaxBreadcrumbs = 1, ReportAssembliesMode = ReportAssembliesMode.None, SendDefaultPii = true, IsEnvironmentUser = true, MaxCacheItems = 1, CacheDirectoryPath = enableOfflineCaching ? _fixture.Application.PersistentDataPath : null, InitCacheFlushTimeout = TimeSpan.FromSeconds(1), SampleRate = 0.5f, ShutdownTimeout = TimeSpan.FromSeconds(1), MaxQueueItems = 1, Release = "testRelease", Environment = "testEnvironment", Debug = true, DebugOnlyInEditor = true, DiagnosticLevel = SentryLevel.Info, }; var scriptableOptions = ScriptableObject.CreateInstance <ScriptableSentryUnityOptions>(); scriptableOptions.Enabled = expectedOptions.Enabled; scriptableOptions.Dsn = expectedOptions.Dsn; scriptableOptions.CaptureInEditor = expectedOptions.CaptureInEditor; scriptableOptions.EnableLogDebouncing = expectedOptions.EnableLogDebouncing; scriptableOptions.TracesSampleRate = expectedOptions.TracesSampleRate; scriptableOptions.AutoSessionTracking = expectedOptions.AutoSessionTracking; scriptableOptions.AutoSessionTrackingInterval = (int)expectedOptions.AutoSessionTrackingInterval.TotalMilliseconds; scriptableOptions.AttachStacktrace = expectedOptions.AttachStacktrace; scriptableOptions.MaxBreadcrumbs = expectedOptions.MaxBreadcrumbs; scriptableOptions.ReportAssembliesMode = expectedOptions.ReportAssembliesMode; scriptableOptions.SendDefaultPii = expectedOptions.SendDefaultPii; scriptableOptions.IsEnvironmentUser = expectedOptions.IsEnvironmentUser; scriptableOptions.MaxCacheItems = expectedOptions.MaxCacheItems; scriptableOptions.EnableOfflineCaching = enableOfflineCaching; scriptableOptions.InitCacheFlushTimeout = (int)expectedOptions.InitCacheFlushTimeout.TotalMilliseconds; scriptableOptions.SampleRate = expectedOptions.SampleRate; scriptableOptions.ShutdownTimeout = (int)expectedOptions.ShutdownTimeout.TotalMilliseconds; scriptableOptions.MaxQueueItems = expectedOptions.MaxQueueItems; scriptableOptions.ReleaseOverride = expectedOptions.Release; scriptableOptions.EnvironmentOverride = expectedOptions.Environment; scriptableOptions.Debug = expectedOptions.Debug; scriptableOptions.DebugOnlyInEditor = expectedOptions.DebugOnlyInEditor; scriptableOptions.DiagnosticLevel = expectedOptions.DiagnosticLevel; var optionsActual = ScriptableSentryUnityOptions.ToSentryUnityOptions(scriptableOptions, isBuilding, _fixture.Application); AssertOptions(expectedOptions, optionsActual); }
internal static void Display(ScriptableSentryUnityOptions options) { options.Debug = EditorGUILayout.BeginToggleGroup( new GUIContent("Enable Debug Output", "Whether the Sentry SDK should print its " + "diagnostic logs to the console."), options.Debug); options.DebugOnlyInEditor = EditorGUILayout.Toggle( new GUIContent("Only In Editor", "Only print logs when in the editor. Development " + "builds of the player will not include Sentry's SDK diagnostics."), options.DebugOnlyInEditor); options.DiagnosticLevel = (SentryLevel)EditorGUILayout.EnumPopup( new GUIContent("Verbosity Level", "The minimum level allowed to be printed to the console. " + "Log messages with a level below this level are dropped."), options.DiagnosticLevel); EditorGUILayout.EndToggleGroup(); EditorGUILayout.Space(); EditorGUI.DrawRect(EditorGUILayout.GetControlRect(false, 1), Color.gray); EditorGUILayout.Space(); options.AutoSessionTracking = EditorGUILayout.BeginToggleGroup( new GUIContent("Auto Session Tracking", "Whether the SDK should start and end sessions " + "automatically. If the timeout is reached the old session will" + "be ended and a new one started."), options.AutoSessionTracking); options.AutoSessionTrackingInterval = EditorGUILayout.IntField( new GUIContent("Session Timeout [ms]", "The duration of time a session can stay paused " + "(i.e. the application has been put in the background) before " + "it is considered ended."), options.AutoSessionTrackingInterval); options.AutoSessionTrackingInterval = Mathf.Max(0, options.AutoSessionTrackingInterval); EditorGUILayout.EndToggleGroup(); EditorGUILayout.Space(); EditorGUI.DrawRect(EditorGUILayout.GetControlRect(false, 1), Color.gray); EditorGUILayout.Space(); GUILayout.Label("Native Support", EditorStyles.boldLabel); options.IosNativeSupportEnabled = EditorGUILayout.Toggle( new GUIContent("iOS Native Support", "Whether to enable Native iOS support to capture" + "errors written in languages such as Objective-C, Swift, C and C++."), options.IosNativeSupportEnabled); options.AndroidNativeSupportEnabled = EditorGUILayout.Toggle( new GUIContent("Android Native Support", "Whether to enable Native Android support to " + "capture errors written in languages such as Java, Kotlin, C and C++."), options.AndroidNativeSupportEnabled); options.WindowsNativeSupportEnabled = EditorGUILayout.Toggle( new GUIContent("Windows Native Support", "Whether to enable Native Windows support to " + "capture errors written in languages such as C and C++."), options.WindowsNativeSupportEnabled); }
internal static void Display(ScriptableSentryUnityOptions options) { options.EnableOfflineCaching = EditorGUILayout.BeginToggleGroup( new GUIContent("Enable Offline Caching", ""), options.EnableOfflineCaching); options.MaxCacheItems = EditorGUILayout.IntField( new GUIContent("Max Cache Items", "The maximum number of files to keep in the disk cache. " + "The SDK deletes the oldest when the limit is reached.\nDefault: 30"), options.MaxCacheItems); options.MaxCacheItems = Math.Max(0, options.MaxCacheItems); options.InitCacheFlushTimeout = EditorGUILayout.IntField( new GUIContent("Init Flush Timeout [ms]", "The timeout that limits how long the SDK " + "will attempt to flush existing cache during initialization, " + "potentially slowing down app start up to the specified time." + "\nThis features allows capturing errors that happen during " + "game startup and would not be captured because the process " + "would be killed before Sentry had a chance to capture the event."), options.InitCacheFlushTimeout); options.InitCacheFlushTimeout = Math.Max(0, options.InitCacheFlushTimeout); EditorGUILayout.EndToggleGroup(); EditorGUILayout.Space(); EditorGUI.DrawRect(EditorGUILayout.GetControlRect(false, 1), Color.gray); EditorGUILayout.Space(); // Options.RequestBodyCompressionLevel = (CompressionLevelWithAuto)EditorGUILayout.EnumPopup( // new GUIContent("Compress Payload", "The level of which to compress the Sentry event " + // "before sending to Sentry."), // Options.RequestBodyCompressionLevel); var sampleRate = options.SampleRate ??= 1.0f; sampleRate = EditorGUILayout.Slider( new GUIContent("Event Sample Rate", "Indicates the percentage of events that are " + "captured. Setting this to 0.1 captures 10% of events. " + "Setting this to 1.0 captures all events." + "\nThis affects only errors and logs, not performance " + "(transactions) data. See TraceSampleRate for that."), sampleRate, 0.01f, 1); options.SampleRate = (sampleRate < 1.0f) ? sampleRate : null; options.ShutdownTimeout = EditorGUILayout.IntField( new GUIContent("Shut Down Timeout [ms]", "How many seconds to wait before shutting down to " + "give Sentry time to send events from the background queue."), options.ShutdownTimeout); options.ShutdownTimeout = Mathf.Clamp(options.ShutdownTimeout, 0, int.MaxValue); options.MaxQueueItems = EditorGUILayout.IntField( new GUIContent("Max Queue Items", "The maximum number of events to keep in memory while " + "the worker attempts to send them."), options.MaxQueueItems ); options.MaxQueueItems = Math.Max(0, options.MaxQueueItems); }
public void ToSentryUnityOptions_HasOptionsConfiguration_GetsCalled(bool isBuilding) { var optionsConfiguration = ScriptableObject.CreateInstance <TestOptionsConfiguration>(); var scriptableOptions = ScriptableObject.CreateInstance <ScriptableSentryUnityOptions>(); scriptableOptions.OptionsConfiguration = optionsConfiguration; ScriptableSentryUnityOptions.ToSentryUnityOptions(scriptableOptions, isBuilding); Assert.IsTrue(optionsConfiguration.GotCalled); }
public static void OnPostProcessBuild(BuildTarget target, string pathToProject) { if (target != BuildTarget.iOS) { return; } var options = ScriptableSentryUnityOptions.LoadSentryUnityOptions(BuildPipeline.isBuildingPlayer); var logger = options?.DiagnosticLogger ?? new UnityLogger(new SentryUnityOptions()); try { // Unity doesn't allow an appending builds when switching iOS SDK versions and this will make sure we always copy the correct version of the Sentry.framework var frameworkDirectory = PlayerSettings.iOS.sdkVersion == iOSSdkVersion.DeviceSDK ? "Device" : "Simulator"; var frameworkPath = Path.GetFullPath(Path.Combine("Packages", SentryPackageInfo.GetName(), "Plugins", "iOS", frameworkDirectory, "Sentry.framework")); CopyFramework(frameworkPath, Path.Combine(pathToProject, "Frameworks", "Sentry.framework"), options?.DiagnosticLogger); var nativeBridgePath = Path.GetFullPath(Path.Combine("Packages", SentryPackageInfo.GetName(), "Plugins", "iOS", "SentryNativeBridge.m")); CopyFile(nativeBridgePath, Path.Combine(pathToProject, "Libraries", SentryPackageInfo.GetName(), "SentryNativeBridge.m"), options?.DiagnosticLogger); using var sentryXcodeProject = SentryXcodeProject.Open(pathToProject); sentryXcodeProject.AddSentryFramework(); sentryXcodeProject.AddSentryNativeBridge(); if (options?.IsValid() is not true) { logger.LogWarning("Failed to validate Sentry Options. Native support disabled."); return; } if (!options.IosNativeSupportEnabled) { logger.LogDebug("iOS Native support disabled through the options."); return; } sentryXcodeProject.AddNativeOptions(options); sentryXcodeProject.AddSentryToMain(options); var sentryCliOptions = SentryCliOptions.LoadCliOptions(); if (sentryCliOptions.IsValid(logger)) { SentryCli.CreateSentryProperties(pathToProject, sentryCliOptions); SentryCli.AddExecutableToXcodeProject(pathToProject, logger); sentryXcodeProject.AddBuildPhaseSymbolUpload(logger); } } catch (Exception e) { logger.LogError("Failed to add the Sentry framework to the generated Xcode project", e); } }
private ScriptableSentryUnityOptions LoadOptions() { var options = AssetDatabase.LoadAssetAtPath( ScriptableSentryUnityOptions.GetConfigPath(SentryOptionsAssetName), typeof(ScriptableSentryUnityOptions)) as ScriptableSentryUnityOptions; if (options is null) { options = CreateOptions(SentryOptionsAssetName); } return(options); }
public void ToScriptableOptions_ConvertJsonOptions_AreEqual(bool isBuilding) { var jsonTextAsset = new TextAsset(File.ReadAllText(GetTestOptionsFilePath())); var expectedOptions = JsonSentryUnityOptions.LoadFromJson(jsonTextAsset); var scriptableOptions = ScriptableObject.CreateInstance <ScriptableSentryUnityOptions>(); SentryOptionsUtility.SetDefaults(scriptableOptions); JsonSentryUnityOptions.ToScriptableOptions(jsonTextAsset, scriptableOptions); var actualOptions = ScriptableSentryUnityOptions.ToSentryUnityOptions(scriptableOptions, isBuilding); AssertOptions(expectedOptions, actualOptions); }
public void Setup() { var options = AssetDatabase.LoadAssetAtPath(ScriptableSentryUnityOptions.GetConfigPath(ScriptableSentryUnityOptions.ConfigName), typeof(ScriptableSentryUnityOptions)) as ScriptableSentryUnityOptions; if (options?.Enabled != true) { return; } Debug.Log("Disabling local options for the duration of the test."); _optionsToRestore = options; _optionsToRestore.Enabled = false; }
public static void Display(ScriptableSentryUnityOptions options) { GUILayout.BeginHorizontal(); options.OptionsConfiguration = EditorGUILayout.ObjectField( new GUIContent(".NET (C#)", "A scriptable object that inherits from " + "'ScriptableOptionsConfiguration' and allows you to " + "programmatically modify Sentry options."), options.OptionsConfiguration, typeof(ScriptableOptionsConfiguration), false) as ScriptableOptionsConfiguration; if (GUILayout.Button("New", GUILayout.ExpandWidth(false))) { CreateScript(); } GUILayout.EndHorizontal(); }
private void OnLostFocus() { // Make sure the actual config asset exists before validating/saving. Crashes the editor otherwise. if (!File.Exists(ScriptableSentryUnityOptions.GetConfigPath(SentryOptionsAssetName))) { new UnityLogger(new SentryOptions()).LogWarning("Sentry option could not been saved. " + "The configuration asset is missing."); return; } Validate(); EditorUtility.SetDirty(Options); EditorUtility.SetDirty(CliOptions); AssetDatabase.SaveAssets(); }
public void ToSentryOptions_OptionsCreated_AreEqualToNewOptions(bool isBuilding) { var expectedOptions = new SentryUnityOptions(_fixture.Application, isBuilding); var scriptableOptions = ScriptableObject.CreateInstance <ScriptableSentryUnityOptions>(); SentryOptionsUtility.SetDefaults(scriptableOptions); // These are config window specific differences in default values we actually want scriptableOptions.Debug = false; scriptableOptions.DebugOnlyInEditor = false; scriptableOptions.DiagnosticLevel = SentryLevel.Debug; var actualOptions = ScriptableSentryUnityOptions.ToSentryUnityOptions(scriptableOptions, isBuilding, _fixture.Application); AssertOptions(expectedOptions, actualOptions); }
public static void Display(ScriptableSentryUnityOptions options) { GUILayout.Label("Programmatic Options Configuration", EditorStyles.boldLabel); EditorGUILayout.Space(); EditorGUILayout.HelpBox("The options configuration allows you to programmatically modify " + "the Sentry options object during runtime initialization of the SDK. " + "This allows you to override configuration otherwise unavailable from the " + "editor UI, e.g. set a custom BeforeSend callback. \n\n" + // TODO other platforms // "Because Sentry Unity integration includes both managed C# Unity SDK and a " + // "platform specific one, you can specify the respective overrides separately.\n\n" + "You can either select an existing script, or create a new one by clicking the " + "'New' button, which will create one from a template at a selected location.", MessageType.Info); EditorGUILayout.Space(); OptionsConfigurationDotNet.Display(options); }
public static void OnPostProcessBuild(BuildTarget target, string executablePath) { if (target is not(BuildTarget.StandaloneWindows or BuildTarget.StandaloneWindows64)) { return; } var options = ScriptableSentryUnityOptions.LoadSentryUnityOptions(BuildPipeline.isBuildingPlayer); var logger = options?.DiagnosticLogger ?? new UnityLogger(options ?? new SentryUnityOptions()); try { if (PlayerSettings.GetScriptingBackend(EditorUserBuildSettings.selectedBuildTargetGroup) != ScriptingImplementation.IL2CPP) { logger.LogWarning("Failed to enable Native support - only availabile with IL2CPP scripting backend."); return; } if (options?.IsValid() is not true) { logger.LogWarning("Failed to validate Sentry Options. Native support disabled."); return; } if (!options.WindowsNativeSupportEnabled) { logger.LogDebug("Windows Native support disabled through the options."); return; } var projectDir = Path.GetDirectoryName(executablePath); AddCrashHandler(logger, projectDir); UploadDebugSymbols(logger, projectDir, Path.GetFileName(executablePath)); } catch (Exception e) { logger.LogError("Failed to add the Sentry native integration to the built application", e); throw new BuildFailedException("Sentry Native BuildPostProcess failed"); } }
internal static ScriptableSentryUnityOptions CreateOptions(string?notDefaultConfigName = null) { if (!AssetDatabase.IsValidFolder("Assets/Resources")) { AssetDatabase.CreateFolder("Assets", "Resources"); } if (!AssetDatabase.IsValidFolder($"Assets/Resources/{ScriptableSentryUnityOptions.ConfigRootFolder}")) { AssetDatabase.CreateFolder("Assets/Resources", ScriptableSentryUnityOptions.ConfigRootFolder); } var scriptableOptions = CreateInstance <ScriptableSentryUnityOptions>(); SentryOptionsUtility.SetDefaults(scriptableOptions); AssetDatabase.CreateAsset(scriptableOptions, ScriptableSentryUnityOptions.GetConfigPath(notDefaultConfigName)); AssetDatabase.SaveAssets(); return(scriptableOptions); }
public void Dispose() { Close(); // calls 'OnLostFocus' implicitly AssetDatabase.DeleteAsset(ScriptableSentryUnityOptions.GetConfigPath(SentryOptionsAssetName)); }
internal static void Display(ScriptableSentryUnityOptions options) { GUILayout.Label("Tag Overrides", EditorStyles.boldLabel); options.ReleaseOverride = EditorGUILayout.TextField( new GUIContent("Override Release", "By default release is built from " + "'Application.productName'@'Application.version'. " + "This option is an override."), options.ReleaseOverride); options.EnvironmentOverride = EditorGUILayout.TextField( new GUIContent("Override Environment", "Auto detects 'production' or 'editor' by " + "default based on 'Application.isEditor." + "\nThis option is an override."), options.EnvironmentOverride); EditorGUILayout.Space(); EditorGUI.DrawRect(EditorGUILayout.GetControlRect(false, 1), Color.gray); EditorGUILayout.Space(); GUILayout.Label("Stacktrace", EditorStyles.boldLabel); options.AttachStacktrace = EditorGUILayout.Toggle( new GUIContent("Stacktrace For Logs", "Whether to include a stack trace for non " + "error events like logs. Even when Unity didn't include and no " + "exception was thrown. Refer to AttachStacktrace on sentry docs."), options.AttachStacktrace); // Enhanced not supported on IL2CPP so not displaying this for the time being: // Options.StackTraceMode = (StackTraceMode) EditorGUILayout.EnumPopup( // new GUIContent("Stacktrace Mode", "Enhanced is the default." + // "\n - Enhanced: Include async, return type, args,..." + // "\n - Original - Default .NET stack trace format."), // Options.StackTraceMode); EditorGUILayout.Space(); EditorGUI.DrawRect(EditorGUILayout.GetControlRect(false, 1), Color.gray); EditorGUILayout.Space(); options.SendDefaultPii = EditorGUILayout.BeginToggleGroup( new GUIContent("Send default Pii", "Whether to include default Personal Identifiable " + "Information."), options.SendDefaultPii); options.IsEnvironmentUser = EditorGUILayout.Toggle( new GUIContent("Auto Set UserName", "Whether to report the 'Environment.UserName' as " + "the User affected in the event. Should be disabled for " + "Android and iOS."), options.IsEnvironmentUser); EditorGUILayout.EndToggleGroup(); EditorGUILayout.Space(); EditorGUI.DrawRect(EditorGUILayout.GetControlRect(false, 1), Color.gray); EditorGUILayout.Space(); options.MaxBreadcrumbs = EditorGUILayout.IntField( new GUIContent("Max Breadcrumbs", "Maximum number of breadcrumbs that get captured." + "\nDefault: 100"), options.MaxBreadcrumbs); options.MaxBreadcrumbs = Math.Max(0, options.MaxBreadcrumbs); options.ReportAssembliesMode = (ReportAssembliesMode)EditorGUILayout.EnumPopup( new GUIContent("Report Assemblies Mode", "Whether or not to include referenced assemblies " + "Version or InformationalVersion in each event sent to sentry."), options.ReportAssembliesMode); }