Skip to content

Default SentryOptions.Debug = true for Debug build configurations #4330

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

Draft
wants to merge 9 commits into
base: main
Choose a base branch
from

Conversation

jamescrosswell
Copy link
Collaborator

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

@Flash0ver any idea how I can get the source generator working in the Sentry.Tests?

I think we need some way to test this... my thinking was basically to wire up SentryTests the same way the Samples are wired up and then set expectations based on #if DEBUG, which is implicitly set by the build configuration as well.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Actually, from what I can tell it's not just in the unit tests... the source generators don't appear to be working anywhere (even in the main branch):

Copy link
Member

@Flash0ver Flash0ver Jul 9, 2025

Choose a reason for hiding this comment

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

Indeed ... @jamescrosswell and I figured out that the [Generator] is loaded correctly, and is actually executing as well in consuming projects, but we made a mistake in the implementation so that no sources are ever emitted.

{
return trimmed;
}

if (TryGetBoolean("publishaot", out var aot))
if (BuildProperties.TryGetBoolean("PublishAot", out var aot))
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I think this is a major bug that was introduced by the initial PR including the source generator...

Copy link
Member

@Flash0ver Flash0ver Jul 9, 2025

Choose a reason for hiding this comment

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

Great catch!
MSBuild is case-insensitive, and so should be the source that the [Generator] emits.
Will fix in #4331.

Copy link
Member

@Flash0ver Flash0ver Jul 10, 2025

Choose a reason for hiding this comment

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

Fixed in #4333:

Changed the generated code to use case-insensitive lookup:

-BuildProperties.Initialize(new Dictionary<string, string>()
+BuildProperties.Initialize(new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)

@@ -1324,6 +1325,18 @@ public SentryOptions()
);

NetworkStatusListener = new PollingNetworkStatusListener(this);

#if NET8_0_OR_GREATER
Copy link
Member

@Flash0ver Flash0ver Jul 9, 2025

Choose a reason for hiding this comment

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

suggestion: Remove the preprocessor directive.

User code could build a .NET Framework app or a netcoreapp or older net app, while using a .NET SDK - or another Toolchain invoking the Compiler - that is compatible with Roslyn 4.3, such as the .NET SDK 6.0.400 or above.

In this case, I don't see a reason for "Auto Debug Mode" not to work.

The only thing, that we need to make very sure of, is that the source code that our Generator emits is compatible with <LangVersion>7.3</LangVersion>, which is the default C# language version used for .NET Standard 2.0 and .NET Framework TFMs.
Or alternatively let the Generator only emit code if the consuming project supports the C# language version that our generated source code requires via CSharpParseOptions.LanguageVersion.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Looks like from #4333 we need to leave the #if clause in there but we can change it to #if NET5_0_OR_GREATER

Copy link
Member

@Flash0ver Flash0ver Jul 10, 2025

Choose a reason for hiding this comment

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

Indeed ... I was not able to remove it entirely from the generated source.
The highest dependency is ModuleInitializerAttribute, available since net5.0.

/// <param name="key">The item key</param>
/// <param name="value">The value (if any)</param>
/// <returns>True if the key was found, false otherwise</returns>
public static bool TryGetBoolean(string key, out bool value)
Copy link
Member

@Flash0ver Flash0ver Jul 9, 2025

Choose a reason for hiding this comment

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

suggestion: make internal

I don't think this needs to be accessible from the user's assembly where the Generator is emitting source to.


On the same note ... I think that the only member here, that needs to be accessible from the user's assembly, is the method Initialize(Dictionary<string, string>).

So I'm wondering if we should also make the Values property internal, since it should only be Sentry code reading it. And it's only the Initialize method that needs to be accessible for the source-generated [ModuleInitializer] to work.

Technically a breaking change, but since our source generator wasn't emitting any source code up until now, this IReadOnlyDictionary<string, string>? was always null anyways, so perhaps now may just be the time to make the Values property internal too.

Perhaps
see also https://github.com/getsentry/sentry-dotnet/pull/4330/files#r2194786902
we could make the Values property all private, so that Sentry also only access it via internal methods.

// See: https://develop.sentry.dev/sdk/expected-features/#auto-debug-mode
string? buildConfig = null;
BuildProperties.Values?.TryGetValue("Configuration", out buildConfig);
if (buildConfig == "Debug")
Copy link
Member

Choose a reason for hiding this comment

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

question: Case-sensitivity?

I wonder if this string equality check should be case insensitive 🤔

buildConfig.Equals("Debug", StringComparison.OrdinalIgnoreCase)

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I think it should, but we should configure the underlying dictionary to be case insensitive... that way we don't have to worry about it in method calls like this right?

Copy link
Member

Choose a reason for hiding this comment

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

Via #4333, the generated lookup type is now case-insensitive:

-BuildProperties.Initialize(new Dictionary<string, string>()
+BuildProperties.Initialize(new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)

So we can lookup the "Configuration" Property case-insensitively.

But comparing the Value of the "Configuration"-Property here should also be done in a case-insensitive fashion. Or am I mixing something up here 🤔?

Comment on lines +1333 to +1335
string? buildConfig = null;
BuildProperties.Values?.TryGetValue("Configuration", out buildConfig);
if (buildConfig == "Debug")
Copy link
Member

Choose a reason for hiding this comment

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

nitpick(style): Could we make this a one-liner?

I find this code a bit verbose.
Perhaps we could make this a one-liner:

if (BuildProperties.TryGetString("Configuration", out var buildConfig) && buildConfig == "Debug")

by adding a new internal method to BuildProperties:

// public static class BuildProperties

internal static bool TryGetString(string key, [NotNullWhen(true)] out string? value)
{
  if (Values?.TryGetValue(key, out var foundValue) == true)
  {
    value = foundValue;
    return true;
  }

  value = null;
  return false;
}

and perhaps we could make the BuildProperties.Values property all private, so that we only have nicely consumable methods that work around the nullability of the IReadOnlyDictionary<string, string>.

@@ -44,4 +44,12 @@
<ItemGroup Condition="'$(TargetFramework)' != 'net48'">
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="8.0.1" />
</ItemGroup>

<!-- These are needed to test the AutoDebug functionality in SentryOptions on net8.0 targets and greater -->
Copy link
Member

Choose a reason for hiding this comment

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

note: Rephrase comment.

Depending on https://github.com/getsentry/sentry-dotnet/pull/4330/files#r2194449284
it may be independent of the target framework.

Copy link
Member

@Flash0ver Flash0ver Jul 10, 2025

Choose a reason for hiding this comment

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

Couldn't make it TFM-agnostic, but lowered it in #4333:

-#if NET8_0_OR_GREATER
+#if NET5_0_OR_GREATER

due to the generated code's dependency on ModuleInitializerAttribute, added in net5.0.

@@ -675,4 +675,17 @@ public void CachesInstallationId()
installationId2.Should().Be(installationId1);
logger.Received(0).Log(SentryLevel.Debug, "Resolved installation ID '{0}'.", null, Arg.Any<string>());
}

#if NET8_0_OR_GREATER
Copy link
Member

Choose a reason for hiding this comment

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

Copy link
Member

@Flash0ver Flash0ver Jul 10, 2025

Choose a reason for hiding this comment

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

Couldn't make it TFM-agnostic, but lowered it in #4333:

-#if NET8_0_OR_GREATER
+#if NET5_0_OR_GREATER

due to the generated code's dependency on ModuleInitializerAttribute, added in net5.0.

@@ -7,6 +7,7 @@
<Import Project="$(MSBuildThisFileDirectory)..\src\Sentry.Bindings.Cocoa\buildTransitive\Sentry.Bindings.Cocoa.targets"
Condition="'$(OutputType)' == 'Exe' And ('$(TargetPlatformIdentifier)' == 'ios' Or '$(TargetPlatformIdentifier)' == 'maccatalyst')" />
<Import Project="$(MSBuildThisFileDirectory)..\src\Sentry\Platforms\Native\buildTransitive\Sentry.Native.targets" />
<Import Project="$(MSBuildThisFileDirectory)..\src\Sentry\buildTransitive\Sentry.SourceGenerators.targets" />
Copy link
Member

Choose a reason for hiding this comment

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

note: We deleted Sentry.SourceGenerators.targets in #4333.

It was redundant in the NuGet package, as only Sentry.props and Sentry.targets are automatically picked up in consuming projects (via PackageReference), and Sentry.SourceGenerators.targets was never Imported in any of these MSBuild files either.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Support Auto Debug Mode
2 participants