DebugReporter.Avalonia 0.1.1

dotnet add package DebugReporter.Avalonia --version 0.1.1
                    
NuGet\Install-Package DebugReporter.Avalonia -Version 0.1.1
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="DebugReporter.Avalonia" Version="0.1.1" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="DebugReporter.Avalonia" Version="0.1.1" />
                    
Directory.Packages.props
<PackageReference Include="DebugReporter.Avalonia" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add DebugReporter.Avalonia --version 0.1.1
                    
#r "nuget: DebugReporter.Avalonia, 0.1.1"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package DebugReporter.Avalonia@0.1.1
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=DebugReporter.Avalonia&version=0.1.1
                    
Install as a Cake Addin
#tool nuget:?package=DebugReporter.Avalonia&version=0.1.1
                    
Install as a Cake Tool

DebugReporter.Avalonia

Reusable Avalonia bug-report dialog for desktop apps: problem description, screenshots (file / clipboard / OS snip / annotation), optional local speech-to-text, automatic session-log attachment, and a host-provided send pipeline (Gmail API, SMTP, webhook, etc.).

NuGet: DebugReporter.Avalonia
Assembly / namespaces: AvaloniaDebugReporter (unchanged for API stability)


What you get vs what you implement

Provided by the package Implemented by your app (required for production)
Bug-report UI (dialog, annotation, recipient prompt) IDebugReportSender — actually deliver the report
Read & summarize a log file you point to LogFilePathProvider — path to your session log on disk
Built-in en/sv UI strings (optional) IDebugReportLocalizer — other languages or your own wording
Default Whisper.net dictation (KB-Whisper model download) ITextDictationService (optional) — use your own STT instead
MIME builder for email bodies + attachments Gmail / SMTP / API credentials and transport
NoOpDebugReportSender if you forget registration Replace with a real sender before shipping

The package does not ship Gmail, SMTP, or Serilog. It does not send anything until you register IDebugReportSender.


Install

dotnet add package DebugReporter.Avalonia

Requirements: .NET 8+ host, Avalonia 11.x, Microsoft.Extensions.DependencyInjection.


Quick start (dialog only)

using AvaloniaDebugReporter.Services;
using Microsoft.Extensions.DependencyInjection;

services.AddAvaloniaDebugReporter(options =>
{
    options.AppName = "My App";
    options.DeveloperName = "the developer";
    options.LogFilePathProvider = () => MyApp.CurrentSessionLogPath;
    options.VersionProvider = () => "1.2.3";
});

// Register AFTER AddAvaloniaDebugReporter (replaces the built-in no-op sender):
services.AddSingleton<IDebugReportSender, MyDebugReportSender>();

Open the dialog from a window:

var dialog = serviceProvider.GetRequiredService<IDebugReportDialogService>();
bool? sent = await dialog.ShowAsync(ownerWindow);
// true = sender returned success, false = send failed, null = user cancelled

Until IDebugReportSender is registered, Send logs a warning and returns false.


Integration checklist

Use this order when wiring a production app:

  1. AddAvaloniaDebugReporter — set AppName, LogFilePathProvider, and optional providers (language, version, developer display name).
  2. IDebugReportSender — send DebugReport (email, ticket system, HTTP, …).
  3. IDebugReportLocalizer (recommended if not en/sv) — UI + email body strings.
  4. ITextDictationService (optional) — replace built-in Whisper dictation.
  5. ILoggerFactory (optional) — route package diagnostics to your logging (see below).
  6. Menu / command — call IDebugReportDialogService.ShowAsync(owner).

Extension points

IDebugReportSender (required for real delivery)

public interface IDebugReportSender
{
    Task<bool> SendAsync(DebugReport report, CancellationToken cancellationToken = default);
}

DebugReport contains everything the user entered plus collected data:

  • Description, ReproductionSteps
  • SessionLog (summarized text, not the raw file path)
  • Attachments (image bytes + file names)
  • RecipientEmail — who receives the report (see Recipient email)
  • ReporterContact — optional; set in the sender if you know the user's email
  • Language — language code used for email body labels (e.g. en, sv, de)
  • Version, AppName, OS / architecture, CreatedAtUtc

Return true only when delivery succeeded.

IDebugReportLocalizer (optional — UI and email text)

public interface IDebugReportLocalizer
{
    string? GetString(string key, string? language);
}

Used for:

  • All dialog, annotation, recipient, and dictation UI strings
  • Email plain-text section headings via DebugReportMimeMessageBuilder (Report.* keys)

Return null or the key itself to fall back to built-in English, then Swedish for known keys.

Built-in languages: en, sv (prefix match, e.g. sv-SE → Swedish).

Dynamic UI language: set options.Language or options.LanguageProvider (called when the dialog opens).

Email language: taken from DebugReport.Language (same provider / option at send time).

Keys are defined in DefaultDebugReportLocalizer (e.g. Dialog.BugReport.Title, Dialog.Recipient.Message, Report.SessionLog). Copy that class or grep the source when adding locales.

Dialog.BugReport.Title supports {DeveloperName} — set DeveloperName or DeveloperNameProvider.

ITextDictationService (optional — dictation button)

Default registration: WhisperTextDictationService (Whisper.net + PvRecorder).

Replace when your app already has speech-to-text:

services.AddSingleton<ITextDictationService, MySpeechToTextAdapter>();

Disable dictation entirely:

options.EnableDictation = false;

IDebugLogCollector (optional)

Default: reads the file from LogFilePathProvider and summarizes it. Replace only if you need a custom log source.

IDebugReportSettingsStore (optional)

Default: saves prompted recipient email under
%LocalAppData%/{DataDirectoryName}/debug-reporter-settings.json.


Session logs (Serilog-friendly, not Serilog-coupled)

The package does not reference Serilog. It reads a text file path you supply:

options.LogFilePathProvider = () => pathToSessionLogFile;

LogSummarizer expects lines similar to Serilog file output, for example:

[Instance] [12:53:19.177 INF App] Initialized localization with language: sv

It collapses consecutive duplicate lines and truncates to MaxSummarizedLogLength (default 60 000). The result is embedded in DebugReport.SessionLog when the user sends.

Typical Serilog setup (host app):

Log.Logger = new LoggerConfiguration()
    .WriteTo.File(sessionLogPath, shared: true, ...)
    .CreateLogger();

options.LogFilePathProvider = () => sessionLogPath;

Use shared: true if the dialog reads the log while the app is still writing.


Package diagnostics (Microsoft.Extensions.Logging)

Internal features (screen snip, clipboard, Whisper install, etc.) log through ILogger with category AvaloniaDebugReporter.

By default the package registers NullLoggerFactory — nothing is written.

To see package logs in your pipeline (e.g. Serilog), register a factory before or after AddAvaloniaDebugReporter so it replaces the null factory:

services.AddLogging(builder => builder.AddSerilog(Log.Logger));
// or: services.AddSingleton<ILoggerFactory>(myLoggerFactory);
services.AddAvaloniaDebugReporter(...);

Dictation (local AI — KB-Whisper)

When EnableDictation is true (default), the dictation button uses:

Setting Default Meaning
WhisperModelFileName kb-whisper-small.bin Local file name under app data
WhisperModelUrl KBLab Hugging Face URL Downloaded on first use
WhisperLanguage sv Whisper language code

The model is downloaded once; the UI shows install / record / transcribe states (Dictation.* strings).

Dependencies bundled in the package: Whisper.net, Whisper.net.Runtime, PvRecorder, NAudio.Core.

Override with ITextDictationService if you use another engine or want to share models with the rest of your app.


Email delivery (Gmail, SMTP, or anything else)

The package builds MIME messages; you send them.

Helper: DebugReportMimeMessageBuilder

// Plain MIME (SMTP, MailKit, etc.)
var mime = DebugReportMimeMessageBuilder.BuildMimeMessage(
    report, from: sender@app.com, to: report.RecipientEmail!,
    subject: $"[{report.AppName}] Debug report",
    localizer: myLocalizer, language: report.Language);

// Gmail API `users.messages.send` raw field:
var raw = DebugReportMimeMessageBuilder.BuildGmailRaw(
    report, from, to, subject, myLocalizer, report.Language);

Pass the same IDebugReportLocalizer you use for the UI so the email body matches the user's language.

Example sender skeleton (SMTP pseudo-code)

public sealed class SmtpDebugReportSender : IDebugReportSender
{
    public async Task<bool> SendAsync(DebugReport report, CancellationToken ct)
    {
        if (string.IsNullOrWhiteSpace(report.RecipientEmail))
            return false;

        var mime = DebugReportMimeMessageBuilder.BuildMimeMessage(
            report,
            from: "noreply@myapp.com",
            to: report.RecipientEmail,
            subject: $"[{report.AppName}] v{report.Version} debug report");

        // Send `mime` with MailKit / System.Net.Mail / your provider
        return await SendMimeAsync(mime, ct);
    }
}

Gmail API

Use BuildGmailRaw, then Users.Messages.Send with Message.Raw (base64url). Your app must own OAuth / service account setup — same as any Gmail integration.


Recipient email (who receives reports)

Flow when the user clicks Send:

  1. If DeveloperEmail / DeveloperEmailProvider is set → used as recipient.
  2. Else if PromptForDeveloperEmailIfMissing (default true) → show Recipient address dialog (Dialog.Recipient.* strings).
  3. If RememberPromptedDeveloperEmail (default true) → save to
    %LocalAppData%/{DataDirectoryName}/debug-reporter-settings.json.

Set a fixed support address and skip the prompt:

options.DeveloperEmail = "support@example.com";
options.PromptForDeveloperEmailIfMissing = false;

report.RecipientEmail in IDebugReportSender is the resolved address.


Configuration reference (DebugReportOptions)

Property Default Description
AppName "Avalonia app" Shown in UI and report title
DeveloperName "the developer" Title token {DeveloperName}
DeveloperEmail null Fixed recipient; skips prompt when set
Language "en" UI language if no LanguageProvider
LanguageProvider null Dynamic UI language (e.g. app settings)
DeveloperNameProvider null Localized “developer” label in title
DeveloperEmailProvider null Dynamic recipient
LogFilePathProvider null Recommended — session log file path
VersionProvider null App version in report
ReporterContactProvider null Prefill reporter email in payload
DataDirectoryName "AvaloniaDebugReporter" Subfolder under %LocalAppData% for settings
ScreenClipSourceName "AvaloniaDebugReporter" OS snip source name (Windows)
EnableDictation true Show dictation buttons
PromptForDeveloperEmailIfMissing true Ask for recipient when not configured
RememberPromptedDeveloperEmail true Persist recipient JSON settings
MaxAttachments 12 Image count limit
MaxTotalAttachmentBytes 18 MiB Total attachment size
MaxSummarizedLogLength 60000 Truncation for session log text
AllowedImageExtensions png, jpg, … File picker / validation
WhisperLanguage "sv" Default Whisper language
WhisperModelFileName kb-whisper-small.bin Local model file name
WhisperModelUrl KBLab URL Model download URL

UI resources

Dialogs and styles are embedded in the assembly (avares://AvaloniaDebugReporter/...). You do not need to copy XAML into your app.


Return values

IDebugReportDialogService.ShowAsync:

Result Meaning
true User sent; IDebugReportSender returned true
false User sent; sender failed or no sender
null User cancelled or closed the dialog

Minimal vs full registration

Playground / UI test only

services.AddAvaloniaDebugReporter(o => o.AppName = "Demo");
// No IDebugReportSender → Send does nothing useful

Production

services.AddLogging(...); // optional
services.AddAvaloniaDebugReporter(options => { /* see checklist */ });
services.AddSingleton<IDebugReportLocalizer, MyLocalizer>(); // if needed
services.AddSingleton<ITextDictationService, MyStt>();       // if needed
services.AddSingleton<IDebugReportSender, MySender>();       // required

License

MIT — see repository for details.

Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
0.1.1 79 5/30/2026
0.1.0 88 5/30/2026