From b04eef5c5fdfdbb003a690d449682d72953aae00 Mon Sep 17 00:00:00 2001 From: Serhii Snitsaruk Date: Mon, 8 Jun 2026 13:43:08 +0200 Subject: [PATCH 01/18] docs(godot): Document C#/.NET support Add documentation for the Godot SDK's C#/.NET support (available in 2.0.0). Introduce a dedicated "C#/.NET Support" page covering setup, initialization, the Sentry.Godot.SentrySdk API, how the native and .NET layers stay in sync, and current limitations. Add GDScript/C# code tabs to the shared snippet includes (usage, enriching events, configuration, sensitive data) so C# examples appear across the Godot docs, and document managed-code stack trace symbolication on the stack traces page. Refs getsentry/sentry-godot#752 Co-Authored-By: Claude Opus 4.8 (1M context) --- .../godot/configuration/stack-traces.mdx | 29 ++++ docs/platforms/godot/dotnet/index.mdx | 152 ++++++++++++++++++ .../enriching-events/attachments/index.mdx | 8 +- platform-includes/capture-message/godot.mdx | 6 +- .../configuration/before-send/godot.mdx | 28 +++- .../configuration/config-intro/godot.mdx | 6 + .../configuration/sample-rate/godot.mdx | 9 +- .../attachment-init-with-bytes/godot.mdx | 11 +- .../attachment-init-with-path/godot.mdx | 12 +- .../attachment-upload/godot.mdx | 13 +- .../breadcrumbs/breadcrumbs-example/godot.mdx | 15 +- .../enriching-events/set-context/godot.mdx | 15 +- .../enriching-events/set-tag/godot.mdx | 8 +- .../enriching-events/set-user/godot.mdx | 14 +- .../enriching-events/unset-user/godot.mdx | 6 +- .../getting-started-primer/godot.mdx | 3 +- .../getting-started-verify/godot.mdx | 15 +- .../sensitive-data/set-tag/godot.mdx | 6 +- .../sensitive-data/set-user/godot.mdx | 14 +- platform-includes/set-environment/godot.mdx | 10 +- platform-includes/set-level/godot.mdx | 10 +- platform-includes/set-release/godot.mdx | 9 +- 22 files changed, 377 insertions(+), 22 deletions(-) create mode 100644 docs/platforms/godot/dotnet/index.mdx diff --git a/docs/platforms/godot/configuration/stack-traces.mdx b/docs/platforms/godot/configuration/stack-traces.mdx index 9674a51dc492d..ee675bc2646c9 100644 --- a/docs/platforms/godot/configuration/stack-traces.mdx +++ b/docs/platforms/godot/configuration/stack-traces.mdx @@ -57,6 +57,7 @@ For more information, refer to [Building from Source](https://docs.godotengine.o ## Getting Godot Source Start in a terminal with Git available. Clone Godot Engine repository and switch to your [preferred version tag](https://github.com/godotengine/godot/releases) (or branch): + ```bash git clone https://github.com/godotengine/godot cd godot @@ -135,18 +136,22 @@ With your custom templates compiled, you can now export your project with debug 3. Configure the custom template in the **Options** tab: **For Windows/Linux:** + - Find the **Custom Template** section - Under **Release**, browse and select your compiled template executable from the `bin/` directory **For macOS** + - Find the **Custom Template** section - Under **Release**, browse and select `godot_macos.zip` bundle from the `bin/` directory **For iOS:** + - Find the **Custom Template** section - Under both **Release** and **Debug**, browse and select the same `godot_ios.zip` bundle from the `bin/` directory **For Android:** + - Enable **Gradle Build** in the **Gradle** section - Set **Android Source Template** to point to the `android_source.zip` file generated during compilation - Install the Android build template by navigating to **Project > Install Android Build Template...** in the editor menu @@ -280,6 +285,30 @@ Congratulations! You're all set up. Your exported project should now produce sym ![Symbolicated Issue](./imgs/symbolicated_issue.png) +## C# (Managed Code) + +The steps above cover native engine and GDExtension (C/C++) frames. Stack frames from your C# code are symbolicated separately. What you need to do depends on the platform: + +- **Desktop (Windows, Linux, and macOS):** No upload is required if you ship debug symbols with your game. The SDK then resolves file names and line numbers at runtime from the `.pdb` files next to your game, which the **dotnet/include_debug_symbols** export option bundles (enabled by default). If you'd rather not ship them, turn that option off and upload the portable PDBs to Sentry with `sentry-cli` instead, the same way as for Android (below). + +- **Android:** Upload the portable PDB files for your managed assemblies. The SDK reads the packed assemblies on the device automatically, so you don't need to recompile export templates for managed frames — only the PDB upload is required. + + After exporting, Godot writes the assemblies and their `.pdb` companions under `.godot/mono/temp/bin/`. Point the command at that directory, and the CLI scans it recursively, picking up every architecture and export profile: + + ```bash {tabTitle:Bash/PowerShell} + sentry-cli debug-files upload --type portablepdb --org ___ORG_SLUG___ --project ___PROJECT_SLUG___ .godot/mono/temp/bin + ``` + +- **iOS:** Godot compiles C# ahead of time (NativeAOT) on iOS, so managed frames are part of the native binary. Upload the dSYM debug symbols produced by the export: + + ```bash {tabTitle:Bash/PowerShell} + sentry-cli debug-files upload --type dsym --org ___ORG_SLUG___ --project ___PROJECT_SLUG___ + ``` + + As with native iOS symbols, export your project to a directory first, then run the upload against that directory. + +- **Web:** Godot 4.x doesn't support C# in web exports, so managed symbolication doesn't apply to the Web platform. + ## Known Limitations ### Web (WASM) diff --git a/docs/platforms/godot/dotnet/index.mdx b/docs/platforms/godot/dotnet/index.mdx new file mode 100644 index 0000000000000..54854efbf249f --- /dev/null +++ b/docs/platforms/godot/dotnet/index.mdx @@ -0,0 +1,152 @@ +--- +title: C#/.NET Support +sidebar_title: C#/.NET +sidebar_order: 15 +description: "Learn how to capture errors from your Godot game's C# (.NET) code with Sentry." +--- + +The SDK for Godot Engine can capture errors from your game's C# code, in addition to GDScript and the engine itself. C# support is available in version 2.0.0 and later. + +The SDK runs two layers side by side: the **native layer**, which reports GDScript and engine errors, and a **.NET layer**, which reports C# errors. You configure Sentry once, and your options, scope, and trace stay synchronized across both layers automatically. See [How the two layers work together](#how-the-two-layers-work-together) for what this means in practice. + +## Prerequisites + +- The **.NET (Mono) build** of Godot Engine 4.5 or later. C# isn't available in the standard build. +- A project with C# enabled. Godot generates a `.csproj` file when you add your first C# script. +- C# error reporting is supported on **desktop** (Windows, Linux, and macOS), **Android**, and **iOS**. Godot doesn't support C# in web exports. + +## Install + +The Sentry addon already ships the .NET libraries in `addons/sentry/dotnet/`. When you open your project in the editor, the SDK adds an import to your `.csproj` that wires them in: + +```xml {filename:YourGame.csproj} + +``` + +This references the `Sentry` NuGet package, the `Sentry.Godot.dll` wrapper, and a Roslyn analyzer that guides you toward the correct API (see [Use the SDK in C#](#use-the-sdk-in-c)). Build your project (for example, with the editor's **Build** button) to restore the NuGet package. + + + +If the import isn't added the first time, restart the Godot editor. + + + +## Configure + +Set your [DSN](/product/sentry-basics/dsn-explainer/) in **Project Settings > Sentry > Options**. With **Auto Init** enabled (the default), both the native and .NET layers initialize automatically when your game starts, so there's nothing else to do. + +### Manual Initialization + +If you need to set options from code — for example, to define a [`before_send`](/platforms/godot/configuration/options/#before_send) callback — disable **Auto Init** in **Project Settings > Sentry > Options** and initialize the SDK from code: + +```csharp +using Sentry; +using Sentry.Godot; + +SentrySdk.Init(options => +{ + options.Release = "my-game@{app_version}"; + options.Environment = "{auto}"; + options.AttachScreenshot = true; +}); +``` + +Initializing Sentry from either language brings up both layers, so a single `Init()` call is all you need — there's no need to initialize it separately in C# and GDScript. + +Options come from `SentryGodotOptions`, which extends the .NET SDK's `SentryOptions` with Godot-specific settings such as `AttachLog`, `AttachSceneTree`, and `AttachScreenshot`. Shared options like the DSN, release, environment, and sample rate default to the values from your Project Settings, so you only need to set what you want to override. + +## Verify + +Throw an exception from any C# script to confirm that reporting works: + +```csharp +using Godot; +using System; + +public partial class SentryTest : Node +{ + public override void _Ready() + { + throw new Exception("Hello from Sentry .NET!"); + } +} +``` + +The SDK captures unhandled exceptions from your C# code automatically. + +## Use the SDK in C# + +Make your Sentry calls through `Sentry.Godot.SentrySdk`. The addon ships a global alias, so it resolves to the Godot wrapper automatically, even alongside `using Sentry;`: + +```csharp +SentrySdk.CaptureMessage("Something went wrong"); +``` + + + +Don't call `Sentry.SentrySdk` (the upstream .NET SDK) directly. It skips Godot-specific initialization and options. The bundled analyzer flags this with a warning (`SENTRYGD1001`) and offers a one-click fix. + + + +`SentrySdk` exposes the full Sentry .NET SDK API. Here are a few common operations. + +### Capture an Exception + +Unhandled exceptions are captured automatically. To capture a handled one: + +```csharp +try +{ + ProcessSave(); +} +catch (Exception ex) +{ + SentrySdk.CaptureException(ex); +} +``` + +### Add a Breadcrumb + +```csharp +SentrySdk.AddBreadcrumb("Player respawned", category: "gameplay"); +``` + +### Set the User and Tags + +There's no `SetUser` method on the SDK — configure the user through the scope instead: + +```csharp +SentrySdk.SetTag("biome", "jungle"); + +SentrySdk.ConfigureScope(scope => +{ + scope.User = new SentryUser + { + Id = "12345", + Username = "Jane", + }; +}); +``` + +## How the Two Layers Work Together + +The native and .NET layers keep their state in sync, so you configure Sentry once and both report consistent data. + +- **Options are synchronized.** The DSN, release, environment, sample rate, and other shared options apply to both layers, so you only need to set them once — in Project Settings, or in a C# or GDScript init callback. +- **Scope syncs both ways.** Tags, breadcrumbs, and the user you set in GDScript appear on C# events, and the ones you set in C# appear on GDScript and engine events. There's no need to set them twice. +- **Events share a trace.** C# and GDScript events from the same session are linked, so you can follow an issue across both languages. +- **Default attachments carry over.** The log file, screenshot, and scene tree attachments you've enabled are included on C# events too. +- **Sessions are tracked once.** [Release Health](/platforms/godot/configuration/releases/#release-health) is handled for the whole game automatically. Don't enable session tracking in C# — it would double-count sessions. + +## Readable Stack Traces + +Getting file names and line numbers for C# stack frames depends on the platform: on desktop, the SDK resolves them at runtime from the debug symbols shipped with your game; on Android and iOS, you upload debug symbols to Sentry. See [Readable Stack Traces](/platforms/godot/configuration/stack-traces/#c-managed-code) for the details. + +## Limitations + +C# support has the following limitations: + +- Custom contexts and user-added attachments aren't synced between the native and .NET layers. They appear only on events captured by the layer that set them. Tags, breadcrumbs, and the user are synced. +- The error throttling [limits](/platforms/godot/configuration/options/#logger_limits) apply to GDScript and engine errors only, not to C# exceptions. +- On mobile, C# events currently report the wrong operating system — `Linux` on Android and `Darwin` on iOS — instead of `Android` or `iOS`. +- On Android, C# exceptions can't be captured while the Godot debugger is attached to the app. The debugger attaches when you deploy to a device from the editor with **Debug > Deploy with Remote Debug** enabled (the default). Turn that menu option off, or test with an exported build, to capture them. diff --git a/docs/platforms/godot/enriching-events/attachments/index.mdx b/docs/platforms/godot/enriching-events/attachments/index.mdx index 50e6bca385530..43f9850f60916 100644 --- a/docs/platforms/godot/enriching-events/attachments/index.mdx +++ b/docs/platforms/godot/enriching-events/attachments/index.mdx @@ -31,7 +31,7 @@ The filename is the name of the file to display in Sentry. When using bytes you The specific media content type that determines how the attachment is rendered in the Sentry UI. Any [MIME type](https://www.iana.org/assignments/media-types/media-types.xhtml) may be used; the default is `application/octet-stream`. - We currently support and can render the following MIME types: +We currently support and can render the following MIME types: - `text/plain` - `text/css` @@ -62,10 +62,14 @@ SentrySDK.init(func(options: SentryOptions) -> void: To clear all user-added attachments, use . Built-in attachments such as log files, screenshots, and view hierarchy are preserved. -```GDScript +```gdscript {tabTitle:GDScript} SentrySDK.clear_attachments() ``` +```csharp {tabTitle:C#} +SentrySdk.ConfigureScope(scope => scope.ClearAttachments()); +``` + Sentry allows at most 40MB for a compressed request, and at most 200MB of uncompressed attachments per event, including the crash report file (if applicable). Uploads exceeding this size are rejected with HTTP error `413 Payload Too Large` and the data is dropped immediately. To add larger or more files, consider secondary storage options. diff --git a/platform-includes/capture-message/godot.mdx b/platform-includes/capture-message/godot.mdx index 95daee23a7367..fbc9b0d37b240 100644 --- a/platform-includes/capture-message/godot.mdx +++ b/platform-includes/capture-message/godot.mdx @@ -1,3 +1,7 @@ -```GDScript +```gdscript {tabTitle:GDScript} SentrySDK.capture_message("Something went wrong") ``` + +```csharp {tabTitle:C#} +SentrySdk.CaptureMessage("Something went wrong"); +``` diff --git a/platform-includes/configuration/before-send/godot.mdx b/platform-includes/configuration/before-send/godot.mdx index 66c1c60425c50..ffee14f65d757 100644 --- a/platform-includes/configuration/before-send/godot.mdx +++ b/platform-includes/configuration/before-send/godot.mdx @@ -1,4 +1,4 @@ -```GDScript +```gdscript {tabTitle:GDScript} class_name ProjectMainLoop extends SceneTree ## Tip: Set "ProjectMainLoop" as your main loop type in the project settings @@ -20,3 +20,29 @@ func _before_send(event: SentryEvent) -> SentryEvent: event.set_exception_value(0, redacted_message) return event ``` + +```csharp {tabTitle:C#} +// The .NET before-send hook filters events captured from your C# code. +SentrySdk.Init(options => +{ + options.SetBeforeSend((sentryEvent, hint) => + { + if (sentryEvent.Environment?.Contains("editor") == true) + { + // Discard the event if running from the editor. + return null; + } + + foreach (var exception in sentryEvent.SentryExceptions ?? []) + { + if (exception.Value?.Contains("Bruno") == true) + { + // Remove sensitive information from the event. + exception.Value = exception.Value.Replace("Bruno", "REDACTED"); + } + } + + return sentryEvent; + }); +}); +``` diff --git a/platform-includes/configuration/config-intro/godot.mdx b/platform-includes/configuration/config-intro/godot.mdx index e9c33d112bdf2..841c4f8a8c9f3 100644 --- a/platform-includes/configuration/config-intro/godot.mdx +++ b/platform-includes/configuration/config-intro/godot.mdx @@ -51,3 +51,9 @@ func _before_send(event: SentryEvent) -> SentryEvent: Prefer automatic initialization when possible — it runs before your code and helps ensure no startup events are missed. Use manual initialization only for cases that require runtime customization (custom handler, dynamic release values, programmatic sampling, etc.). + + + +In C#, initialize the SDK by calling `Sentry.Godot.SentrySdk.Init()` from your code. See C#/.NET Support for details. + + diff --git a/platform-includes/configuration/sample-rate/godot.mdx b/platform-includes/configuration/sample-rate/godot.mdx index fd8424b8e88c1..bb47cd0361714 100644 --- a/platform-includes/configuration/sample-rate/godot.mdx +++ b/platform-includes/configuration/sample-rate/godot.mdx @@ -1,5 +1,12 @@ -```GDScript +```gdscript {tabTitle:GDScript} SentrySDK.init(func(options: SentryOptions) -> void: options.sample_rate = 0.25 ) ``` + +```csharp {tabTitle:C#} +SentrySdk.Init(options => +{ + options.SampleRate = 0.25f; +}); +``` diff --git a/platform-includes/enriching-events/attachment-init-with-bytes/godot.mdx b/platform-includes/enriching-events/attachment-init-with-bytes/godot.mdx index da1dfdda81000..6c6bd12c4526a 100644 --- a/platform-includes/enriching-events/attachment-init-with-bytes/godot.mdx +++ b/platform-includes/enriching-events/attachment-init-with-bytes/godot.mdx @@ -1,5 +1,14 @@ -```GDScript +```gdscript {tabTitle:GDScript} var bytes: PackedByteArray = "Hello, world!".to_ascii_buffer() var attachment := SentryAttachment.create_with_bytes(bytes, "hello.txt") attachment.content_type = "text/plain" ``` + +```csharp {tabTitle:C#} +byte[] bytes = System.Text.Encoding.UTF8.GetBytes("Hello, world!"); +var attachment = new SentryAttachment( + AttachmentType.Default, + new ByteAttachmentContent(bytes), + "hello.txt", + "text/plain"); +``` diff --git a/platform-includes/enriching-events/attachment-init-with-path/godot.mdx b/platform-includes/enriching-events/attachment-init-with-path/godot.mdx index c56c37f3c2de5..555500970959d 100644 --- a/platform-includes/enriching-events/attachment-init-with-path/godot.mdx +++ b/platform-includes/enriching-events/attachment-init-with-path/godot.mdx @@ -1,4 +1,14 @@ -```GDScript +```gdscript {tabTitle:GDScript} var attachment := SentryAttachment.create_with_path("user://logs/godot.log") attachment.content_type = "text/plain" ``` + +```csharp {tabTitle:C#} +// Resolve the Godot "user://" path to an absolute filesystem path. +string path = ProjectSettings.GlobalizePath("user://logs/godot.log"); +var attachment = new SentryAttachment( + AttachmentType.Default, + new FileAttachmentContent(path), + "godot.log", + "text/plain"); +``` diff --git a/platform-includes/enriching-events/attachment-upload/godot.mdx b/platform-includes/enriching-events/attachment-upload/godot.mdx index 9c2228e0be279..dbfc51ef64f11 100644 --- a/platform-includes/enriching-events/attachment-upload/godot.mdx +++ b/platform-includes/enriching-events/attachment-upload/godot.mdx @@ -1,6 +1,15 @@ -```GDScript -# Global scope +```gdscript {tabTitle:GDScript} var attachment := SentryAttachment.create_with_path("user://logs/godot.log") attachment.content_type = "text/plain" SentrySDK.add_attachment(attachment) ``` + +```csharp {tabTitle:C#} +string path = ProjectSettings.GlobalizePath("user://logs/godot.log"); +var attachment = new SentryAttachment( + AttachmentType.Default, + new FileAttachmentContent(path), + "godot.log", + "text/plain"); +SentrySdk.ConfigureScope(scope => scope.AddAttachment(attachment)); +``` diff --git a/platform-includes/enriching-events/breadcrumbs/breadcrumbs-example/godot.mdx b/platform-includes/enriching-events/breadcrumbs/breadcrumbs-example/godot.mdx index 7d8b18e3b6d8c..d3aa7521c63fc 100644 --- a/platform-includes/enriching-events/breadcrumbs/breadcrumbs-example/godot.mdx +++ b/platform-includes/enriching-events/breadcrumbs/breadcrumbs-example/godot.mdx @@ -1,4 +1,4 @@ -```GDScript +```gdscript {tabTitle:GDScript} var crumb := SentryBreadcrumb.create("Player respawned") crumb.category = "gameplay" crumb.level = SentrySDK.LEVEL_INFO @@ -9,3 +9,16 @@ crumb.data = { } SentrySDK.add_breadcrumb(crumb) ``` + +```csharp {tabTitle:C#} +SentrySdk.AddBreadcrumb( + message: "Player respawned", + category: "gameplay", + level: BreadcrumbLevel.Info, + type: "info", + data: new Dictionary + { + ["player_id"] = "1", + ["spawn_point"] = "forest", + }); +``` diff --git a/platform-includes/enriching-events/set-context/godot.mdx b/platform-includes/enriching-events/set-context/godot.mdx index 98b06774799e2..95e223e1b7bbf 100644 --- a/platform-includes/enriching-events/set-context/godot.mdx +++ b/platform-includes/enriching-events/set-context/godot.mdx @@ -1,4 +1,4 @@ -```GDScript +```gdscript {tabTitle:GDScript} SentrySDK.set_context( "ship", { @@ -9,3 +9,16 @@ SentrySDK.set_context( } ) ``` + +```csharp {tabTitle:C#} +SentrySdk.ConfigureScope(scope => +{ + scope.Contexts["ship"] = new Dictionary + { + ["name"] = "Rocket Ship 2000", + ["speed"] = 100, + ["boost"] = true, + ["parts"] = new[] { "engine", "rocket_launcher", "escape_pod" }, + }; +}); +``` diff --git a/platform-includes/enriching-events/set-tag/godot.mdx b/platform-includes/enriching-events/set-tag/godot.mdx index 76449be51b859..dd9711bc00f2e 100644 --- a/platform-includes/enriching-events/set-tag/godot.mdx +++ b/platform-includes/enriching-events/set-tag/godot.mdx @@ -1,3 +1,7 @@ -```GDScript -SentrySDK.set_tag("biome", "jungle"); +```gdscript {tabTitle:GDScript} +SentrySDK.set_tag("biome", "jungle") +``` + +```csharp {tabTitle:C#} +SentrySdk.SetTag("biome", "jungle"); ``` diff --git a/platform-includes/enriching-events/set-user/godot.mdx b/platform-includes/enriching-events/set-user/godot.mdx index 0062cb31b936c..e39c3356e4985 100644 --- a/platform-includes/enriching-events/set-user/godot.mdx +++ b/platform-includes/enriching-events/set-user/godot.mdx @@ -1,4 +1,4 @@ -```GDScript +```gdscript {tabTitle:GDScript} var user := SentryUser.new() user.generate_new_id() user.infer_ip_address() @@ -6,6 +6,18 @@ user.email = "jane.doe@example.com" SentrySDK.set_user(user) ``` +```csharp {tabTitle:C#} +SentrySdk.ConfigureScope(scope => +{ + scope.User = new SentryUser + { + Id = Guid.NewGuid().ToString(), + IpAddress = "{{auto}}", + Email = "jane.doe@example.com", + }; +}); +``` + To see user statistics in [Release Health](/platforms/godot/configuration/releases/#release-health), set at least one of the following: `id`, `username`, or `email`. diff --git a/platform-includes/enriching-events/unset-user/godot.mdx b/platform-includes/enriching-events/unset-user/godot.mdx index 6cbcbfb3b6c8a..6bc45885881a0 100644 --- a/platform-includes/enriching-events/unset-user/godot.mdx +++ b/platform-includes/enriching-events/unset-user/godot.mdx @@ -1,3 +1,7 @@ -```GDScript +```gdscript {tabTitle:GDScript} SentrySDK.remove_user() ``` + +```csharp {tabTitle:C#} +SentrySdk.ConfigureScope(scope => scope.User = new SentryUser()); +``` diff --git a/platform-includes/getting-started-primer/godot.mdx b/platform-includes/getting-started-primer/godot.mdx index ff4b08b01cfac..fd052223a2373 100644 --- a/platform-includes/getting-started-primer/godot.mdx +++ b/platform-includes/getting-started-primer/godot.mdx @@ -9,12 +9,13 @@ Our SDK for Godot Engine builds on top of existing Sentry SDKs, extending them w - Android using the [Android SDK](/platforms/android/) to support Java, Kotlin, C and C++ - Web using the [JavaScript SDK](/platforms/javascript/) to support WebAssembly and JavaScript - Automatically capture Godot runtime errors, such as script and shader errors +- Capture errors from [C# (.NET) code](/platforms/godot/dotnet/), with scope and traces shared across both languages - GDScript stack traces with optional [local and member variable](/platforms/godot/configuration/options/#logger_include_variables) information - Include surrounding script source code with events when available at runtime - [Structured Logs](/platforms/godot/logs/) that automatically capture console output like `print()` statements and connect to your traces with searchable attributes - [Enrich events](/platforms/godot/enriching-events/) with tags, breadcrumbs, contexts, and attachments - Information about user configuration like GPU, CPU, platform and such -- [Filter and customize events](/platforms/godot/data-management/sensitive-data/#scrubbing-data) in `before_send` callback (in GDScript) +- [Filter and customize events](/platforms/godot/data-management/sensitive-data/#scrubbing-data) in `before_send` callback (in GDScript or C#) - [Log-file attachments](/platforms/godot/configuration/options/#attach_log) for events - [Scene tree data attachments](/platforms/godot/enriching-events/view-hierarchy/) for events - [Screenshot attachments](/platforms/godot/enriching-events/screenshots/) for events (experimental) diff --git a/platform-includes/getting-started-verify/godot.mdx b/platform-includes/getting-started-verify/godot.mdx index 0af4d27b72f9d..e83d0e06d5e80 100644 --- a/platform-includes/getting-started-verify/godot.mdx +++ b/platform-includes/getting-started-verify/godot.mdx @@ -1,7 +1,20 @@ -```GDScript +```gdscript {tabTitle:GDScript} extends Node func _ready(): SentrySDK.add_breadcrumb(SentryBreadcrumb.create("Just about to welcome the World.")) SentrySDK.capture_message("Hello, World!") ``` + +```csharp {tabTitle:C#} +using Godot; + +public partial class SentryTest : Node +{ + public override void _Ready() + { + SentrySdk.AddBreadcrumb("Just about to welcome the World."); + SentrySdk.CaptureMessage("Hello, World!"); + } +} +``` diff --git a/platform-includes/sensitive-data/set-tag/godot.mdx b/platform-includes/sensitive-data/set-tag/godot.mdx index 72dabf4d15c20..387cc1415afbb 100644 --- a/platform-includes/sensitive-data/set-tag/godot.mdx +++ b/platform-includes/sensitive-data/set-tag/godot.mdx @@ -1,3 +1,7 @@ -```GDScript +```gdscript {tabTitle:GDScript} SentrySDK.set_tag("birthday", str("08/12/1990".hash())) ``` + +```csharp {tabTitle:C#} +SentrySdk.SetTag("birthday", "08/12/1990".GetHashCode().ToString()); +``` diff --git a/platform-includes/sensitive-data/set-user/godot.mdx b/platform-includes/sensitive-data/set-user/godot.mdx index 89024c47c3095..dd33d24037ace 100644 --- a/platform-includes/sensitive-data/set-user/godot.mdx +++ b/platform-includes/sensitive-data/set-user/godot.mdx @@ -1,7 +1,19 @@ -```GDScript +```gdscript {tabTitle:GDScript} # Assuming client_user is an Object containing user data. var user := SentryUser.new() user.id = client_user.id user.username = client_user.username SentrySDK.set_user(user) ``` + +```csharp {tabTitle:C#} +// Assuming clientUser holds your user data. +SentrySdk.ConfigureScope(scope => +{ + scope.User = new SentryUser + { + Id = clientUser.Id, + Username = clientUser.Username, + }; +}); +``` diff --git a/platform-includes/set-environment/godot.mdx b/platform-includes/set-environment/godot.mdx index ad8925163dbb7..8055a2467780b 100644 --- a/platform-includes/set-environment/godot.mdx +++ b/platform-includes/set-environment/godot.mdx @@ -1,10 +1,18 @@ -```GDScript +```gdscript {tabTitle:GDScript} SentrySDK.init(func(options: SentryOptions) -> void: options.environment = "production" ) ``` +```csharp {tabTitle:C#} +SentrySdk.Init(options => +{ + options.Environment = "production"; +}); +``` + The SDK automatically detects the following Godot-specific environments: + - `headless_server` when running in headless mode - `export_release` for release exports - `export_debug` for debug exports diff --git a/platform-includes/set-level/godot.mdx b/platform-includes/set-level/godot.mdx index 6810847fdd20b..0cf756ea0290e 100644 --- a/platform-includes/set-level/godot.mdx +++ b/platform-includes/set-level/godot.mdx @@ -1,5 +1,13 @@ -```GDScript +```gdscript {tabTitle:GDScript} var event = SentrySDK.create_event() event.level = SentrySDK.LEVEL_WARNING SentrySDK.capture_event(event) ``` + +```csharp {tabTitle:C#} +var sentryEvent = new SentryEvent +{ + Level = SentryLevel.Warning, +}; +SentrySdk.CaptureEvent(sentryEvent); +``` diff --git a/platform-includes/set-release/godot.mdx b/platform-includes/set-release/godot.mdx index 489bc8d358401..0b62eca7af0cb 100644 --- a/platform-includes/set-release/godot.mdx +++ b/platform-includes/set-release/godot.mdx @@ -1,9 +1,16 @@ -```GDScript +```gdscript {tabTitle:GDScript} SentrySDK.init(func(options: SentryOptions) -> void: options.release = "my-game@1.2.34" ) ``` +```csharp {tabTitle:C#} +SentrySdk.Init(options => +{ + options.Release = "my-game@1.2.34"; +}); +``` + By default, the SDK builds the release identifier from `application/config/name` and `application/config/version` project settings, using the format: `"{app_name}@{app_version}"`. From b0ad11e002f33cdd0958f210c8207f9bcb28c4cb Mon Sep 17 00:00:00 2001 From: Serhii Snitsaruk Date: Mon, 8 Jun 2026 14:06:40 +0200 Subject: [PATCH 02/18] Correction --- docs/platforms/godot/dotnet/index.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/platforms/godot/dotnet/index.mdx b/docs/platforms/godot/dotnet/index.mdx index 54854efbf249f..4ec67da4019de 100644 --- a/docs/platforms/godot/dotnet/index.mdx +++ b/docs/platforms/godot/dotnet/index.mdx @@ -11,7 +11,7 @@ The SDK runs two layers side by side: the **native layer**, which reports GDScri ## Prerequisites -- The **.NET (Mono) build** of Godot Engine 4.5 or later. C# isn't available in the standard build. +- The **.NET build** of Godot Engine 4.5 or later. C# isn't available in the standard build. - A project with C# enabled. Godot generates a `.csproj` file when you add your first C# script. - C# error reporting is supported on **desktop** (Windows, Linux, and macOS), **Android**, and **iOS**. Godot doesn't support C# in web exports. From 75bc438c598ef5de129c21e9d08e09a85fb4505b Mon Sep 17 00:00:00 2001 From: Serhii Snitsaruk Date: Mon, 8 Jun 2026 17:29:02 +0200 Subject: [PATCH 03/18] Add {mdExpandTabs} for LLMs --- platform-includes/capture-message/godot.mdx | 2 +- platform-includes/configuration/before-send/godot.mdx | 2 +- platform-includes/configuration/sample-rate/godot.mdx | 2 +- .../enriching-events/attachment-init-with-bytes/godot.mdx | 2 +- .../enriching-events/attachment-init-with-path/godot.mdx | 2 +- platform-includes/enriching-events/attachment-upload/godot.mdx | 2 +- .../enriching-events/breadcrumbs/breadcrumbs-example/godot.mdx | 2 +- platform-includes/enriching-events/set-context/godot.mdx | 2 +- platform-includes/enriching-events/set-tag/godot.mdx | 2 +- platform-includes/enriching-events/set-user/godot.mdx | 2 +- platform-includes/enriching-events/unset-user/godot.mdx | 2 +- platform-includes/getting-started-verify/godot.mdx | 2 +- platform-includes/sensitive-data/set-tag/godot.mdx | 2 +- platform-includes/sensitive-data/set-user/godot.mdx | 2 +- platform-includes/set-environment/godot.mdx | 2 +- platform-includes/set-level/godot.mdx | 2 +- platform-includes/set-release/godot.mdx | 2 +- 17 files changed, 17 insertions(+), 17 deletions(-) diff --git a/platform-includes/capture-message/godot.mdx b/platform-includes/capture-message/godot.mdx index fbc9b0d37b240..80f706cf7ea95 100644 --- a/platform-includes/capture-message/godot.mdx +++ b/platform-includes/capture-message/godot.mdx @@ -1,4 +1,4 @@ -```gdscript {tabTitle:GDScript} +```gdscript {tabTitle:GDScript} {mdExpandTabs} SentrySDK.capture_message("Something went wrong") ``` diff --git a/platform-includes/configuration/before-send/godot.mdx b/platform-includes/configuration/before-send/godot.mdx index ffee14f65d757..ba4aa7cd3645f 100644 --- a/platform-includes/configuration/before-send/godot.mdx +++ b/platform-includes/configuration/before-send/godot.mdx @@ -1,4 +1,4 @@ -```gdscript {tabTitle:GDScript} +```gdscript {tabTitle:GDScript} {mdExpandTabs} class_name ProjectMainLoop extends SceneTree ## Tip: Set "ProjectMainLoop" as your main loop type in the project settings diff --git a/platform-includes/configuration/sample-rate/godot.mdx b/platform-includes/configuration/sample-rate/godot.mdx index bb47cd0361714..3eeca3334c96e 100644 --- a/platform-includes/configuration/sample-rate/godot.mdx +++ b/platform-includes/configuration/sample-rate/godot.mdx @@ -1,4 +1,4 @@ -```gdscript {tabTitle:GDScript} +```gdscript {tabTitle:GDScript} {mdExpandTabs} SentrySDK.init(func(options: SentryOptions) -> void: options.sample_rate = 0.25 ) diff --git a/platform-includes/enriching-events/attachment-init-with-bytes/godot.mdx b/platform-includes/enriching-events/attachment-init-with-bytes/godot.mdx index 6c6bd12c4526a..fe7890fdef496 100644 --- a/platform-includes/enriching-events/attachment-init-with-bytes/godot.mdx +++ b/platform-includes/enriching-events/attachment-init-with-bytes/godot.mdx @@ -1,4 +1,4 @@ -```gdscript {tabTitle:GDScript} +```gdscript {tabTitle:GDScript} {mdExpandTabs} var bytes: PackedByteArray = "Hello, world!".to_ascii_buffer() var attachment := SentryAttachment.create_with_bytes(bytes, "hello.txt") attachment.content_type = "text/plain" diff --git a/platform-includes/enriching-events/attachment-init-with-path/godot.mdx b/platform-includes/enriching-events/attachment-init-with-path/godot.mdx index 555500970959d..8dbc5f6bfe160 100644 --- a/platform-includes/enriching-events/attachment-init-with-path/godot.mdx +++ b/platform-includes/enriching-events/attachment-init-with-path/godot.mdx @@ -1,4 +1,4 @@ -```gdscript {tabTitle:GDScript} +```gdscript {tabTitle:GDScript} {mdExpandTabs} var attachment := SentryAttachment.create_with_path("user://logs/godot.log") attachment.content_type = "text/plain" ``` diff --git a/platform-includes/enriching-events/attachment-upload/godot.mdx b/platform-includes/enriching-events/attachment-upload/godot.mdx index dbfc51ef64f11..c437243c07601 100644 --- a/platform-includes/enriching-events/attachment-upload/godot.mdx +++ b/platform-includes/enriching-events/attachment-upload/godot.mdx @@ -1,4 +1,4 @@ -```gdscript {tabTitle:GDScript} +```gdscript {tabTitle:GDScript} {mdExpandTabs} var attachment := SentryAttachment.create_with_path("user://logs/godot.log") attachment.content_type = "text/plain" SentrySDK.add_attachment(attachment) diff --git a/platform-includes/enriching-events/breadcrumbs/breadcrumbs-example/godot.mdx b/platform-includes/enriching-events/breadcrumbs/breadcrumbs-example/godot.mdx index d3aa7521c63fc..390ff1a5d6884 100644 --- a/platform-includes/enriching-events/breadcrumbs/breadcrumbs-example/godot.mdx +++ b/platform-includes/enriching-events/breadcrumbs/breadcrumbs-example/godot.mdx @@ -1,4 +1,4 @@ -```gdscript {tabTitle:GDScript} +```gdscript {tabTitle:GDScript} {mdExpandTabs} var crumb := SentryBreadcrumb.create("Player respawned") crumb.category = "gameplay" crumb.level = SentrySDK.LEVEL_INFO diff --git a/platform-includes/enriching-events/set-context/godot.mdx b/platform-includes/enriching-events/set-context/godot.mdx index 95e223e1b7bbf..08d6a77732cef 100644 --- a/platform-includes/enriching-events/set-context/godot.mdx +++ b/platform-includes/enriching-events/set-context/godot.mdx @@ -1,4 +1,4 @@ -```gdscript {tabTitle:GDScript} +```gdscript {tabTitle:GDScript} {mdExpandTabs} SentrySDK.set_context( "ship", { diff --git a/platform-includes/enriching-events/set-tag/godot.mdx b/platform-includes/enriching-events/set-tag/godot.mdx index dd9711bc00f2e..f151abab8ca91 100644 --- a/platform-includes/enriching-events/set-tag/godot.mdx +++ b/platform-includes/enriching-events/set-tag/godot.mdx @@ -1,4 +1,4 @@ -```gdscript {tabTitle:GDScript} +```gdscript {tabTitle:GDScript} {mdExpandTabs} SentrySDK.set_tag("biome", "jungle") ``` diff --git a/platform-includes/enriching-events/set-user/godot.mdx b/platform-includes/enriching-events/set-user/godot.mdx index e39c3356e4985..f0a39750ebcbd 100644 --- a/platform-includes/enriching-events/set-user/godot.mdx +++ b/platform-includes/enriching-events/set-user/godot.mdx @@ -1,4 +1,4 @@ -```gdscript {tabTitle:GDScript} +```gdscript {tabTitle:GDScript} {mdExpandTabs} var user := SentryUser.new() user.generate_new_id() user.infer_ip_address() diff --git a/platform-includes/enriching-events/unset-user/godot.mdx b/platform-includes/enriching-events/unset-user/godot.mdx index 6bc45885881a0..def9b0b0f537e 100644 --- a/platform-includes/enriching-events/unset-user/godot.mdx +++ b/platform-includes/enriching-events/unset-user/godot.mdx @@ -1,4 +1,4 @@ -```gdscript {tabTitle:GDScript} +```gdscript {tabTitle:GDScript} {mdExpandTabs} SentrySDK.remove_user() ``` diff --git a/platform-includes/getting-started-verify/godot.mdx b/platform-includes/getting-started-verify/godot.mdx index e83d0e06d5e80..e1d12c0a42f0c 100644 --- a/platform-includes/getting-started-verify/godot.mdx +++ b/platform-includes/getting-started-verify/godot.mdx @@ -1,4 +1,4 @@ -```gdscript {tabTitle:GDScript} +```gdscript {tabTitle:GDScript} {mdExpandTabs} extends Node func _ready(): diff --git a/platform-includes/sensitive-data/set-tag/godot.mdx b/platform-includes/sensitive-data/set-tag/godot.mdx index 387cc1415afbb..23cc8b1098c4b 100644 --- a/platform-includes/sensitive-data/set-tag/godot.mdx +++ b/platform-includes/sensitive-data/set-tag/godot.mdx @@ -1,4 +1,4 @@ -```gdscript {tabTitle:GDScript} +```gdscript {tabTitle:GDScript} {mdExpandTabs} SentrySDK.set_tag("birthday", str("08/12/1990".hash())) ``` diff --git a/platform-includes/sensitive-data/set-user/godot.mdx b/platform-includes/sensitive-data/set-user/godot.mdx index dd33d24037ace..ab928d166299a 100644 --- a/platform-includes/sensitive-data/set-user/godot.mdx +++ b/platform-includes/sensitive-data/set-user/godot.mdx @@ -1,4 +1,4 @@ -```gdscript {tabTitle:GDScript} +```gdscript {tabTitle:GDScript} {mdExpandTabs} # Assuming client_user is an Object containing user data. var user := SentryUser.new() user.id = client_user.id diff --git a/platform-includes/set-environment/godot.mdx b/platform-includes/set-environment/godot.mdx index 8055a2467780b..2e6ce250938eb 100644 --- a/platform-includes/set-environment/godot.mdx +++ b/platform-includes/set-environment/godot.mdx @@ -1,4 +1,4 @@ -```gdscript {tabTitle:GDScript} +```gdscript {tabTitle:GDScript} {mdExpandTabs} SentrySDK.init(func(options: SentryOptions) -> void: options.environment = "production" ) diff --git a/platform-includes/set-level/godot.mdx b/platform-includes/set-level/godot.mdx index 0cf756ea0290e..2c4e6c1c3c6d0 100644 --- a/platform-includes/set-level/godot.mdx +++ b/platform-includes/set-level/godot.mdx @@ -1,4 +1,4 @@ -```gdscript {tabTitle:GDScript} +```gdscript {tabTitle:GDScript} {mdExpandTabs} var event = SentrySDK.create_event() event.level = SentrySDK.LEVEL_WARNING SentrySDK.capture_event(event) diff --git a/platform-includes/set-release/godot.mdx b/platform-includes/set-release/godot.mdx index 0b62eca7af0cb..913d58d940256 100644 --- a/platform-includes/set-release/godot.mdx +++ b/platform-includes/set-release/godot.mdx @@ -1,4 +1,4 @@ -```gdscript {tabTitle:GDScript} +```gdscript {tabTitle:GDScript} {mdExpandTabs} SentrySDK.init(func(options: SentryOptions) -> void: options.release = "my-game@1.2.34" ) From 5ff153efbb7b7c069197dc6ea030a7ff4aa6f2c1 Mon Sep 17 00:00:00 2001 From: Serhii Snitsaruk Date: Mon, 8 Jun 2026 19:12:11 +0200 Subject: [PATCH 04/18] Convert more samples --- .../godot/data-management/data-collected.mdx | 15 +++- .../enriching-events/screenshots/index.mdx | 9 ++- .../enriching-events/view-hierarchy/index.mdx | 9 ++- docs/platforms/godot/user-feedback/index.mdx | 19 ++++- platform-includes/logs/options/godot.mdx | 20 ++++- platform-includes/logs/setup/godot.mdx | 9 ++- platform-includes/logs/usage/godot.mdx | 61 +++++++++++++-- platform-includes/metrics/options/godot.mdx | 27 +++++-- platform-includes/metrics/setup/godot.mdx | 13 +++- platform-includes/metrics/usage/godot.mdx | 74 +++++++++++++++++-- 10 files changed, 228 insertions(+), 28 deletions(-) diff --git a/docs/platforms/godot/data-management/data-collected.mdx b/docs/platforms/godot/data-management/data-collected.mdx index 73b613c98fb77..44658a0d64a16 100644 --- a/docs/platforms/godot/data-management/data-collected.mdx +++ b/docs/platforms/godot/data-management/data-collected.mdx @@ -14,7 +14,7 @@ By default, the Sentry SDK doesn't send any information about users, such as ema You can also set user information from code: -```GDScript +```gdscript {tabTitle:GDScript} {mdExpandTabs} var user := SentryUser.new() user.id = "custom_id" user.email = "bob@example.com" @@ -23,6 +23,19 @@ user.ip_address = "127.0.0.1" SentrySDK.set_user(user) ``` +```csharp {tabTitle:C#} +SentrySdk.ConfigureScope(scope => +{ + scope.User = new SentryUser + { + Id = "custom_id", + Email = "bob@example.com", + Username = "bob", + IpAddress = "127.0.0.1", + }; +}); +``` + ## Device Information The Sentry SDK collects information about the device, such as the name, version and build of your operating system or Linux distribution. This information is sent to Sentry by default. diff --git a/docs/platforms/godot/enriching-events/screenshots/index.mdx b/docs/platforms/godot/enriching-events/screenshots/index.mdx index 800f187cb7e76..127f394223497 100644 --- a/docs/platforms/godot/enriching-events/screenshots/index.mdx +++ b/docs/platforms/godot/enriching-events/screenshots/index.mdx @@ -24,12 +24,19 @@ Because screenshots may contain configuring things programmatically: -```GDScript +```gdscript {tabTitle:GDScript} {mdExpandTabs} SentrySDK.init(func(options: SentryOptions) -> void: options.attach_screenshot = true ) ``` +```csharp {tabTitle:C#} +SentrySdk.Init(options => +{ + options.AttachScreenshot = true; +}); +``` + ## Viewing Screenshots If one is available, you'll see a thumbnail of the screenshot when you click on a specific issue from the [**Issues**](https://demo.sentry.io/issues/) page. diff --git a/docs/platforms/godot/enriching-events/view-hierarchy/index.mdx b/docs/platforms/godot/enriching-events/view-hierarchy/index.mdx index 7b7c12dead457..c1dfbe9498b25 100644 --- a/docs/platforms/godot/enriching-events/view-hierarchy/index.mdx +++ b/docs/platforms/godot/enriching-events/view-hierarchy/index.mdx @@ -23,12 +23,19 @@ Scene tree capturing is an opt-in feature. To attach scene tree information to y Or, like so, if you're configuring things programmatically: -```GDScript +```gdscript {tabTitle:GDScript} {mdExpandTabs} SentrySDK.init(func(options: SentryOptions) -> void: options.attach_scene_tree = true ) ``` +```csharp {tabTitle:C#} +SentrySdk.Init(options => +{ + options.AttachSceneTree = true; +}); +``` + ## Viewing Scene Tree Attachments Scene tree information is attached as `view-hierarchy.json` file. You can find it in the "Attachments" tab, where you can view all attachments, as well as associated events. Click the event ID to open the [Issue Details](/product/issues/issue-details) page of that specific event. diff --git a/docs/platforms/godot/user-feedback/index.mdx b/docs/platforms/godot/user-feedback/index.mdx index 970d8be46cf52..9ea74b53f629c 100644 --- a/docs/platforms/godot/user-feedback/index.mdx +++ b/docs/platforms/godot/user-feedback/index.mdx @@ -66,7 +66,7 @@ To customize the form's appearance, use the provided reference theme file (`sent The User Feedback API allows you to collect user feedback while using your own UI controls. You can submit feedback directly by creating an instance of `SentryFeedback` class, setting the required `message` and optional fields, then submitting it using `SentrySDK.capture_feedback(feedback)`. -```GDScript +```gdscript {tabTitle:GDScript} {mdExpandTabs} var feedback := SentryFeedback.new() feedback.message = "I'm stuck in the wall!" feedback.contact_email = "bob@example.com" @@ -75,10 +75,25 @@ feedback.name = "Bob" SentrySDK.capture_feedback(feedback) ``` +```csharp {tabTitle:C#} +SentrySdk.CaptureFeedback( + "I'm stuck in the wall!", + contactEmail: "bob@example.com", + name: "Bob"); +``` + Sentry can optionally pair this feedback with an event, giving you additional insight into issues. Sentry needs the `event_id` to be able to associate the user feedback to the corresponding event. For example, to get the `event_id`, you can use before_send, or the return value of the method capturing an event. -```GDScript +```gdscript {tabTitle:GDScript} {mdExpandTabs} var event_id = SentrySDK.capture_message("An event that will get user feedback.") # ... feedback.associated_event_id = event_id ``` + +```csharp {tabTitle:C#} +SentryId eventId = SentrySdk.CaptureMessage("An event that will get user feedback."); +// ... +SentrySdk.CaptureFeedback( + "I'm stuck in the wall!", + associatedEventId: eventId); +``` diff --git a/platform-includes/logs/options/godot.mdx b/platform-includes/logs/options/godot.mdx index 90553463ea8b4..b6c1934522bd0 100644 --- a/platform-includes/logs/options/godot.mdx +++ b/platform-includes/logs/options/godot.mdx @@ -2,7 +2,7 @@ To filter logs, or update them before they are sent to Sentry, you can use the `before_send_log` option. -```GDScript +```gdscript {tabTitle:GDScript} {mdExpandTabs} SentrySDK.init(func(options: SentryOptions) -> void: options.enable_logs = true options.before_send_log = _before_send_log @@ -19,4 +19,22 @@ func _before_send_log(log_entry: SentryLog) -> SentryLog: return log_entry ``` +```csharp {tabTitle:C#} +SentrySdk.Init(options => +{ + options.EnableLogs = true; + options.SetBeforeSendLog(log => + { + // Filter junk. + if (log.Message == "Junk message") + { + return null; + } + // Add custom attributes. + log.SetAttribute("current_scene", currentScene.Name); + return log; + }); +}); +``` + The `before_send_log` function receives a `SentryLog` object, and should return either the same log object, with or without modifications, or `null` if you want to discard it. diff --git a/platform-includes/logs/setup/godot.mdx b/platform-includes/logs/setup/godot.mdx index 0d4eec2fa87ef..5046401fa680d 100644 --- a/platform-includes/logs/setup/godot.mdx +++ b/platform-includes/logs/setup/godot.mdx @@ -10,8 +10,15 @@ To enable logging in your Godot project, you need to configure the Sentry SDK wi Alternatively, you can enable logging programmatically when initializing the SDK: -```GDScript +```gdscript {tabTitle:GDScript} {mdExpandTabs} SentrySDK.init(func(options: SentryOptions) -> void: options.enable_logs = true ) ``` + +```csharp {tabTitle:C#} +SentrySdk.Init(options => +{ + options.EnableLogs = true; +}); +``` diff --git a/platform-includes/logs/usage/godot.mdx b/platform-includes/logs/usage/godot.mdx index a0ce09d0069f2..99a65c6ea1ab8 100644 --- a/platform-includes/logs/usage/godot.mdx +++ b/platform-includes/logs/usage/godot.mdx @@ -3,7 +3,7 @@ Once the feature is enabled on the SDK and the SDK is initialized, you can send The `SentrySDK.logger` exposes six methods that you can use to log messages at different log levels: `trace`, `debug`, `info`, `warn`, `error`, and `fatal`. -```GDScript +```gdscript {tabTitle:GDScript} {mdExpandTabs} SentrySDK.logger.trace("Initialized inventory database") SentrySDK.logger.debug("Player inventory updated") SentrySDK.logger.info("Level loaded successfully") @@ -12,11 +12,21 @@ SentrySDK.logger.error("Failed to save game state") SentrySDK.logger.fatal("Inventory data corrupted") ``` -The methods support string interpolation using Godot's format strings syntax. The log message can contain format -placeholders (e.g., `%s`, `%d`), and the optional `parameters` array provides values to substitute into placeholders -using Godot's format strings. These will be sent to Sentry as log attributes, and can be searched from within the Logs UI. +```csharp {tabTitle:C#} +SentrySdk.Logger.LogTrace("Initialized inventory database"); +SentrySdk.Logger.LogDebug("Player inventory updated"); +SentrySdk.Logger.LogInfo("Level loaded successfully"); +SentrySdk.Logger.LogWarning("Item configuration not found"); +SentrySdk.Logger.LogError("Failed to save game state"); +SentrySdk.Logger.LogFatal("Inventory data corrupted"); +``` + +The methods also accept a message template with placeholders, plus the values to fill them. GDScript uses Godot's format +strings (`%s`, `%d`) with a parameters array, while C# uses positional placeholders (`{0}`, `{1}`) with the values +passed as arguments. In both cases, the template and its parameters are sent to Sentry as separate log attributes, which +you can search from within the Logs UI. -```GDScript +```gdscript {tabTitle:GDScript} {mdExpandTabs} # String interpolation automatically extracts parameters as log attributes SentrySDK.logger.info("Spawned %d enemies on level %s", [5, "forest_1"]) @@ -29,10 +39,15 @@ SentrySDK.logger.info(message, [], { }) ``` +```csharp {tabTitle:C#} +// Parameters are automatically extracted as log attributes +SentrySdk.Logger.LogInfo("Spawned {0} enemies on level {1}", 5, "forest_1"); +``` + You can also use structured attributes to provide additional context for your logs. For example, you can add a `current_scene` attribute to log messages related to currently loaded scene. -```GDScript +```gdscript {tabTitle:GDScript} {mdExpandTabs} # Adding custom attributes, which can be searched from within the Logs UI SentrySDK.logger.debug("Spawning %s with %d units", ["enemies", 5], { "current_scene": get_tree().current_scene.scene_file_path, @@ -40,13 +55,24 @@ SentrySDK.logger.debug("Spawning %s with %d units", ["enemies", 5], { }) ``` +```csharp {tabTitle:C#} +// Adding custom attributes, which can be searched from within the Logs UI +SentrySdk.Logger.LogDebug( + log => + { + log.SetAttribute("current_scene", GetTree().CurrentScene.SceneFilePath); + log.SetAttribute("wave_id", "main_wave_3"); + }, + "Spawning {0} with {1} units", "enemies", 5); +``` + Structured attributes support `bool`, `int`, `float`, and `String` data types. Other types will be converted to strings. ### Global Attributes You can set global attributes that are automatically included in all log entries and metrics. This is useful for attaching contextual information like player IDs or game state that should appear on every log. -```GDScript +```gdscript {tabTitle:GDScript} {mdExpandTabs} # Set global attributes that apply to all logs and metrics SentrySDK.set_attribute("level", "castle") SentrySDK.set_attribute("difficulty", "hard") @@ -58,6 +84,27 @@ SentrySDK.logger.info("Level loaded") SentrySDK.remove_attribute("level") ``` +```csharp {tabTitle:C#} +SentrySdk.Init(options => +{ + options.EnableLogs = true; + options.SetBeforeSendLog(log => + { + log.SetAttribute("level", "castle"); + log.SetAttribute("difficulty", "hard"); + return log; + }); +}); + +// All subsequent logs will include these attributes +SentrySdk.Logger.LogInfo("Level loaded"); +``` + + + The C# SDK doesn't have a scope-level attribute API yet. The before-send hook + is the closest equivalent: it applies attributes to every log. + + ### Godot Logging Integration When the feature is enabled, the SDK automatically captures Godot messages, warnings, and errors as logs. You can use diff --git a/platform-includes/metrics/options/godot.mdx b/platform-includes/metrics/options/godot.mdx index 40a8e72550ba7..ff4b9fdadfdf1 100644 --- a/platform-includes/metrics/options/godot.mdx +++ b/platform-includes/metrics/options/godot.mdx @@ -1,15 +1,15 @@ The following configuration options are available for Sentry's [Application Metrics](/product/explore/metrics/) in Godot Engine: -| Option | Description | Default | -|--------|-------------|---------| -| **enable_metrics** | Toggle for the metrics feature (experimental) | `true` | -| **before_send_metric** | Callback to modify or filter metrics before sending (experimental) | None | +| Option | Description | Default | +| ---------------------- | ------------------------------------------------------------------ | ------- | +| **enable_metrics** | Toggle for the metrics feature (experimental) | `true` | +| **before_send_metric** | Callback to modify or filter metrics before sending (experimental) | None | ### before_send_metric To filter metrics or modify them before they are sent to Sentry, you can use the `before_send_metric` option: -```GDScript +```gdscript {tabTitle:GDScript} {mdExpandTabs} SentrySDK.init(func(options: SentryOptions) -> void: options.experimental.before_send_metric = _before_send_metric ) @@ -23,4 +23,21 @@ func _before_send_metric(metric: SentryMetric) -> SentryMetric: return metric ``` +```csharp {tabTitle:C#} +SentrySdk.Init(options => +{ + options.SetBeforeSendMetric(metric => + { + // Drop debug-only metrics in release builds. + if (!OS.IsDebugBuild() && metric.Name.StartsWith("debug.")) + { + return null; + } + // Enrich with runtime context. + metric.SetAttribute("current_scene", GetTree().CurrentScene.Name); + return metric; + }); +}); +``` + The `before_send_metric` callback receives a `SentryMetric` object, and should return either the same metric object (with or without modifications) or `null` to discard it. diff --git a/platform-includes/metrics/setup/godot.mdx b/platform-includes/metrics/setup/godot.mdx index 9a15696ac49ec..64465d84fb607 100644 --- a/platform-includes/metrics/setup/godot.mdx +++ b/platform-includes/metrics/setup/godot.mdx @@ -1,8 +1,8 @@ Metrics are enabled by default in the Sentry Godot SDK. No additional setup is required to start sending metrics. - Metrics are not supported on Apple platforms (macOS and iOS). Attempting to use - metrics on these platforms will result in a warning. + Adding metrics from GDScript isn't supported on Apple platforms yet (macOS and iOS). + The first attempt to use metrics on these platforms will result in a warning. ### Project Settings Configuration @@ -13,8 +13,15 @@ To disable metrics, navigate to **Project Settings > Sentry > Experimental** and Alternatively, you can disable metrics programmatically when initializing the SDK: -```GDScript +```gdscript {tabTitle:GDScript} {mdExpandTabs} SentrySDK.init(func(options: SentryOptions) -> void: options.experimental.enable_metrics = false ) ``` + +```csharp {tabTitle:C#} +SentrySdk.Init(options => +{ + options.EnableMetrics = false; +}); +``` diff --git a/platform-includes/metrics/usage/godot.mdx b/platform-includes/metrics/usage/godot.mdx index 96b454cedda7d..ff8cc819a215d 100644 --- a/platform-includes/metrics/usage/godot.mdx +++ b/platform-includes/metrics/usage/godot.mdx @@ -12,7 +12,7 @@ Once metrics are enabled and the SDK is initialized, you can emit metrics using Track the number of times something happens. Each increment adds to a cumulative total: -```GDScript +```gdscript {tabTitle:GDScript} {mdExpandTabs} # Increment by 1 (default) SentrySDK.metrics.count("match_started") @@ -20,30 +20,52 @@ SentrySDK.metrics.count("match_started") SentrySDK.metrics.count("in_app_purchase", 1, {"item": "sword_of_fire"}) ``` +```csharp {tabTitle:C#} +// Increment by 1 +SentrySdk.Metrics.EmitCounter("match_started", 1); + +// Increment by a specific amount with attributes +SentrySdk.Metrics.EmitCounter("in_app_purchase", 1, new Dictionary +{ + ["item"] = "sword_of_fire", +}); +``` + ### Gauges Track current values at a point in time, like a snapshot. Sentry computes aggregates like min, max, avg, sum, and count: -```GDScript +```gdscript {tabTitle:GDScript} {mdExpandTabs} SentrySDK.metrics.gauge("players_online", lobby.get_player_count()) # With a unit SentrySDK.metrics.gauge("memory_usage", OS.get_static_memory_usage(), SentryUnit.byte) ``` +```csharp {tabTitle:C#} +SentrySdk.Metrics.EmitGauge("players_online", lobby.GetPlayerCount()); + +// With a unit +SentrySdk.Metrics.EmitGauge("memory_usage", (long)OS.GetStaticMemoryUsage(), MeasurementUnit.Information.Byte); +``` + ### Distributions Record numeric values to compute statistical aggregates such as p50, p95, avg, min, and max: -```GDScript +```gdscript {tabTitle:GDScript} {mdExpandTabs} SentrySDK.metrics.distribution("level_load_time", load_time, SentryUnit.millisecond) ``` +```csharp {tabTitle:C#} +SentrySdk.Metrics.EmitDistribution("level_load_time", loadTime, MeasurementUnit.Duration.Millisecond); +``` + ### Custom Attributes Add attributes to filter and group metrics in Sentry: -```GDScript +```gdscript {tabTitle:GDScript} {mdExpandTabs} SentrySDK.metrics.count("enemies_spawned", wave_size, {"level": "castle"}) SentrySDK.metrics.distribution("level_load_time", load_time, SentryUnit.millisecond, { @@ -51,13 +73,25 @@ SentrySDK.metrics.distribution("level_load_time", load_time, SentryUnit.millisec }) ``` +```csharp {tabTitle:C#} +SentrySdk.Metrics.EmitCounter("enemies_spawned", waveSize, new Dictionary +{ + ["level"] = "castle", +}); + +SentrySdk.Metrics.EmitDistribution("level_load_time", loadTime, MeasurementUnit.Duration.Millisecond, new Dictionary +{ + ["scene"] = GetTree().CurrentScene.Name, +}); +``` + Attributes support `bool`, `int`, `float`, and `String` data types. Other types will be converted to strings. ### Global Attributes You can set global attributes that are automatically included in all metrics and logs. This is useful for attaching contextual information that should appear on every metric entry. -```GDScript +```gdscript {tabTitle:GDScript} {mdExpandTabs} # Set global attributes that apply to all metrics and logs SentrySDK.set_attribute("level", "castle") SentrySDK.set_attribute("difficulty", "hard") @@ -69,11 +103,31 @@ SentrySDK.metrics.count("enemy_defeated") SentrySDK.remove_attribute("level") ``` +```csharp {tabTitle:C#} +SentrySdk.Init(options => +{ + options.SetBeforeSendMetric(metric => + { + metric.SetAttribute("level", "castle"); + metric.SetAttribute("difficulty", "hard"); + return metric; + }); +}); + +// All subsequent metrics will include these attributes +SentrySdk.Metrics.EmitCounter("enemy_defeated", 1); +``` + + + The C# SDK doesn't have a scope-level attribute API yet. The before-send hook + is the closest equivalent: it applies attributes to every log. + + ### Units For gauge and distribution metrics, you can specify a unit to help Sentry display values in a human-readable format. The `SentryUnit` singleton provides predefined constants for common units. See [supported units](https://develop.sentry.dev/sdk/foundations/data-model/attributes/#units) for the full list. -```GDScript +```gdscript {tabTitle:GDScript} {mdExpandTabs} # Duration units SentrySDK.metrics.distribution("level_load_time", load_time, SentryUnit.millisecond) @@ -83,3 +137,11 @@ SentrySDK.metrics.gauge("memory_usage", OS.get_static_memory_usage(), SentryUnit # Custom units (as strings) SentrySDK.metrics.gauge("items_in_inventory", item_count, "item") ``` + +```csharp {tabTitle:C#} +// Duration units +SentrySdk.Metrics.EmitDistribution("level_load_time", loadTime, MeasurementUnit.Duration.Millisecond); + +// Information units +SentrySdk.Metrics.EmitGauge("memory_usage", (long)OS.GetStaticMemoryUsage(), MeasurementUnit.Information.Byte); +``` From 561eee50ccc55f2a18ae98427666b6061bac7d7f Mon Sep 17 00:00:00 2001 From: Serhii Snitsaruk Date: Mon, 8 Jun 2026 19:19:10 +0200 Subject: [PATCH 05/18] Update godot.mdx --- platform-includes/getting-started-primer/godot.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform-includes/getting-started-primer/godot.mdx b/platform-includes/getting-started-primer/godot.mdx index fd052223a2373..bad0355022b2d 100644 --- a/platform-includes/getting-started-primer/godot.mdx +++ b/platform-includes/getting-started-primer/godot.mdx @@ -15,7 +15,7 @@ Our SDK for Godot Engine builds on top of existing Sentry SDKs, extending them w - [Structured Logs](/platforms/godot/logs/) that automatically capture console output like `print()` statements and connect to your traces with searchable attributes - [Enrich events](/platforms/godot/enriching-events/) with tags, breadcrumbs, contexts, and attachments - Information about user configuration like GPU, CPU, platform and such -- [Filter and customize events](/platforms/godot/data-management/sensitive-data/#scrubbing-data) in `before_send` callback (in GDScript or C#) +- [Filter and customize events](/platforms/godot/data-management/sensitive-data/#scrubbing-data) in `before_send` callback - [Log-file attachments](/platforms/godot/configuration/options/#attach_log) for events - [Scene tree data attachments](/platforms/godot/enriching-events/view-hierarchy/) for events - [Screenshot attachments](/platforms/godot/enriching-events/screenshots/) for events (experimental) From d04e6b559d348f26313e8a8b43be351f431f18a0 Mon Sep 17 00:00:00 2001 From: Serhii Snitsaruk Date: Tue, 9 Jun 2026 11:11:24 +0200 Subject: [PATCH 06/18] Add missing samples in options (except init) --- .../platforms/godot/configuration/options.mdx | 65 +++++++++++++++++-- 1 file changed, 61 insertions(+), 4 deletions(-) diff --git a/docs/platforms/godot/configuration/options.mdx b/docs/platforms/godot/configuration/options.mdx index 8c2acb0f7cf9a..28b923e7cb7e7 100644 --- a/docs/platforms/godot/configuration/options.mdx +++ b/docs/platforms/godot/configuration/options.mdx @@ -197,28 +197,41 @@ This option is turned on by default. Specifies the types of errors captured as breadcrumbs. Accepts a single value or a bitwise combination of `GodotErrorMask` masks. The default value captures native errors, warnings, script and shader errors (`MASK_ERROR | MASK_WARNING | MASK_SCRIPT | MASK_SHADER`). `GodotErrorMask` values: + - `MASK_NONE`: No logger errors will be captured. - `MASK_ERROR`: Native errors will be captured. These are typically C++ errors, which may also originate from a script. - `MASK_WARNING`: Warnings will be captured. - `MASK_SCRIPT`: Script errors will be captured. - `MASK_SHADER`: Shader errors will be captured. -```GDScript +```gdscript {tabTitle:GDScript} {mdExpandTabs} var mask = SentryOptions.MASK_ERROR | SentryOptions.MASK_SCRIPT options.logger_breadcrumb_mask = mask ``` +```csharp {tabTitle:C#} +var mask = SentryGodotOptions.GodotLoggerEventMask.Error + | SentryGodotOptions.GodotLoggerEventMask.Script; +options.LoggerBreadcrumbMask = mask; +``` + Specifies the types of errors captured as events. Accepts a single value or a bitwise combination of `GodotErrorMask` masks. The default value captures native, script and shader errors (`MASK_ERROR | MASK_SCRIPT` | `MASK_SHADER`). -```GDScript +```gdscript {tabTitle:GDScript} {mdExpandTabs} var mask = SentryOptions.MASK_ERROR | SentryOptions.MASK_SCRIPT options.logger_event_mask = mask ``` +```csharp {tabTitle:C#} +var mask = SentryGodotOptions.GodotLoggerEventMask.Error + | SentryGodotOptions.GodotLoggerEventMask.Script; +options.LoggerEventMask = mask; +``` + @@ -278,7 +291,7 @@ thread-safe APIs and only use Godot-specific APIs after you've checked that you' If assigned, this callback runs before an event is sent to Sentry. You can only set it [programmatically](#programmatic-configuration). It takes `SentryEvent` as a parameter and returns either the same event object, with or without modifications, or `null` to skip reporting the event. This can be used, for instance, for stripping PII before sending. -```GDScript +```gdscript {tabTitle:GDScript} {mdExpandTabs} func _before_send(event: SentryEvent) -> SentryEvent: if event.environment.contains("editor"): # Discard event if running from the editor. @@ -291,6 +304,29 @@ func _before_send(event: SentryEvent) -> SentryEvent: return event ``` +```csharp {tabTitle:C#} +// The .NET hook filters events captured from your C# code. +options.SetBeforeSend((sentryEvent, hint) => +{ + if (sentryEvent.Environment?.Contains("editor") == true) + { + // Discard the event if running from the editor. + return null; + } + + foreach (var exception in sentryEvent.SentryExceptions ?? []) + { + if (exception.Value?.Contains("Bruno") == true) + { + // Remove sensitive information from the event. + exception.Value = exception.Value.Replace("Bruno", "REDACTED"); + } + } + + return sentryEvent; +}); +``` + @@ -304,6 +340,12 @@ func _before_capture_screenshot(event: SentryEvent) -> bool: return true ``` + + +This callback isn't available in the .NET layer yet, so it can only be set from GDScript. + + + @@ -311,7 +353,7 @@ func _before_capture_screenshot(event: SentryEvent) -> bool: If assigned, this callback will be called before sending a log message to Sentry. It can be used to modify the log message or prevent it from being sent. -```GDScript +```gdscript {tabTitle:GDScript} {mdExpandTabs} func _before_send_log(log_entry: SentryLog) -> SentryLog: # Filter junk. if log_entry.body == "Junk message": @@ -323,4 +365,19 @@ func _before_send_log(log_entry: SentryLog) -> SentryLog: return log_entry ``` +```csharp {tabTitle:C#} +// The .NET hook applies to logs emitted from your C# code. +options.SetBeforeSendLog(log => +{ + // Filter junk. + if (log.Message == "Junk message") + { + return null; + } + // Add custom attributes. + log.SetAttribute("current_scene", currentScene.Name); + return log; +}); +``` + From af24e30ef0dcff8dc4c558997de078cb109f4fcd Mon Sep 17 00:00:00 2001 From: Serhii Snitsaruk Date: Tue, 9 Jun 2026 11:12:07 +0200 Subject: [PATCH 07/18] Clarify statement in attachments docs --- docs/platforms/godot/enriching-events/attachments/index.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/platforms/godot/enriching-events/attachments/index.mdx b/docs/platforms/godot/enriching-events/attachments/index.mdx index 43f9850f60916..b8e015082063f 100644 --- a/docs/platforms/godot/enriching-events/attachments/index.mdx +++ b/docs/platforms/godot/enriching-events/attachments/index.mdx @@ -49,7 +49,7 @@ You can add attachments that will be sent with every event using -You can also add attachments inside the `SentrySDK.init()` configuration callback. This is useful when you want to register attachments as part of SDK setup: +In GDScript, you can also add attachments inside the `SentrySDK.init()` configuration callback. This is useful when you want to register attachments as part of SDK setup: ```GDScript SentrySDK.init(func(options: SentryOptions) -> void: From bf60156ffeff46f484dd06b9ee5fdce7eb270bd6 Mon Sep 17 00:00:00 2001 From: Serhii Snitsaruk Date: Tue, 9 Jun 2026 11:25:59 +0200 Subject: [PATCH 08/18] Add missing samples in logs --- .../logs/best-practices/godot.mdx | 65 +++++++++++++++++-- 1 file changed, 60 insertions(+), 5 deletions(-) diff --git a/platform-includes/logs/best-practices/godot.mdx b/platform-includes/logs/best-practices/godot.mdx index 6466d64ffd63c..a55037c73a746 100644 --- a/platform-includes/logs/best-practices/godot.mdx +++ b/platform-includes/logs/best-practices/godot.mdx @@ -11,7 +11,7 @@ This makes debugging dramatically faster — one query returns everything about -```gdscript +```gdscript {tabTitle:GDScript} {mdExpandTabs} # ❌ Scattered thin logs SentrySDK.logger.info("Starting checkout") SentrySDK.logger.info("Validating cart") @@ -22,7 +22,7 @@ SentrySDK.logger.info("Checkout complete") SentrySDK.logger.info("Checkout completed", [], { "order_id": order.id, "user_id": user.id, - "user_tier": user.subscription, + "user_tier": user.plan, "cart_value": cart.total, "item_count": cart.items.size(), "payment_method": "stripe", @@ -30,6 +30,26 @@ SentrySDK.logger.info("Checkout completed", [], { }) ``` +```csharp {tabTitle:C#} +// ❌ Scattered thin logs +SentrySdk.Logger.LogInfo("Starting checkout"); +SentrySdk.Logger.LogInfo("Validating cart"); +SentrySdk.Logger.LogInfo("Processing payment"); +SentrySdk.Logger.LogInfo("Checkout complete"); + +// ✅ One wide event with full context +SentrySdk.Logger.LogInfo(log => +{ + log.SetAttribute("order_id", order.Id); + log.SetAttribute("user_id", user.Id); + log.SetAttribute("user_tier", user.Plan); + log.SetAttribute("cart_value", cart.Total); + log.SetAttribute("item_count", cart.Items.Count); + log.SetAttribute("payment_method", "stripe"); + log.SetAttribute("duration_ms", Time.GetTicksMsec() - startTime); +}, "Checkout completed"); +``` + @@ -50,7 +70,7 @@ This lets you filter logs by high-value customers or specific features. -```gdscript +```gdscript {tabTitle:GDScript} {mdExpandTabs} SentrySDK.logger.info("Level completed", [], { # User context "user_id": user.id, @@ -67,6 +87,24 @@ SentrySDK.logger.info("Level completed", [], { }) ``` +```csharp {tabTitle:C#} +SentrySdk.Logger.LogInfo(log => +{ + // User context + log.SetAttribute("user_id", user.Id); + log.SetAttribute("user_tier", user.Plan); // "free" | "pro" | "enterprise" + log.SetAttribute("account_age_days", user.AgeDays); + + // Game context + log.SetAttribute("current_scene", GetTree().CurrentScene.SceneFilePath); + log.SetAttribute("level", currentLevel); + log.SetAttribute("score", player.Score); + + // Business context + log.SetAttribute("is_premium", user.IsPremium); +}, "Level completed"); +``` + @@ -77,12 +115,12 @@ SentrySDK.logger.info("Level completed", [], { Pick a naming convention and stick with it across your codebase. Inconsistent names make queries impossible. -**Recommended:** Use `snake_case` for custom attributes to match GDScript conventions. +**Recommended:** Use `snake_case` for custom attributes to match common conventions. -```gdscript +```gdscript {tabTitle:GDScript} {mdExpandTabs} # ❌ Inconsistent naming {"user": "123"} {"userId": "123"} @@ -98,6 +136,23 @@ SentrySDK.logger.info("Order processed", [], { }) ``` +```csharp {tabTitle:C#} +// ❌ Inconsistent naming +log.SetAttribute("user", "123"); +log.SetAttribute("userId", "123"); +log.SetAttribute("user_id", "123"); +log.SetAttribute("UserID", "123"); + +// ✅ Consistent snake_case +SentrySdk.Logger.LogInfo(log => +{ + log.SetAttribute("user_id", "123"); + log.SetAttribute("order_id", "456"); + log.SetAttribute("cart_value", 99.99f); + log.SetAttribute("item_count", 3); +}, "Order processed"); +``` + From a1f1126be49274582632f40c8e492883eb82518c Mon Sep 17 00:00:00 2001 From: Serhii Snitsaruk Date: Tue, 9 Jun 2026 12:09:32 +0200 Subject: [PATCH 09/18] Add sample in user feedback form --- docs/platforms/godot/user-feedback/index.mdx | 26 +++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/docs/platforms/godot/user-feedback/index.mdx b/docs/platforms/godot/user-feedback/index.mdx index 9ea74b53f629c..d8885e51ccae4 100644 --- a/docs/platforms/godot/user-feedback/index.mdx +++ b/docs/platforms/godot/user-feedback/index.mdx @@ -43,7 +43,7 @@ Add `user_feedback_form.tscn` as a preview while editing the theme file to see y For custom UI integration, use `user_feedback_form.tscn` instead. This component scene provides a flexible panel that can be embedded into other UI controls. Unlike the standalone GUI, you'll need to manage its visibility manually. The form exposes two signals for handling user interactions: `feedback_submitted` (triggered when feedback is sent) and `feedback_cancelled` (triggered when the user cancels the operation). After you instantiate the form inside your UI scene, you can use the provided signals to hide the form when it's no longer needed (or perform some other action): -```GDScript +```gdscript {tabTitle:GDScript} {mdExpandTabs} # Assuming you have already added the form to your scene with "UserFeedbackForm" unique name. @onready var user_feedback_form = %UserFeedbackForm @@ -60,6 +60,30 @@ func _ready(): ) ``` +```csharp {tabTitle:C#} +// Assuming you have already added the form to your scene with "UserFeedbackForm" unique name. +public partial class FeedbackMenu : Control +{ + public override void _Ready() + { + var userFeedbackForm = GetNode("%UserFeedbackForm"); + + // Connect the form's GDScript signals by name to hide it after the user submits or cancels. + // The submitted feedback is passed as a GodotObject. + userFeedbackForm.Connect("feedback_submitted", Callable.From((GodotObject feedback) => + { + userFeedbackForm.Hide(); + GD.Print("User feedback submitted."); + })); + userFeedbackForm.Connect("feedback_cancelled", Callable.From(() => + { + userFeedbackForm.Hide(); + GD.Print("User feedback cancelled."); + })); + } +} +``` + To customize the form's appearance, use the provided reference theme file (`sentry_theme.tres`), which can be duplicated to create a custom UI style. Simply assign your customized theme to the form's `theme` property in the Inspector to apply your styling changes. ## User Feedback API From 779f9326e09265d2fa837ff6ec491d4bbb5988d0 Mon Sep 17 00:00:00 2001 From: Serhii Snitsaruk Date: Tue, 9 Jun 2026 12:29:03 +0200 Subject: [PATCH 10/18] Add init example C# in config-intro --- .../configuration/config-intro/godot.mdx | 60 +++++++++++++++---- 1 file changed, 50 insertions(+), 10 deletions(-) diff --git a/platform-includes/configuration/config-intro/godot.mdx b/platform-includes/configuration/config-intro/godot.mdx index 841c4f8a8c9f3..3ad9a31ffea3d 100644 --- a/platform-includes/configuration/config-intro/godot.mdx +++ b/platform-includes/configuration/config-intro/godot.mdx @@ -8,18 +8,20 @@ If **Auto Init** is enabled in **Project Settings**, the SDK initializes automat However, if you need finer control — for example, to define callbacks like — you can disable **Auto Init** and manually initialize the SDK from code. -The earliest point to configure and initialize the SDK is `MainLoop._initialize()`. +The earliest point to configure and initialize the SDK is the main loop's `_initialize()` method (`_Initialize()` in C#). To do this: 1. Disable **Auto Init** in **Project Settings -> Sentry -> Options**. -2. Create a new script that extends `SceneTree` and add a `class_name`. -3. Assign that `class_name` as your main loop type in **Project Settings → Application → Run → Main Loop Type**. -4. Define `_initialize()` method in your script and call `SentrySDK.init()` there. +2. Create a new script that extends `SceneTree`. In GDScript, give it a `class_name`; in C#, mark the class `[GlobalClass]` and `partial`. +3. Assign that script as your main loop type in **Project Settings → Application → Run → Main Loop Type**. +4. Define the `_initialize()` method (`_Initialize()` in C#) and call `SentrySDK.init()` (`Sentry.Godot.SentrySdk.Init()` in C#) there. + +A single `Init()` call from either language initializes both the native and .NET layers, so there's no need to initialize them separately. Here’s a complete example: -```gdscript +```gdscript {tabTitle:GDScript} {mdExpandTabs} class_name ProjectMainLoop extends SceneTree ## Tip: Set "ProjectMainLoop" as your main loop type in the project settings @@ -46,14 +48,52 @@ func _before_send(event: SentryEvent) -> SentryEvent: return event ``` - +```csharp {tabTitle:C#} +using Godot; +using Sentry; +using Sentry.Godot; -Prefer automatic initialization when possible — it runs before your code and helps ensure no startup events are missed. Use manual initialization only for cases that require runtime customization (custom handler, dynamic release values, programmatic sampling, etc.). +// Tip: Set "ProjectMainLoop" as your main loop type in the project settings +// under `application/run/main_loop_type`. +[GlobalClass] +public partial class ProjectMainLoop : SceneTree +{ + public override void _Initialize() + { + SentrySdk.Init(options => + { + if (OS.IsDebugBuild()) + { + options.Environment = "debug"; + options.Debug = true; + } + options.Release = "mygame@1.0.0"; + options.SetBeforeSend((sentryEvent, hint) => + { + if (sentryEvent.Environment?.Contains("editor") == true) + { + // Discard the event if running from the editor. + return null; + } - + foreach (var exception in sentryEvent.SentryExceptions ?? []) + { + if (exception.Value?.Contains("Bruno") == true) + { + // Remove sensitive information from the event. + exception.Value = exception.Value.Replace("Bruno", "REDACTED"); + } + } - + return sentryEvent; + }); + }); + } +} +``` + + -In C#, initialize the SDK by calling `Sentry.Godot.SentrySdk.Init()` from your code. See C#/.NET Support for details. +Prefer automatic initialization when possible — it runs before your code and helps ensure no startup events are missed. Use manual initialization only for cases that require runtime customization (custom handler, dynamic release values, programmatic sampling, etc.). From cd24ee5e6e258028363e213aa64ba46a10536ee9 Mon Sep 17 00:00:00 2001 From: Serhii Snitsaruk Date: Tue, 9 Jun 2026 12:39:08 +0200 Subject: [PATCH 11/18] Trim init example from C# guide, link to main config-intro --- docs/platforms/godot/dotnet/index.mdx | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/docs/platforms/godot/dotnet/index.mdx b/docs/platforms/godot/dotnet/index.mdx index 4ec67da4019de..9c9531eff2c86 100644 --- a/docs/platforms/godot/dotnet/index.mdx +++ b/docs/platforms/godot/dotnet/index.mdx @@ -37,19 +37,7 @@ Set your [DSN](/product/sentry-basics/dsn-explainer/) in **Project Settings > Se ### Manual Initialization -If you need to set options from code — for example, to define a [`before_send`](/platforms/godot/configuration/options/#before_send) callback — disable **Auto Init** in **Project Settings > Sentry > Options** and initialize the SDK from code: - -```csharp -using Sentry; -using Sentry.Godot; - -SentrySdk.Init(options => -{ - options.Release = "my-game@{app_version}"; - options.Environment = "{auto}"; - options.AttachScreenshot = true; -}); -``` +If you need to set options from code — for example, to define a [`before_send`](/platforms/godot/configuration/options/#before_send) callback — disable **Auto Init** in **Project Settings > Sentry > Options** and initialize the SDK from C# code. See [Programmatic Configuration](/platforms/godot/configuration/options/#programmatic-configuration) for a complete C# example. Initializing Sentry from either language brings up both layers, so a single `Init()` call is all you need — there's no need to initialize it separately in C# and GDScript. From d9a02a3a45e3d13997cff18b6247a9050b9f9177 Mon Sep 17 00:00:00 2001 From: Serhii Snitsaruk Date: Tue, 9 Jun 2026 12:41:30 +0200 Subject: [PATCH 12/18] Fix log => metric --- platform-includes/metrics/usage/godot.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform-includes/metrics/usage/godot.mdx b/platform-includes/metrics/usage/godot.mdx index ff8cc819a215d..aee99d2fb5181 100644 --- a/platform-includes/metrics/usage/godot.mdx +++ b/platform-includes/metrics/usage/godot.mdx @@ -120,7 +120,7 @@ SentrySdk.Metrics.EmitCounter("enemy_defeated", 1); The C# SDK doesn't have a scope-level attribute API yet. The before-send hook - is the closest equivalent: it applies attributes to every log. + is the closest equivalent: it applies attributes to every metric. ### Units From edc4961c6161be94f83735f29c606eeea078079e Mon Sep 17 00:00:00 2001 From: Serhii Snitsaruk Date: Tue, 9 Jun 2026 12:49:48 +0200 Subject: [PATCH 13/18] Comment IP address inference in Godot example --- platform-includes/enriching-events/set-user/godot.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform-includes/enriching-events/set-user/godot.mdx b/platform-includes/enriching-events/set-user/godot.mdx index f0a39750ebcbd..ea86443a2edab 100644 --- a/platform-includes/enriching-events/set-user/godot.mdx +++ b/platform-includes/enriching-events/set-user/godot.mdx @@ -12,7 +12,7 @@ SentrySdk.ConfigureScope(scope => scope.User = new SentryUser { Id = Guid.NewGuid().ToString(), - IpAddress = "{{auto}}", + IpAddress = "{{auto}}", // Tells Sentry to infer the IP address Email = "jane.doe@example.com", }; }); From 71bfa769b193e4626eb953249b1ee3cc64470263 Mon Sep 17 00:00:00 2001 From: Serhii Snitsaruk Date: Tue, 9 Jun 2026 13:41:00 +0200 Subject: [PATCH 14/18] Use language-neutral instructions in config-intro --- .../configuration/config-intro/godot.mdx | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/platform-includes/configuration/config-intro/godot.mdx b/platform-includes/configuration/config-intro/godot.mdx index 3ad9a31ffea3d..ba026fafe9493 100644 --- a/platform-includes/configuration/config-intro/godot.mdx +++ b/platform-includes/configuration/config-intro/godot.mdx @@ -6,16 +6,13 @@ or override them programmatically when initializing the SDK in code. If **Auto Init** is enabled in **Project Settings**, the SDK initializes automatically when the game starts. However, if you need finer control — for example, to define callbacks like — -you can disable **Auto Init** and manually initialize the SDK from code. - -The earliest point to configure and initialize the SDK is the main loop's `_initialize()` method (`_Initialize()` in C#). +disable **Auto Init** and initialize the SDK yourself from the main loop, the earliest point available in code. To do this: -1. Disable **Auto Init** in **Project Settings -> Sentry -> Options**. -2. Create a new script that extends `SceneTree`. In GDScript, give it a `class_name`; in C#, mark the class `[GlobalClass]` and `partial`. -3. Assign that script as your main loop type in **Project Settings → Application → Run → Main Loop Type**. -4. Define the `_initialize()` method (`_Initialize()` in C#) and call `SentrySDK.init()` (`Sentry.Godot.SentrySdk.Init()` in C#) there. +1. Disable **Auto Init** in **Project Settings → Sentry → Options**. +2. Create a script that extends `SceneTree` with a global class name, then enter that name in **Project Settings → Application → Run → Main Loop Type**. +3. Initialize the SDK in the script's `_initialize()` method. A single `Init()` call from either language initializes both the native and .NET layers, so there's no need to initialize them separately. From 2477a0d2a37a0fc83334a8cc44be3882a274fb11 Mon Sep 17 00:00:00 2001 From: Serhii Snitsaruk Date: Tue, 9 Jun 2026 13:58:42 +0200 Subject: [PATCH 15/18] Language-neutral context instruction --- docs/platforms/godot/enriching-events/context/index.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/platforms/godot/enriching-events/context/index.mdx b/docs/platforms/godot/enriching-events/context/index.mdx index 082fbc951d7da..c1f7c3e5e5205 100644 --- a/docs/platforms/godot/enriching-events/context/index.mdx +++ b/docs/platforms/godot/enriching-events/context/index.mdx @@ -17,7 +17,7 @@ If you need to be able to search on custom data, [use tags](../tags) instead. The best way to attach custom data is with a structured context. A context must always be an object and its values can be arbitrary. -Then, use and give the context a unique name: +Then, set a context and give it a unique name: From 3265f21c4e2f94a78580c3bd2a7dfdc57179f1ab Mon Sep 17 00:00:00 2001 From: Serhii Snitsaruk Date: Tue, 9 Jun 2026 14:05:14 +0200 Subject: [PATCH 16/18] Add cross-layer context sync alert --- docs/platforms/godot/enriching-events/context/index.mdx | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/platforms/godot/enriching-events/context/index.mdx b/docs/platforms/godot/enriching-events/context/index.mdx index c1f7c3e5e5205..30d22ffffe5db 100644 --- a/docs/platforms/godot/enriching-events/context/index.mdx +++ b/docs/platforms/godot/enriching-events/context/index.mdx @@ -21,6 +21,12 @@ Then, set a context and give it a unique name: + + +Custom contexts aren't synced between the SDK's native and .NET layers yet. A context you set from C# appears only on C# events — not on the GDScript and engine errors captured by the native layer (and vice versa). See [C#/.NET Support](/platforms/godot/dotnet/#limitations) for the full list of cross-layer differences. + + + There are no restrictions on context name. In the context object, all keys are allowed except for `type`, which is used internally. Learn more about conventions for common contexts in the [contexts interface developer documentation](https://develop.sentry.dev/sdk/foundations/transport/event-payloads/contexts/). From cb8d7b2ea772ec5bb64a2e1c933a67ef6abb7e50 Mon Sep 17 00:00:00 2001 From: Serhii Snitsaruk Date: Tue, 9 Jun 2026 14:11:33 +0200 Subject: [PATCH 17/18] Add mdExpandTabs --- docs/platforms/godot/enriching-events/attachments/index.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/platforms/godot/enriching-events/attachments/index.mdx b/docs/platforms/godot/enriching-events/attachments/index.mdx index b8e015082063f..6b4e9aec4b688 100644 --- a/docs/platforms/godot/enriching-events/attachments/index.mdx +++ b/docs/platforms/godot/enriching-events/attachments/index.mdx @@ -62,7 +62,7 @@ SentrySDK.init(func(options: SentryOptions) -> void: To clear all user-added attachments, use . Built-in attachments such as log files, screenshots, and view hierarchy are preserved. -```gdscript {tabTitle:GDScript} +```gdscript {tabTitle:GDScript} {mdExpandTabs} SentrySDK.clear_attachments() ``` From 92d21ea6b2e94c454f3212815088d6ab4665479d Mon Sep 17 00:00:00 2001 From: Serhii Snitsaruk Date: Tue, 9 Jun 2026 16:03:37 +0200 Subject: [PATCH 18/18] Clarify statement in programmatic config section --- platform-includes/configuration/config-intro/godot.mdx | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/platform-includes/configuration/config-intro/godot.mdx b/platform-includes/configuration/config-intro/godot.mdx index ba026fafe9493..fc7782e7a9e3e 100644 --- a/platform-includes/configuration/config-intro/godot.mdx +++ b/platform-includes/configuration/config-intro/godot.mdx @@ -6,9 +6,7 @@ or override them programmatically when initializing the SDK in code. If **Auto Init** is enabled in **Project Settings**, the SDK initializes automatically when the game starts. However, if you need finer control — for example, to define callbacks like — -disable **Auto Init** and initialize the SDK yourself from the main loop, the earliest point available in code. - -To do this: +disable **Auto Init** and initialize the SDK yourself. The main loop's `_initialize()` method is the earliest point you can do this in code: 1. Disable **Auto Init** in **Project Settings → Sentry → Options**. 2. Create a script that extends `SceneTree` with a global class name, then enter that name in **Project Settings → Application → Run → Main Loop Type**.