SpproApiLogger.Client 0.4.0

dotnet add package SpproApiLogger.Client --version 0.4.0
                    
NuGet\Install-Package SpproApiLogger.Client -Version 0.4.0
                    
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="SpproApiLogger.Client" Version="0.4.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="SpproApiLogger.Client" Version="0.4.0" />
                    
Directory.Packages.props
<PackageReference Include="SpproApiLogger.Client" />
                    
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 SpproApiLogger.Client --version 0.4.0
                    
#r "nuget: SpproApiLogger.Client, 0.4.0"
                    
#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 SpproApiLogger.Client@0.4.0
                    
#: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=SpproApiLogger.Client&version=0.4.0
                    
Install as a Cake Addin
#tool nuget:?package=SpproApiLogger.Client&version=0.4.0
                    
Install as a Cake Tool

SpproApiLogger.Client

Microsoft.Extensions.Logging provider that ships log entries to a Sppro Api Logger instance over HTTPS.

Targets: net48, net6.0, net8.0, net9.0.

Install

dotnet add package SpproApiLogger.Client

Register

builder.Logging.AddSpproApiLogger(o =>
{
    o.BaseUrl     = "https://logs.example.com";
    o.ApiKey      = "spk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
    o.ProjectName = "my-service";
    o.MinimumLevel = LogLevel.Error;
});

Or bind from configuration:

builder.Logging.AddSpproApiLogger(builder.Configuration.GetSection("SpproApiLogger"));
{
  "SpproApiLogger": {
    "BaseUrl":      "https://logs.example.com",
    "ApiKey":       "spk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
    "ProjectName":  "my-service",
    "MinimumLevel": "Error"
  }
}

Behaviour

  • Non-blocking. Log calls write to a bounded in-memory channel and a background worker batches them off the hot path.
  • Crash-safe — globally. From 0.3.1, calling AddSpproApiLogger(...) automatically installs an ILoggerFactory wrapper that catches exceptions from every logging provider (Console, Debug, AppInsights, anything else). A buggy message template like _logger.LogError("{Score:N2}", "abc") will not tear down your process even though every provider's string.Format raises FormatException.
  • Captures structured properties from message templates (logger.LogError("Order {OrderId} failed", id)) and from BeginScope.
  • Captures Exception.GetType().FullName, message, stack trace, and full inner-exception chain.
  • Captures Activity.Current trace/span IDs when present.
  • 3 retries with linear backoff on transient failures; drops the batch on persistent errors and logs the reason via the in-process fallback.
  • Optional file fallback — see FileFallbackPath below. When set, every dropped batch (server unreachable, 4xx, retries exhausted) is appended to a JSON Lines file so nothing is lost when the API is down.

Global crash protection

AddSpproApiLogger(...) automatically calls AddCrashProtection(), which decorates the registered ILoggerFactory. After this:

  • _logger.LogError(...) — and every other ILogger.Log<TState>() call in your app — never throws back to the caller.
  • Provider-level exceptions are still emitted to Debug.WriteLine so they're visible in your IDE/event-tracing while developing.
  • This is intentionally aggressive. If you need provider exceptions to surface for debugging, call AddCrashProtection() only on the loggers you want protected, and avoid the auto-install path.

Options

Option Default Notes
BaseUrl Required. Root URL of your Sppro Api Logger instance.
ApiKey Required. Created on the API keys page.
ProjectName Required. Logs are grouped per project on the server side.
Environment env var Falls back to ASPNETCORE_ENVIRONMENT / DOTNET_ENVIRONMENT.
AppVersion asm ver Falls back to your entry assembly's InformationalVersion.
MinimumLevel Error Lower-severity entries are dropped at the source.
BatchSize 50 Max entries per HTTP request.
FlushIntervalMs 2000 Worker flushes a partial batch after this idle window.
QueueCapacity 10000 Bounded channel; oldest entries are dropped under sustained load.
FileFallbackPath null When set, dropped batches and SDK diagnostics are appended to this file as JSON Lines. Disabled when null.
FileFallbackDailyRolling false When true, the date is injected before the extension (sppro.logsppro-2026-04-30.log).

File fallback

Configure exactly like any other option — through appsettings.json, environment variables, or the lambda overload:

{
  "SpproApiLogger": {
    "BaseUrl":                  "https://logs.example.com",
    "ApiKey":                   "spk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
    "ProjectName":              "my-service",
    "FileFallbackPath":         "C:/logs/sppro-fallback.log",
    "FileFallbackDailyRolling": true
  }
}

Each line in the file is a JSON object: either {"@fallback":"<reason>","@payload":{...}} for a dropped log entry or {"@timestamp":"...","@diagnostic":"..."} for an internal SDK error. The directory is created if missing. File-write failures (disk full, permission denied) are themselves swallowed — the fallback path can never crash the host either.

License

MIT.

Product Compatible and additional computed target framework versions.
.NET net6.0 is compatible.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  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 is compatible.  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. 
.NET Framework net48 is compatible.  net481 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.4.0 87 5/6/2026
0.3.2 92 5/1/2026
0.3.1 94 5/1/2026
0.3.0 87 4/30/2026
0.2.2 89 4/28/2026
0.2.1 88 4/28/2026
0.2.0 86 4/28/2026
0.1.2 100 4/24/2026
0.1.1 86 4/24/2026
0.1.0 99 4/24/2026

0.4.0 - Full diagnostic surface. New options for observability + debugging when the SDK seems to silently fail: (1) OnSent / OnError / OnDropped event hooks let consumers wire SDK lifecycle straight into their existing logging or metrics pipeline — every internal failure surfaces immediately instead of being swallowed. (2) DiagnosticLogPath + DiagnosticLogLevel write a verbose append-only trace of every lifecycle event (init, level filter, enqueue, flush, HTTP attempt + response code + latency, retries, drop reasons) to a file. (3) FlushAsync(TimeSpan timeout) on LogShipper / SpproApiLoggerProvider drains queued events and waits for in-flight batches — makes end-to-end tests deterministic. (4) Synchronous = true bypasses the queue, blocks per Log(), and throws on non-2xx — for smoke tests only. (5) Status property exposes LastSuccessfulSendUtc / LastErrorUtc / LastErrorMessage / CurrentQueueDepth / TotalSent / TotalDropped / TotalEnqueued for dashboards and readiness probes. (6) BootAuthCheck (default on) probes GET /api/logs?take=1 on first send and fires OnError("auth") on 401/403 instead of silently dropping every batch with a bad key. (7) Options.Validate() catches typos at startup; opt in to fail-loud-at-startup with StrictValidation = true. Fully backwards compatible.

0.3.2 - Logging-site stack trace capture. New LoggingSiteStackTraceMinimumLevel option (default Warning) makes the SDK capture and ship a separate stack trace from the call-site of each ILogger.Log(...) call, alongside the exception's own StackTrace. This is the fix for the very common case where exception.StackTrace is null because the exception was constructed but never thrown (e.g. _logger.LogError(new InvalidOperationException("..."), ...)). The capture filters out logging-infrastructure frames so user code is on top, is wrapped in the same crash-safe envelope as the rest of the SDK, and adds a single new optional field (LoggingSiteStackTrace) to the wire format. Fully backwards compatible. Set LoggingSiteStackTraceMinimumLevel = LogLevel.None to disable.

0.3.1 - Global crash protection. AddSpproApiLogger now also wraps the host's ILoggerFactory so calls like _logger.LogError("{Score:N2}", "abc") cannot crash the host even when OTHER providers (Console, Debug, AppInsights) raise FormatException - the framework's AggregateException("An error occurred while writing to logger(s).") is swallowed before it can escape. Opt out by NOT calling AddSpproApiLogger, or call AddCrashProtection() on its own to install only the wrapper without the SDK provider.

0.3.0 - Crash-safety hardening: every entry point in the SDK is now wrapped so a logging call can never tear down the host process (fixes FormatException escapes from message templates like "{Value:F2}" with non-numeric args). New optional FileFallbackPath / FileFallbackDailyRolling options append dropped batches and SDK diagnostics to a JSON Lines file when the API is unreachable. Inner-exception serialization is now depth-capped at 10. Fully backwards compatible - no API or config changes required for existing consumers.