SpproApiLogger.Client
0.4.0
dotnet add package SpproApiLogger.Client --version 0.4.0
NuGet\Install-Package SpproApiLogger.Client -Version 0.4.0
<PackageReference Include="SpproApiLogger.Client" Version="0.4.0" />
<PackageVersion Include="SpproApiLogger.Client" Version="0.4.0" />
<PackageReference Include="SpproApiLogger.Client" />
paket add SpproApiLogger.Client --version 0.4.0
#r "nuget: SpproApiLogger.Client, 0.4.0"
#:package SpproApiLogger.Client@0.4.0
#addin nuget:?package=SpproApiLogger.Client&version=0.4.0
#tool nuget:?package=SpproApiLogger.Client&version=0.4.0
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, callingAddSpproApiLogger(...)automatically installs anILoggerFactorywrapper 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'sstring.FormatraisesFormatException. - Captures structured properties from message templates (
logger.LogError("Order {OrderId} failed", id)) and fromBeginScope. - Captures
Exception.GetType().FullName, message, stack trace, and full inner-exception chain. - Captures
Activity.Currenttrace/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
FileFallbackPathbelow. 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 otherILogger.Log<TState>()call in your app — never throws back to the caller.- Provider-level exceptions are still emitted to
Debug.WriteLineso 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.log → sppro-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 | Versions 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. |
-
.NETFramework 4.8
- Microsoft.Extensions.Http (>= 8.0.0)
- Microsoft.Extensions.Logging.Configuration (>= 8.0.0)
- System.Diagnostics.DiagnosticSource (>= 8.0.1)
- System.Net.Http.Json (>= 8.0.0)
- System.Text.Json (>= 8.0.5)
- System.Threading.Channels (>= 8.0.0)
-
net6.0
- Microsoft.Extensions.Http (>= 6.0.0)
- Microsoft.Extensions.Logging.Configuration (>= 6.0.0)
-
net8.0
- Microsoft.Extensions.Http (>= 8.0.0)
- Microsoft.Extensions.Logging.Configuration (>= 8.0.0)
-
net9.0
- Microsoft.Extensions.Http (>= 9.0.0)
- Microsoft.Extensions.Logging.Configuration (>= 9.0.0)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
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.