LogDuck 3.0.0

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

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

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 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. 
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
3.0.0 116 8/4/2026
2.0.1 119 8/2/2026
2.0.0 130 2/15/2026
1.0.0 228 2/2/2026