Before you start
Create the project with the .NET / ASP.NET Core integration type.
| What you need | Why it matters |
|---|---|
| Project API token | Authenticates the app when sending events |
| Logister instance base URL | Required. The SDK has no default host and builds the ingest, check-in, and deployment endpoints from this value. See Base URL. |
| .NET 8+ app | Both packages target .NET 8 and .NET 10; .NET 9 apps use the .NET 8 target |
| Optional GitHub App installation | Lets Logister use Repository, CommitSha, Branch, and deployment records for source excerpts and deploy links |
Upgrading an existing app to 0.5.0
0.5.0 has breaking changes: BaseUrl is required, http:// needs AllowInsecureHttp outside loopback, and ASP.NET Core events are sent from a background queue. Read Upgrading to 0.5.0 before you update the package.
What you get
Use the .NET integration to make ASP.NET Core failures and deploys easier to act on.
| Need | What appears in Logister |
|---|---|
| Catch uncaught request exceptions | Issues with .NET exception details, stack frames, request URL, request ID, trace ID, user ID, framework metadata, and runtime metadata. |
| Understand failed ASP.NET requests | A .NET-focused detail view with stack, query, optional cookies, headers, routing, runtime, inner exceptions, and exception data when captured. |
| Track request latency | Request transaction events and optional request spans that power project performance and request load waterfall charts. |
| Monitor workers and business signals | Metrics, logs, custom transactions, spans, and check-ins from injected LogisterClient calls. |
| Resolve source and deploy history | Repository, CommitSha, Branch, release, and deployment records that let Logister show source excerpts, GitHub links, and "started after deploy" context when a GitHub repository is connected to the project. |
| Connect traces and logs | Release, request ID, trace ID, session ID, and user ID context that helps Logister show release health and related logs. |
Install
Install the base client or ASP.NET Core package from NuGet.
Use the published NuGet packages when you want a .NET service to send errors, logs, metrics, transactions, spans, and check-ins into Logister. The NuGet listings are the canonical package pages for install commands, version history, and package metadata.
dotnet add package Logister
dotnet add package Logister.AspNetCorePackage links: NuGet Logister, NuGet Logister.AspNetCore, and GitHub. For local development, forks, or unreleased SDK changes, reference the project from that repo directly.
<ProjectReference Include="../logister-dotnet/src/Logister/Logister.csproj" />
<ProjectReference Include="../logister-dotnet/src/Logister.AspNetCore/Logister.AspNetCore.csproj" />Base URL
Point the SDK at your Logister instance before the first event.
BaseUrl is required and has no default. Set it to the root URL of the Logister instance that owns the project: your self-hosted host, or https://logister.org if the project lives in the hosted app. Set it in one of three places:
| Where | Setting | Read by |
|---|---|---|
| Environment | LOGISTER_BASE_URL | LogisterOptions.FromEnvironment() |
| appsettings, user secrets, or any ASP.NET Core configuration source | Logister:BaseUrl | AddLogister(builder.Configuration) |
| Code | BaseUrl = new Uri("https://your-logister-host.example") | LogisterOptions (options.Client in ASP.NET Core) |
Keep the API 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"For ASP.NET Core local development, user secrets work the same way:
dotnet user-secrets set "Logister:ApiKey" "your-project-api-token"
dotnet user-secrets set "Logister:BaseUrl" "https://your-logister-host.example"The SDK checks the value at startup:
- It must be an absolute URL. A missing or invalid value throws
LogisterConfigurationException. The base client throws when it is created. In ASP.NET Core, an invalidLogister:BaseUrlthrows fromAddLogisterand a missing one throws when the host starts. - It must use
https://, unless the host is loopback (localhost,127.0.0.1,::1) or you setAllowInsecureHttp = true(LOGISTER_ALLOW_INSECURE_HTTP=true). UseAllowInsecureHttponly for trusted internal networks. - It must not contain a user name or password. Send the project API key through
ApiKeyinstead.
// Plain HTTP to a non-loopback host on a trusted internal network.
builder.Services.AddLogister(builder.Configuration, options =>
{
options.Client.AllowInsecureHttp = true;
});Send one test event to prove the key and base URL work:
using Logister;
using var client = new LogisterClient(LogisterOptions.FromEnvironment());
await client.CaptureExceptionAsync(
new InvalidOperationException(".NET test error"),
new CaptureOptions
{
Fingerprint = "dotnet-test-error",
Context = new Dictionary<string, object?>
{
["component"] = "checkout"
}
});Verify it
Open the project inbox and confirm that .NET test error appears. A LogisterConfigurationException means the base URL is missing, invalid, or uses http:// without AllowInsecureHttp. A 401 response usually means the API key or base URL is wrong.
ASP.NET Core
Capture uncaught exceptions and optional request transactions.
using Logister.AspNetCore;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddLogister(builder.Configuration, options =>
{
options.Client.DefaultContext["service"] = "quriatime-web";
options.Client.Repository = "acme/timesheets";
options.Client.CommitSha = Environment.GetEnvironmentVariable("GITHUB_SHA");
options.Client.Branch = Environment.GetEnvironmentVariable("GITHUB_REF_NAME");
options.CaptureRequestSpans = true;
});
var app = builder.Build();
app.UseLogisterExceptionReporting();
app.UseLogisterRequestTransactions();
app.Run();Logister:BaseUrl must be set in configuration or in the AddLogister callback; see Base URL. The exception middleware captures structured .NET exception details, stack frames when available, inner exceptions, Exception.Data, request URL, request ID, trace ID, user ID, framework metadata, and runtime metadata, after redaction. Request transactions record total request duration; request spans add the root server timing used by request load waterfall charts.
Background delivery
The middleware never waits for Logister. Each exception, transaction, or span is prepared on the request thread and placed on a bounded in-memory LogisterEventQueue. The hosted LogisterDeliveryService sends queued events in batches of up to 100 through SendEventsAsync. AddLogister registers both the queue and the delivery service.
| Option | Default | What it does |
|---|---|---|
QueueCapacity | 1,000 | Maximum queued events. When the queue is full, new events are dropped and counted in LogisterEventQueue.DroppedCount. |
ShutdownFlushTimeout | 5 seconds | How long the delivery service keeps sending queued events when the host stops. |
TransactionSampleRate | 1 | Fraction (0–1) of requests whose transaction and span are reported. Exceptions are always reported. |
Capture and delivery failures are logged at debug level and never replace your application's exception or response. If you construct LogisterExceptionMiddleware or LogisterRequestTransactionMiddleware yourself, pass a LogisterEventQueue to the constructor.
Verify it
Throw a test exception from one endpoint and confirm it appears in the project inbox. Delivery is asynchronous, so allow a moment for the batch to send. If events stop appearing under load, check LogisterEventQueue.DroppedCount and raise QueueCapacity. If only some requests show transactions, check TransactionSampleRate.
Privacy and redaction
Captured data is redacted before it leaves your process.
The SDK applies the same default redaction rules as the other Logister SDKs. You do not need to enable it.
- Sensitive keys. A key is sensitive when, after lowercasing and removing every non-alphanumeric character, it equals one of
password,passwd,pwd,secret,token,apikey,authorization,proxyauthorization,cookie,setcookie,sessiontoken,sessionkey,credential,credentials,privatekey,clientsecret,accesstoken,refreshtoken,idtoken,authtoken,xapikey,xauthtoken,xaccesstoken,xcsrftoken,xxsrftoken,signature,ssn,creditcard,cardnumber, orcvv, or containstoken,secret,password,passwd,apikey,authorization,credential, orcookie. Its value becomes[REDACTED]. - Sensitive values. Strings are scrubbed for
Bearer …andBasic …credentials, JWT-shaped tokens,lgst_…keys, and passwords in URLs (scheme://user:[REDACTED]@host). - URLs and query strings. Captured URLs, query strings, and referers keep scheme, host, and path, drop the fragment, and redact sensitive query parameter values, for example
/callback?state=1&access_token=[REDACTED]. - Where it applies. Context and
DefaultContext, the event message, exception messages,Exception.Data, request URL, path, query string, route values, headers, and cookies. The SDK's own identifiers (uuid,trace_id,span_id,parent_span_id,request_id,session_id) are never rewritten.
Add your own keys with LogisterOptions.RedactKeys, the Logister:RedactKeys setting (array or comma-separated string), or LOGISTER_REDACT_KEYS. Entries are normalized the same way and must match exactly. Configure them before the client is created. The default list does not include generic names such as OAuth code or Azure SAS sig; add them if your URLs carry such values:
var options = LogisterOptions.FromEnvironment();
options.RedactKeys.Add("code");
options.RedactKeys.Add("sig");The same rules are available as the public LogisterValueSanitizer class for custom integrations that build their own payloads.
Request headers and cookies
| Option | Behavior |
|---|---|
CaptureRequestHeaders | Records header values. A header's value becomes [REDACTED] when its name matches the shared rule (for example Authorization, Cookie, X-Api-Key, X-CSRF-Token), is a platform credential header (x-functions-key, x-ms-client-principal*, x-ms-token-*, x-goog-iap-jwt-assertion, cf-access-jwt-assertion, x-amzn-oidc-*, webhook signature headers), or is listed in SensitiveRequestHeaderNames. |
SensitiveRequestHeaderNames | Extra header names whose values are redacted. |
CaptureRequestCookies | Off by default. When enabled, records cookie names. Every value is redacted unless the name is in AllowedRequestCookieNames. |
AllowedRequestCookieNames | Cookie names whose values are recorded. .AspNetCore.* and their chunks (.AspNetCore.CookiesC1, C2, …), __Host-*, __Secure-*, XSRF-TOKEN, names matching the shared rule, and names in SensitiveRequestCookieNames (including their chunks) stay redacted even when listed here. |
SensitiveRequestCookieNames | Cookie names that always stay redacted, including their chunks. Add your own authentication cookie names here. |
RedactedCookieValue | Replacement text for redacted cookie values. Defaults to [REDACTED]. |
builder.Services.AddLogister(builder.Configuration, options =>
{
options.CaptureRequestCookies = true;
options.AllowedRequestCookieNames.Add("theme");
options.SensitiveRequestCookieNames.Add("checkout_auth");
options.SensitiveRequestHeaderNames.Add("X-Tenant-Signature");
});Opt-in identity fields
| Option | Default | When enabled |
|---|---|---|
CaptureClientIp (Logister:CaptureClientIp) | false | Captures client_ip and forwarding headers such as X-Forwarded-For, Forwarded, X-Real-IP, and CF-Connecting-IP. |
LogisterOptions.CaptureHostIdentity (Logister:CaptureHostIdentity) | false | Sends machine_name and process_id. |
CaptureExceptionData | true | Sends Exception.Data. Set it to false to omit it entirely. |
Captured values are also bounded: nesting deeper than 12 levels becomes [MaxDepth], collections keep their first 200 items, reference cycles become [Circular], and IQueryable or lazy IEnumerable values are reported by type name or ToString() instead of being enumerated.
Build paths in stack frames
Stack frames include the file paths recorded in your PDBs, which can be absolute build-machine paths that include a user name. Build with <ContinuousIntegrationBuild>true</ContinuousIntegrationBuild> (paths are recorded under the deterministic /_/ root) or a <PathMap>, and set the matching runtime root in Logister so frames still link to GitHub source.
Custom events
Use the injected client for metrics and events you choose.
public sealed class ApprovalService(LogisterClient logister)
{
public async Task RecordQueueDepthAsync(int pending)
{
await logister.CaptureMetricAsync(
"timesheet.approvals.pending",
pending,
new MetricOptions { Unit = "count" });
await logister.CaptureSpanAsync(
"approval queue db load",
42.6,
new SpanOptions
{
Kind = "db",
Status = "ok",
TraceId = "trace-123",
ParentSpanId = "span-root",
Context = new Dictionary<string, object?>
{
["queue"] = "approvals"
}
});
await logister.CheckInAsync(
"nightly-import",
"ok",
new CheckInOptions
{
Release = "worker@2026.05.21",
ExpectedIntervalSeconds = 3600,
DurationMs = 122.5,
TraceId = "trace-123",
RequestId = "req-123"
});
}
}The same client supports CaptureExceptionAsync(), CaptureMessageAsync(), CaptureMetricAsync(), CaptureTransactionAsync(), CaptureSpanAsync(), CheckInAsync(), and RecordDeploymentAsync(). Capture options support per-event environment, release, trace ID, request ID, session ID, and user ID fields; span options add span ID, parent span ID, kind, status, and start/end timestamps; check-ins also send top-level release and monitor timing metadata to match the HTTP API.
For your own queues or replay, prepare events with PrepareEvent(), PrepareException(), PrepareTransaction(), or PrepareSpan() and send them with SendPreparedEventAsync() or SendEventsAsync(). Prepared events keep their serialized context, UUID, and capture time across retries. Ingestion retries transient failures up to three times with jittered backoff (LogisterOptions.RetryPolicy), and every HTTP attempt, including check-ins and deployments, is bounded by LogisterOptions.Timeout (default 5 seconds), even when you supply your own HttpClient.
Source and deployments
Set source context once, then record each deployed commit.
If the project is connected to the GitHub App, Logister can use source context to resolve .NET stack frames to repository files. Deployment records map a release and environment to the exact commit shipped by CI/CD.
await client.RecordDeploymentAsync(new DeploymentOptions
{
Release = "timesheets@2026.06.18",
Environment = "production",
Repository = "acme/timesheets",
CommitSha = "4f8c2d1a9b7e6c5d4a3b2c1d0e9f8a7b6c5d4e3f",
Branch = "main",
DeployedAt = DateTimeOffset.UtcNow,
ReleaseTag = "v2026.06.18",
WorkflowRunUrl = "https://github.com/acme/timesheets/actions/runs/123"
});| Field | Set it from | Used for |
|---|---|---|
Repository | LOGISTER_REPOSITORY or GITHUB_REPOSITORY | Finds the GitHub repository connected to the project. |
CommitSha | LOGISTER_COMMIT_SHA or GITHUB_SHA | Resolves stack frames and deployment context to the exact commit. |
Branch | LOGISTER_BRANCH or GITHUB_REF_NAME | Falls back when an event has no commit or deployment record yet. |
Release | Your app version, build ID, tag, or package version | Connects event filters, release health, and deployments. |
Verify it
After a deploy, send one test exception with the same Release. Open the event detail and check for source lookup status, deployment context, and GitHub links. If source is missing, confirm the GitHub App is installed, linked to the project, and the repository is connected; then check that the event has repository plus either commit_sha or a matching deployment record.
Configuration
Configure with appsettings or environment variables.
{
"Logister": {
"ApiKey": "your-project-api-token",
"BaseUrl": "https://your-logister-host.example",
"Environment": "production",
"Release": "quriatime@2026.06.18",
"Repository": "acme/quriatime",
"CommitSha": "4f8c2d1a9b7e6c5d4a3b2c1d0e9f8a7b6c5d4e3f",
"Branch": "main",
"CaptureRequestTransactions": true,
"CaptureRequestSpans": true,
"CaptureRequestHeaders": true,
"CaptureRequestCookies": false,
"CaptureClientIp": false,
"TransactionSampleRate": 0.2,
"QueueCapacity": 1000,
"RedactKeys": [ "tenant_key" ],
"AllowedRequestCookieNames": [ "theme" ]
}
}Logister:BaseUrl is required. Logister:RedactKeys accepts a JSON array or a comma-separated string. The base client also reads LOGISTER_API_KEY, LOGISTER_BASE_URL (required; must be an absolute URL), LOGISTER_ALLOW_INSECURE_HTTP, LOGISTER_REDACT_KEYS (comma-separated), LOGISTER_ENVIRONMENT, LOGISTER_RELEASE, LOGISTER_REPOSITORY, LOGISTER_COMMIT_SHA, LOGISTER_BRANCH, and LOGISTER_TIMEOUT. In GitHub Actions it falls back to GITHUB_REPOSITORY, GITHUB_SHA, and GITHUB_REF_NAME when the Logister-specific source variables are not set.
Upgrading to 0.5.0
Make these changes when you move to 0.5.0.
0.5.0 of Logister and Logister.AspNetCore contains breaking changes and new privacy defaults. Work through the table, then send one test event as described in Base URL.
| Change | What to do |
|---|---|
Breaking: BaseUrl is required and has no default. LogisterOptions.BaseUrl is now Uri?. A missing or invalid value throws LogisterConfigurationException at startup. | Set LOGISTER_BASE_URL, Logister:BaseUrl, or BaseUrl in code. For the hosted app, use https://logister.org. Handle a null value in code that reads BaseUrl. |
Breaking: http:// base URLs are rejected unless the host is loopback. Base URLs with a user name or password are rejected. | Use https://, or a loopback http:// URL for local development. On a trusted internal network, set AllowInsecureHttp = true or LOGISTER_ALLOW_INSECURE_HTTP=true. Move credentials out of the URL and into ApiKey. |
Breaking: ASP.NET Core middleware no longer waits for delivery. Events go through LogisterEventQueue and the hosted LogisterDeliveryService. Both middleware constructors take a LogisterEventQueue. | Keep using AddLogister, which registers both. If you construct LogisterExceptionMiddleware or LogisterRequestTransactionMiddleware yourself, pass a LogisterEventQueue. Tune QueueCapacity and ShutdownFlushTimeout if needed. |
| Changed default: captured values are redacted with the shared Logister rules. | No action needed. Add app-specific keys with RedactKeys, Logister:RedactKeys, or LOGISTER_REDACT_KEYS. |
Changed default: cookie values are [REDACTED] unless allowlisted; RedactedCookieValue defaults to [REDACTED]. | Add cookies you want to see to AllowedRequestCookieNames. Authentication, session, and antiforgery cookies stay redacted. |
Changed default: sensitive request header values are [REDACTED]. | Add app-specific header names to SensitiveRequestHeaderNames. |
Changed default: client_ip and forwarding headers are not captured. | Set CaptureClientIp = true if you rely on them. |
Changed default: machine_name and process_id are not sent. | Set CaptureHostIdentity = true (Logister:CaptureHostIdentity) if you rely on them. |
New: TransactionSampleRate for ASP.NET Core request transactions and spans. | Optional. Defaults to 1, so every request is still reported until you lower it. |
builder.Services.AddLogister(builder.Configuration, options =>
{
// Required: set here or through Logister:BaseUrl / LOGISTER_BASE_URL.
options.Client.BaseUrl = new Uri("https://your-logister-host.example");
// Only if you relied on these fields before 0.5.0.
options.CaptureClientIp = true;
options.Client.CaptureHostIdentity = true;
options.AllowedRequestCookieNames.Add("theme");
});Troubleshooting
Match the symptom to the setting.
| Symptom | Likely cause | Check |
|---|---|---|
LogisterConfigurationException at startup | Base URL missing, not absolute, uses http:// on a non-loopback host, or contains credentials | Set LOGISTER_BASE_URL or Logister:BaseUrl to an https:// URL, or set AllowInsecureHttp for a trusted internal network. |
401 response | Wrong API key or base URL | Check the key under Project settings → API keys and confirm the base URL points at the instance that owns the project. |
| Some ASP.NET Core events missing under load | The delivery queue was full | Read LogisterEventQueue.DroppedCount and raise QueueCapacity. |
| Events missing after a deploy or restart | Shutdown flush ran out of time | Raise ShutdownFlushTimeout. |
| Only some requests show transactions | Sampling | Check TransactionSampleRate. |
Cookie values show [REDACTED] | Cookie is not allowlisted, or is an authentication, session, or antiforgery cookie | Add the name to AllowedRequestCookieNames. Authentication cookies stay redacted by design. |
No client_ip, machine_name, or process_id | These fields are opt-in | Enable CaptureClientIp or CaptureHostIdentity. |
For instance-side ingestion checks, see Troubleshooting. Report SDK problems in the logister-dotnet repository.
Follow requests between projects
Logister 3.7 adds explicit project connections and request-identifier evidence. See request correlation setup for the required SDK versions, origin allowlists, permissions, and verification.