-
Notifications
You must be signed in to change notification settings - Fork 0
Crash Reporting
When a spell fails in a player's game, EternalGarden.Rzeka.Reporting can send its causal story to a server: which matter led to the failure, which spells shaped it and when, and what the river was doing just before. Structure only, never the values inside your matter, and only after the player agrees.
The package knows nothing about any particular cloud: it POSTs JSON to an HTTP endpoint. The reference backend (Azure Functions, Service Bus, Azure SQL) lives in rzeka-reporting-azure, which also documents the report format.
π The package isn't on NuGet yet. Until it is, reference
reporting/Rzeka.Reporting.csprojfrom the rzeka repository directly.
Every failure caught by rzeka's Error Boundary:
- a Strand, Pluck, Loom or Shuttle whose observable errors,
- a Weave whose subscriber throws.
Exceptions outside the river (in your engine callbacks, or ones that end the process) are not captured.
Enable it on the Spring before creating the river, the same way as the Eris dev server:
Spring spring = new();
CrashReporting reporting = spring.EnableCrashReporting(new CrashReportingOptions
{
Endpoint = new Uri(reportsUrl), // e.g. https://β¦/api/reports?code=β¦
AppName = "sanctuary",
AppVersion = "0.4.2",
});
Q += reporting;
IRzeka rzeka = spring.Create("Sanctuary", mainThread);π Don't commit the endpoint URL if it contains a key, especially in an open-source game. Inject it at build time (a CI secret, or a gitignored config file during development).
Nothing is sent until the player agrees. Consent has three states:
| Consent | Reports |
|---|---|
Unknown (default) |
held in memory only, never sent |
Granted |
held ones are sent, new ones are sent right away |
Denied |
held ones are discarded, new ones aren't even built |
If you know the player's choice at startup, pass it in the options (Consent = ReportingConsent.Granted). Otherwise, or when the player changes the setting, call:
reporting.SetConsent(granted: true);It's safe from any thread, and from inside the river, e.g. in a Weave on your settings matter:
Q += rzeka.Weave<Settings>(this, s => s
.Where(x => x.CrashReports is not null)
.Subscribe(x => reporting.SetConsent(x.CrashReports!.Value)));π A "yes" also sends failures held from earlier in the same session. Say so on your consent screen, e.g. "Send crash reports, including any errors from this session?"
- the failing spell: title, school, owner type;
- the exception: type, scrubbed message, stack trace (file names only, no directories);
- the causal chain: the matter the spell was handling, and its circumstances, walked back up to 50 matter. For each one: its type, ID, which spell shaped it and when;
- breadcrumbs: the last 20 matter emissions before the failure, related to it or not;
- the app's name and version, rzeka and .NET versions, and the OS family.
| Answers | Contains | |
|---|---|---|
| Causal chain | "what led to the input that broke?" | only matter connected to the failure, through circumstances |
| Breadcrumbs | "what was the river doing just before?" | the latest emissions in time order, connected or not |
Reports contain structure, never values: matter properties are never read. On top of that:
- exception messages are scrubbed (paths, quoted text, emails, URLs and long numbers removed), or left out entirely with
IncludeExceptionMessages = false; - owner labels from
describeOwner(e.g. Godot node names) are only sent withIncludeOwnerLabels = true; - times are UTC, and the OS is sent as a family only (
Linux,Windowsβ¦).
| Option | Default | |
|---|---|---|
Endpoint |
β | the URL reports are POSTed to |
AppName, AppVersion
|
β (required) | sent with every report |
Consent |
Unknown |
the starting consent state |
IncludeExceptionMessages |
true |
scrubbed messages; false leaves them out |
IncludeOwnerLabels |
false |
send describeOwner labels |
MaxReportsPerSession |
10 |
held reports count too |
Sink |
β | replaces the HTTP sending (ICrashReportSink), e.g. for tests or another destination |
Reporting never slows down or breaks the river:
- the report is built on the river thread (it has to read live matter), then handed to a small queue;
- sending happens on a background thread; a full queue drops the report instead of waiting;
- network errors are swallowed, and nothing reporting does can throw into your spells.
samples/CrashReportDemo in the rzeka repository triggers three failures (two identical, one different) and sends them to an endpoint of your choice:
RZEKA_REPORTS_URL='https://β¦/api/reports?code=β¦' dotnet run --project samples/CrashReportDemo