NetMauiLogger 1.0.0
dotnet add package NetMauiLogger --version 1.0.0
NuGet\Install-Package NetMauiLogger -Version 1.0.0
<PackageReference Include="NetMauiLogger" Version="1.0.0" />
<PackageVersion Include="NetMauiLogger" Version="1.0.0" />
<PackageReference Include="NetMauiLogger" />
paket add NetMauiLogger --version 1.0.0
#r "nuget: NetMauiLogger, 1.0.0"
#:package NetMauiLogger@1.0.0
#addin nuget:?package=NetMauiLogger&version=1.0.0
#tool nuget:?package=NetMauiLogger&version=1.0.0
NetMauiLogger
A comprehensive, fully asynchronous logging, error-handling, and crash-reporting library for .NET MAUI applications. All operations run on background threads—your UI is never blocked.
Features
| Feature | Description |
|---|---|
| Structured Logging | Log with screen name, module, message, and severity. Stored locally in SQLite. |
| Consolidated Email Reports | Beautiful HTML email sent on a configurable schedule with all log entries. |
| Immediate Error Emails | Unhandled exceptions trigger an instant, detailed HTML email. |
| Crash Reporting | Fatal crashes are captured, persisted, and emailed on the next app launch. |
| Background Queue | All email delivery happens via a Channel<T>-backed queue—zero UI impact. |
| Local SQLite Storage | Logs survive restarts; unsent reports are retried automatically. |
| Fully Async | Every method is async/await; no Task.Wait() on the UI thread. |
Installation
To Start with Reference the package
dotnet add package NetMauiLogger --source ./nupkgs
Quick Start
1. Register in MauiProgram.cs
using NetMauiLogger;
using NetMauiLogger.Configuration;
public static class MauiProgram
{
public static MauiApp CreateMauiApp()
{
var builder = MauiApp.CreateBuilder();
builder.UseMauiApp<App>();
builder.UseNetMauiLogger(cfg =>
{
// Application metadata
cfg.App.Name = "MyAwesomeApp";
cfg.App.Version = AppInfo.VersionString;
cfg.App.Environment = "Production"; // Development | Staging | Production
// SMTP / email settings
cfg.Email.SmtpHost = "smtp.gmail.com";
cfg.Email.SmtpPort = 587;
cfg.Email.UseSsl = true;
cfg.Email.Username = "alerts@yourcompany.com";
cfg.Email.Password = "your-app-password"; // Use an app password, not your main password
cfg.Email.FromAddress = "alerts@yourcompany.com";
cfg.Email.FromDisplayName = "MyApp Alerts";
cfg.Email.ToAddresses.Add("devteam@yourcompany.com");
cfg.Email.ToAddresses.Add("support@yourcompany.com");
// Log level thresholds
cfg.LogLevel.MinimumDatabaseLevel = LogSeverity.Debug; // Persist Debug+ to SQLite
cfg.LogLevel.MinimumReportLevel = LogSeverity.Information; // Include Info+ in reports
cfg.LogLevel.ImmediateEmailLevel = LogSeverity.Error; // Email immediately for Error+
// Scheduled reporting
cfg.Reporting.ReportInterval = TimeSpan.FromHours(6); // Every 6 hours
cfg.Reporting.MaxEntriesPerReport = 500;
cfg.Reporting.PurgeSentLogs = true;
cfg.Reporting.LogRetentionDays = 14;
});
return builder.Build();
}
}
2. Activate at App Startup (App.xaml.cs)
using NetMauiLogger.Services;
public partial class App : Application
{
public App(IErrorHandler errorHandler, ICrashReporter crashReporter)
{
InitializeComponent();
// Register global unhandled exception hooks
errorHandler.Register();
// Register crash hooks & dispatch any pending crash reports from last session
_ = crashReporter.InitialiseAsync();
MainPage = new AppShell();
}
}
Logging
Inject ILogService
public class ProductViewModel
{
private readonly ILogService _log;
public ProductViewModel(ILogService log) => _log = log;
public async Task LoadProductsAsync()
{
await _log.LogInfoAsync("ProductsPage", "ProductViewModel", "Loading products...");
try
{
// ... business logic ...
}
catch (Exception ex)
{
// Logs to SQLite AND sends an immediate email (severity >= ImmediateEmailLevel)
await _log.LogErrorAsync("ProductsPage", "ProductViewModel", "Failed to load products", ex);
}
}
}
All logging methods
// Convenience shortcuts
await _log.LogDebugAsync(screenName, module, message);
await _log.LogInfoAsync(screenName, module, message);
await _log.LogWarningAsync(screenName, module, message, exception);
await _log.LogErrorAsync(screenName, module, message, exception);
await _log.LogCriticalAsync(screenName, module, message, exception);
// Full signature with optional context dictionary
await _log.LogAsync(
screenName: "CheckoutPage",
module: "PaymentService",
message: "Payment declined",
severity: LogSeverity.Warning,
exception: null,
context: new Dictionary<string, string>
{
["OrderId"] = "ORD-12345",
["UserId"] = "usr-678",
["Amount"] = "99.99"
});
// Manually trigger the consolidated report outside the schedule
await _log.SendConsolidatedReportNowAsync();
Error Handling
IErrorHandler hooks into:
AppDomain.CurrentDomain.UnhandledException— synchronous unhandled exceptionsTaskScheduler.UnobservedTaskException— unobserved async task exceptions
// Auto-registered via errorHandler.Register() in App.xaml.cs
// For manual capture inside a catch block:
try
{
await riskyOperation();
}
catch (Exception ex)
{
await _errorHandler.HandleExceptionAsync(ex, "PaymentPage", "PaymentService");
// Shows user-friendly message, sends detailed email in background
}
Email includes:
- Exception type, message, full stack trace
- Inner exception chain
- Screen name & module
- Device model, platform, OS version
- App version & environment
Crash Reporting
ICrashReporter hooks into AppDomain.CurrentDomain.UnhandledException for terminating crashes.
// Activated via crashReporter.InitialiseAsync() at startup
// Manual crash capture:
await _crashReporter.ReportCrashAsync(exception, origin: "NativeCallback");
Crash email includes everything in the error email, plus:
- Crash origin (FatalUnhandledException / ManualReport)
- Last 20 log entries before the crash
- Available memory at crash time
Retry on next launch: If email delivery fails (no network), the crash report is stored in SQLite and automatically dispatched when InitialiseAsync() is called on the next app start.
Email Report Samples
Consolidated Log Report
- Gradient blue header with app name, version, environment
- Summary table: total entries grouped by severity with colour-coded badges
- Full log table: timestamp, level badge, screen, module, message
Error Report
- Gradient red header (⚠️ alert styling)
- Exception type & message
- Syntax-highlighted dark stack trace block
- Device & app information table
Crash Report
- Gradient purple header (💥 critical styling)
- Full crash details + available memory
- Dark stack trace block
- Recent log history table showing the 20 entries before the crash
Configuration Reference
LoggerConfiguration
| Property | Type | Description |
|---|---|---|
App |
AppMetadata |
Application name, version, environment |
Email |
EmailConfiguration |
SMTP settings and recipients |
LogLevel |
LogLevelConfiguration |
Minimum severity thresholds |
Reporting |
ReportingConfiguration |
Report schedule and retention |
EmailConfiguration
| Property | Default | Description |
|---|---|---|
SmtpHost |
— | SMTP server hostname |
SmtpPort |
587 |
SMTP port |
UseSsl |
true |
Enable STARTTLS |
Username |
— | SMTP auth username |
Password |
— | SMTP auth password |
FromAddress |
— | Sender email address |
FromDisplayName |
"NetMauiLogger" |
Sender display name |
ToAddresses |
[] |
List of recipient addresses |
LogLevelConfiguration
| Property | Default | Description |
|---|---|---|
MinimumDatabaseLevel |
Debug |
Lowest level persisted to SQLite |
MinimumReportLevel |
Information |
Lowest level included in reports |
ImmediateEmailLevel |
Error |
Level that triggers an instant email |
ReportingConfiguration
| Property | Default | Description |
|---|---|---|
ReportInterval |
1 hour |
Consolidated report cadence |
MaxEntriesPerReport |
500 |
Cap entries per report email |
PurgeSentLogs |
true |
Delete sent entries after reporting |
LogRetentionDays |
30 |
Days to keep unsent entries |
LogSeverity enum
Debug (0) → Information (1) → Warning (2) → Error (3) → Critical (4)
Architecture
MauiProgram / App
│
▼
ServiceCollectionExtensions.AddNetMauiLogger()
│
├── ILogService (LogService)
│ ├── Persists entries → ILogDatabase (SQLite)
│ ├── PeriodicTimer → SendConsolidatedReportNowAsync()
│ └── High-severity entries → BackgroundEmailQueue
│
├── IErrorHandler (ErrorHandler)
│ ├── AppDomain.UnhandledException hook
│ ├── TaskScheduler.UnobservedTaskException hook
│ └── Immediate email → BackgroundEmailQueue
│
├── ICrashReporter (CrashReporter)
│ ├── Fatal crash hook (terminating)
│ ├── Synchronous SQLite save (survives process death)
│ └── Pending reports dispatched on next launch
│
└── BackgroundEmailQueue (Channel<EmailWorkItem>)
├── Single-reader background loop
├── MailKit SMTP delivery
└── Post-send DB updates (mark as sent / purge)
NuGet Packaging
# Pack a Release build
dotnet pack src/NetMauiLogger/NetMauiLogger.csproj \
-c Release \
-o ./nupkgs \
/p:PackageVersion=1.0.0
To publish to NuGet.org:
dotnet nuget push ./nupkgs/NetMauiLogger.1.0.0.nupkg \
--api-key YOUR_NUGET_API_KEY \
--source https://api.nuget.org/v3/index.json
Dependencies
| Package | Purpose |
|---|---|
Microsoft.Maui.Controls |
MAUI platform APIs (DeviceInfo, FileSystem) |
MailKit |
Robust SMTP email delivery |
sqlite-net-pcl |
Local SQLite database |
SQLitePCLRaw.bundle_green |
SQLite native binaries for all platforms |
Microsoft.Extensions.DependencyInjection.Abstractions |
DI interfaces |
Security Notes
- Never commit SMTP credentials to source control. Use environment variables, MAUI
SecureStorage, or a configuration service. - Use app-specific passwords (Gmail, Outlook) rather than your main account password.
- The library never logs credentials; all sensitive config stays in
LoggerConfigurationat runtime only.
License
MIT — see LICENSE for details.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net9.0-android35.0 is compatible. net9.0-ios18.0 is compatible. net9.0-maccatalyst18.0 is compatible. net9.0-windows10.0.19041 is compatible. net10.0-android was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-windows was computed. |
-
net9.0-android35.0
- MailKit (>= 4.12.0)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 9.0.9)
- Microsoft.Maui.Controls (>= 9.0.120)
- Microsoft.Maui.Dependencies (>= 6.0.553)
- sqlite-net-pcl (>= 1.9.172)
- SQLitePCLRaw.bundle_green (>= 2.1.10)
-
net9.0-ios18.0
- MailKit (>= 4.12.0)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 9.0.9)
- Microsoft.Maui.Controls (>= 9.0.120)
- Microsoft.Maui.Dependencies (>= 6.0.553)
- sqlite-net-pcl (>= 1.9.172)
- SQLitePCLRaw.bundle_green (>= 2.1.10)
-
net9.0-maccatalyst18.0
- MailKit (>= 4.12.0)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 9.0.9)
- Microsoft.Maui.Controls (>= 9.0.120)
- Microsoft.Maui.Dependencies (>= 6.0.553)
- sqlite-net-pcl (>= 1.9.172)
- SQLitePCLRaw.bundle_green (>= 2.1.10)
-
net9.0-windows10.0.19041
- MailKit (>= 4.12.0)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 9.0.9)
- Microsoft.Maui.Controls (>= 9.0.120)
- Microsoft.Maui.Dependencies (>= 6.0.553)
- sqlite-net-pcl (>= 1.9.172)
- SQLitePCLRaw.bundle_green (>= 2.1.10)
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 |
|---|---|---|
| 1.0.0 | 127 | 4/28/2026 |