Skip to content

Commit

Permalink
Merge pull request #16 from MindscapeHQ/ro/ps-99/maui-rum-spike
Browse files Browse the repository at this point in the history
RUM Support for Raygun4Maui
  • Loading branch information
ProRedCat committed Apr 23, 2024
2 parents 996531f + 2e353e3 commit 637912c
Show file tree
Hide file tree
Showing 107 changed files with 3,835 additions and 470 deletions.
48 changes: 48 additions & 0 deletions CHANGE-LOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,53 @@
# Full Change Log for Raygun4Maui package

### v2.0.0
Adds support for Real User Monitoring (RUM) for Windows, Android, iOS, and MacCatalyst

#### Implemented RUM Features:
- Page Tracking
- Page Load Times
- Time between PageDisappearing and PageAppearing
- Session Tracking
- Custom Timings
- Native iOS Timings
- iOS/MacCatalyst specific
- Network Timings
- See [README.md](https://github.com/MindscapeHQ/raygun4maui/blob/master/README.md) for support information

#### Provider Changes
- `Raygun4MauiSettings` no longer inherits from `RaygunLoggerConfiguration`
- `RaygunSettings` and `RaygunLoggerConfiguration` are now child elements
- `RaygunLoggerConfiguration` no longer inherits `RaygunSettings`
- Changes `.AddRaygun4Maui` to `.AddRaygun`
- Introduces `appsettings.json` style configuration options
- Adds overload for `appsettings.json` configuration method with an `Action<Raygun4MauiSettings>` to change settings at runtime
- Keeps overload for `.AddRaygun(Raygun4MauiSettings)` - other two are more recommended
- Adds more configuration options for RUM features
- `IgnoredViews` a list of views to ignore when tracking
- `IgnoredUrls` a list of URLs to ignore when tracking
- `RumApiEndpoint` endpoint to where the RUM data is sent
- `EnableRealUserMonitoring` to enable RUM - defaults to `false`
- `RumFeatureFlags` a enum flag to enable specific RUM features, (e.g. RumFeatures.Page | RumFeatures.Network)
- Adds `Raygun4MauiSettings` to service provider for DI dependent services to edit it
- Includes fixes from Raygun4Maui 1.4.1 and 1.4.2
- 1.4.1
- Fixes Android native crash due to concurrent access to environment information
- 1.4.2
- Fixes issues on iOS when sending a crash report on another thread
- Fixes Android crash when ILogger is spammed with logs/errors
- Minor version bump for Raygun4Net.NetCore to 8.2.0
- Raygun4Net.NetCore now handles the unhandled exceptions
- Introduces `ThrottledBackgroundMessageProcessor`
- Major version bump for Raygun4Net.NetCore to v10.0.0 see [changes](https://github.com/MindscapeHQ/raygun4net/blob/master/CHANGE-LOG.md)
- Brings in IRaygunUserProvider which we wrap in an abstract class called RaygunMauiUserProvider
- Obsoletes `User` and `UserInfo` in the Raygun client
- `User` and `UserInfo` are no longer supported in Raygun4Maui
- Fixes uninstantiated fields in Raygun message causing null pointers
- Fixes situations where Raygun client settings did not reflect the `RaygunSettings` object
- Minor version bump for Raygun4Net.NetCore v10.1.0
- Allows environment variables to be included in the crash report see [changes](https://github.com/MindscapeHQ/raygun4net/pull/523)


### v1.4.2
- Fixed issue with SendInBackground where environment variables are collected on the wrong thread causing it to fail silently

Expand Down
File renamed without changes.
150 changes: 128 additions & 22 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Raygun4Maui

Raygun's Crash Reporting provider for .NET MAUI
Raygun's Crash Reporting and Real User Monitoring provider for .NET MAUI

## Installation

Expand Down Expand Up @@ -29,45 +29,142 @@ Import the module by:
using Raygun4Maui;
```

To activate sending of unhandled exceptions and logs to Raygun, you must add Raygun4Maui to your MauiApp builder. To do so, open your main MauiProgram class (MauiProgram.cs) and change the `CreateMauiApp` method by adding the `AddRaygun4Maui` extension method:
To activate sending of unhandled exceptions and logs to Raygun, you must add Raygun4Maui to your MauiApp builder. To do so, open your main MauiProgram class (MauiProgram.cs) and change the `CreateMauiApp` method by adding the `AddRaygun` extension method:

``` csharp
var builder = MauiApp.CreateBuilder();
builder
.UseMauiApp<App>()
...
.AddRaygun4Maui("paste_your_api_key_here");
.AddRaygun();
```

## Additional configuration
The default method uses the configuration service to pull in your configuration and create the Raygun client

The `AddRaygun4Maui` extension method contains an overloaded method that takes a `RaygunMauiSettings` options object. This extends `RaygunSettings` from [Raygun4Net](https://raygun.com/documentation/language-guides/dotnet/crash-reporting/net-core/).
## Configuration

**RaygunMauiSettings supports the following configurations:**
- Any configuration available in the Raygun4Net `RaygunSettings`, such as `ApiKey`.
- `SendDefaultTags` (defaulted to `true`) adds the Log Level (e.g., Severe, Warning, etc.) and the Build Platform (e.g., Windows, Android, iOS, etc.) to reports and logs sent to Raygun.
- `SendDefaultCustomData` (defaulted to `true`) adds all available information in the uncaught exception as custom data on the crash report sent to Raygun.
- `MinLogLevel` and `MaxLogLevel` that specify the range of logging levels to be sent to Raygun.
### Appsettings

To use these additional configurations, create and initialize a new `RaygunMauiSettings` object as follows:
Configuration settings can be added via an appsettings.json file. To add appsettings.json to the bundled app you should add it as an embedded resource (consult IDE specific instructions). If you do not provide one we create a default Raygun4MauiSettings object which you can change using a lambda to change the options. This must be added to the configuration before you call the `.AddRaygun()` method.
```csharp
var a = Assembly.GetExecutingAssembly();
using var stream = a.GetManifestResourceStream("Raygun4Maui.SampleApp.appsettings.json");

builder.Configuration.AddJsonStream(stream!);
```

Below is an example appsettings.json file, two key notes are that you need to use Raygun4MauiSettings as the configuration will not pull it in otherwise. Additionally, the RumFeatureFlags are comma seperated so that they can be loaded in correctly as a bitwise feature flag.

```json
{
"Raygun4MauiSettings": {
"RaygunSettings": {
"ApiKey": "paste_your_api_key_here",
"ApplicationVersion": "1.0.0",
},
"RaygunLoggerConfiguration": {
"SendDefaultTags": true,
"SendDefaultCustomData": true,
"MinLogLevel": "Debug",
"MaxLogLevel": "Critical"
},
"IgnoredViews": [
"LoginView",
"SettingsView"
],
"IgnoredUrls": [
"https://example.com/ignore"
],
"EnableRealUserMonitoring": true,
"RumFeatureFlags": "Network, Page, AppleNativeTimings"
}
}
```

### Lambda Options

Mentioned previously, we provide an options lambda which you can use to make in-code changes to the configuration, e.g.
```csharp
.AddRaygun(options => {
options.RaygunSettings.ApiKey = "paste_your_api_key_here";
options.EnableRealUserMonitoring = true;
options.RumFeatureFlags = RumFeatures.Page | RumFeatures.Network | RumFeatures.AppleNativeTimings;
})
```

### Raygun4MauiSettings overload

The `AddRaygun` extension method contains an overloaded method that takes a `Raygun4MauiSettings` options object which can be used instead of the configuration service. This contains a `RaygunSettings` from [Raygun4Net](https://raygun.com/documentation/language-guides/dotnet/crash-reporting/net-core/).

**Raygun4MauiSettings supports the following configurations:**
- RaygunSettings
- Any configuration available in the Raygun4Net `RaygunSettings`, such as `ApiKey`.
- RaygunLoggerConfiguration
- `SendDefaultTags` (defaulted to `true`) adds the Log Level (e.g., Severe, Warning, etc.) and the Build Platform (e.g., Windows, Android, iOS, etc.) to reports and logs sent to Raygun.
- `SendDefaultCustomData` (defaulted to `true`) adds all available information in the uncaught exception as custom data on the crash report sent to Raygun.
- `MinLogLevel` and `MaxLogLevel` that specify the range of logging levels to be sent to Raygun.
- `IgnoredViews` a list of views to ignore when tracking
- `IgnoredUrls` a list of URLs to ignore when tracking
- `RumApiEndpoint` endpoint to where the RUM data is sent
- `EnableRealUserMonitoring` to enable RUM
- `RumFeatureFlags` a enum flag to enable specific RUM features, (e.g. RumFeatures.Page | RumFeatures.Network)


To use these additional configurations, create and initialize a new `RaygunLoggerConfiguration` object as follows:

``` csharp
Raygun4MauiSettings raygunMauiSettings = new Raygun4MauiSettings {
ApiKey = "paste_your_api_key_here",
SendDefaultTags = true, // defaults to true
SendDefaultCustomData = true, // defaults to true
MinLogLevel = LogLevel.Debug, // defaults to true
MaxLogLevel = LogLevel.Critical // defaults to true
RaygunSettings = new RaygunSettings() {
ApiKey = "paste_your_api_key_here",

},
RaygunLoggerConfiguration = new RaygunLoggerConfiguration {
SendDefaultTags = true, // defaults to true
SendDefaultCustomData = true, // defaults to true
MinLogLevel = LogLevel.Debug, // defaults to Debug
MaxLogLevel = LogLevel.Critical // defaults to Critical
}
EnableRealUserMonitoring = true, // defaults to false
RumFeatureFlags = RumFeatures.Page | RumFeatures.Network | RumFeatures.AppleNativeTimings // Enables Page, Network, and Native Apple Timings
};
```

Then add Raygun4Maui to your MauiApp builder. This time, passing in the `RaygunMauiSettings` object instead of the API key directly:
The Raygun4MauiSettings are added to the service provider so that any DI dependent service can pull in the Raygun4MauiSettings and make changes. For example the application version may be obtained from an endpoint, so this can be assigned later rather than at instantiation.

``` csharp
builder
.UseMauiApp<App>()
...
.AddRaygun4Maui(raygunMauiSettings);

### User Management
As part of Raygun4Net.NetCore v10.0.0, we are moving away from the use of UserInfo and User.
These are now marked as obsolete, and within the Raygun4Maui provider we no longer support this.

We now have introduced the `IRaygunUserProvider`, which offers a `GetUser` function that our crash reporting can use to get the current user.
Only having GetUser makes sense for NetCore, but since MAUI supports RUM we need a way of notifying the RUM module that a user has changed.

We therefore, provide a `IRaygunMauiUserProvider` interface which adds a `SetUser` method. With this we can notify the RUM module. There is a default implementation of this class for this provider which takes in a user with `SetUser` and provides this user through `GetUser`.

You can obtain an instance of this provider through dependency injection using `IRaygunMauiUserProvider`, then you can set the user by calling `SetUser`.

```csharp
public MainPage(IRaygunMauiUserProvider userProvider) {
userProivder.SetUser(new RaygunIdentifierMessage("anonymous");
}
```

You can implement your own custom user provider if the default does not fit your needs. This can be done by implementing the `IRaygunMauiUserProvider`, specifically `GetUser` and `SetUser`.

Please note, if you create a custom implementation you must send a user changed event to the `RaygunAppEventPublisher` for our RUM module to be notified.

```csharp
RaygunAppEventPublisher.Publish(new RaygunUserChanged
{
User = _user
});
```


As mentioned, we obtain this user provider by using dependency injection, so to add your instance of the user provider to the DI container we provide an extension on the app builder.

```csharp
builder.AddRaygunUserProvider<CustomRaygunMauiUserProvider>();
```

---
Expand Down Expand Up @@ -143,6 +240,15 @@ Raygun4Maui will automatically collect information specific to the environment t
| 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) |

---
## Development Instructions

Expand Down
20 changes: 19 additions & 1 deletion Raygun.MAUI.sln
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,16 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SolutionItems", "SolutionIt
.gitattributes = .gitattributes
.gitignore = .gitignore
CHANGE-LOG.md = CHANGE-LOG.md
LICENSE = LICENSE
LICENSE.txt = LICENSE.txt
README.md = README.md
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Raygun4Maui.Binding.NetworkMonitor.Android", "Raygun4Maui.Binding.NetworkMonitor.Android\Raygun4Maui.Binding.NetworkMonitor.Android.csproj", "{815DB4B5-DDE0-4627-8C44-DCCAE559133B}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Raygun4Maui.Binding.NetworkMonitor.iOS", "Raygun4Maui.Binding.NetworkMonitor.iOS\Raygun4Maui.Binding.NetworkMonitor.iOS.csproj", "{D9810D84-129C-4DF4-97CC-41182A071CC0}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Raygun4Maui.Platform", "Raygun4Maui.Platform\Raygun4Maui.Platform.csproj", "{FE13831C-7EDB-492B-8C0A-4B8FFE082508}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand All @@ -40,6 +46,18 @@ Global
{C4364C88-B953-45E4-B25E-FAE8F2FEDD4F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C4364C88-B953-45E4-B25E-FAE8F2FEDD4F}.Release|Any CPU.Build.0 = Release|Any CPU
{C4364C88-B953-45E4-B25E-FAE8F2FEDD4F}.Release|Any CPU.Deploy.0 = Release|Any CPU
{815DB4B5-DDE0-4627-8C44-DCCAE559133B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{815DB4B5-DDE0-4627-8C44-DCCAE559133B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{815DB4B5-DDE0-4627-8C44-DCCAE559133B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{815DB4B5-DDE0-4627-8C44-DCCAE559133B}.Release|Any CPU.Build.0 = Release|Any CPU
{D9810D84-129C-4DF4-97CC-41182A071CC0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D9810D84-129C-4DF4-97CC-41182A071CC0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D9810D84-129C-4DF4-97CC-41182A071CC0}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D9810D84-129C-4DF4-97CC-41182A071CC0}.Release|Any CPU.Build.0 = Release|Any CPU
{FE13831C-7EDB-492B-8C0A-4B8FFE082508}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{FE13831C-7EDB-492B-8C0A-4B8FFE082508}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FE13831C-7EDB-492B-8C0A-4B8FFE082508}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FE13831C-7EDB-492B-8C0A-4B8FFE082508}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
Additions allow you to add arbitrary C# to the generated classes
before they are compiled. This can be helpful for providing convenience
methods or adding pure C# classes.

== Adding Methods to Generated Classes ==

Let's say the library being bound has a Rectangle class with a constructor
that takes an x and y position, and a width and length size. It will look like
this:

public partial class Rectangle
{
public Rectangle (int x, int y, int width, int height)
{
// JNI bindings
}
}

Imagine we want to add a constructor to this class that takes a Point and
Size structure instead of 4 ints. We can add a new file called Rectangle.cs
with a partial class containing our new method:

public partial class Rectangle
{
public Rectangle (Point location, Size size) :
this (location.X, location.Y, size.Width, size.Height)
{
}
}

At compile time, the additions class will be added to the generated class
and the final assembly will a Rectangle class with both constructors.


== Adding C# Classes ==

Another thing that can be done is adding fully C# managed classes to the
generated library. In the above example, let's assume that there isn't a
Point class available in Java or our library. The one we create doesn't need
to interact with Java, so we'll create it like a normal class in C#.

By adding a Point.cs file with this class, it will end up in the binding library:

public class Point
{
public int X { get; set; }
public int Y { get; set; }
}
24 changes: 24 additions & 0 deletions Raygun4Maui.Binding.NetworkMonitor.Android/Jars/AboutJars.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
This directory is for Android .jars.

There are 2 types of jars that are supported:

== Input Jar ==

This is the jar that bindings should be generated for.

For example, if you were binding the Google Maps library, this would
be Google's "maps.jar".

Set the build action for these jars in the properties page to "InputJar".


== Reference Jars ==

These are jars that are referenced by the input jar. C# bindings will
not be created for these jars. These jars will be used to resolve
types used by the input jar.

NOTE: Do not add "android.jar" as a reference jar. It will be added automatically
based on the Target Framework selected.

Set the build action for these jars in the properties page to "ReferenceJar".
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net7.0-android</TargetFramework>
<SupportedOSPlatformVersion>24</SupportedOSPlatformVersion>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>

<ItemGroup>
<LibraryProjectZip Include="Jars\networkmonitorlibrary.aar" />
</ItemGroup>

<ItemGroup>
<TransformFile Include="Transforms\Metadata.xml" />
<TransformFile Include="Transforms\EnumFields.xml" />
<TransformFile Include="Transforms\EnumMethods.xml" />
</ItemGroup>

<ItemGroup>
<Content Include="Additions\AboutAdditions.txt" />
</ItemGroup>
</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<enum-field-mappings>
<!--
This example converts the constants Fragment_id, Fragment_name,
and Fragment_tag from android.support.v4.app.FragmentActivity.FragmentTag
to an enum called Android.Support.V4.App.FragmentTagType with values
Id, Name, and Tag.
<mapping jni-class="android/support/v4/app/FragmentActivity$FragmentTag" clr-enum-type="Android.Support.V4.App.FragmentTagType">
<field jni-name="Fragment_name" clr-name="Name" value="0" />
<field jni-name="Fragment_id" clr-name="Id" value="1" />
<field jni-name="Fragment_tag" clr-name="Tag" value="2" />
</mapping>
-->
</enum-field-mappings>
Loading

0 comments on commit 637912c

Please sign in to comment.