LogDuck 3.0.0
dotnet add package LogDuck --version 3.0.0
NuGet\Install-Package LogDuck -Version 3.0.0
<PackageReference Include="LogDuck" Version="3.0.0" />
<PackageVersion Include="LogDuck" Version="3.0.0" />
<PackageReference Include="LogDuck" />
paket add LogDuck --version 3.0.0
#r "nuget: LogDuck, 3.0.0"
#:package LogDuck@3.0.0
#addin nuget:?package=LogDuck&version=3.0.0
#tool nuget:?package=LogDuck&version=3.0.0
LogDuck .NET SDK
Official .NET SDK for LogDuck - an event logging and notification service for developers.
Supports .NET 8, .NET 9, and .NET 10.
Installation
dotnet add package LogDuck
Create an API key in your project settings — see Authentication.
Setup
Option 1: Configuration File (Recommended)
Add to appsettings.json:
{
"LogDuck": {
"ApiKey": "ld_your_api_key",
"Source": "my-backend-service"
}
}
Register in Program.cs:
builder.Services.AddLogDuck(builder.Configuration);
Option 2: Programmatic Configuration
builder.Services.AddLogDuck(options =>
{
options.ApiKey = builder.Configuration["LogDuck:ApiKey"]!;
options.Source = "order-service";
});
Usage
Inject ILogDuckClient and send events:
public class OrderService
{
private readonly ILogDuckClient _logDuck;
public OrderService(ILogDuckClient logDuck)
{
_logDuck = logDuck;
}
public async Task ProcessOrder(Order order)
{
await _logDuck.SendEventAsync(new LogDuckEvent
{
Type = "order.completed",
Subject = $"order_{order.Id}",
Message = $"Order #{order.Id} completed",
Data = new Dictionary<string, object?>
{
["orderId"] = order.Id,
["amount"] = order.Total
}
});
}
}
Configuration Options
| Option | Type | Default | Description |
|---|---|---|---|
ApiKey |
string | "" |
Your LogDuck API key (required, must start with ld_) |
Source |
string | "" |
Identifies your app/service (required, max 200 chars) |
ThrowOnError |
bool | false |
When true, throws LogDuckException on errors |
RetryEnabled |
bool | true |
Retries once on transient errors (5xx, network failures, 429) |
MaxRetryDelay |
TimeSpan | 10s | Longest the client will wait before retrying a rate-limited (429) request |
Timeout |
TimeSpan | 30s | HTTP request timeout |
Retry Behavior
| Response | Behaviour |
|---|---|
| 5xx, network failure, timeout | Retried once after 1 second |
| 429 | Retried once after the server's Retry-After, but only if that fits inside MaxRetryDelay |
| Any other 4xx | Never retried — it will fail identically the second time |
The server rate-limits each API key in fixed one-minute windows, so Retry-After can be as much as 60 seconds. Blocking your caller that long is rarely acceptable, so beyond MaxRetryDelay the client gives up immediately and puts the remaining wait on LogDuckException.RetryAfter, letting you queue the event instead of losing it.
Each request includes an Idempotency-Key header (auto-generated UUID). The same key is sent on retries so the server can deduplicate. This header is required — if you're using the HTTP API directly, you must set it yourself. The value can be any string matching ^[a-zA-Z0-9_-]{16,36}$ (e.g. UUID v4, nanoid). We recommend UUID v4:
POST /v1/events
X-API-Key: ld_your_api_key
Idempotency-Key: your-unique-request-id
Disable retries if needed:
builder.Services.AddLogDuck(options =>
{
options.ApiKey = "ld_your_api_key";
options.Source = "my-service";
options.RetryEnabled = false;
});
Error Handling
By default, errors are logged and methods return null. Enable ThrowOnError to catch exceptions:
builder.Services.AddLogDuck(options =>
{
options.ApiKey = "ld_your_api_key";
options.Source = "my-service";
options.ThrowOnError = true;
});
// _logDuck is the injected ILogDuckClient — see Usage above.
try
{
await _logDuck.SendEventAsync(new LogDuckEvent { Type = "order.completed" });
}
catch (LogDuckException ex)
{
if (ex.RetryAfter is { } retryAfter)
{
// Rate limited for longer than the client will wait.
// Queue it rather than lose it — this queue is yours, not the SDK's.
_pendingEvents.Enqueue((eventToSend, DateTimeOffset.UtcNow + retryAfter));
}
Console.WriteLine($"Status: {ex.StatusCode}, Body: {ex.ResponseBody}");
}
Validation
The SDK validates events before sending:
| Field | Constraint |
|---|---|
Type |
Required, max 100 characters |
Source (from config) |
Required, max 200 characters |
Subject |
Max 500 characters |
SessionId |
Max 256 characters |
Message |
Max 500 characters |
Emoji |
Max 10 characters |
Use ValidateConfiguration() to check your setup at startup:
var logDuck = serviceProvider.GetRequiredService<ILogDuckClient>();
if (!logDuck.ValidateConfiguration())
{
// Handle misconfiguration
}
Wire names. The event is a CloudEvents 1.0 document, and a CloudEvents
extension attribute name must be lowercase alphanumeric. SessionId is
therefore sent as sessionid. Every other property maps to its own lowercase
name. You only need this if you are comparing against the raw HTTP API.
Message is what a push notification shows. Without it the notification
body falls back to listing the first few Data keys, which reads like
orderId: 1234, amount: 4999 rather than "Order #1234 completed".
Naming Type: the server lowercases it and requires ^[a-z][a-z0-9_.]*$ — letters, digits, _ and ., starting with a letter. So order.placed and user.signup_completed are fine; order-placed is rejected with a 400. Dots are the conventional separator.
Using the API without the SDK
The SDK is a convenience, not a requirement — POST /v1/events is a plain JSON endpoint over HTTPS, usable from any language or from curl:
curl -X POST https://api.logduck.com/v1/events \
-H "X-API-Key: ld_your_api_key" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{"type":"order.completed","source":"my-service","subject":"Order #1234"}'
Full request and response reference: logduck.com/docs#api-reference.
Going direct means you take on what the SDK handles: generating a valid Idempotency-Key per event and reusing it across retries, honouring Retry-After on a 429, and deciding which failures are worth retrying.
Development
dotnet build
dotnet test
dotnet pack -c Release
Releases are published by CI. Bump <Version> in LogDuck/LogDuck.csproj,
commit, then tag that commit:
git tag v2.1.0 && git push origin v2.1.0
publish.yml refuses the release if the tag and the csproj disagree, or if that
version is already on nuget.org — NuGet versions can be unlisted but never
replaced, so a mistake there is permanent.
License
MIT
| Product | Versions 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 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 is compatible. 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. |
-
net10.0
- Microsoft.Extensions.Http (>= 8.0.0)
- Microsoft.Extensions.Logging.Abstractions (>= 8.0.0)
- Microsoft.Extensions.Options (>= 8.0.0)
-
net8.0
- Microsoft.Extensions.Http (>= 8.0.0)
- Microsoft.Extensions.Logging.Abstractions (>= 8.0.0)
- Microsoft.Extensions.Options (>= 8.0.0)
-
net9.0
- Microsoft.Extensions.Http (>= 8.0.0)
- Microsoft.Extensions.Logging.Abstractions (>= 8.0.0)
- Microsoft.Extensions.Options (>= 8.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.