Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
- Remove `IDisposable` from `SentryStructuredLogger`. Disposal is intended through the owning `IHub` instance ([#4424](https://github.com/getsentry/sentry-dotnet/pull/4424))
- Ensure all buffered logs are sent to Sentry when the application terminates unexpectedly ([#4425](https://github.com/getsentry/sentry-dotnet/pull/4425))
- `InvalidOperationException` potentially thrown during a race condition, especially in concurrent high-volume logging scenarios ([#4428](https://github.com/getsentry/sentry-dotnet/pull/4428))
- Only detects custom session replay masks when necessary to avoid performance issues in MAUI apps with complex UIs ([#4445](https://github.com/getsentry/sentry-dotnet/pull/4445))

### Dependencies

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,25 +9,40 @@ namespace Sentry.Maui.Internal;
/// <summary>
/// Masks or unmasks visual elements for session replay recordings
/// </summary>
internal class MauiVisualElementEventsBinder : IMauiElementEventBinder
internal class MauiCustomSessionReplayMaskBinder : IMauiElementEventBinder
{
private readonly SentryMauiOptions _options;
private readonly bool _isEnabled;

public MauiVisualElementEventsBinder(IOptions<SentryMauiOptions> options)
public MauiCustomSessionReplayMaskBinder(IOptions<SentryMauiOptions> options)
{
_options = options.Value;
#if __ANDROID__
var replayOptions = _options.Native.ExperimentalOptions.SessionReplay;
_isEnabled = (replayOptions.SessionSampleRate > 0.0 || replayOptions.OnErrorSampleRate > 0.0)
&& replayOptions is not { MaskAllImages: true, MaskAllText: true }
&& !replayOptions.DisableCustomSessionReplayMasks;
#else
_isEnabled = false; // Session replay is only supported on Android for now
#endif
}

/// <inheritdoc />
public void Bind(VisualElement element, Action<BreadcrumbEvent> _)
{
element.Loaded += OnElementLoaded;
if (_isEnabled)
{
element.Loaded += OnElementLoaded;
}
}

/// <inheritdoc />
public void UnBind(VisualElement element)
{
element.Loaded -= OnElementLoaded;
if (_isEnabled)
{
element.Loaded -= OnElementLoaded;
}
}

internal void OnElementLoaded(object? sender, EventArgs _)
Expand Down
2 changes: 1 addition & 1 deletion src/Sentry.Maui/SentryMauiAppBuilderExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ public static MauiAppBuilder UseSentry(this MauiAppBuilder builder,
services.AddSingleton<IMauiElementEventBinder, MauiButtonEventsBinder>();
services.AddSingleton<IMauiElementEventBinder, MauiImageButtonEventsBinder>();
services.AddSingleton<IMauiElementEventBinder, MauiGestureRecognizerEventsBinder>();
services.AddSingleton<IMauiElementEventBinder, MauiVisualElementEventsBinder>();
services.AddSingleton<IMauiElementEventBinder, MauiCustomSessionReplayMaskBinder>();

// Resolve the configured options and register any event binders that have been injected by integrations
var options = new SentryMauiOptions();
Expand Down
24 changes: 24 additions & 0 deletions src/Sentry/Platforms/Android/NativeOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,30 @@ public class NativeSentryReplayOptions
public double? SessionSampleRate { get; set; }
public bool MaskAllImages { get; set; } = true;
public bool MaskAllText { get; set; } = true;

/// <summary>
/// <para>
/// Apps with complex user interfaces, consisting of hundreds of visual controls on a single page, may experience
/// performance issues due to the overhead of detecting custom masking of visual elements for Session Replays.
/// </para>
/// <para>
/// In such cases you have a few different options:
/// <list type="bullet">
/// <item>
/// <description>Disable Session Replays entirely</description>
/// </item>
/// <item>
/// <description>Mask all text and all images</description>
/// </item>
/// <item>
/// <description>Disable custom session replay masks (so nothing gets masked)</description>
/// </item>
/// </list>
/// Set this option to <c>true</c> to disable custom session replay masks.
/// </para>
/// </summary>
public bool DisableCustomSessionReplayMasks { get; set; } = false;

internal HashSet<Type> MaskedControls { get; } = [];
internal HashSet<Type> UnmaskedControls { get; } = [];

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@

namespace Sentry.Maui.Tests;

public class MauiVisualElementEventsBinderTests
public class MauiCustomSessionReplayMaskBinderTests
{
private class Fixture
{
public MauiVisualElementEventsBinder Binder { get; }
public MauiCustomSessionReplayMaskBinder Binder { get; }

public SentryMauiOptions Options { get; } = new();

Expand All @@ -21,7 +21,7 @@ public Fixture()
logger.IsEnabled(Arg.Any<SentryLevel>()).Returns(true);
Options.DiagnosticLogger = logger;
var options = Microsoft.Extensions.Options.Options.Create(Options);
Binder = new MauiVisualElementEventsBinder(options);
Binder = new MauiCustomSessionReplayMaskBinder(options);
}
}

Expand Down
Loading