diff --git a/CHANGELOG.md b/CHANGELOG.md index 5956af1b8b..a6f5ef1ec5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,7 @@ - Fix logging loop with NLog sentry ([#1824](https://github.com/getsentry/sentry-dotnet/pull/1824)) - Fix logging loop with Serilog sentry ([#1828](https://github.com/getsentry/sentry-dotnet/pull/1828)) - Skip attachment if stream is empty ([#1854](https://github.com/getsentry/sentry-dotnet/pull/1854)) +- Allow some mobile options to be modified from defaults ([#1857](https://github.com/getsentry/sentry-dotnet/pull/1857)) ## 3.20.1 diff --git a/samples/Sentry.Samples.Android/MainActivity.cs b/samples/Sentry.Samples.Android/MainActivity.cs index 78cee4630a..07baaf96f8 100644 --- a/samples/Sentry.Samples.Android/MainActivity.cs +++ b/samples/Sentry.Samples.Android/MainActivity.cs @@ -6,7 +6,7 @@ public class MainActivity : Activity { protected override void OnCreate(Bundle? savedInstanceState) { - SentrySdk.Init(this, o => + SentrySdk.Init(o => { o.Dsn = "https://eb18e953812b41c3aeb042e666fd3b5c@o447951.ingest.sentry.io/5428537"; o.SendDefaultPii = true; // adds the user's IP address automatically diff --git a/samples/Sentry.Samples.Maui/MainPage.xaml.cs b/samples/Sentry.Samples.Maui/MainPage.xaml.cs index 2a1b0f0bf1..9b91d23ce8 100644 --- a/samples/Sentry.Samples.Maui/MainPage.xaml.cs +++ b/samples/Sentry.Samples.Maui/MainPage.xaml.cs @@ -23,7 +23,7 @@ protected override void OnAppearing() JavaCrashBtn.IsVisible = false; #endif -#if !(ANDROID || IOS || MACCATALYST) +#if !__MOBILE__ NativeCrashBtn.IsVisible = false; #endif base.OnAppearing(); @@ -73,7 +73,7 @@ private void OnJavaCrashClicked(object sender, EventArgs e) private void OnNativeCrashClicked(object sender, EventArgs e) { -#if ANDROID || IOS || MACCATALYST +#if __MOBILE__ SentrySdk.CauseCrash(CrashType.Native); #endif } diff --git a/src/Sentry.Maui/Internal/SentryMauiInitializer.cs b/src/Sentry.Maui/Internal/SentryMauiInitializer.cs index 8d6e2a9d6d..4a7d48949c 100644 --- a/src/Sentry.Maui/Internal/SentryMauiInitializer.cs +++ b/src/Sentry.Maui/Internal/SentryMauiInitializer.cs @@ -13,13 +13,8 @@ public void Initialize(IServiceProvider services) { var options = services.GetRequiredService>().Value; var disposer = services.GetRequiredService(); - -#if ANDROID - var context = global::Android.App.Application.Context; - var disposable = SentrySdk.Init(context, options); -#else + var disposable = SentrySdk.Init(options); -#endif // Register the return value from initializing the SDK with the disposer. // This will ensure that it gets disposed when the service provider is disposed. diff --git a/src/Sentry.Maui/Internal/SentryMauiOptionsSetup.cs b/src/Sentry.Maui/Internal/SentryMauiOptionsSetup.cs index 7fc3e708c3..b8bc44991e 100644 --- a/src/Sentry.Maui/Internal/SentryMauiOptionsSetup.cs +++ b/src/Sentry.Maui/Internal/SentryMauiOptionsSetup.cs @@ -13,6 +13,9 @@ public override void Configure(SentryMauiOptions options) { base.Configure(options); + // NOTE: Anything set here will overwrite options set by the user. + // For option defaults that can be changed, use the constructor in SentryMauiOptions instead. + // We'll initialize the SDK in SentryMauiInitializer options.InitializeSdk = false; diff --git a/src/Sentry.Maui/SentryMauiOptions.cs b/src/Sentry.Maui/SentryMauiOptions.cs index bb5cf07573..1a50b8fbdd 100644 --- a/src/Sentry.Maui/SentryMauiOptions.cs +++ b/src/Sentry.Maui/SentryMauiOptions.cs @@ -7,6 +7,20 @@ namespace Sentry.Maui; /// public class SentryMauiOptions : SentryLoggingOptions { + /// + /// Creates a new instance of . + /// + public SentryMauiOptions() + { + // Set defaults for options that are different for MAUI. + // The user can change these. If you want to force a value, use SentryMauiOptionsSetup instead. + // Also, some of these are already set in the base Sentry SDK, but since we don't yet have native targets + // there for all MAUI targets, we'll set them again here. + + AutoSessionTracking = true; + DetectStartupTime = StartupTimeDetectionMode.Fast; + } + /// /// Gets or sets whether elements that implement /// (such as , , , and others) diff --git a/src/Sentry/CrashType.cs b/src/Sentry/CrashType.cs index 8812a7e6f6..316fda878a 100644 --- a/src/Sentry/CrashType.cs +++ b/src/Sentry/CrashType.cs @@ -31,7 +31,7 @@ public enum CrashType JavaBackgroundThread, #endif -#if ANDROID || IOS || MACCATALYST +#if __MOBILE__ /// /// A native operation that will crash the appliction will be performed by a C library. /// diff --git a/src/Sentry/Internal/Constants.cs b/src/Sentry/Internal/Constants.cs index b6c0683e6c..c0a2bdeb8a 100644 --- a/src/Sentry/Internal/Constants.cs +++ b/src/Sentry/Internal/Constants.cs @@ -35,7 +35,7 @@ internal static class Constants // See: https://github.com/getsentry/sentry-release-registry #if ANDROID public const string SdkName = "sentry.dotnet.android"; -#elif IOS || MACCATALYST +#elif __IOS__ public const string SdkName = "sentry.dotnet.cocoa"; #else public const string SdkName = "sentry.dotnet"; diff --git a/src/Sentry/Internal/ProcessInfo.cs b/src/Sentry/Internal/ProcessInfo.cs index f9779f0e52..1a1d9aea59 100644 --- a/src/Sentry/Internal/ProcessInfo.cs +++ b/src/Sentry/Internal/ProcessInfo.cs @@ -72,7 +72,7 @@ internal ProcessInfo( // https://issuetracker.unity3d.com/issues/il2cpp-player-crashes-when-calling-process-dot-getcurrentprocess-dot-starttime if (options.DetectStartupTime == StartupTimeDetectionMode.Best) { -#if ANDROID || IOS || MACCATALYST +#if __MOBILE__ options.LogWarning("StartupTimeDetectionMode.Best is not available on this platform. Using 'Fast' mode."); #else // StartupTime is set to UtcNow in this constructor. @@ -98,7 +98,7 @@ internal ProcessInfo( } } -#if !(ANDROID || IOS || MACCATALYST) +#if !__MOBILE__ private static DateTimeOffset GetStartupTime() { using var proc = Process.GetCurrentProcess(); diff --git a/src/Sentry/Internal/SentryScopeManager.cs b/src/Sentry/Internal/SentryScopeManager.cs index e1900c0c73..351b9c2dce 100644 --- a/src/Sentry/Internal/SentryScopeManager.cs +++ b/src/Sentry/Internal/SentryScopeManager.cs @@ -29,6 +29,7 @@ public SentryScopeManager( ISentryClient rootClient) { ScopeStackContainer = scopeStackContainer; + _options = options; NewStack = () => new[] { new KeyValuePair(new Scope(options), rootClient) }; } diff --git a/src/Sentry/PlatformAbstractions/DeviceInfo.cs b/src/Sentry/PlatformAbstractions/DeviceInfo.cs new file mode 100644 index 0000000000..1f9d0abb5c --- /dev/null +++ b/src/Sentry/PlatformAbstractions/DeviceInfo.cs @@ -0,0 +1,13 @@ +namespace Sentry.PlatformAbstractions +{ + internal static class DeviceInfo + { +#if ANDROID + public const string PlatformName = "Android"; +#elif IOS + public const string PlatformName = "iOS"; +#elif MACCATALYST + public const string PlatformName = "Mac Catalyst"; +#endif + } +} diff --git a/src/Sentry/Platforms/Android/SentrySdk.cs b/src/Sentry/Platforms/Android/SentrySdk.cs index 1fcbf91652..a3c033bcc2 100644 --- a/src/Sentry/Platforms/Android/SentrySdk.cs +++ b/src/Sentry/Platforms/Android/SentrySdk.cs @@ -3,7 +3,6 @@ using Sentry.Android; using Sentry.Android.Callbacks; using Sentry.Android.Extensions; -using Sentry.Extensibility; using Sentry.Protocol; // ReSharper disable once CheckNamespace @@ -11,7 +10,7 @@ namespace Sentry; public static partial class SentrySdk { - private static AndroidContext? AndroidContext; + private static AndroidContext AppContext { get; set; } = Application.Context; /// /// Initializes the SDK for Android, with an optional configuration options callback. @@ -19,11 +18,12 @@ public static partial class SentrySdk /// The Android application context. /// The configuration options callback. /// An object that should be disposed when the application terminates. + [Obsolete("It is no longer required to provide the application context when calling Init. " + + "This method may be removed in a future major release.")] public static IDisposable Init(AndroidContext context, Action? configureOptions) { - var options = new SentryOptions(); - configureOptions?.Invoke(options); - return Init(context, options); + AppContext = context; + return Init(configureOptions); } /// @@ -32,40 +32,26 @@ public static IDisposable Init(AndroidContext context, Action? co /// The Android application context. /// The configuration options instance. /// An object that should be disposed when the application terminates. + [Obsolete("It is no longer required to provide the application context when calling Init. " + + "This method may be removed in a future major release.")] public static IDisposable Init(AndroidContext context, SentryOptions options) { - AndroidContext = context; + AppContext = context; return Init(options); } private static void InitSentryAndroidSdk(SentryOptions options) { - // Set options for the managed SDK that don't depend on the Android SDK - options.AutoSessionTracking = true; - options.IsGlobalModeEnabled = true; - // Set default release and distribution options.Release ??= GetDefaultReleaseString(); options.Distribution ??= GetDefaultDistributionString(); - // "Best" mode throws permission exception on Android - options.DetectStartupTime = StartupTimeDetectionMode.Fast; - // Make sure we capture managed exceptions from the Android environment AndroidEnvironment.UnhandledExceptionRaiser += AndroidEnvironment_UnhandledExceptionRaiser; - // Now initialize the Android SDK if we have been given an AndroidContext - var context = AndroidContext; - if (context == null) - { - options.LogWarning("Running on Android, but did not initialize Sentry with an AndroidContext. " + - "The embedded Sentry Android SDK is disabled. " + - "Call SentrySdk.Init(AndroidContext, SentryOptions) instead."); - return; - } - + // Now initialize the Android SDK SentryAndroidOptions? androidOptions = null; - SentryAndroid.Init(context, new JavaLogger(options), + SentryAndroid.Init(AppContext, new JavaLogger(options), new OptionsConfigurationCallback(o => { // Capture the android options reference on the outer scope @@ -179,7 +165,7 @@ private static void InitSentryAndroidSdk(SentryOptions options) o.AddIgnoredExceptionForType(JavaClass.ForName("android.runtime.JavaProxyThrowable")); })); - // Set options for the managed SDK that depend on the Android SDK + // Set options for the managed SDK that depend on the Android SDK. (The user will not be able to modify these.) options.AddEventProcessor(new AndroidEventProcessor(androidOptions!)); options.CrashedLastRun = () => Java.Sentry.IsCrashedLastRun()?.BooleanValue() is true; options.EnableScopeSync = true; @@ -201,14 +187,13 @@ private static void AndroidEnvironment_UnhandledExceptionRaiser(object? _, Raise private static string? GetDefaultReleaseString() { - var context = AndroidContext ?? Application.Context; - var packageName = context.PackageName; + var packageName = AppContext.PackageName; if (packageName == null) { return null; } - var packageInfo = context.PackageManager?.GetPackageInfo(packageName, PackageInfoFlags.Permissions); + var packageInfo = AppContext.PackageManager?.GetPackageInfo(packageName, PackageInfoFlags.Permissions); return packageInfo == null ? null : $"{packageName}@{packageInfo.VersionName}+{packageInfo.GetVersionCode()}"; } @@ -216,14 +201,13 @@ private static void AndroidEnvironment_UnhandledExceptionRaiser(object? _, Raise private static long? GetAndroidPackageVersionCode() { - var context = AndroidContext ?? Application.Context; - var packageName = context.PackageName; + var packageName = AppContext.PackageName; if (packageName == null) { return null; } - var packageInfo = context.PackageManager?.GetPackageInfo(packageName, PackageInfoFlags.Permissions); + var packageInfo = AppContext.PackageManager?.GetPackageInfo(packageName, PackageInfoFlags.Permissions); return packageInfo?.GetVersionCode(); } diff --git a/src/Sentry/Platforms/iOS/SentrySdk.cs b/src/Sentry/Platforms/iOS/SentrySdk.cs index f1ba0e5f47..f404962f61 100644 --- a/src/Sentry/Platforms/iOS/SentrySdk.cs +++ b/src/Sentry/Platforms/iOS/SentrySdk.cs @@ -14,17 +14,10 @@ private static void InitSentryCocoaSdk(SentryOptions options) args.ExceptionMode = ObjCRuntime.MarshalManagedExceptionMode.UnwindNativeCode; }; - // Set options for the managed SDK that don't depend on the Cocoa SDK - options.AutoSessionTracking = true; - options.IsGlobalModeEnabled = true; - // Set default release and distribution options.Release ??= GetDefaultReleaseString(); options.Distribution ??= GetDefaultDistributionString(); - // "Best" mode throws platform not supported exception. Use "Fast" mode instead. - options.DetectStartupTime = StartupTimeDetectionMode.Fast; - // Set options for the Cocoa SDK var cocoaOptions = new SentryCocoaOptions(); @@ -170,7 +163,7 @@ private static void InitSentryCocoaSdk(SentryOptions options) // Now initialize the Cocoa SDK SentryCocoaSdk.StartWithOptionsObject(cocoaOptions); - // Set options for the managed SDK that depend on the Cocoa SDK + // Set options for the managed SDK that depend on the Cocoa SDK. (The user will not be able to modify these.) options.AddEventProcessor(new IosEventProcessor(cocoaOptions!)); options.CrashedLastRun = () => SentryCocoaSdk.CrashedLastRun; options.EnableScopeSync = true; diff --git a/src/Sentry/Properties/AssemblyInfo.cs b/src/Sentry/Properties/AssemblyInfo.cs index 9074a8b9ea..cd3d86afcc 100644 --- a/src/Sentry/Properties/AssemblyInfo.cs +++ b/src/Sentry/Properties/AssemblyInfo.cs @@ -37,6 +37,6 @@ // The targets for these platforms are not CLS Compliant -#if !(ANDROID || IOS || MACCATALYST) +#if !__MOBILE__ [assembly: CLSCompliant(true)] #endif diff --git a/src/Sentry/SentryOptions.cs b/src/Sentry/SentryOptions.cs index 9ed6e1e427..9798d68884 100644 --- a/src/Sentry/SentryOptions.cs +++ b/src/Sentry/SentryOptions.cs @@ -11,8 +11,9 @@ using Sentry.Internal; using Sentry.Internal.Http; using Sentry.Internal.ScopeStack; +using Sentry.PlatformAbstractions; using static Sentry.Constants; -using Runtime = Sentry.PlatformAbstractions.Runtime; + #if HAS_DIAGNOSTIC_INTEGRATION using Sentry.Internals.DiagnosticSource; #endif @@ -26,6 +27,26 @@ public partial class SentryOptions { private Dictionary? _defaultTags; +#if __MOBILE__ + + internal IScopeStackContainer? ScopeStackContainer { get; } = new GlobalScopeStackContainer(); + + /// + /// Specifies whether to use global scope management mode. + /// Always true for mobile targets. + /// + public bool IsGlobalModeEnabled + { + get => true; + set + { + if (value is false) + { + _diagnosticLogger?.LogWarning("Cannot disable Global Mode on {0}", DeviceInfo.PlatformName); + } + } + } +#else internal IScopeStackContainer? ScopeStackContainer { get; set; } /// @@ -36,6 +57,7 @@ public bool IsGlobalModeEnabled get => ScopeStackContainer is GlobalScopeStackContainer; set => ScopeStackContainer = value ? new GlobalScopeStackContainer() : new AsyncLocalScopeStackContainer(); } +#endif /// /// A scope set outside of Sentry SDK. If set, the global parameters from the SDK's scope will be sent to the observed scope.
@@ -573,13 +595,19 @@ public StackTraceMode StackTraceMode public long MaxAttachmentSize { get; set; } = 20 * 1024 * 1024; /// - /// Whether the SDK should attempt to detect the app's and device's startup time. + /// The mode that the SDK should use when attempting to detect the app's and device's startup time. /// /// /// Note that the highest precision value relies on /// which might not be available. For example on Unity's IL2CPP. + /// Additionally, "Best" mode is not available on mobile platforms. /// - public StartupTimeDetectionMode DetectStartupTime { get; set; } = StartupTimeDetectionMode.Best; + public StartupTimeDetectionMode DetectStartupTime { get; set; } = +#if __MOBILE__ + StartupTimeDetectionMode.Fast; +#else + StartupTimeDetectionMode.Best; +#endif /// /// Determines the duration of time a session can stay paused before it's considered ended. @@ -589,10 +617,11 @@ public StackTraceMode StackTraceMode /// public TimeSpan AutoSessionTrackingInterval { get; set; } = TimeSpan.FromSeconds(30); -#if ANDROID || IOS || MACCATALYST +#if __MOBILE__ /// /// Whether the SDK should start a session automatically when it's initialized and /// end the session when it's closed. + /// On mobile application platforms, this is enabled by default. /// public bool AutoSessionTracking { get; set; } = true; #else @@ -601,8 +630,8 @@ public StackTraceMode StackTraceMode /// end the session when it's closed. /// /// - /// Note: this is disabled by default in the current version, but will become - /// enabled by default in the next major version. + /// Note: this is disabled by default in the current version (except for mobile targets and MAUI), + /// but will become enabled by default in the next major version. /// Currently this only works for release health in client mode /// (desktop, mobile applications, but not web servers). /// @@ -691,7 +720,7 @@ public SentryOptions() #if ANDROID Android = new AndroidOptions(this); -#elif IOS || MACCATALYST +#elif __IOS__ iOS = new IosOptions(this); #endif diff --git a/src/Sentry/SentrySdk.cs b/src/Sentry/SentrySdk.cs index 83242f7114..2b736d3646 100644 --- a/src/Sentry/SentrySdk.cs +++ b/src/Sentry/SentrySdk.cs @@ -54,7 +54,7 @@ internal static IHub InitHub(SentryOptions options) // Initialize bundled platform SDKs here #if ANDROID InitSentryAndroidSdk(options); -#elif IOS || MACCATALYST +#elif __IOS__ InitSentryCocoaSdk(options); #endif return new Hub(options); @@ -497,7 +497,7 @@ public static void CauseCrash(CrashType crashType) case CrashType.Native: NativeCrash(); break; -#elif IOS || MACCATALYST +#elif __IOS__ case CrashType.Native: SentryCocoaSdk.Crash(); break;