Skip to content

Commit

Permalink
feat: Breadcrumb level (#57)
Browse files Browse the repository at this point in the history
  • Loading branch information
miquelbeltran authored Oct 22, 2024
1 parent 184834b commit 78063c5
Show file tree
Hide file tree
Showing 10 changed files with 102 additions and 14 deletions.
12 changes: 11 additions & 1 deletion src/Raygun.Blazor/Models/BreadcrumbDetails.cs
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,14 @@ public record BreadcrumbDetails
[JsonInclude]
public BreadcrumbType Type { get; set; }

/// <summary>
/// The level of the breadcrumb.
/// </summary>
/// <remarks>
/// Defaults to <see cref="BreadcrumbLevel.Info"/>.
/// </remarks>
public BreadcrumbLevel Level { get; set; } = BreadcrumbLevel.Info;

#endregion

#region Constructors
Expand All @@ -98,7 +106,8 @@ private BreadcrumbDetails()
/// <param name="category">A custom value used to arbitrarily group this Breadcrumb.</param>
/// <param name="customData">Any custom data you want to record about application state when the breadcrumb was recorded.</param>
/// <param name="platform">Specifies the platform that the breadcrumb was recorded on. Possible values are "DotNet", and "JavaScript.</param>
public BreadcrumbDetails(string? message, BreadcrumbType type = BreadcrumbType.Manual, string? category = null, Dictionary<string, object>? customData = null, string? platform = "DotNet")
/// <param name="level">Set the severity level of this breadcrumb. Defaults to <see cref="BreadcrumbLevel.Info"/>.</param>
public BreadcrumbDetails(string? message, BreadcrumbType type = BreadcrumbType.Manual, string? category = null, Dictionary<string, object>? customData = null, string? platform = "DotNet", BreadcrumbLevel level = BreadcrumbLevel.Info)
{
Message = message;
Type = type;
Expand All @@ -114,6 +123,7 @@ public BreadcrumbDetails(string? message, BreadcrumbType type = BreadcrumbType.M
ClassName = names.ClassName;
MethodName = names.MethodName;
LineNumber = stackFrame.GetFileLineNumber();
Level = level;
}

#endregion
Expand Down
33 changes: 33 additions & 0 deletions src/Raygun.Blazor/Models/BreadcrumbLevel.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
using System.Text.Json.Serialization;
using Raygun.Blazor.Converters;

namespace Raygun.Blazor.Models
{

/// <summary>
/// Specifies the different types of <see cref="BreadcrumbLevel" /> that are currently supported by the Raygun API.
/// </summary>
[JsonConverter(typeof(KebabCaseJsonStringEnumConverter<BreadcrumbLevel>))]
public enum BreadcrumbLevel
{
/// <summary>
/// Debug level breadcrumb.
/// </summary>
Debug,

/// <summary>
/// Info level breadcrumb.
/// </summary>
Info,

/// <summary>
/// Warning level breadcrumb.
/// </summary>
Warning,

/// <summary>
/// Error level breadcrumb.
/// </summary>
Error
}
}
16 changes: 14 additions & 2 deletions src/Raygun.Blazor/RaygunBlazorClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -166,19 +166,31 @@ public async Task InitializeAsync()
/// <param name="type">The <see cref="BreadcrumbType"> for the message. Defaults to <see cref="BreadcrumbType.Manual"/>.</param>
/// <param name="category">A custom value used to arbitrarily group this Breadcrumb.</param>
/// <param name="customData">Any custom data you want to record about application state when the Breadcrumb was recorded.</param>
/// <param name="level">Set the severity level of this breadcrumb. Defaults to <see cref="BreadcrumbLevel.Info"/>.</param>
/// <remarks>
/// Breadcrumbs will be queued internally by the <see cref="RaygunBlazorClient" /> and sent with the next Exception report.
/// </remarks>
/// <code>
/// TBD
/// </code>
public void RecordBreadcrumb(string? message, BreadcrumbType breadcrumbType = BreadcrumbType.Manual,
string? category = null, Dictionary<string, object>? customData = null, string? platform = "DotNet")
string? category = null, Dictionary<string, object>? customData = null, string? platform = "DotNet",
BreadcrumbLevel level = BreadcrumbLevel.Info)
{
_breadcrumbs.Add(new BreadcrumbDetails(message, breadcrumbType, category, customData, platform));
_breadcrumbs.Add(new BreadcrumbDetails(message, breadcrumbType, category, customData, platform, level));
_raygunLogger?.Verbose("[RaygunBlazorClient] Breadcrumb recorded: " + message);
}

/// <summary>
/// Records a Breadcrumb to help you track what was going on in your application before an error occurred.
/// </summary>
/// <param name="breadcrumb">Breadcrumb details object</param>
public void RecordBreadcrumb(BreadcrumbDetails breadcrumb)
{
_breadcrumbs.Add(breadcrumb);
_raygunLogger?.Verbose("[RaygunBlazorClient] Breadcrumb recorded: " + breadcrumb.Message);
}


/// <summary>
/// Queues an exception to be sent to Raygun.
Expand Down
12 changes: 7 additions & 5 deletions src/Raygun.Blazor/RaygunBrowserInterop.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public class RaygunBrowserInterop : IAsyncDisposable
private readonly RaygunSettings _raygunSettings;
private readonly IRaygunLogger? _raygunLogger;
private readonly IWindowService _windowService;
private Action<string, BreadcrumbType, string?, Dictionary<string, object>?, string?>? _breadcrumbAction;
private Action<string, BreadcrumbType, string?, Dictionary<string, object>?, string?, BreadcrumbLevel>? _breadcrumbAction;
private Func<Exception, UserDetails?, List<string>?, Dictionary<string, object>?, CancellationToken, Task>? _exceptionAction;

#endregion
Expand Down Expand Up @@ -95,19 +95,21 @@ public RaygunBrowserInterop(IJSRuntime jsRuntime, IWindowService windowService,
#region Public Methods

/// <summary>
///
/// Method invoked by JavaScript to record a breadcrumb.
/// See Raygun.Blazor.ts for more information.
/// </summary>
/// <param name="message"></param>
/// <param name="breadcrumbType"></param>
/// <param name="category"></param>
/// <param name="level"></param>
/// <param name="customData"></param>
/// <returns></returns>
[JSInvokable]
public ValueTask RecordJsBreadcrumb(string message, BreadcrumbType breadcrumbType = BreadcrumbType.Manual,
string? category = null, Dictionary<string, object>? customData = null)
string? category = null, BreadcrumbLevel level = Models.BreadcrumbLevel.Info, Dictionary<string, object>? customData = null)
{
_raygunLogger?.Verbose("[RaygunBrowserInterop] Recording breadcrumb: " + message);
_breadcrumbAction!.Invoke(message, breadcrumbType, category, customData, "JavaScript");
_breadcrumbAction!.Invoke(message, breadcrumbType, category, customData, "JavaScript", level);
return ValueTask.CompletedTask;
}

Expand Down Expand Up @@ -154,7 +156,7 @@ internal async Task<EnvironmentDetails> GetBrowserEnvironment()
/// <param name="breadcrumbAction"></param>
/// <param name="exceptionAction"></param>
internal async Task InitializeAsync(Func<ErrorEvent, Task> onUnhandledJsException,
Action<string, BreadcrumbType, string?, Dictionary<string, object>?, string?>? breadcrumbAction,
Action<string, BreadcrumbType, string?, Dictionary<string, object>?, string?, BreadcrumbLevel>? breadcrumbAction,
Func<Exception, UserDetails?, List<string>?, Dictionary<string, object>?, CancellationToken, Task>? exceptionAction)
{
_breadcrumbAction = breadcrumbAction;
Expand Down
4 changes: 2 additions & 2 deletions src/Raygun.Blazor/wwwroot/Raygun.Blazor.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@ window.raygunBlazor = {
/**
*
*/
recordBreadcrumb: function (message, category, level, customData) {
recordBreadcrumb: function (message, type, category, level, customData) {
return __awaiter(this, void 0, void 0, function* () {
yield this._raygunInterop.invokeMethodAsync('RecordJsBreadcrumb', message, category, level, customData);
yield this._raygunInterop.invokeMethodAsync('RecordJsBreadcrumb', message, type, category, level, customData);
});
},
/**
Expand Down
4 changes: 2 additions & 2 deletions src/Raygun.Blazor/wwwroot/Raygun.Blazor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@
/**
*
*/
recordBreadcrumb: async function(message: string, category: string, level: string, customData: Record<string, string>) {
await this._raygunInterop.invokeMethodAsync('RecordJsBreadcrumb', message, category, level, customData);
recordBreadcrumb: async function(message: string, type: string, category: string, level: string, customData: Record<string, string>) {
await this._raygunInterop.invokeMethodAsync('RecordJsBreadcrumb', message, type, category, level, customData);
},

/**
Expand Down
10 changes: 9 additions & 1 deletion src/Raygun.Samples.Blazor.WebAssembly/Pages/Counter.razor
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,9 @@
<button class="btn btn-primary" @onclick="@IncrementUserDetailsAsync">Handle Exception with UserDetails</button>
<button class="btn btn-primary" @onclick="@Throw">Throw Unhandled JS Exception</button>
<button class="btn btn-primary" @onclick="@(() => { var y = 0; var x = 3; var z = x / y; })">Throw .NET Exception</button>
<button class="btn btn-primary" onclick="window.raygunBlazor.recordBreadcrumb('Clicked manual button', 'click-event');">Record JS Breadcrumb</button>
<button class="btn btn-primary" onclick="window.raygunBlazor.recordBreadcrumb('Clicked manual button', 'click-event', null, 'warning', {});">Record JS Breadcrumb</button>
<button class="btn btn-primary" @onclick="@SendCustomJsException">Send Custom JS Exception</button>
<button class="btn btn-primary" @onclick="@SendCustomJsBreadcrumb">Send Custom JS Breadcrumb</button>

@code {

Expand Down Expand Up @@ -63,4 +64,11 @@
await ViewModel.SendCustomJsException();
}

protected async Task SendCustomJsBreadcrumb()
{
RaygunClient.RecordBreadcrumb(new BreadcrumbDetails(message: "Send Custom JS Breadcrumb",
type: BreadcrumbType.ClickEvent, level: BreadcrumbLevel.Debug));
await ViewModel.SendCustomJsBreadcrumb();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -62,5 +62,11 @@ public async Task SendCustomJsException()
var window = await _windowService.GetWindowAsync();
await window.PostMessageAsync("recordException");
}

public async Task SendCustomJsBreadcrumb()
{
var window = await _windowService.GetWindowAsync();
await window.PostMessageAsync("recordBreadcrumb");
}
}
}
15 changes: 15 additions & 0 deletions src/Raygun.Samples.Blazor.WebAssembly/wwwroot/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,21 @@
if (e.data == "causeError") {
causeErrors();
}

if (e.data === "recordBreadcrumb") {
window.raygunBlazor.recordBreadcrumb(
// message
'Custom JS Breadcrumb Message',
// type
'console',
// category
'manual',
// level
'debug',
// custom data
{custom: 'data'}
);
}

if (e.data == "recordException") {
let error = new Error();
Expand Down
4 changes: 3 additions & 1 deletion src/Raygun.Tests.Blazor/RaygunBlazorClientTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,8 @@ public async Task RaygunBlazorClient_BasicException_WithBreadcrumbs_ShouldSend()
var raygunClient = TestHost.Services.GetService<RaygunBlazorClient>();
raygunClient.Should().NotBeNull();

raygunClient.RecordBreadcrumb("About to send the test exception", BreadcrumbType.Manual, "Unit Tests");
raygunClient.RecordBreadcrumb("About to send the test exception", BreadcrumbType.Manual,
"Unit Tests", new Dictionary<string, object>(), "DotNet", BreadcrumbLevel.Error);

Func<Task> recordException = async () => await raygunClient.RecordExceptionAsync(new Exception("Test"));
await recordException.Should().NotThrowAsync();
Expand All @@ -206,6 +207,7 @@ public async Task RaygunBlazorClient_BasicException_WithBreadcrumbs_ShouldSend()
raygunMsg.Details.Breadcrumbs[0].Message.Should().Be("About to send the test exception");
raygunMsg.Details.Breadcrumbs[0].Type.Should().Be(BreadcrumbType.Manual);
raygunMsg.Details.Breadcrumbs[0].Category.Should().Be("Unit Tests");
raygunMsg.Details.Breadcrumbs[0].Level.Should().Be(BreadcrumbLevel.Error);
}

/// <summary>
Expand Down

0 comments on commit 78063c5

Please sign in to comment.