Logister.AspNetCore
0.4.0
dotnet add package Logister.AspNetCore --version 0.4.0
NuGet\Install-Package Logister.AspNetCore -Version 0.4.0
<PackageReference Include="Logister.AspNetCore" Version="0.4.0" />
<PackageVersion Include="Logister.AspNetCore" Version="0.4.0" />
<PackageReference Include="Logister.AspNetCore" />
paket add Logister.AspNetCore --version 0.4.0
#r "nuget: Logister.AspNetCore, 0.4.0"
#:package Logister.AspNetCore@0.4.0
#addin nuget:?package=Logister.AspNetCore&version=0.4.0
#tool nuget:?package=Logister.AspNetCore&version=0.4.0
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.
Package Links
- NuGet
Logister: https://www.nuget.org/packages/Logister - NuGet
Logister.AspNetCore: https://www.nuget.org/packages/Logister.AspNetCore - GitHub releases: https://github.com/taimoorq/logister-dotnet/releases
- Source repository: https://github.com/taimoorq/logister-dotnet
- Integration docs: https://logister.org/docs/integrations/dotnet/
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:
- Create or open a project.
- Set the integration type to
.NET / ASP.NET Core. - Generate a project API key from project settings.
- 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_RELEASEorLogister: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, andworker.active_jobswith stablequeueandservicecontext keys. - ASP.NET Core performance triage: enable
CaptureRequestSpansto feed request load waterfall charts, then add matchingroute,tenant_tier, orfeature_flagcontext 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_KEYLOGISTER_BASE_URLLOGISTER_ENVIRONMENTLOGISTER_RELEASELOGISTER_REPOSITORYLOGISTER_COMMIT_SHALOGISTER_BRANCHLOGISTER_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_KEYwith permission to publish theLogisterandLogister.AspNetCorepackages. - The NuGet package IDs are
LogisterandLogister.AspNetCore. - The release workflow configuration lives at
config/release.yml.
Release process:
- Bump the
<Version>value in both package project files to the next NuGet version. - Add a matching
CHANGELOG.mdsection named## vX.Y.Z - YYYY-MM-DD. - Merge the change to
mainand 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 | 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 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. |
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.