Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
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 @@ -10,6 +10,7 @@

- InvalidCastException in SentrySpanProcessor when using the Sentry.OpenTelemetry integration ([#4245](https://github.com/getsentry/sentry-dotnet/pull/4245))
- Fix InApp Exclude for frames without Module by checking against frame's Package ([#4236](https://github.com/getsentry/sentry-dotnet/pull/4236))
- ExtraData not captured for Breadcrumbs in MauiEventsBinder ([#4254](https://github.com/getsentry/sentry-dotnet/pull/4254))

## 5.9.0

Expand Down
50 changes: 50 additions & 0 deletions src/Sentry.Maui/BreadcrumbEvent.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
namespace Sentry.Maui;

/// <summary>
/// Argument to the OnBreadcrumbCreateCallback
/// </summary>
public sealed class BreadcrumbEvent
{
/// <summary>
/// The sender of the event, usually the control that triggered it.
/// </summary>
public object? Sender { get; }

/// <summary>
/// The event name (e.g. "Tapped", "Swiped", etc.)
/// </summary>
public string EventName { get; }

/// <summary>
/// Any extra data to be included in the breadcrumb. This would typically be event specific information (for example
/// it could include the X, Y coordinates of a tap event).
/// </summary>
public (string Key, string Value)[] ExtraData { get; }

/// <summary>
/// Creates a new BreadcrumbEvent
/// </summary>
public BreadcrumbEvent(
object? sender,
string eventName,
params (string Key, string Value)[] extraData)
{
Sender = sender;
EventName = eventName;
ExtraData = extraData;
}

/// <summary>
/// This constructor remains for backward compatibility.
/// </summary>
/// <param name="sender"></param>
/// <param name="eventName"></param>
/// <param name="extraData"></param>
[Obsolete("Use the simpler constructor with params (string Key, string Value)[] extraData instead.")]
public BreadcrumbEvent(
object? sender,
string eventName,
IEnumerable<(string Key, string Value)>[] extraData) : this(sender, eventName, extraData.SelectMany(e => e).ToArray())
{
}
}
12 changes: 0 additions & 12 deletions src/Sentry.Maui/IMauiElementEventBinder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,3 @@ public interface IMauiElementEventBinder
/// <param name="element"></param>
public void UnBind(VisualElement element);
}

/// <summary>
/// Breadcrumb arguments
/// </summary>
/// <param name="Sender"></param>
/// <param name="EventName"></param>
/// <param name="ExtraData"></param>
public record BreadcrumbEvent(
object? Sender,
string EventName,
params IEnumerable<(string Key, string Value)>[] ExtraData
);
9 changes: 8 additions & 1 deletion src/Sentry.Maui/Internal/MauiEventsBinder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,14 @@ internal void OnBreadcrumbCreateCallback(BreadcrumbEvent breadcrumb)
breadcrumb.Sender,
breadcrumb.EventName,
UserType,
UserActionCategory
UserActionCategory,
extra =>
{
foreach (var (key, value) in breadcrumb.ExtraData)
{
extra[key] = value;
}
}
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ private static void OnPointerEnteredGesture(object? sender, PointerEventArgs e)
ToPointerData(e)
));

private static IEnumerable<(string Key, string Value)> ToPointerData(PointerEventArgs e) =>
private static (string Key, string Value)[] ToPointerData(PointerEventArgs e) =>
[
#if ANDROID
("MotionEventAction", e.PlatformArgs?.MotionEvent.Action.ToString() ?? string.Empty)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,22 @@ namespace Microsoft.Maui.Hosting
}
namespace Sentry.Maui
{
public class BreadcrumbEvent : System.IEquatable<Sentry.Maui.BreadcrumbEvent>
public sealed class BreadcrumbEvent
{
public BreadcrumbEvent(object? Sender, string EventName, [System.Runtime.CompilerServices.TupleElementNames(new string[] {
[System.Obsolete("Use the simpler constructor with params (string Key, string Value)[] extraData in" +
"stead.")]
public BreadcrumbEvent(object? sender, string eventName, [System.Runtime.CompilerServices.TupleElementNames(new string[] {
"Key",
"Value"})] params System.Collections.Generic.IEnumerable<System.ValueTuple<string, string>>[] ExtraData) { }
public string EventName { get; init; }
"Value"})] System.Collections.Generic.IEnumerable<System.ValueTuple<string, string>>[] extraData) { }
public BreadcrumbEvent(object? sender, string eventName, [System.Runtime.CompilerServices.TupleElementNames(new string[] {
"Key",
"Value"})] params System.ValueTuple<string, string>[] extraData) { }
public string EventName { get; }
[System.Runtime.CompilerServices.TupleElementNames(new string[] {
"Key",
"Value"})]
public System.Collections.Generic.IEnumerable<System.ValueTuple<string, string>>[] ExtraData { get; init; }
public object? Sender { get; init; }
public System.ValueTuple<string, string>[] ExtraData { get; }
public object? Sender { get; }
}
public interface IMauiElementEventBinder
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,22 @@ namespace Microsoft.Maui.Hosting
}
namespace Sentry.Maui
{
public class BreadcrumbEvent : System.IEquatable<Sentry.Maui.BreadcrumbEvent>
public sealed class BreadcrumbEvent
{
public BreadcrumbEvent(object? Sender, string EventName, [System.Runtime.CompilerServices.TupleElementNames(new string[] {
[System.Obsolete("Use the simpler constructor with params (string Key, string Value)[] extraData in" +
"stead.")]
public BreadcrumbEvent(object? sender, string eventName, [System.Runtime.CompilerServices.TupleElementNames(new string[] {
"Key",
"Value"})] params System.Collections.Generic.IEnumerable<System.ValueTuple<string, string>>[] ExtraData) { }
public string EventName { get; init; }
"Value"})] System.Collections.Generic.IEnumerable<System.ValueTuple<string, string>>[] extraData) { }
public BreadcrumbEvent(object? sender, string eventName, [System.Runtime.CompilerServices.TupleElementNames(new string[] {
"Key",
"Value"})] params System.ValueTuple<string, string>[] extraData) { }
public string EventName { get; }
[System.Runtime.CompilerServices.TupleElementNames(new string[] {
"Key",
"Value"})]
public System.Collections.Generic.IEnumerable<System.ValueTuple<string, string>>[] ExtraData { get; init; }
public object? Sender { get; init; }
public System.ValueTuple<string, string>[] ExtraData { get; }
public object? Sender { get; }
}
public interface IMauiElementEventBinder
{
Expand Down
28 changes: 28 additions & 0 deletions test/Sentry.Maui.Tests/BreadcrumbEventTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
using System.Collections.Generic;
using FluentAssertions;
using Xunit;

namespace Sentry.Maui.Tests;

public class BreadcrumbEventTests
{
[Fact]
public void BreadcrumbEvent_OldConstructor_EquivalentToNewConstructor()
{
// Arrange
var sender = new object();
var eventName = "TestEvent";

// Act
IEnumerable<(string Key, string Value)>[] extraData = [[("key1", "value1")], [("key2", "value2")]];
#pragma warning disable CS0618 // Type or member is obsolete
var oldEvent = new BreadcrumbEvent(sender, eventName, extraData);
#pragma warning restore CS0618 // Type or member is obsolete
var newEvent = new BreadcrumbEvent(sender, eventName, ("key1", "value1"), ("key2", "value2"));

// Assert
oldEvent.Sender.Should().Be(newEvent.Sender);
oldEvent.EventName.Should().Be(newEvent.EventName);
oldEvent.ExtraData.Should().BeEquivalentTo(newEvent.ExtraData);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@

namespace Sentry.Maui.Tests;

public partial class MauiEventsBinderTests
public class MauiButtonEventsBinderTests
{
private readonly MauiEventsBinderFixture _fixture = new(new MauiButtonEventsBinder());

[Theory]
[InlineData(nameof(Button.Clicked))]
[InlineData(nameof(Button.Pressed))]
Expand Down
37 changes: 37 additions & 0 deletions test/Sentry.Maui.Tests/MauiEventsBinderFixture.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
using Sentry.Maui.Internal;

namespace Sentry.Maui.Tests;

internal class MauiEventsBinderFixture
{
public IHub Hub { get; }

public MauiEventsBinder Binder { get; }

public Scope Scope { get; } = new();

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

public MauiEventsBinderFixture(params IEnumerable<IMauiElementEventBinder> elementEventBinders)
{
Hub = Substitute.For<IHub>();
Hub.When(h => h.ConfigureScope(Arg.Any<Action<Scope>>()))
.Do(c =>
{
c.Arg<Action<Scope>>()(Scope);
});

Scope.Transaction = Substitute.For<ITransactionTracer>();

Options.Debug = true;
var logger = Substitute.For<IDiagnosticLogger>();
logger.IsEnabled(Arg.Any<SentryLevel>()).Returns(true);
Options.DiagnosticLogger = logger;
var options = Microsoft.Extensions.Options.Options.Create(Options);
Binder = new MauiEventsBinder(
Hub,
options,
elementEventBinders
);
}
}
58 changes: 24 additions & 34 deletions test/Sentry.Maui.Tests/MauiEventsBinderTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,45 +4,35 @@ namespace Sentry.Maui.Tests;

public partial class MauiEventsBinderTests
{
private class Fixture
{
public IHub Hub { get; }
private readonly MauiEventsBinderFixture _fixture = new();

public MauiEventsBinder Binder { get; }
// Most of the tests for this class are in separate partial class files for better organisation

public Scope Scope { get; } = new();
[Fact]
public void OnBreadcrumbCreateCallback_CreatesBreadcrumb()
{
// Arrange
var breadcrumbEvent = new BreadcrumbEvent(new object(), "TestName",
("key1", "value1"), ("key2", "value2")
);

public SentryMauiOptions Options { get; } = new();
// Act
_fixture.Binder.OnBreadcrumbCreateCallback(breadcrumbEvent);

public Fixture()
// Assert
using (new AssertionScope())
{
Hub = Substitute.For<IHub>();
Hub.When(h => h.ConfigureScope(Arg.Any<Action<Scope>>()))
.Do(c =>
{
c.Arg<Action<Scope>>()(Scope);
});

Scope.Transaction = Substitute.For<ITransactionTracer>();

Options.Debug = true;
var logger = Substitute.For<IDiagnosticLogger>();
logger.IsEnabled(Arg.Any<SentryLevel>()).Returns(true);
Options.DiagnosticLogger = logger;
var options = Microsoft.Extensions.Options.Options.Create(Options);
Binder = new MauiEventsBinder(
Hub,
options,
[
new MauiButtonEventsBinder(),
new MauiImageButtonEventsBinder(),
new MauiGestureRecognizerEventsBinder()
]
);
var crumb = Assert.Single(_fixture.Scope.Breadcrumbs);
Assert.Equal("Object.TestName", crumb.Message);
Assert.Equal(BreadcrumbLevel.Info, crumb.Level);
Assert.Equal(MauiEventsBinder.UserType, crumb.Type);
Assert.Equal(MauiEventsBinder.UserActionCategory, crumb.Category);
Assert.NotNull(crumb.Data);
Assert.Equal(breadcrumbEvent.ExtraData.Length, crumb.Data.Count);
foreach (var (key, value) in breadcrumbEvent.ExtraData)
{
crumb.Data.Should().Contain(kvp => kvp.Key == key && kvp.Value == value);
}
}
}

private readonly Fixture _fixture = new();

// Tests are in partial class files for better organization
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@

namespace Sentry.Maui.Tests;

public partial class MauiEventsBinderTests
public class MauiGestureRecognizerEventsBinderTests
{
private readonly MauiEventsBinderFixture _fixture = new(new MauiGestureRecognizerEventsBinder());

[SkippableFact]
public void TapGestureRecognizer_LifecycleEvents_AddsBreadcrumb()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@

namespace Sentry.Maui.Tests;

public partial class MauiEventsBinderTests
public class MauiImageButtonEventsBinderTests
{
private readonly MauiEventsBinderFixture _fixture = new(new MauiImageButtonEventsBinder());

[Theory]
[InlineData(nameof(ImageButton.Clicked))]
[InlineData(nameof(ImageButton.Pressed))]
Expand Down
Loading