Documentation / .NET

Integrate a .NET app with Logister.

The recommended path for ASP.NET Core projects is Logister.AspNetCore. It captures uncaught request exceptions, optional request transactions and spans, runtime metadata, structured .NET exception chains, and custom metrics you choose from your own C# services.

Before you start

Create the project with the .NET / ASP.NET Core integration type.

What you needWhy it matters
Project API tokenAuthenticates the app when sending events
Logister instance base URLRequired. The SDK has no default host and builds the ingest, check-in, and deployment endpoints from this value. See Base URL.
.NET 8+ appBoth packages target .NET 8 and .NET 10; .NET 9 apps use the .NET 8 target
Optional GitHub App installationLets 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.

NeedWhat appears in Logister
Catch uncaught request exceptionsIssues with .NET exception details, stack frames, request URL, request ID, trace ID, user ID, framework metadata, and runtime metadata.
Understand failed ASP.NET requestsA .NET-focused detail view with stack, query, optional cookies, headers, routing, runtime, inner exceptions, and exception data when captured.
Track request latencyRequest transaction events and optional request spans that power project performance and request load waterfall charts.
Monitor workers and business signalsMetrics, logs, custom transactions, spans, and check-ins from injected LogisterClient calls.
Resolve source and deploy historyRepository, 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 logsRelease, 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.

shell
dotnet add package Logister
dotnet add package Logister.AspNetCore

Package links: NuGet Logister, NuGet Logister.AspNetCore, and GitHub. For local development, forks, or unreleased SDK changes, reference the project from that repo directly.

xml
<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:

WhereSettingRead by
EnvironmentLOGISTER_BASE_URLLogisterOptions.FromEnvironment()
appsettings, user secrets, or any ASP.NET Core configuration sourceLogister:BaseUrlAddLogister(builder.Configuration)
CodeBaseUrl = 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:

shell
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:

shell
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 invalid Logister:BaseUrl throws from AddLogister and 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 set AllowInsecureHttp = true (LOGISTER_ALLOW_INSECURE_HTTP=true). Use AllowInsecureHttp only for trusted internal networks.
  • It must not contain a user name or password. Send the project API key through ApiKey instead.
csharp
// 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:

csharp
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.

csharp
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.

OptionDefaultWhat it does
QueueCapacity1,000Maximum queued events. When the queue is full, new events are dropped and counted in LogisterEventQueue.DroppedCount.
ShutdownFlushTimeout5 secondsHow long the delivery service keeps sending queued events when the host stops.
TransactionSampleRate1Fraction (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, or cvv, or contains token, secret, password, passwd, apikey, authorization, credential, or cookie. Its value becomes [REDACTED].
  • Sensitive values. Strings are scrubbed for Bearer … and Basic … 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:

csharp
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

OptionBehavior
CaptureRequestHeadersRecords 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.
SensitiveRequestHeaderNamesExtra header names whose values are redacted.
CaptureRequestCookiesOff by default. When enabled, records cookie names. Every value is redacted unless the name is in AllowedRequestCookieNames.
AllowedRequestCookieNamesCookie 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.
SensitiveRequestCookieNamesCookie names that always stay redacted, including their chunks. Add your own authentication cookie names here.
RedactedCookieValueReplacement text for redacted cookie values. Defaults to [REDACTED].
csharp
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

OptionDefaultWhen enabled
CaptureClientIp (Logister:CaptureClientIp)falseCaptures client_ip and forwarding headers such as X-Forwarded-For, Forwarded, X-Real-IP, and CF-Connecting-IP.
LogisterOptions.CaptureHostIdentity (Logister:CaptureHostIdentity)falseSends machine_name and process_id.
CaptureExceptionDatatrueSends 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.

csharp
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.

csharp
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"
});
FieldSet it fromUsed for
RepositoryLOGISTER_REPOSITORY or GITHUB_REPOSITORYFinds the GitHub repository connected to the project.
CommitShaLOGISTER_COMMIT_SHA or GITHUB_SHAResolves stack frames and deployment context to the exact commit.
BranchLOGISTER_BRANCH or GITHUB_REF_NAMEFalls back when an event has no commit or deployment record yet.
ReleaseYour app version, build ID, tag, or package versionConnects 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.

json
{
  "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.

ChangeWhat 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.
csharp
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.

SymptomLikely causeCheck
LogisterConfigurationException at startupBase URL missing, not absolute, uses http:// on a non-loopback host, or contains credentialsSet LOGISTER_BASE_URL or Logister:BaseUrl to an https:// URL, or set AllowInsecureHttp for a trusted internal network.
401 responseWrong API key or base URLCheck 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 loadThe delivery queue was fullRead LogisterEventQueue.DroppedCount and raise QueueCapacity.
Events missing after a deploy or restartShutdown flush ran out of timeRaise ShutdownFlushTimeout.
Only some requests show transactionsSamplingCheck TransactionSampleRate.
Cookie values show [REDACTED]Cookie is not allowlisted, or is an authentication, session, or antiforgery cookieAdd the name to AllowedRequestCookieNames. Authentication cookies stay redacted by design.
No client_ip, machine_name, or process_idThese fields are opt-inEnable 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.