Skip to content

Rework Initialization #2227

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 52 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 27 commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
14427b6
initial working implementation
bitsandfoxes Jul 3, 2025
bb4dbc0
fixed using in smoketester
bitsandfoxes Jul 4, 2025
0f97f0b
we actually need both. idk if that's great. doesn't look great
bitsandfoxes Jul 4, 2025
a76e957
bumped .NET to have the comment
bitsandfoxes Jul 7, 2025
e494279
Updated CHANGELOG.md
bitsandfoxes Jul 7, 2025
df211a3
bumped to cleaned up version of .NET
bitsandfoxes Jul 7, 2025
19c4e78
added services logging to init
bitsandfoxes Jul 7, 2025
00e788a
added summary to platformservices
bitsandfoxes Jul 7, 2025
bfcd0f1
fixed namespaces
bitsandfoxes Jul 7, 2025
4448334
cleaned up bugfarmbuttons
bitsandfoxes Jul 7, 2025
232833c
namespace clean followup
bitsandfoxes Jul 7, 2025
bcbb551
fixed qualification
bitsandfoxes Jul 7, 2025
deb6aa7
moved scenetracing integration into the SDK
bitsandfoxes Jul 8, 2025
a66a5a6
updated CI to 2020
bitsandfoxes Jul 8, 2025
857e492
env bump
bitsandfoxes Jul 8, 2025
eefad70
removed now redundant test
bitsandfoxes Jul 8, 2025
16c9fcf
bumped uniy-of-bugs to 2020
bitsandfoxes Jul 8, 2025
6542706
updated the package
bitsandfoxes Jul 8, 2025
b48e60d
removed now redundant asmdef
bitsandfoxes Jul 8, 2025
76e05b2
Updated CHANGELOG.md
bitsandfoxes Jul 8, 2025
3fa372c
missing option field?
bitsandfoxes Jul 8, 2025
1f5e5cc
merged unity 2019 drop
bitsandfoxes Jul 8, 2025
83deeec
finished fixing the startup tracing
bitsandfoxes Jul 8, 2025
011ba1d
merged main
bitsandfoxes Jul 9, 2025
2a46b5f
bump android API level to 21 for 2020
bitsandfoxes Jul 9, 2025
7ac68be
Merge branch 'fix/android-2020-ci' into fix/initialization
bitsandfoxes Jul 9, 2025
43f5ae9
updated test to ignore harmless warning
bitsandfoxes Jul 9, 2025
ad0ae02
move startup tracing into the SDK
bitsandfoxes Jul 9, 2025
bb6f80a
.
bitsandfoxes Jul 9, 2025
c53ccb5
fix naming
bitsandfoxes Jul 9, 2025
d100d4f
Format code
getsentry-bot Jul 9, 2025
7faafb9
added tests
bitsandfoxes Jul 9, 2025
490e033
merged
bitsandfoxes Jul 9, 2025
2f42440
Format code
getsentry-bot Jul 9, 2025
d2709d1
updated snapshot
bitsandfoxes Jul 9, 2025
326dc32
Merge branch 'chore/cleanup-init' of https://github.com/getsentry/sen…
bitsandfoxes Jul 9, 2025
1183370
.
bitsandfoxes Jul 9, 2025
f1388b4
merged the init cleanup
bitsandfoxes Jul 10, 2025
594dc4a
fixed test
bitsandfoxes Jul 10, 2025
3bfc5fa
use platform services where applicable
bitsandfoxes Jul 10, 2025
0843ba5
forgot webgl
bitsandfoxes Jul 10, 2025
a4cbc59
rename setup platform services
bitsandfoxes Jul 10, 2025
32876ac
public close cutback
bitsandfoxes Jul 10, 2025
c6cbb0c
review
bitsandfoxes Jul 10, 2025
3a2328b
Format code
getsentry-bot Jul 10, 2025
2e4b3db
Merge branch 'main' into chore/cleanup-init
bitsandfoxes Jul 10, 2025
99bbb4d
Merge branch 'chore/cleanup-init' into fix/initialization
bitsandfoxes Jul 10, 2025
d67b2b9
Merge branch 'fix/initialization' of https://github.com/getsentry/sen…
bitsandfoxes Jul 10, 2025
ac366e7
Update CHANGELOG.md
bitsandfoxes Jul 11, 2025
76868b8
merged main
bitsandfoxes Jul 11, 2025
1f520ee
hold platformservices in options and handle tests
bitsandfoxes Jul 11, 2025
a47872d
Format code
getsentry-bot Jul 11, 2025
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
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,17 @@

### Breaking Changes

- **Breaking Change**: The Unity SDK's static API has been simplified moved from `Sentry.Unity.SentryUnity` and `Sentry.SentrySdk`
to `Sentry.Unity.SentrySdk`.
This change enables manual SDK initialization with full functionality, previously only available through auto-initialization.
The underlying .NET SDK's `SentrySdk` class is now internal, and several previously public classes like `SentryInitialization`
and `SentryIntegrations` are now internal.

**Migration**: Update your using statements from `using Sentry;` to `using Sentry.Unity;`. IDEs like Rider can automatically
import the missing references. In some cases, you may need both `using Sentry.Unity;` (for the static API) and `using Sentry;`
(for types like `SentryId`). No changes are required to your actual SDK method calls (e.g., `SentrySdk.CaptureException()`
remains the same). ([#2227](https://github.com/getsentry/sentry-unity/pull/2227))
- Updated Unity support by updating to Unity versions (2020+), removing Unity 2019 which reached End of Life in 2022 ([#2231](https://github.com/getsentry/sentry-unity/pull/2231))
- Dropped support for Unity 2019. It reached End of Life in 2022 ([#2231](https://github.com/getsentry/sentry-unity/pull/2231))

### Features
Expand Down
82 changes: 24 additions & 58 deletions package-dev/Runtime/SentryInitialization.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@
#endif

using System;
using Sentry.Unity;
using Sentry.Extensibility;
using Sentry.Unity.NativeUtils;
#if UNITY_2020_3_OR_NEWER
using System.Buffers;
using System.Runtime.InteropServices;
Expand All @@ -39,91 +41,55 @@

namespace Sentry.Unity
{
public static class SentryInitialization
internal static class SentryInitialization
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can safely make this internal. The SDK ships with it's own .asmdef that allows us to hide internal types from the user.

{
public const string StartupTransactionOperation = "app.start";
public static ISpan InitSpan;
private const string InitSpanOperation = "runtime.init";
public static ISpan SubSystemRegistrationSpan;
private const string SubSystemSpanOperation = "runtime.init.subsystem";

#if SENTRY_WEBGL
// On WebGL SubsystemRegistration is too early for the UnityWebRequestTransport and errors with 'URI empty'
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
#else
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
#endif
public static void Init()
internal static void Init()
{
var unityInfo = new SentryUnityInfo();
// We're setting up `UnityInfo` and the platform specific configure callbacks as the very first thing to be
// available during initialization.
SetupPlatformConfiguration();

// Loading the options invokes the ScriptableOption`Configure` callback. Users can disable the SDK via code.
var options = ScriptableSentryUnityOptions.LoadSentryUnityOptions(unityInfo);
var options = ScriptableSentryUnityOptions.LoadSentryUnityOptions();
if (options != null && options.ShouldInitializeSdk())
{
// Certain integrations require access to preprocessor directives so we provide them as `.cs` and
// compile them with the game instead of precompiling them with the rest of the SDK.
// i.e. SceneManagerAPI requires UNITY_2020_3_OR_NEWER
SentryIntegrations.Configure(options);
// Configures scope sync and (by default) initializes the native SDK.
SetupNativeSdk(options, unityInfo);
SentryUnity.Init(options);
SetupStartupTracing(options);
// We have to keep the StartupTracing outside the SDK as the integration relies on the `RuntimeInitializeOnLoadMethod`
// attribute.
SentryStartupTracing.SetUpTracingIntration(options);

SentrySdk.Init(options);

SentryStartupTracing.StartTracing();
}
else
{
// If the SDK is not `enabled` we're closing down the native layer as well. This is especially relevant
// in a `built-time-initialization` scenario where the native SDKs self-initialize.
#if SENTRY_NATIVE_COCOA
SentryNativeCocoa.Close(options, unityInfo);
SentryNativeCocoa.Close(options, SentryPlatformServices.UnityInfo);
#elif SENTRY_NATIVE_ANDROID
SentryNativeAndroid.Close(options, unityInfo);
SentryNativeAndroid.Close(options, SentryPlatformServices.UnityInfo);
#endif
}
}

private static void SetupNativeSdk(SentryUnityOptions options, SentryUnityInfo unityInfo)
private static void SetupPlatformConfiguration()
{
try
{
SentryPlatformServices.UnityInfo = new SentryUnityInfo();
#if SENTRY_NATIVE_COCOA
SentryNativeCocoa.Configure(options, unityInfo);
SentryPlatformServices.PlatformConfiguration = SentryNativeCocoa.Configure;
#elif SENTRY_NATIVE_ANDROID
SentryNativeAndroid.Configure(options, unityInfo);
SentryPlatformServices.PlatformConfiguration = SentryNativeAndroid.Configure;
#elif SENTRY_NATIVE
SentryNative.Configure(options, unityInfo);
SentryPlatformServices.PlatformConfiguration = SentryNative.Configure;
#elif SENTRY_WEBGL
SentryWebGL.Configure(options);
#endif
}
catch (DllNotFoundException e)
{
options.DiagnosticLogger?.LogError(e,
"Sentry native-error capture configuration failed to load a native library. This usually " +
"means the library is missing from the application bundle or the installation directory.");
}
catch (Exception e)
{
options.DiagnosticLogger?.LogError(e, "Sentry native error capture configuration failed.");
}
}

private static void SetupStartupTracing(SentryUnityOptions options)
{
#if !SENTRY_WEBGL
if (options.TracesSampleRate > 0.0f && options.AutoStartupTraces)
{
options.DiagnosticLogger?.LogInfo("Creating '{0}' transaction for runtime initialization.",
StartupTransactionOperation);

var runtimeStartTransaction =
SentrySdk.StartTransaction("runtime.initialization", StartupTransactionOperation);
SentrySdk.ConfigureScope(scope => scope.Transaction = runtimeStartTransaction);

options.DiagnosticLogger?.LogDebug("Creating '{0}' span.", InitSpanOperation);
InitSpan = runtimeStartTransaction.StartChild(InitSpanOperation, "runtime initialization");
options.DiagnosticLogger?.LogDebug("Creating '{0}' span.", SubSystemSpanOperation);
SubSystemRegistrationSpan = InitSpan.StartChild(SubSystemSpanOperation, "subsystem registration");
}
SentryPlatformServices.PlatformConfiguration = SentryWebGL.Configure;
#endif
}
}
Expand Down
66 changes: 53 additions & 13 deletions package-dev/Runtime/SentryIntegrations.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,30 +7,50 @@
using Sentry.Extensibility;
using Sentry.Integrations;
using UnityEngine;
using UnityEngine.SceneManagement;

namespace Sentry.Unity
{
public static class SentryIntegrations
internal static class SentryStartupTracing
{
public static void Configure(SentryUnityOptions options)
#if !SENTRY_WEBGL
private static StartupTracingIntegration StartupTracingIntegration;
#endif

public static void SetUpTracingIntration(SentryUnityOptions options)
{
if (options.TracesSampleRate > 0.0)
{
// On WebGL the SDK initializes on BeforeScene so the Startup Tracing won't work properly. https://github.com/getsentry/sentry-unity/issues/1000
#if !SENTRY_WEBGL
if (options.AutoStartupTraces)
{
options.AddIntegration(new StartupTracingIntegration());
StartupTracingIntegration = new StartupTracingIntegration();
options.AddIntegration(StartupTracingIntegration);
}
#endif
}
}

public static void StartTracing()
{
#if !SENTRY_WEBGL
if (StartupTracingIntegration != null)
{
StartupTracingIntegration.StartTracing();
}
#endif
}

}

#if !SENTRY_WEBGL
public class StartupTracingIntegration : ISdkIntegration
internal class StartupTracingIntegration : ISdkIntegration
{
private const string StartupTransactionOperation = "app.start";
private static ISpan InitSpan;
private const string InitSpanOperation = "runtime.init";
public static ISpan SubSystemRegistrationSpan;
private const string SubSystemSpanOperation = "runtime.init.subsystem";
private static ISpan AfterAssembliesSpan;
private const string AfterAssembliesSpanOperation = "runtime.init.afterassemblies";
private static ISpan SplashScreenSpan;
Expand All @@ -50,6 +70,26 @@ public void Register(IHub hub, SentryOptions options)
IntegrationRegistered = true;
}

public static void StartTracing()
{
if (!IntegrationRegistered || StartupAlreadyCaptured)
{
return;
}

Logger.LogInfo("Creating '{0}' transaction for runtime initialization.",
StartupTransactionOperation);

var runtimeStartTransaction =
SentrySdk.StartTransaction("runtime.initialization", StartupTransactionOperation);
SentrySdk.ConfigureScope(scope => scope.Transaction = runtimeStartTransaction);

Logger.LogDebug("Creating '{0}' span.", InitSpanOperation);
InitSpan = runtimeStartTransaction.StartChild(InitSpanOperation, "runtime initialization");
Logger.LogDebug("Creating '{0}' span.", SubSystemSpanOperation);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could these two be combined in 1 log message? Debug log can be overwhelming at times

SubSystemRegistrationSpan = InitSpan.StartChild(SubSystemSpanOperation, "subsystem registration");
}

[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.AfterAssembliesLoaded)]
public static void AfterAssembliesLoaded()
{
Expand All @@ -58,11 +98,11 @@ public static void AfterAssembliesLoaded()
return;
}

SentryInitialization.SubSystemRegistrationSpan?.Finish(SpanStatus.Ok);
SentryInitialization.SubSystemRegistrationSpan = null;
SubSystemRegistrationSpan?.Finish(SpanStatus.Ok);
SubSystemRegistrationSpan = null;

Logger?.LogDebug("Creating '{0}' span.", AfterAssembliesSpanOperation);
AfterAssembliesSpan = SentryInitialization.InitSpan?.StartChild(AfterAssembliesSpanOperation, "after assemblies");
AfterAssembliesSpan = InitSpan?.StartChild(AfterAssembliesSpanOperation, "after assemblies");
}

[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSplashScreen)]
Expand All @@ -77,7 +117,7 @@ public static void BeforeSplashScreen()
AfterAssembliesSpan = null;

Logger?.LogDebug("Creating '{0}' span.", SplashScreenSpanOperation);
SplashScreenSpan = SentryInitialization.InitSpan?.StartChild(SplashScreenSpanOperation, "splashscreen");
SplashScreenSpan = InitSpan?.StartChild(SplashScreenSpanOperation, "splashscreen");
}

[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
Expand All @@ -92,7 +132,7 @@ public static void BeforeSceneLoad()
SplashScreenSpan = null;

Logger?.LogDebug("Creating '{0}' span.", FirstSceneLoadSpanOperation);
FirstSceneLoadSpan = SentryInitialization.InitSpan?.StartChild(FirstSceneLoadSpanOperation, "first scene load");
FirstSceneLoadSpan = InitSpan?.StartChild(FirstSceneLoadSpanOperation, "first scene load");
}

[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.AfterSceneLoad)]
Expand All @@ -106,10 +146,10 @@ public static void AfterSceneLoad()
FirstSceneLoadSpan?.Finish(SpanStatus.Ok);
FirstSceneLoadSpan = null;

SentryInitialization.InitSpan?.Finish(SpanStatus.Ok);
SentryInitialization.InitSpan = null;
InitSpan?.Finish(SpanStatus.Ok);
InitSpan = null;

Logger?.LogInfo("Finishing '{0}' transaction.", SentryInitialization.StartupTransactionOperation);
Logger?.LogInfo("Finishing '{0}' transaction.", StartupTransactionOperation);
SentrySdk.ConfigureScope(s =>
{
s.Transaction?.Finish(SpanStatus.Ok);
Expand Down
4 changes: 2 additions & 2 deletions package-dev/Runtime/SentryUserFeedback.cs
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ public void SendFeedback()
else
{
// Since there is no screenshot added we can capture the feedback right away
SentryUnity.CaptureFeedback(_description.text, _email.text, _name.text, addScreenshot: false);
SentrySdk.CaptureFeedback(_description.text, _email.text, _name.text, addScreenshot: false);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the desired effect. All things reside within SentrySdk.

}
}

Expand All @@ -99,7 +99,7 @@ private IEnumerator HideFormAndCaptureFeedback()
// We're waiting for the EndOfFrame so the FeedbackForm gets updated before capturing the screenshot
yield return new WaitForEndOfFrame();

SentryUnity.CaptureFeedback(_description.text, _email.text, _name.text, addScreenshot: true);
SentrySdk.CaptureFeedback(_description.text, _email.text, _name.text, addScreenshot: true);

ResetUserFeedback();
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
using System.Collections;
using System.Threading;
using System.Threading.Tasks;
using Sentry;
using Sentry.Unity;
using UnityEngine;

public class AdditionalButtons : MonoBehaviour
Expand Down
3 changes: 2 additions & 1 deletion samples/unity-of-bugs/Assets/Scripts/BugFarmButtons.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
using System;
using System.Globalization;
using System.Runtime.CompilerServices;
using Sentry;
using Sentry.Unity;
using UnityEngine;
using UnityEngine.Assertions;


public class BugFarmButtons : MonoBehaviour
{
private void Awake()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
using Sentry;
using System;
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using Sentry.Unity;
using UnityEngine;
using UnityEngine.Diagnostics;
using UnityEngine.UI;
Expand Down
2 changes: 1 addition & 1 deletion samples/unity-of-bugs/Assets/Scripts/ThreadingSamples.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;
using Sentry;
using Sentry.Unity;
using UnityEngine;
using UnityEngine.Assertions;

Expand Down
15 changes: 15 additions & 0 deletions src/Sentry.Unity/NativeUtils/SentryPlatformServices.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using System;

namespace Sentry.Unity.NativeUtils;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Putting the services into a very distinctive namespace to "discourage" usage.


/// <summary>
/// These are SDK's services that are only available at runtime and cannot be baked into the SDK. The
/// <c>SentryInitialization.cs</c> is provided as <c>.cs</c> and gets compiled with the game. It sets <c>IUnityInfo</c>
/// and the <c>PlatformConfiguration</c> callback during the game's startup so that they are available during initializtion.
/// </summary>
/// <remarks>Consider this <c>internal</c>.</remarks>
public static class SentryPlatformServices
{
public static ISentryUnityInfo? UnityInfo { get; set; }
public static Action<SentryUnityOptions, ISentryUnityInfo>? PlatformConfiguration { get; set; }
}
5 changes: 3 additions & 2 deletions src/Sentry.Unity/ScriptableSentryUnityOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using System.Collections.Generic;
using Sentry.Extensibility;
using Sentry.Unity.Integrations;
using Sentry.Unity.NativeUtils;
using UnityEngine;

namespace Sentry.Unity;
Expand Down Expand Up @@ -120,12 +121,12 @@ public static string GetConfigPath(string? notDefaultConfigName = null)
/// <remarks>
/// Used for loading the SentryUnityOptions from the ScriptableSentryUnityOptions during runtime.
/// </remarks>
public static SentryUnityOptions? LoadSentryUnityOptions(ISentryUnityInfo unityInfo)
public static SentryUnityOptions? LoadSentryUnityOptions()
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We no longer need to provide the IUnityInfo since these are getting set up during startup as part of the new platform services that are statically available.

{
var scriptableOptions = Resources.Load<ScriptableSentryUnityOptions>($"{ConfigRootFolder}/{ConfigName}");
if (scriptableOptions is not null)
{
return scriptableOptions.ToSentryUnityOptions(false, unityInfo);
return scriptableOptions.ToSentryUnityOptions(false, SentryPlatformServices.UnityInfo);
}

return null;
Expand Down
Loading
Loading