Logister.AspNetCore 0.4.0

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

logister-dotnet

.NET SDK for sending errors, logs, metrics, transactions, spans, and scheduled-job check-ins to Logister.

This repo contains two packages:

  • Logister: the base client for services, workers, console apps, and custom integrations.
  • Logister.AspNetCore: dependency injection plus exception and request-timing middleware for ASP.NET Core.

Both packages target .NET 8 and .NET 10. .NET 9 applications can consume the .NET 8 target.

Quick start

Create a project in Logister and generate a project API key under Project settings → API keys, then install the base package:

dotnet add package Logister

Keep the key in your secret store or environment, not in source control:

export LOGISTER_API_KEY="<project-api-key>"
export LOGISTER_BASE_URL="https://logister.example.com"
export LOGISTER_ENVIRONMENT="development"

Send a test event from an async entry point:

using Logister;

using var client = new LogisterClient(LogisterOptions.FromEnvironment());

await client.CaptureExceptionAsync(
    new InvalidOperationException("README test error"),
    new CaptureOptions
    {
        Fingerprint = "readme-test-error",
        Context = new Dictionary<string, object?>
        {
            ["component"] = "checkout"
        }
    });

Open the project inbox and confirm that README test error appears. A 401 response usually means the API key or base URL is wrong; use the .NET integration guide for the complete setup and troubleshooting path.

Which package should I install?

App type Package
Worker, console app, service, or custom framework Logister
ASP.NET Core app that needs automatic request and exception capture Logister.AspNetCore (which depends on Logister)

The base package uses the built-in HttpClient and System.Text.Json; it does not add a third-party HTTP, logging, or retry stack to your application.

Install

dotnet add package Logister
dotnet add package Logister.AspNetCore

For local development, forks, or unreleased SDK changes, reference the projects locally:

<ProjectReference Include="../logister-dotnet/src/Logister/Logister.csproj" />
<ProjectReference Include="../logister-dotnet/src/Logister.AspNetCore/Logister.AspNetCore.csproj" />

Connect to Logister

In the Logister web app:

  1. Create or open a project.
  2. Set the integration type to .NET / ASP.NET Core.
  3. Generate a project API key from project settings.
  4. Configure your .NET app with that API key and your Logister base URL.

Project Insights guide: https://logister.org/docs/product/#insights

Do not commit real API keys to this repo or your application repo. Use environment variables, .NET user secrets, your hosting provider's secret store, or another deployment secret manager.

ASP.NET Core

Add configuration:

{
  "Logister": {
    "ApiKey": "your-project-api-token",
    "BaseUrl": "https://your-logister-host.example",
    "Environment": "production",
    "Release": "checkout@2026.04.30",
    "CaptureRequestTransactions": true,
    "CaptureRequestSpans": true,
    "CaptureRequestHeaders": true,
    "CaptureRequestCookies": false
  }
}

For local development, prefer user secrets or environment variables for the real token:

dotnet user-secrets set "Logister:ApiKey" "your-project-api-token"
dotnet user-secrets set "Logister:BaseUrl" "https://your-logister-host.example"

Wire it into Program.cs:

using Logister.AspNetCore;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddLogister(builder.Configuration, options =>
{
    options.Client.DefaultContext["service"] = "checkout-web";
    options.CaptureRequestCookies = true;
    options.SensitiveRequestCookieNames.Add("checkout_auth");
});

var app = builder.Build();

app.UseLogisterExceptionReporting();
app.UseLogisterRequestTransactions();

app.Run();

Cookie capture is disabled by default because cookie values often contain authentication or session material. When enabled, common ASP.NET Core auth and session cookie names are redacted automatically. Add application-specific cookie names to SensitiveRequestCookieNames when you want the cookie name to appear in Logister without storing its value.

Direct client

using Logister;

var client = new LogisterClient(new LogisterOptions
{
    ApiKey = Environment.GetEnvironmentVariable("LOGISTER_API_KEY"),
    BaseUrl = new Uri("https://your-logister-host.example"),
    Environment = "production",
    Release = "worker@2026.04.30"
});

try
{
    RunImport();
}
catch (Exception exception)
{
    await client.CaptureExceptionAsync(exception, new CaptureOptions
    {
        Context = new Dictionary<string, object?>
        {
            ["job"] = "nightly-import"
        }
    });
}

await client.CaptureMetricAsync("timesheet.approvals.pending", 7, new MetricOptions
{
    Unit = "count"
});

await client.CaptureSpanAsync("render checkout", 82.1, new SpanOptions
{
    Kind = "render",
    Status = "ok",
    TraceId = "trace-123",
    ParentSpanId = "span-root",
    Context = new Dictionary<string, object?>
    {
        ["route"] = "POST /checkout"
    }
});

await client.CheckInAsync("nightly-import", "ok", new CheckInOptions
{
    Release = "worker@2026.04.30",
    DurationMs = 122.5,
    ExpectedIntervalSeconds = 3600,
    TraceId = "trace-123",
    RequestId = "req-123"
});

CaptureOptions supports per-event Environment, Release, TraceId, RequestId, SessionId, and UserId for errors, logs, metrics, and transactions. MetricOptions adds Unit; SpanOptions adds SpanId, ParentSpanId, Kind, Status, StartedAt, and EndedAt; and CheckInOptions supports Release, DurationMs, ExpectedIntervalSeconds, TraceId, and RequestId so monitor records line up with the Logister API.

Using project Insights

The Logister project Insights tab combines Inbox, Activity, and Performance data into live dashboard views. .NET services get the most useful Insights view when they send consistent Environment, Release, and stable top-level context attributes.

Set deployment context once through configuration or environment variables, then attach low-cardinality dimensions to metrics, transactions, logs, and check-ins:

using Logister;

var options = LogisterOptions.FromEnvironment();
options.DefaultContext["service"] = "billing-api";
options.DefaultContext["region"] = "us-east-1";

using var client = new LogisterClient(options);

await client.CaptureMetricAsync("queue.depth", 42, new MetricOptions
{
    Unit = "jobs",
    Context = new Dictionary<string, object?>
    {
        ["service"] = "billing-worker",
        ["queue"] = "billing",
        ["tenant_tier"] = "enterprise"
    }
});

await client.CaptureTransactionAsync("POST /checkout", 182.4, new CaptureOptions
{
    RequestId = "req_123",
    Context = new Dictionary<string, object?>
    {
        ["route"] = "POST /checkout",
        ["feature_flag"] = "new_checkout",
        ["tenant_tier"] = "enterprise"
    }
});

await client.CaptureSpanAsync("render checkout", 82.1, new SpanOptions
{
    Kind = "render",
    Status = "ok",
    TraceId = "trace_123",
    ParentSpanId = "span_root",
    Context = new Dictionary<string, object?>
    {
        ["route"] = "POST /checkout"
    }
});

await client.CaptureMessageAsync("payment provider retry", new CaptureOptions
{
    Level = "warn",
    Context = new Dictionary<string, object?>
    {
        ["service"] = "billing-worker",
        ["provider"] = "stripe",
        ["queue"] = "billing"
    }
});

await client.CheckInAsync("nightly-reconcile", "ok", new CheckInOptions
{
    ExpectedIntervalSeconds = 3600,
    DurationMs = 842.7,
    Context = new Dictionary<string, object?>
    {
        ["service"] = "billing-worker",
        ["queue"] = "reconcile"
    }
});

Practical Insights recipes:

  • Release validation: set LOGISTER_RELEASE or Logister:Release, then filter Insights to the new release and compare error count, transaction P95, and custom metrics.
  • Queue monitoring: report metrics such as queue.depth, queue.latency, jobs.retry_count, and worker.active_jobs with stable queue and service context keys.
  • ASP.NET Core performance triage: enable CaptureRequestSpans to feed request load waterfall charts, then add matching route, tenant_tier, or feature_flag context to custom logs and metrics.
  • Instrumentation audit: open Insights after deploy and confirm errors, logs, metrics, transactions, spans, and check-ins all appear in the recent stream.

Keep custom attributes stable and low-cardinality. Good top-level context keys include service, region, queue, route, tenant_tier, provider, and feature_flag. Avoid raw IDs, emails, request bodies, SQL text, and per-user values as Insights dimensions.

GitHub source context and deployments

When a Logister project is connected to a GitHub repository, set source context once so events can resolve stack frames to the exact deployed code:

var options = LogisterOptions.FromEnvironment();
options.Repository = "acme/checkout";
options.CommitSha = "4f8c2d1a9b7e6c5d4a3b2c1d0e9f8a7b6c5d4e3f";
options.Branch = "main";

using var client = new LogisterClient(options);

ASP.NET Core apps can also use Logister:Repository, Logister:CommitSha, and Logister:Branch configuration keys. LogisterOptions.FromEnvironment() reads LOGISTER_REPOSITORY, LOGISTER_COMMIT_SHA, and LOGISTER_BRANCH, falling back to GitHub Actions variables when present.

CI/CD can record the release-to-commit mapping directly:

await client.RecordDeploymentAsync(new DeploymentOptions
{
    Release = "checkout@2026.06.18",
    Environment = "production",
    Repository = "acme/checkout",
    CommitSha = "4f8c2d1a9b7e6c5d4a3b2c1d0e9f8a7b6c5d4e3f",
    Branch = "main",
    WorkflowRunUrl = "https://github.com/acme/checkout/actions/runs/123"
});

Environment variables

The base client can be created from environment variables:

var client = new LogisterClient(LogisterOptions.FromEnvironment());

Supported variables:

  • LOGISTER_API_KEY
  • LOGISTER_BASE_URL
  • LOGISTER_ENVIRONMENT
  • LOGISTER_RELEASE
  • LOGISTER_REPOSITORY
  • LOGISTER_COMMIT_SHA
  • LOGISTER_BRANCH
  • LOGISTER_TIMEOUT

Development

dotnet restore Logister.sln
dotnet list Logister.sln package --vulnerable --include-transitive --no-restore
dotnet build Logister.sln --configuration Release --no-restore
dotnet run --project tests/Logister.Tests/Logister.Tests.csproj --framework net8.0 --configuration Release --no-restore
dotnet run --project tests/Logister.Tests/Logister.Tests.csproj --framework net10.0 --configuration Release --no-restore

Publishing

Pull requests and pushes to main restore, audit, build, test, and pack both target frameworks. After CI passes on main, the release-from-main workflow creates the matching vX.Y.Z tag. The tag workflow publishes both NuGet packages before creating the GitHub Release.

Repository setup:

  • Add a GitHub Actions secret named NUGET_API_KEY with permission to publish the Logister and Logister.AspNetCore packages.
  • The NuGet package IDs are Logister and Logister.AspNetCore.
  • The release workflow configuration lives at config/release.yml.

Release process:

  1. Bump the <Version> value in both package project files to the next NuGet version.
  2. Add a matching CHANGELOG.md section named ## vX.Y.Z - YYYY-MM-DD.
  3. Merge the change to main and let the release-from-main workflow create and dispatch the matching tag, or create the tag manually:
git tag vX.Y.Z
git push origin vX.Y.Z

The release workflow verifies that the tag matches both .csproj package versions, audits and tests both frameworks, packs both packages, publishes missing NuGet packages, and then uses the matching changelog section as the GitHub release notes. NuGet versions are immutable; if either package has been published, make corrections in a new patch version.

Verify both package IDs and the GitHub Release before calling a release complete:

curl -fsSL https://api.nuget.org/v3-flatcontainer/logister/index.json
curl -fsSL https://api.nuget.org/v3-flatcontainer/logister.aspnetcore/index.json
gh release view vX.Y.Z

Coordinated release preparation

For a coordinated ecosystem release, keep the version-changing PR unmerged until the final agreed Rails PR has been published and its deployment verified. Recheck the upstream contract/workflow pin against that final backend commit before merge. Successful source CI, a tag, or a release-impact dispatch alone is not backend readiness. After independent review, merging the new version runs CI, creates an immutable tag, and explicitly dispatches publication. A tag without a package remains incomplete.

To recover an existing reviewed tag, dispatch the publisher workflow from main with -f tag=vX.Y.Z (Python uses publish.yml; other SDKs use release.yml). The workflow checks out that exact tag, proves it belongs to main, and verifies public package identity before creating the GitHub Release. Never move a consumed tag.

Weekly CI audits/tests current dependencies and cannot trigger automatic publication. Dependabot groups compatible minor/patch updates; major toolchain migrations keep separate PRs. Pin Actions to full commits and retain supported runtime floors.

Reliable event delivery

var prepared = client.PrepareEvent("log", "info", "Job started");
await client.SendPreparedEventAsync(prepared, cancellationToken);
var results = await client.SendEventsAsync(new[] { prepared }, cancellationToken);
foreach (var result in results)
    if (result.Error is not null) Console.WriteLine($"{result.EventId}: {result.Error.GetType().Name}");

Prepared events retain serialized context, UUID and capture time across retries and explicit replay. Ingestion retries transient network/HTTP failures up to three times; LogisterOptions.RetryPolicy controls the attempt limit, capped Retry-After/backoff, and the default 15-second total deadline. One batch call shares that deadline across all chunks, splits and fallback. maximumAttempts: 1 disables retries.

Batches accept at most 1,000 prepared events and send at most 100 per request. Each result identifies an accepted or failed/unsent event. Cancellation interrupts the call and propagates; retain the prepared input to safely replay after cancellation. Acceptance does not mean projection has completed. Dedicated check-ins and deployment writes retain their single-request behavior.

NuGet.org adds a repository signature; .NET 10's packer also generates opaque core-properties IDs. Release verification authenticates the downloaded signature, compares every package content byte, and normalizes only those generated metadata IDs. DLLs, nuspecs, README and complete core-property values must match. A different compiler/build output fails verification and requires recovery with the original build environment or a new version; it is never silently accepted as equivalent.

Request correlation (0.4.0+)

ASP.NET Core middleware reuses the current W3C Activity and creates a fallback request activity only when needed. Automatic and manual captures share the server span, request ID, and incoming parent. LogisterTraceContext.Current returns an immutable snapshot that can be retained across awaits.

For transports without native Activity propagation, use a child handle:

var trace = LogisterTraceContext.Current?.Child();
var destination = new Uri("https://api.example.test/orders");
if (trace is not null)
{
    var headers = trace.HeadersFor(destination, new[] { new Uri("https://api.example.test") });
    // Apply to this request only; disable automatic redirects.
    // Supply trace.Fields() as capture context if reporting its failure later.
}

Native HttpClient/Activity instrumentation remains the owner of its outbound spans. Do not layer manual header injection over a native instrumented client. The helper validates an exact origin; recheck each redirect, and exclude telemetry and token endpoints. It does not configure native HttpClient propagation policy.

A linked-project lookup also requires Logister 3.7+, the instance flag LOGISTER_CROSS_PROJECT_CORRELATIONS=true, and explicit project/environment connections under Settings → Integrations → Connected projects. Enable related requests on both projects. A connection never grants project access.

Use the returned request handle when reporting a handled HTTP failure later. Do not attach the most recent request to an unrelated crash or OS diagnostic. Configure each app's own release and environment; mobile and backend releases are independent. The backend shows exact identifier evidence and retention gaps. See the request correlation guide.

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 was computed.  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
0.4.0 99 9/24/2026
0.3.0 102 9/11/2026
0.2.0 212 7/25/2026
0.1.5 190 6/18/2026
0.1.4 190 5/22/2026
0.1.3 121 5/22/2026
0.1.1 367 5/1/2026
0.1.0 160 4/30/2026