Skip to content

feat: sync environment to the native layers#5365

Draft
bitsandfoxes wants to merge 7 commits into
mainfrom
feat/sync-scope-environment
Draft

feat: sync environment to the native layers#5365
bitsandfoxes wants to merge 7 commits into
mainfrom
feat/sync-scope-environment

Conversation

@bitsandfoxes

Copy link
Copy Markdown
Contributor

Since the scope exposes Environment to be overwritten after initialization, this needs to be propagated to the respective native layers. sentry-native and sentry-cocoa already accept this. I'll follow up on sentry-java.

@github-actions github-actions Bot added the risk: medium PR risk score: medium label Jul 9, 2026

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit cc9de07. Configure here.

Comment thread src/Sentry/Scope.cs
Comment thread src/Sentry/Platforms/Native/CFunctions.cs
@bitsandfoxes bitsandfoxes marked this pull request as draft July 9, 2026 17:41
Comment thread src/Sentry/IScopeObserver.cs
/// <summary>
/// Sets the environment.
/// </summary>
public void SetEnvironment(string? environment);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

thought: interface vs abstract class

Making the ScopeObserver an interface, rather than an abstract class, is a design decision that is haunting us now: we continuously add new (non-default) members to it in minor versions, which is breaking user code when implementing their own ScopeObserver ... arguably the ScopeObserver it a more niche use case .. but source breaking nonetheless.

I wonder if an abstract class would have alleviated this problem, with which we could add new virtual members with an empty implementation, that user code might then override, but does not have to.

Changing this interface into an abstract class now would be even more unexpectedly breaking. But something to consider for every public interface that we expose in the future.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

We could make the change in the next major version... I think it's a good suggestion. We can mock/substitute abstract classes just as well as interfaces.

@bitsandfoxes bitsandfoxes Jul 10, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I understand the "technically source breaking" argument but we have this discussion every time I make changes to the interface. The thing should go being internal in the next major and we'd be done with it.

For what it's worth we're not really breaking user code. This is a hypothetical. The ScopeObserver is public because when we added it we had no other mechanism to make it available to sentry-unity and not because it's some load-bearing functionality we're expecting users to use in the first place.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Can / should we make IScopeObserver internal,
since we're exposing this feature to user code:

/// <summary>
/// A scope set outside of Sentry SDK. If set, the global parameters from the SDK's scope will be sent to the observed scope.<br/>
/// NOTE: EnableScopeSync must be set true for the scope to be synced.
/// </summary>
public IScopeObserver? ScopeObserver { get; set; }
/// <summary>
/// If true, the SDK's scope will be synced with the observed scope.
/// </summary>
public bool EnableScopeSync { get; set; }

Users might today already provide their own Scope-Observer.

The AndroidScopeObserver and CocoaScopeObserver do wrap any Options/User-provided IScopeObserver.
But the NativeScopeObserver does not, and just overwrites any user-provided IScopeObserver.

So we do have a bit of an incomplete story here.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

The wrapping is happening because you guys asked me to respect any potentially added ScopeObserver since it is public. Fair enough. But that should not be a precedence of us having to support this or not change it. We have a very limited set of hooks that we want to support on the SDK, right? Where users are supposed to filter, mutate or drop data/events, i.e. in Init and all those Before_X callbacks, the X_Samplers. The ScopeObserver is an outlier built out of necessity.
Like what problem is this supposed to solve for the user? How is the user supposed to use this? They want to receive a callback when they are setting something (but not everything) on the scope?

We can continue weighing the pros and cons of dropping it in #4529

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

sounds good ... I actually didn't quite intend to spawn off a heavy discussion on this ... just wanted to note, that for the next public interface we design, we should consider making it an abstract class if it's going to "evolve"

Comment thread src/Sentry/Scope.cs
/// <inheritdoc />
public string? Distribution { get; set; }

private string? _environment;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

nitpick: could use field keyword instead of explicit backing field

If we don't use the _environment backing field anywhere outside of the Environment property accessors, with C# 14.0, we could remove that explicit backing field, and use "field backed properties" instead.

See https://learn.microsoft.com/dotnet/csharp/whats-new/csharp-14#the-field-keyword

@github-actions github-actions Bot added the public API Additions/modifications to, or removals from, the public API surface area. label Jul 10, 2026
@codecov

codecov Bot commented Jul 10, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 72.22222% with 5 lines in your changes missing coverage. Please review.
✅ Project coverage is 74.22%. Comparing base (4b51c11) to head (b4821a3).
⚠️ Report is 5 commits behind head on main.

Files with missing lines Patch % Lines
src/Sentry/Internal/ScopeObserver.cs 0.00% 4 Missing ⚠️
src/Sentry/Platforms/Native/NativeScopeObserver.cs 0.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #5365      +/-   ##
==========================================
+ Coverage   74.14%   74.22%   +0.08%     
==========================================
  Files         509      509              
  Lines       18386    18428      +42     
  Branches     3600     3608       +8     
==========================================
+ Hits        13633    13679      +46     
+ Misses       3880     3875       -5     
- Partials      873      874       +1     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

public API Additions/modifications to, or removals from, the public API surface area. risk: medium PR risk score: medium

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants