Skip to content

Commit

Permalink
Merge pull request #19 from MindscapeHQ/sean/maui-offline-store
Browse files Browse the repository at this point in the history
Add offline crash report storage for MAUI
  • Loading branch information
xenolightning committed Jun 9, 2024
2 parents b606bb9 + 83f7883 commit fff1a1d
Show file tree
Hide file tree
Showing 6 changed files with 144 additions and 25 deletions.
8 changes: 8 additions & 0 deletions CHANGE-LOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
# Full Change Log for Raygun4Maui package

### v2.1.0
- Version bump to `Raygun4Net.NetCore v11.0.0`
- Added support for capturing debug information for PDB symbolication
- This is automatically captured for supported platforms
- Currently, there is limited Android support, due to the changes with single file assembly stores
- Added support for storing crash reports offline when exceptions fail to send to the Raygun API
- See [README.md](https://github.com/MindscapeHQ/raygun4maui/blob/master/README.md#offline-storage) for more information and usage documentation

### v2.0.1
Version bump to Raygun4Net.NetCore v10.1.2
- Fix issue where uncaught exceptions could sometimes not be reported to Raygun
Expand Down
62 changes: 50 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -232,22 +232,60 @@ Raygun4Maui will automatically collect information specific to the environment t
- on iOS, Raygun4Maui cannot obtain the device's name. This is a privacy restriction put in place by Apple. If you would like this information to be collected and sent with crash reports you will have to [request for permission from apple](https://developer.apple.com/documentation/bundleresources/entitlements/com_apple_developer_device-information_user-assigned-device-name?language=objc).
- The `Total physical memory` and `Available physical memory` properties mean different things across platforms. Below is a table explaining the differences for each platform.

| Platform | Total physical memory | Available physical memory |
| ----- | ---- | ------- |
| Mac | Total installed ram | Total memory available for user-level processes |
| iOS | Total installed ram | Total memory available for user-level processes |
| Windows |Total installed ram | Total amount of private memory used by the process at the time of the measurement. For a number of reasons this might not be the actual total memory usage |
| Android |Total amount of memory that the JVM has allocated for the application | Total amount of free memory that the JVM has available for the application to use |
| Platform | Total physical memory | Available physical memory |
|----------|-----------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------|
| Mac | Total installed ram | Total memory available for user-level processes |
| iOS | Total installed ram | Total memory available for user-level processes |
| Windows | Total installed ram | Total amount of private memory used by the process at the time of the measurement. For a number of reasons this might not be the actual total memory usage |
| Android | Total amount of memory that the JVM has allocated for the application | Total amount of free memory that the JVM has available for the application to use |


### Networking

| Platform | Networking support | Conditions |
| ----- |--------------------|--------------------------------------------------|
| Mac | Yes | HttpClient, NSURLSession, and NSURLConnection |
| iOS | Yes | HttpClient, NSURLSession, and NSURLConnection |
| Windows | Yes | HttpClient |
| Android | Yes | HttpURLConnection (see SampleApp) |
| Platform | Networking support | Conditions |
|----------|--------------------|-----------------------------------------------|
| Mac | Yes | HttpClient, NSURLSession, and NSURLConnection |
| iOS | Yes | HttpClient, NSURLSession, and NSURLConnection |
| Windows | Yes | HttpClient |
| Android | Yes | HttpURLConnection (see SampleApp) |

---

## Offline Storage

You can optionally specify an Offline Store for crash reports when creating your `Raygun4MauiClient`.

When an offline store is specified, if there are any issues sending an exception to the Raygun API, a copy of the exception may be stored locally to be retried at a later date.

An exception is stored offline when one of the following conditions are met:
- There was a network connectivity issue, e.g. no active internet connection on a mobile device
- The Raygun API responded with an HTTP 5xx, indicating an unexpected server error


### Configuration

```csharp
// This will initialize Raygun with the default Application Data Store
mauiAppBuilder.AddRaygun(options =>
{
options.UseOfflineStorage();
});
```

You can also define the background send strategy and store separately

```csharp
// Attempt to send any offline crash reports every 30 seconds
var sendStrategy = new TimerBasedSendStrategy(TimeSpan.FromSeconds(30));

// Store crash reports in directory relative to the Application (`FileSystem.AppDataDirectory`)
var offlineStore = new RaygunMauiOfflineStore(sendStrategy);

mauiAppBuilder.AddRaygun(options =>
{
options.OfflineStore = offlineStore;
});
```

---
## Development Instructions
Expand Down
11 changes: 5 additions & 6 deletions Raygun4Maui.SampleApp/MauiProgram.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
using System.Diagnostics;
using System.Reflection;
using System.Reflection;
using Microsoft.Extensions.Configuration;
using Microsoft.Maui.Controls.Hosting;
using Mindscape.Raygun4Net;
using Raygun4Net.RaygunLogger;
using Serilog;

namespace Raygun4Maui.SampleApp;
Expand Down Expand Up @@ -31,7 +27,10 @@ public static MauiApp CreateMauiApp()
fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold");
})
.AddRaygun();
.AddRaygun(options =>
{
options.UseOfflineStorage();
});


builder.Services.AddSingleton<MainPage>();
Expand Down
6 changes: 3 additions & 3 deletions Raygun4Maui/Raygun4Maui.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@
<TargetPlatformMinVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'windows'">10.0.17763.0</TargetPlatformMinVersion>
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'tizen'">6.5</SupportedOSPlatformVersion>
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
<Version>2.0.1</Version>
<PackageVersion>2.0.1</PackageVersion>
<Version>2.1.0</Version>
<PackageVersion>2.1.0</PackageVersion>
<Authors>Raygun</Authors>
<Company>Raygun</Company>
<PackageReadmeFile>README.md</PackageReadmeFile>
Expand Down Expand Up @@ -106,7 +106,7 @@

<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Hosting" Version="7.0.1"/>
<PackageReference Include="Mindscape.Raygun4Net.NetCore" Version="10.1.2" />
<PackageReference Include="Mindscape.Raygun4Net.NetCore" Version="11.0.0" />
</ItemGroup>

<ItemGroup Condition="'$(TargetFramework)' == 'net7.0-android'">
Expand Down
43 changes: 39 additions & 4 deletions Raygun4Maui/Raygun4MauiExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
using Microsoft.Extensions.Configuration;
#nullable enable
using Microsoft.Extensions.Configuration;
using Microsoft.Maui.LifecycleEvents;
using Mindscape.Raygun4Net;
using Mindscape.Raygun4Net.Breadcrumbs;
using Mindscape.Raygun4Net.Offline;
using Raygun4Maui.DeviceIdProvider;
using Raygun4Maui.MauiRUM.AppLifecycleHandlers;
using Raygun4Net.RaygunLogger;
Expand Down Expand Up @@ -44,8 +46,7 @@ public static MauiAppBuilder AddRaygun(
/// <param name="mauiAppBuilder"></param>
/// <param name="options">Used to apply changes to a pulled in or default Raygun4MauiSettings object</param>
/// <returns></returns>
public static MauiAppBuilder AddRaygun(this MauiAppBuilder mauiAppBuilder,
Action<Raygun4MauiSettings> options = null)
public static MauiAppBuilder AddRaygun(this MauiAppBuilder mauiAppBuilder, Action<Raygun4MauiSettings>? options = null)
{
var settings = mauiAppBuilder.Configuration.GetSection("Raygun4MauiSettings").Get<Raygun4MauiSettings>() ??
new Raygun4MauiSettings();
Expand All @@ -66,7 +67,41 @@ public static MauiAppBuilder AddRaygunUserProvider<T>(this MauiAppBuilder mauiAp
mauiAppBuilder.Services.AddSingleton<IRaygunMauiUserProvider, T>();
return mauiAppBuilder;
}


/// <summary>
/// Sets the offline store, and a timer to attempt to send any offline crashes at the interval specified. Default 30 seconds.
/// </summary>
/// <param name="mauiSettings"></param>
/// <param name="interval"></param>
/// <returns></returns>
public static Raygun4MauiSettings UseOfflineStorage(this Raygun4MauiSettings mauiSettings, TimeSpan? interval = null)
{
return mauiSettings.UseOfflineStorage(new TimerBasedSendStrategy(interval));
}

/// <summary>
/// Sets the offline store, and the internal sending strategy to that specified
/// </summary>
/// <param name="mauiSettings"></param>
/// <param name="backgroundSendStrategy"></param>
/// <returns></returns>
public static Raygun4MauiSettings UseOfflineStorage(this Raygun4MauiSettings mauiSettings, IBackgroundSendStrategy backgroundSendStrategy)
{
return mauiSettings.UseOfflineStorage(new RaygunMauiOfflineStore(backgroundSendStrategy));
}

/// <summary>
/// Specify a custom implementation of the offline store to store any crash reports that could not be sent due to connectivity or server issues
/// </summary>
/// <param name="mauiSettings"></param>
/// <param name="offlineStore"></param>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public static Raygun4MauiSettings UseOfflineStorage<T>(this Raygun4MauiSettings mauiSettings, T offlineStore) where T : OfflineStoreBase
{
mauiSettings.RaygunSettings.OfflineStore = offlineStore;
return mauiSettings;
}

private static MauiAppBuilder AddRaygunRum(this MauiAppBuilder mauiAppBuilder)
{
Expand Down
39 changes: 39 additions & 0 deletions Raygun4Maui/RaygunMauiOfflineStore.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
using Mindscape.Raygun4Net.Offline;
using Mindscape.Raygun4Net.Storage;

namespace Raygun4Maui;

/// <summary>
/// Represents a crash report store specifically for Raygun in a MAUI application,
/// utilizing the file system to store crash reports offline.
/// </summary>
public sealed class RaygunMauiOfflineStore : FileSystemCrashReportStore
{
private const string OfflineStoreId = "raygun.offline-store-id";

/// <summary>
/// Initializes a new instance of the <see cref="RaygunMauiOfflineStore"/> class.
/// </summary>
/// <param name="backgroundSendStrategy">The strategy used to send crash reports in the background.</param>
/// <param name="maxOfflineFiles">The maximum number of offline files to store. Default is 50.</param>
public RaygunMauiOfflineStore(IBackgroundSendStrategy backgroundSendStrategy, int maxOfflineFiles = 50)
: base(backgroundSendStrategy, GetLocalAppDirectory(), maxOfflineFiles)
{
}

private static string GetLocalAppDirectory()
{
return Path.Combine(FileSystem.AppDataDirectory, GetOrCreateStoreId());
}

private static string GetOrCreateStoreId()
{
var storeId = Preferences.Get(OfflineStoreId, null);
if (string.IsNullOrEmpty(storeId))
{
storeId = Guid.NewGuid().ToString("N");
Preferences.Set(OfflineStoreId, storeId);
}
return storeId;
}
}

0 comments on commit fff1a1d

Please sign in to comment.