"Secret" elmah.io features #5 - Breadcrumbs leading up to errors

It's time for a new post in the series about "secret" elmah.io features. This is the series where I highlight features that some of you may already know while others don't. For today's post, I want to highlight a feature that turns 3 years old this week: Breadcrumbs.

Breadcrumbs is a built-in feature in all of our client integrations and the UI. Debugging what went wrong is often a lot easier by providing a logged error with a list of breadcrumbs leading up to an error. Knowing what the user did to cause an error, will let you replay the steps locally to re-create the error.

I often talk about breadcrumbs in the context of ASP.NET Core. Since this is already thoroughly documented, let's showcase breadcrumbs using another framework for this post: WinUI 3. That's right, elmah.io also supports error monitoring of Windows applications like WPF and WinUI.

For this post, I have created a new WinUI application through Visual Studio by selecting the Black App template:

I then replaced the content of the generated MainWindow.xaml file with the content of the calculator form from this WPFCalc sample. The code-behind needs a bit of tweaking to run on WinUI instead of WPF. Since the purpose of this post is not a tutorial on porting WPF to WinUI or WinUI development in general, I'll skip any additional details here. Interesting code snippets from the converted project will appear in just a minute.

Before we can start storing breadcrumbs from WinUI, we will need to install the Elmah.Io.WinUI package:

dotnet add package Elmah.Io.WinUI --prerelease

Next, add the elmah.io initialization code to the App.xaml.cs file:

public App()
{
    ElmahIoWinUI.Init(new ElmahIoWinUIOptions("API_KEY", new Guid("LOG_ID")));
    this.InitializeComponent();
}

All uncaught exceptions from WinUI are now stored in elmah.io. The full set of possibilities is documented in Logging to elmah.io from WinUI.

Let's see the application in action:

Nice! A working calculator in WinUI. It might not out-compete Windows' built-in calculator but we now have something that we can crash. WPFCalc handles a DivideByZeroException when clicking the equals button so I'll go ahead and comment out that part of the code:

private void btnEquals_Click(object sender, RoutedEventArgs e)
{
    if (CurrentOperation == null)
        return;

    if (txtInput.Text == "")
        return;

    //SecondValue is used for multiple clicks on Equals bringing the newest result of last operation
    decimal val2 = SecondValue ?? Convert.ToDecimal(txtInput.Text);
    //try
    //{
    txtInput.Text = (FirstValue = CurrentOperation.DoOperation(FirstValue, (decimal)(SecondValue = val2))).ToString();
    //}
    //catch(DivideByZeroException)
    //{
    //    MessageBox.Show("Can't divide by zero", "Divided by zero", MessageBoxButton.OK, MessageBoxImage.Error);
    //    btnClearAll.PerformClick();
    //}
}

When trying to divide by zero, we now see the application crashing and the error logged to elmah.io:

Let's add some breadcrumbs. We'll add a breadcrumb when the calculator window is launched as well as when clicking any of the buttons. Like in the initialization code, I'll use ElmahIoWinUI to add the breadcrumb by adding the following line in the OnLaunched method in the App.xaml.cs file:

protected override void OnLaunched(Microsoft.UI.Xaml.LaunchActivatedEventArgs args)
{
    m_window = new MainWindow();
    m_window.Activate();
    // ⬇️ This is where the magic happens
    ElmahIoWinUI.AddBreadcrumb(new Elmah.Io.Client.Breadcrumb(
        DateTimeOffset.UtcNow,
        "Information",
        "navigation",
        "MainWindow loaded"));
}

The interesting line is when calling the AddBreadcrumb method. This will build an in-memory list of steps, well breadcrumbs, that are sent alongside any potential exceptions happening later on. The breadcrumb consists of a date, a severity, an action (navigation in this instance), and a textual description of what happened.

I'll extend three methods in the calculator window with breadcrumbs too:

private void SendToInput(string content)
{
    // ...

    // ⬇️
    ElmahIoWinUI.AddBreadcrumb(new Elmah.Io.Client.Breadcrumb(
        DateTimeOffset.UtcNow,
        "Information",
        "click",
        $"{content} button clicked"));
}

private void operationButton_Click(object sender, RoutedEventArgs e)
{
    // ...

    // ⬇️
    ElmahIoWinUI.AddBreadcrumb(new Elmah.Io.Client.Breadcrumb(
        DateTimeOffset.UtcNow,
        "Information",
        "click",
        $"{CurrentOperation.GetType().Name} button clicked"));
}

private void btnEquals_Click(object sender, RoutedEventArgs e)
{
    // ...

    // ⬇️
    ElmahIoWinUI.AddBreadcrumb(new Elmah.Io.Client.Breadcrumb(
        DateTimeOffset.UtcNow,
        "Information",
        "click",
        "Equals button clicked"));

    // ...
}

All of the added breadcrumbs include a click action and a message indicating what the user clicked.

When causing a new error, we can inspect the breadcrumbs in elmah.io:

I hope this small demo has initiated some thoughts about the possibilities and benefits of decorating errors with breadcrumbs. All of our client integrations support breadcrumbs in either an automated way or manually as in the example in this post.